""" 成交跟进:工作日顺延、线路对负责人、未成交收下原因(不打外网)。 """ from __future__ import annotations import unittest from datetime import date, datetime from zoneinfo import ZoneInfo from agent.policy.deal_followup import ( SHANGHAI, air_route_keys, leader_matches, next_followup_at, shift_workdays, ) class TestWorkdays(unittest.TestCase): def test_skip_weekend(self) -> None: # 2026-09-18 周五,顺延 3 个工作日 → 21、22、23,第四个工作日 24 self.assertEqual(shift_workdays(date(2026, 9, 18), 3), date(2026, 9, 23)) self.assertEqual(shift_workdays(date(2026, 9, 18), 4), date(2026, 9, 24)) def test_skip_national_day(self) -> None: # 2026-09-30 周三,国庆休 → 第四个工作日落到节后 fourth = shift_workdays(date(2026, 9, 30), 4) self.assertGreaterEqual(fourth, date(2026, 10, 9)) self.assertNotEqual(fourth.weekday(), 5) self.assertNotEqual(fourth.weekday(), 6) def test_next_followup_is_9am(self) -> None: when = next_followup_at(datetime(2026, 9, 18, 15, 30, tzinfo=SHANGHAI)) self.assertEqual(when.hour, 9) self.assertEqual(when.minute, 0) self.assertEqual(when.tzinfo, SHANGHAI) self.assertEqual(when.date(), date(2026, 9, 24)) class TestAirRouteKeys(unittest.TestCase): def test_pair_and_dest(self) -> None: keys = air_route_keys({"起运港": "SZX", "目的港": "KUL"}) self.assertIn("SZX-KUL", keys) self.assertIn("KUL", keys) def test_chinese_city_projects_iata(self) -> None: keys = air_route_keys({"起运港": "深圳", "目的港": "吉隆坡"}) self.assertIn("SZX-KUL", keys) self.assertIn("KUL", keys) class TestLeaderMatch(unittest.TestCase): def test_sea_all_line(self) -> None: self.assertTrue( leader_matches( role_code="sea", routes="海运全线", is_leader=True, business_line="SEA", facts={}, ) ) self.assertFalse( leader_matches( role_code="sea", routes="海运全线", is_leader=False, business_line="SEA", facts={}, ) ) def test_land_route_category(self) -> None: self.assertTrue( leader_matches( role_code="land", routes="国内长途/零担,东南亚", is_leader=True, business_line="LAND", facts={"线路类别": "国内长途/零担"}, ) ) self.assertFalse( leader_matches( role_code="land", routes="东南亚", is_leader=True, business_line="LAND", facts={"线路类别": "国内长途/零担"}, ) ) def test_air_pair_dest_and_all(self) -> None: facts = {"起运港": "SZX", "目的港": "KUL"} self.assertTrue( leader_matches( role_code="air", routes="SZX-KUL", is_leader=True, business_line="AIR", facts=facts, ) ) self.assertTrue( leader_matches( role_code="air", routes="KUL", is_leader=True, business_line="AIR", facts=facts, ) ) self.assertTrue( leader_matches( role_code="air", routes="全线", is_leader=True, business_line="AIR", facts=facts, ) ) self.assertFalse( leader_matches( role_code="air", routes="外采-空运", is_leader=True, business_line="AIR", facts=facts, ) ) self.assertTrue( leader_matches( role_code="air", routes="外采-空运", is_leader=True, business_line="AIR", facts={**facts, "外采": "1"}, ) ) if __name__ == "__main__": unittest.main()