空运未填报价日期时不默认当天,查出舱位后由销售点选再写回日期。

包装类型里的托盘不再被抄进增值服务。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-13 18:35:52 +08:00
co-authored by Cursor
parent dda210c219
commit 7ef4a1b1cf
21 changed files with 1068 additions and 58 deletions
+49 -6
View File
@@ -1,7 +1,9 @@
"""
空运文字询价确定性流程(模型只负责抽字段,本文件只编排与执行)。
本文件职责:补问到必填齐 → 核对确定后建单 → 查 TMS(一条出卡,多条 H5 选线路)。
本文件职责:补问到必填齐 → 核对确定后建单 → 查 TMS。
说了报价日期:一条直接出卡,没写起运地且多条才进选线路。
没说报价日期:不填当天,查价不带日期,返回的舱位全部进 H5(1 条也要点),选定后不再查价。
对不上机场也不能跳过查价、本地说暂无报价。
调用:handler 在 Worker/inbox 线程;禁止回调线程同步跑。
禁止:直连 TMS;用图状态冒充主账成功;用户文字冒充文件已生成。
@@ -971,6 +973,8 @@ class AirTextInquiryFlow:
# 让本句按新询价走,避免正文里的「确认」误伤。
sess = self._detach_ticketed_for_new_inquiry(sess)
added_source = text
prev_added = ""
snap = extract_inquiry_snapshot(
text,
injected_facts=injected_facts,
@@ -994,19 +998,26 @@ class AirTextInquiryFlow:
facts = dict(snap.get("facts") or {})
if sess and sess.phase in {"clarify", "need_mode", "wait_confirm"}:
# 补问轮:旧字段打底;运输方式沿用上一句(飞=空运)
# 增值服务按句累加,本句没提时不能把上一句已记下的服务冲掉。
from agent.llm.extract_text import detect_transport_mode
from agent.schema.field_validate import harvest_oral_measures
prev_added = str((sess.facts or {}).get("added_services") or "")
merged = dict(sess.facts)
merged.update(facts)
source = waiting_mode_source(sess, text)
facts = harvest_oral_measures(source, merged)
added_source = waiting_mode_source(sess, text)
facts = harvest_oral_measures(added_source, merged)
mode = mode or (sess.business_line or "").upper()
if not mode:
mode = detect_transport_mode(
f"{sess.immutable_text or ''}\n{text}"
)
if (mode or "").upper() == "AIR":
from agent.schema.added_services import apply_air_value_added
facts = apply_air_value_added(added_source, facts, previous=prev_added)
if not mode:
reply(copy.ask_transport())
self._save(
@@ -1268,9 +1279,31 @@ class AirTextInquiryFlow:
options_matching_origin,
parse_air_options,
project_selected_quote,
sort_cabin_options,
)
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="已报价")
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,
cabin_pick=True,
)
stated_origin = str(
(sess.facts or {}).get("起运港") or (sess.facts or {}).get("起运地") or ""
).strip()
@@ -1335,8 +1368,13 @@ class AirTextInquiryFlow:
work_order_no: str,
quote: dict[str, Any],
reply: ReplyFn,
cabin_pick: bool = False,
) -> str:
"""多条线路:企微只发入口卡,选线在 H5。"""
"""
企微只发入口卡,点选在 H5。
cabin_pick:没填报价日期,列出全部舱位(含 1 条)。选定后用该条总价出报价,不再查价。
"""
from agent.channel.h5.air_route_store import build_air_route_url, issue_air_route_token
from agent.schema.air_route_options import parse_air_options
@@ -1345,6 +1383,7 @@ class AirTextInquiryFlow:
work_order_no=work_order_no,
quote=quote,
facts=dict(sess.facts),
cabin_pick=cabin_pick,
)
url = build_air_route_url(token)
count = len(parse_air_options(quote))
@@ -1353,8 +1392,12 @@ class AirTextInquiryFlow:
sess.wait_version += 1
self._save(sess)
reply(
copy.air_route_entry_text(work_order_no=work_order_no, count=count),
copy.air_route_entry_card(work_order_no=work_order_no, count=count, url=url),
copy.air_route_entry_text(
work_order_no=work_order_no, count=count, cabin_pick=cabin_pick
),
copy.air_route_entry_card(
work_order_no=work_order_no, count=count, url=url, cabin_pick=cabin_pick
),
)
return "wait_air_route"