角色业务范围收紧工单与模板;报价日期不当费用;未选舱不迁已报价;另开一票可清违禁 hold

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-10-15 21:00:01 +08:00
co-authored by Cursor
parent a0c705683f
commit 277cdc1c28
39 changed files with 2083 additions and 217 deletions
+47 -11
View File
@@ -32,6 +32,20 @@ logger = logging.getLogger(__name__)
ReplyFn = Callable[..., Optional[str]]
def _ledger_quote_pending_cabin(quote: dict[str, Any]) -> dict[str, Any]:
"""
未选舱前写主账用的薄快照:保留 airOptions 供恢复,清空总价/费用明细,
并打 pending_cabin_pick,避免后台把备选舱位当成已报价。
"""
out = dict(quote or {})
out["pending_cabin_pick"] = "1"
out["fee_lines"] = []
out["total"] = ""
out.pop("selected_air_option", None)
out.pop("selectedAirOption", None)
return out
@dataclass
class FlowSession:
"""一单会话书签(运行账,不是六态真相)。"""
@@ -334,10 +348,11 @@ class AirTextInquiryFlow:
number = (sess.work_order_no or "").strip()
if number and not is_virtual_no(number):
return None
hold_before = str(getattr(sess, "sensitive_hold", "") or "") if sess else ""
blocked, new_hold, _edits = judge(
text=text,
facts=facts,
hold=str(getattr(sess, "sensitive_hold", "") or "") if sess else "",
hold=hold_before,
)
if sess is not None:
sess.sensitive_hold = new_hold
@@ -1379,19 +1394,23 @@ class AirTextInquiryFlow:
options = parse_air_options(quote)
# 没填报价日期:不按起运地收口,TMS 返回的舱位全部给销售点。1 条也要点。
# 未选定前六态保持询价中,禁止把备选舱位费写进后台「已报价」。
if not str((sess.facts or {}).get("报价日期") or "").strip() and options:
quote = dict(quote)
quote["airOptions"] = sort_cabin_options(options)
up = self._ledger.upsert_quote(work_order_no=no, quote=quote, to_status="已报价")
ledger_quote = _ledger_quote_pending_cabin(quote)
up = self._ledger.upsert_quote(
work_order_no=no, quote=ledger_quote, to_status="询价中"
)
if not up.get("ok"):
reply("主账写入报价失败,不能当作已报价。")
reply("主账写入舱位备选失败,请稍后重试。")
sess.phase = "ledger_fail"
self._save(sess)
return "ledger_fail"
sess.quote = quote
copy.remember_tms_quote(sess, quote)
sess.tms_quote = dict(quote)
sess.status = "已报价"
sess.status = "询价中"
return self._offer_air_routes(
sess=sess,
work_order_no=no,
@@ -1402,6 +1421,9 @@ class AirTextInquiryFlow:
stated_origin = str(
(sess.facts or {}).get("起运港") or (sess.facts or {}).get("起运地") or ""
).strip()
# 摘要占位「-」等于没写起运地,禁止当地名过滤舱位。
if stated_origin in {"-", "—", "-"}:
stated_origin = ""
# 写了起运地:只认这个起运地的线路,直接报价,不让销售再选。
# 没写起运地:TMS 按目的地回多条时,才进选线页。
if stated_origin:
@@ -1425,6 +1447,27 @@ class AirTextInquiryFlow:
)
elif options and not needs_route_pick(quote):
quote = project_selected_quote(quote, options[0])
# 仍要选线:未选定前只落备选快照,六态保持询价中。
if not stated_origin and needs_route_pick(quote):
ledger_quote = _ledger_quote_pending_cabin(quote)
up = self._ledger.upsert_quote(
work_order_no=no, quote=ledger_quote, to_status="询价中"
)
if not up.get("ok"):
reply("主账写入线路备选失败,请稍后重试。")
sess.phase = "ledger_fail"
self._save(sess)
return "ledger_fail"
sess.quote = quote
copy.remember_tms_quote(sess, quote)
sess.tms_quote = dict(quote)
sess.status = "询价中"
return self._offer_air_routes(
sess=sess,
work_order_no=no,
quote=quote,
reply=reply,
)
up = self._ledger.upsert_quote(work_order_no=no, quote=quote, to_status="已报价")
if not up.get("ok"):
reply("主账写入报价失败,不能当作已报价。")
@@ -1435,13 +1478,6 @@ class AirTextInquiryFlow:
copy.remember_tms_quote(sess, quote)
sess.tms_quote = dict(quote)
sess.status = "已报价"
if not stated_origin and needs_route_pick(quote):
return self._offer_air_routes(
sess=sess,
work_order_no=no,
quote=quote,
reply=reply,
)
sess.phase = "wait_collab"
sess.allowed = (copy.BTN_SKIP_COLLAB,)
sess.wait_version += 1