空运人工价锁舱现拉补全舱位并拦清缺参;成交/报价填表与工单陆运费率展示同步收紧。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-10-07 23:35:24 +08:00
co-authored by Cursor
parent 419b4a1bf7
commit e197ecea10
31 changed files with 1607 additions and 150 deletions
+21 -4
View File
@@ -40,8 +40,18 @@ class HttpLedger:
def _post(self, path: str, body: dict[str, Any], *, idem: str = "") -> dict[str, Any]:
resp = self._client.request_json("POST", path, json_body=body, idempotency_key=idem)
if not resp.ok:
logger.warning("http_ledger fail path=%s status=%s err=%s", path, resp.status_code, resp.error)
return {"ok": False, "error": resp.error or f"http_{resp.status_code}"}
# 500 时 Jeecg 仍可能带回 message(如六态非法);勿只留 http_500,
# 否则成交补「已报价」重试认不出「询价中」(WO023)。
data = resp.data if isinstance(resp.data, dict) else {}
msg = ""
if isinstance(data, dict):
msg = str(data.get("message") or "").strip()
unwrapped = _unwrap(data)
if unwrapped.get("error"):
msg = str(unwrapped.get("error") or msg)
err = msg or resp.error or f"http_{resp.status_code}"
logger.warning("http_ledger fail path=%s status=%s err=%s", path, resp.status_code, err)
return {"ok": False, "error": err}
return _unwrap(resp.data)
def find_similar_open(
@@ -166,8 +176,12 @@ class HttpLedger:
"""
no = (work_order_no or "").strip()
src = dict(quote or {})
if not no or not src:
return {"ok": True, "quote_version": 1, "status": to_status or "已报价"}
if not no:
return {"ok": False, "error": "work_order_blank"}
# 空报价不打主账(避免抹掉已有查价),但禁止伪装成「已写入已报价」——
# 否则会话以为已报价、主账仍停询价中,成交三态会失败(WO022)。
if not src:
return {"ok": False, "error": "quote_blank", "skipped": True}
out = self._post(
"/inquiry/agent/ticket/replaceTmsQuote",
{"workOrderNo": no, "quote": src, "toStatus": to_status},
@@ -423,6 +437,7 @@ class HttpLedger:
operator_name: str = "",
instruction_text: str = "",
airline: str = "",
flight_no: str = "",
) -> dict[str, Any]:
body: dict[str, Any] = {
"workOrderNo": work_order_no,
@@ -433,6 +448,8 @@ class HttpLedger:
}
if (airline or "").strip():
body["airline"] = airline.strip().upper()
if (flight_no or "").strip():
body["flightNo"] = flight_no.strip().upper()
return self._post(
"/inquiry/agent/tms/lockCabin",
body,
+28 -2
View File
@@ -827,9 +827,14 @@ class MemoryLedger:
operator_name: str = "",
instruction_text: str = "",
airline: str = "",
flight_no: str = "",
) -> dict[str, Any]:
"""单测可注入 _cabin_lock_result;默认成功。"""
_ = sender_id, operator_name, instruction_text, airline
"""单测可注入 _cabin_lock_result;默认成功。
纯人工且视图无 TMS 舱位时,缺 option/航司/航班 → lock_incomplete,
对齐主账「现拉仍缺才回」的口径(内存账不会真查 TMS)。
"""
_ = sender_id, operator_name, instruction_text
forced = getattr(self, "_cabin_lock_result", None)
if isinstance(forced, dict):
return dict(forced)
@@ -845,6 +850,27 @@ class MemoryLedger:
quote_id = str(quote.get("quoteId") or "").strip()
if quote_id.upper().startswith("QT-WO"):
quote_id = ""
air_opts = quote.get("airOptions") or quote.get("air_options") or []
has_tms_cabin = bool(quote_id) or bool(air_opts)
opt = (option_no or "").strip()
air = (airline or "").strip()
fn = (flight_no or "").strip()
if not has_tms_cabin:
missing: list[str] = []
if not opt:
missing.append("舱位编号optionNo")
if not air:
missing.append("航司airline")
if not fn:
missing.append("航班号flightNo")
if missing:
return {
"ok": False,
"error": "lock_incomplete",
"failReason": "锁舱参数不完整,缺少:"
+ "、".join(missing)
+ "。请按「AIR-OPT01 CZ 航班CZ327」补舱位、航司和航班号后再锁。",
}
return {
"ok": True,
"status": "LOCKED",