assertSame(['mode' => Rule::MODE_NONE, 'effective_from' => null, 'effective_to' => null], Rule::parseRuleText('不记账')); $this->assertSame(Rule::MODE_NORMAL, Rule::parseRuleText('正常记账')['mode']); $this->assertSame(Rule::MODE_DROPSHIP_WRONG, Rule::parseRuleText('代发仓发货错需记账,其他原因均不记账')['mode']); $this->assertSame(Rule::MODE_DROPSHIP_WRONG, Rule::parseRuleText('厂家暂未出货,后期若建立代发仓,发货错需记账,其他原因均不记账')['mode']); $this->assertSame(['mode' => Rule::MODE_NONE, 'effective_from' => '2025-03-01', 'effective_to' => '2026-02-28'], Rule::parseRuleText('不记账(2025.3月-2026.2月)')); $this->assertSame(['mode' => Rule::MODE_NONE, 'effective_from' => '2025-03-01', 'effective_to' => '2027-12-30'], Rule::parseRuleText('不记账(2025.3月-2027.12.30)')); $this->assertSame(Rule::MODE_DROPSHIP_WRONG, Rule::parseRuleText('仅代发仓发错货记账')['mode']); } public function test_rejects_unknown_rule_text(): void { $this->expectException(InvalidArgumentException::class); Rule::parseRuleText('看情况'); } private function row(array $patch = []): array { return array_replace([ 'started_at' => '2026-09-05 10:00:00', 'reason_level_1' => '厂家记账', 'reason_level_2' => '孔位错误', 'shipping_warehouse' => '常州主仓', 'supplier' => '甲厂', ], $patch); } private function configs(): array { return [ '甲厂' => ['mode' => Rule::MODE_NORMAL, 'effective_from' => null, 'effective_to' => null], '乙厂' => ['mode' => Rule::MODE_DROPSHIP_WRONG, 'effective_from' => null, 'effective_to' => null], '丙厂' => ['mode' => Rule::MODE_NONE, 'effective_from' => null, 'effective_to' => null], '丁厂' => ['mode' => Rule::MODE_NONE, 'effective_from' => '2025-03-01', 'effective_to' => '2026-02-28'], ]; } private function judge(array $patch): string { return Rule::decide($this->row($patch), $this->configs())['deduction_status']; } public function test_supplier_reasons_follow_supplier_config(): void { $this->assertSame(Rule::STATUS_DEDUCT, $this->judge([])); $this->assertSame(Rule::STATUS_SKIP, $this->judge(['supplier' => '乙厂'])); $this->assertSame(Rule::STATUS_SKIP, $this->judge(['supplier' => '丙厂'])); // 配置表中没有的供应商视同正常记账,可扣款。 $this->assertSame(Rule::STATUS_DEDUCT, $this->judge(['supplier' => '未知厂'])); $this->assertSame(Rule::STATUS_REVIEW, $this->judge(['supplier' => ''])); // 限期不记账:期外视同不在配置表,可扣款。 $this->assertSame(Rule::STATUS_DEDUCT, $this->judge(['supplier' => '丁厂'])); $this->assertSame(Rule::STATUS_SKIP, $this->judge(['supplier' => '丁厂', 'started_at' => '2026-02-28 23:00:00'])); } public function test_warehouse_reasons_only_deduct_dropship_wrong_shipment(): void { $wrong = ['reason_level_1' => '仓库记账', 'reason_level_2' => '仓库发错货(面单照片,实物照片,条形码照片)', 'shipping_warehouse' => '曹县洪耀代发仓']; $this->assertSame(Rule::STATUS_DEDUCT, $this->judge($wrong + ['supplier' => '乙厂'])); $this->assertSame(Rule::STATUS_DEDUCT, $this->judge($wrong)); $this->assertSame(Rule::STATUS_SKIP, $this->judge($wrong + ['supplier' => '丙厂'])); $this->assertSame(Rule::STATUS_DEDUCT, $this->judge($wrong + ['supplier' => '未知厂'])); // 非代发仓、或代发仓的其他仓库记账原因:一律不作为厂家扣款项,无需配置。 $this->assertSame(Rule::STATUS_SKIP, $this->judge(['shipping_warehouse' => '常州主仓'] + $wrong + ['supplier' => '乙厂'])); $this->assertSame(Rule::STATUS_SKIP, $this->judge(['reason_level_2' => '仓库双面单'] + $wrong + ['supplier' => '乙厂'])); $this->assertSame(Rule::STATUS_SKIP, $this->judge(['reason_level_2' => '退货运费'] + $wrong + ['supplier' => '未知厂'])); } public function test_multiple_suppliers_need_review_when_outcomes_differ(): void { $this->assertSame(Rule::STATUS_DEDUCT, $this->judge(['supplier' => "甲厂\n甲厂"])); $result = Rule::decide($this->row(['supplier' => "甲厂\n丙厂"]), $this->configs()); $this->assertSame(Rule::STATUS_REVIEW, $result['deduction_status']); $this->assertStringContainsString('甲厂:扣款', $result['deduction_basis']); $this->assertSame("正常记账\n不记账", $result['supplier_config']); } }