空运群超时找不到航线成员时写成了「相关人员」。改为 @ 航线同事;销售超时只 @ 本单销售。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-09 00:50:47 +08:00
co-authored by Cursor
parent 2aab38da99
commit 2e8918a5c9
3 changed files with 269 additions and 10 deletions
+158
View File
@@ -20,6 +20,7 @@ from agent.policy.event_exception import (
WAIT_PRODUCT_QUOTE,
conversation_of,
format_timeout_hours,
mentions_for_role,
pick_app_targets,
pick_mentions,
timeout_code,
@@ -270,6 +271,163 @@ class TestPoll(unittest.TestCase):
)
self.assertEqual(n2, 0)
def test_air_group_names_airline_when_members_missing(self) -> None:
"""空运群没记下成员时,超时要 @ 航线姓名,不能写成相关人员。"""
import importlib.util
from datetime import datetime, timedelta
from agent.ledger.memory_ledger import MemoryLedger
from agent.policy.deal_followup import SHANGHAI
path = os.path.join(ROOT, "agent", "jobs", "event_exception_poll.py")
spec = importlib.util.spec_from_file_location("ee_poll_air", path)
self.assertIsNotNone(spec)
self.assertIsNotNone(spec.loader)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
book = MemoryLedger()
book.set_sea_staff(
[
{
"wecomId": "sales1",
"name": "罗小华",
"roleCode": "sales",
"status": "active",
},
{
"wecomId": "air1",
"name": "吴季林",
"roleCode": "air",
"status": "active",
},
]
)
created = book.create_ticket(sender_id="sales1", business_line="AIR", facts={"起运港": "南京"})
wo = created["work_order_no"]
book.start_event_wait(work_order_no=wo, wait_kind="air_quote")
ticket = book.get_ticket(work_order_no=wo)
ticket.collab_chat_id = "wr-air"
ticket.collab_member_ids = []
ticket.event_wait_started_at = (datetime.now(SHANGHAI) - timedelta(hours=3)).strftime(
"%Y-%m-%d %H:%M:%S"
)
book._timeouts["air_route"] = 0.25
groups: list[dict] = []
def send_group(*, chat_id: str, content: str, business_line: str = "") -> bool:
groups.append({"chat_id": chat_id, "content": content, "line": business_line})
return True
n = mod.poll_event_exceptions(
ledger=book,
now=datetime.now(SHANGHAI),
send_group=send_group,
notify_ready=False,
)
self.assertEqual(n, 1)
self.assertEqual(len(groups), 1)
self.assertEqual(
groups[0]["content"],
f"航线响应超时\n关联询价工单 {wo}。@吴季林已超过 0.25 工作小时 无响应,事件异常已记录工单,请及时处理。",
)
self.assertNotIn("相关人员", groups[0]["content"])
def test_sales_timeout_mentions_sales_not_airline(self) -> None:
"""销售超时只 @ 本单销售。私聊也带 @,不点航线,不写相关人员。"""
import importlib.util
from datetime import datetime, timedelta
from agent.ledger.memory_ledger import MemoryLedger
from agent.policy.deal_followup import SHANGHAI
path = os.path.join(ROOT, "agent", "jobs", "event_exception_poll.py")
spec = importlib.util.spec_from_file_location("ee_poll_sales", path)
self.assertIsNotNone(spec)
self.assertIsNotNone(spec.loader)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
book = MemoryLedger()
book.set_sea_staff(
[
{"wecomId": "sales1", "name": "罗小华", "roleCode": "sales", "status": "active"},
{"wecomId": "air1", "name": "吴季林", "roleCode": "air", "status": "active"},
]
)
created = book.create_ticket(sender_id="sales1", business_line="AIR", facts={})
wo = created["work_order_no"]
book.start_event_wait(work_order_no=wo, wait_kind="adopt")
ticket = book.get_ticket(work_order_no=wo)
ticket.event_wait_started_at = (datetime.now(SHANGHAI) - timedelta(hours=3)).strftime(
"%Y-%m-%d %H:%M:%S"
)
book._timeouts["air_sales"] = 0.25
private: list[dict] = []
def enqueue(**kwargs):
private.append(kwargs)
return True, ""
def send_group(**kwargs) -> bool:
raise AssertionError("销售采用超时不应发到群")
n = mod.poll_event_exceptions(
ledger=book,
now=datetime.now(SHANGHAI),
enqueue=enqueue,
send_group=send_group,
notify_ready=False,
)
self.assertEqual(n, 1)
self.assertEqual(len(private), 1)
self.assertEqual(
private[0]["content"],
f"销售响应超时\n关联询价工单 {wo}。@罗小华已超过 0.25 工作小时 无响应,事件异常已记录工单,请及时处理。",
)
self.assertNotIn("吴季林", private[0]["content"])
self.assertNotIn("相关人员", private[0]["content"])
created_deal = book.create_ticket(sender_id="sales1", business_line="AIR", facts={"目的港": "胡志明"})
deal_no = created_deal["work_order_no"]
book.start_event_wait(work_order_no=deal_no, wait_kind="deal")
deal = book.get_ticket(work_order_no=deal_no)
deal.collab_chat_id = "wr-air"
deal.event_wait_started_at = ticket.event_wait_started_at
groups: list[dict] = []
def send_deal_group(*, chat_id: str, content: str, business_line: str = "") -> bool:
groups.append({"chat_id": chat_id, "content": content})
return True
n_deal = mod.poll_event_exceptions(
ledger=book,
now=datetime.now(SHANGHAI),
enqueue=enqueue,
send_group=send_deal_group,
notify_ready=False,
)
self.assertEqual(n_deal, 1)
self.assertEqual(
groups[0]["content"],
f"销售响应超时\n关联询价工单 {deal_no}。@罗小华已超过 0.25 工作小时 无响应,事件异常已记录工单,请及时处理。",
)
self.assertNotIn("吴季林", groups[0]["content"])
class TestMentionsForRole(unittest.TestCase):
def test_keeps_active_named_role_only(self) -> None:
rows = mentions_for_role(
[
{"wecomId": "a1", "name": "吴季林", "roleCode": "air", "status": "active"},
{"wecomId": "s1", "name": "罗小华", "roleCode": "sales", "status": "active"},
{"wecomId": "a2", "name": "停用航线", "roleCode": "air", "status": "disabled"},
{"wecomId": "a3", "name": "", "roleCode": "air", "status": "active"},
],
role_code="air",
)
self.assertEqual([row["name"] for row in rows], ["吴季林"])
if __name__ == "__main__":
unittest.main()