assertSame('虚假交易', StoreViolationAlertCalculator::cleanViolationType('虚假交易(立即删除销量;)')); $this->assertSame('AE', StoreViolationAlertCalculator::cleanViolationType('A(B(C)D)E(F)')); $this->assertSame('订单存在揽收超时行为', StoreViolationAlertCalculator::cleanViolationType(' 订单存在揽收超时行为 ')); $this->assertSame('', StoreViolationAlertCalculator::cleanViolationType(null)); } public function test_match_rule_uses_exact_prefix_parts_and_keywords_in_order(): void { $rules = [ ['id' => 1, 'platform' => 'jd', 'violation_type' => '缺货/无货', 'match_keywords' => null, 'alert_level' => 'P1', 'needs_alert' => 1, 'suggested_action' => '联系客户补发', 'handling_hours' => null], ['id' => 2, 'platform' => 'jingxi', 'violation_type' => '订单延迟发货', 'match_keywords' => null, 'alert_level' => 'P0', 'needs_alert' => 1, 'suggested_action' => null, 'handling_hours' => null], ['id' => 3, 'platform' => 'taobao', 'violation_type' => null, 'match_keywords' => '虚假交易|危及交易安全', 'alert_level' => 'P2', 'needs_alert' => 1, 'suggested_action' => null, 'handling_hours' => null], ['id' => 4, 'platform' => 'douyin', 'violation_type' => '效果虚假', 'match_keywords' => null, 'alert_level' => null, 'needs_alert' => 0, 'suggested_action' => null, 'handling_hours' => null], ]; // 分词包含:规则"缺货/无货"命中"延迟发货/缺货无货" $this->assertSame(1, StoreViolationAlertCalculator::matchRule($rules, 'jd', '延迟发货/缺货无货')['id']); // 相等与前缀 $this->assertSame(2, StoreViolationAlertCalculator::matchRule($rules, 'jingxi', '订单延迟发货')['id']); $this->assertSame(2, StoreViolationAlertCalculator::matchRule($rules, 'jingxi', '订单延迟发货(立即扣分;)')['id']); // 关键词匹配(先去括号) $this->assertSame(3, StoreViolationAlertCalculator::matchRule($rules, 'taobao', '虚假交易(立即删除销量&屏蔽评论内容;)')['id']); // 命中但规则标记为不需要提醒 $this->assertSame(4, StoreViolationAlertCalculator::matchRule($rules, 'douyin', '效果虚假')['id']); // 平台隔离与未命中 $this->assertNull(StoreViolationAlertCalculator::matchRule($rules, 'jd', '效果虚假')); $this->assertNull(StoreViolationAlertCalculator::matchRule($rules, 'pinduoduo', '任意类型')); $this->assertNull(StoreViolationAlertCalculator::matchRule($rules, 'jd', null)); } public function test_deadline_prefers_appeal_date_then_hours_then_level_days(): void { // 申诉截止非空 → 当天 23:59:59 $this->assertSame( '2026-10-11 23:59:59', StoreViolationAlertCalculator::deadlineFor('2026-10-04', '2026-10-11', null, 'P1'), ); // 字典时效(小时) $this->assertSame( '2026-10-04 06:00:00', StoreViolationAlertCalculator::deadlineFor('2026-10-04', null, 6, 'P0'), ); // 级别默认天数:P0+1 / P1+2 / P2+3 天的 23:59:59 $this->assertSame('2026-10-05 23:59:59', StoreViolationAlertCalculator::deadlineFor('2026-10-04', null, null, 'P0')); $this->assertSame('2026-10-06 23:59:59', StoreViolationAlertCalculator::deadlineFor('2026-10-04', null, null, 'P1')); $this->assertSame('2026-10-07 23:59:59', StoreViolationAlertCalculator::deadlineFor('2026-10-04', null, null, 'P2')); // 无违规日期或无级别 → null $this->assertNull(StoreViolationAlertCalculator::deadlineFor(null, null, null, 'P0')); $this->assertNull(StoreViolationAlertCalculator::deadlineFor('2026-10-04', null, null, null)); } public function test_is_overdue_respects_status_and_deadline(): void { $now = Carbon::parse('2026-10-05 10:00:00'); $this->assertTrue(StoreViolationAlertCalculator::isOverdue('未处理', '2026-10-04 23:59:59', $now)); $this->assertTrue(StoreViolationAlertCalculator::isOverdue('处理中', '2026-10-05 09:00:00', $now)); $this->assertFalse(StoreViolationAlertCalculator::isOverdue('处理完成', '2020-01-01 00:00:00', $now)); $this->assertFalse(StoreViolationAlertCalculator::isOverdue('已忽略', '2020-01-01 00:00:00', $now)); $this->assertFalse(StoreViolationAlertCalculator::isOverdue('未处理', null, $now)); $this->assertFalse(StoreViolationAlertCalculator::isOverdue('未处理', '2026-10-06 23:59:59', $now)); } }