空运附件报价锁舱前先提示航线改发纯文字报价,避免附件金额拆不出导致锁舱失败。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -699,6 +699,9 @@ def apply_air_file(
|
|||||||
from agent.policy.event_exception import clear_wait
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
clear_wait(flow.ledger, work_order_no=no)
|
clear_wait(flow.ledger, work_order_no=no)
|
||||||
|
# 附件不拆金额:锁舱常失败。产品口径改为提示航线改发纯文字报价后再锁。
|
||||||
|
tip = copy.air_attachment_quote_lock_tip(work_order_no=no)
|
||||||
|
send_group_text(client, chat_id, tip)
|
||||||
emit_group_deal(flow=flow, ticket=view, quote=quote)
|
emit_group_deal(flow=flow, ticket=view, quote=quote)
|
||||||
return "airline_file_quote"
|
return "airline_file_quote"
|
||||||
|
|
||||||
@@ -952,7 +955,8 @@ def apply_air_lock(
|
|||||||
return "no_quote"
|
return "no_quote"
|
||||||
# 主账在出站前发现三项不齐:只请补,不当 TMS 故障,不通知 IT。
|
# 主账在出站前发现三项不齐:只请补,不当 TMS 故障,不通知 IT。
|
||||||
reason_text = str(out.get("failReason") or "")
|
reason_text = str(out.get("failReason") or "")
|
||||||
if str(out.get("error") or "") == "lock_params_incomplete" or "锁舱参数不完整" in reason_text:
|
err_code = str(out.get("error") or "")
|
||||||
|
if err_code == "lock_params_incomplete" or "锁舱参数不完整" in reason_text:
|
||||||
labels = missing or _labels_from_incomplete_reason(reason_text)
|
labels = missing or _labels_from_incomplete_reason(reason_text)
|
||||||
_remember_partial_lock(
|
_remember_partial_lock(
|
||||||
flow,
|
flow,
|
||||||
@@ -964,8 +968,45 @@ def apply_air_lock(
|
|||||||
)
|
)
|
||||||
send_group_text(group_client_of(flow), chat_id, copy.air_lock_need_params(labels))
|
send_group_text(group_client_of(flow), chat_id, copy.air_lock_need_params(labels))
|
||||||
return "wait_lock_params"
|
return "wait_lock_params"
|
||||||
|
# 附件/手工报价、运价库无舱位:引导纯文字报价,不算系统异常、不通知 IT。
|
||||||
|
src_label = str((quote or {}).get("source_label") or (quote or {}).get("source") or "")
|
||||||
|
need_text_quote = (
|
||||||
|
err_code in {"lock_incomplete", "lock_fail"}
|
||||||
|
and (
|
||||||
|
"航线附件报价" in src_label
|
||||||
|
or "附件" in src_label
|
||||||
|
or any(
|
||||||
|
x in reason_text
|
||||||
|
for x in (
|
||||||
|
"手工报价",
|
||||||
|
"无匹配舱位",
|
||||||
|
"无匹配报价",
|
||||||
|
"运价库无匹配",
|
||||||
|
"标准运价库无匹配",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if need_text_quote:
|
||||||
|
send_group_text(
|
||||||
|
group_client_of(flow),
|
||||||
|
chat_id,
|
||||||
|
copy.air_lock_need_text_quote(
|
||||||
|
work_order_no=no, operator=name, reason=reason_text
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return "need_text_quote"
|
||||||
|
if err_code == "lock_incomplete":
|
||||||
|
send_group_text(
|
||||||
|
group_client_of(flow),
|
||||||
|
chat_id,
|
||||||
|
copy.air_lock_incomplete(
|
||||||
|
work_order_no=no, operator=name, reason=reason_text
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return "lock_incomplete"
|
||||||
# 多段是产品限制,不是 TMS 故障。只回原因,不标系统异常、不暂停工单。
|
# 多段是产品限制,不是 TMS 故障。只回原因,不标系统异常、不暂停工单。
|
||||||
if str(out.get("error") or "") == "multi_no_lock":
|
if err_code == "multi_no_lock":
|
||||||
send_group_text(
|
send_group_text(
|
||||||
group_client_of(flow),
|
group_client_of(flow),
|
||||||
chat_id,
|
chat_id,
|
||||||
|
|||||||
@@ -3273,13 +3273,72 @@ def air_lock_fail(*, work_order_no: str, operator: str, reason: str) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def air_text_quote_for_lock_example(work_order_no: str = "") -> str:
|
||||||
|
"""
|
||||||
|
需要锁舱时,请航线用纯文字报价的示例句。
|
||||||
|
|
||||||
|
附件报价不拆金额、常锁不成;产品口径改为引导航线改发文字价。
|
||||||
|
"""
|
||||||
|
no = (work_order_no or "").strip() or "工单号"
|
||||||
|
return f"{no},空运段,空运费 单价CNY99.00,数量100 ,金额CNY9900.00@询价小助手"
|
||||||
|
|
||||||
|
|
||||||
|
def air_attachment_quote_lock_tip(*, work_order_no: str) -> str:
|
||||||
|
"""
|
||||||
|
航线刚发完 Excel/PDF 附件报价后的提示。
|
||||||
|
|
||||||
|
附件只存档、不拆费用;若还要锁舱,必须再发一版纯文字报价。
|
||||||
|
"""
|
||||||
|
no = (work_order_no or "").strip() or "WO"
|
||||||
|
example = air_text_quote_for_lock_example(no)
|
||||||
|
return (
|
||||||
|
f"工单{no}附件报价已收。\n"
|
||||||
|
"如需锁舱,请航线人员改用纯文字报价(不要只发附件),例如:\n"
|
||||||
|
f"{example}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def air_lock_need_text_quote(*, work_order_no: str, operator: str = "", reason: str = "") -> str:
|
||||||
|
"""
|
||||||
|
附件/手工报价锁舱走不通时:引导航线先发文字报价,不算系统异常、不通知 IT。
|
||||||
|
|
||||||
|
故意不回主账/TMS 原文「原因」(如 AIR-OPT / 运价库无匹配),只留文字报价指引。
|
||||||
|
reason 参数保留兼容旧调用,出站话术不用。
|
||||||
|
"""
|
||||||
|
_ = reason
|
||||||
|
no = (work_order_no or "").strip() or "WO"
|
||||||
|
who = (operator or "").strip()
|
||||||
|
lines = [f"工单{no} 还不能锁舱。"]
|
||||||
|
if who:
|
||||||
|
lines.append(f"操作人:{who}")
|
||||||
|
lines.append("如需锁舱,请航线人员先发纯文字报价,例如:")
|
||||||
|
lines.append(air_text_quote_for_lock_example(no))
|
||||||
|
lines.append("文字报价写入后再发锁舱口令(可带舱位、航司、航班号)。")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
def air_lock_incomplete(*, work_order_no: str, operator: str, reason: str = "") -> str:
|
def air_lock_incomplete(*, work_order_no: str, operator: str, reason: str = "") -> str:
|
||||||
"""
|
"""
|
||||||
锁舱参数不齐(纯手工价、运价库无舱位等):业务补问,不算系统异常,不惊动 IT。
|
锁舱参数不齐(纯手工价、运价库无舱位等):业务补问,不算系统异常,不惊动 IT。
|
||||||
|
|
||||||
航线按示例回舱位+航司+航班后即可再锁。
|
附件/无舱位场景改引导纯文字报价;有 TMS 舱位时仍可补 AIR-OPT 三项。
|
||||||
"""
|
"""
|
||||||
why = (reason or "").strip()
|
why = (reason or "").strip()
|
||||||
|
blob = why
|
||||||
|
if any(
|
||||||
|
x in blob
|
||||||
|
for x in (
|
||||||
|
"手工报价",
|
||||||
|
"附件",
|
||||||
|
"无匹配舱位",
|
||||||
|
"无匹配报价",
|
||||||
|
"运价库无匹配",
|
||||||
|
"标准运价库无匹配",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
return air_lock_need_text_quote(
|
||||||
|
work_order_no=work_order_no, operator=operator, reason=why
|
||||||
|
)
|
||||||
lines = [
|
lines = [
|
||||||
f"工单{work_order_no} 还不能锁舱。",
|
f"工单{work_order_no} 还不能锁舱。",
|
||||||
f"操作人:{operator}",
|
f"操作人:{operator}",
|
||||||
|
|||||||
@@ -1476,6 +1476,8 @@ class AirGroupCollabTests(unittest.TestCase):
|
|||||||
self.assertEqual(ticket.quote.get("quoteId"), "QT-AIR-1")
|
self.assertEqual(ticket.quote.get("quoteId"), "QT-AIR-1")
|
||||||
self.assertEqual(ticket.status, "已报价")
|
self.assertEqual(ticket.status, "已报价")
|
||||||
self.assertTrue(any(f"工单{wo}的1个附件已保存到后台工单" in t for t in self._texts()))
|
self.assertTrue(any(f"工单{wo}的1个附件已保存到后台工单" in t for t in self._texts()))
|
||||||
|
self.assertTrue(any("如需锁舱,请航线人员改用纯文字报价" in t for t in self._texts()))
|
||||||
|
self.assertTrue(any("空运费 单价CNY99.00" in t for t in self._texts()))
|
||||||
self.assertTrue(any("报价单已发送,请确认成交状态" in t for t in self._texts()))
|
self.assertTrue(any("报价单已发送,请确认成交状态" in t for t in self._texts()))
|
||||||
|
|
||||||
def test_reactivate_after_airline_file_is_deal_not_blank_sheet(self) -> None:
|
def test_reactivate_after_airline_file_is_deal_not_blank_sheet(self) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user