完善空运锁舱与海运报价单单选回填,并增强模板预览与协同字段盖写。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -401,17 +401,21 @@ def hydrate_ticket(flow: Any, ticket: object) -> object:
|
||||
)
|
||||
)
|
||||
quote = dict(view.get("quote") or {})
|
||||
has_quote = bool(quote.get("total") or _quote_fee_rows(quote))
|
||||
# total="-" 在 Python 里也是 truthy,不能当成已有总价;只有附加费明细也不算完整。
|
||||
has_sale_total = _quote_has_usable_sale_total(quote)
|
||||
has_fee_rows = bool(_quote_fee_rows(quote))
|
||||
has_quote = has_sale_total or has_fee_rows
|
||||
has_status = bool(ticket_status(ticket))
|
||||
has_tms = bool(dict(view.get("tms_quote") or view.get("tmsQuote") or {}))
|
||||
# 调价后 latest quote 仍有价,但不能因此跳过补 TMS 原价。
|
||||
if has_facts and has_quote and has_status and has_tms:
|
||||
return ticket
|
||||
# 仅有 fee_rows、没有可用总价时仍要往下补全,否则空运出单预估费用会落成明细 SUM。
|
||||
if has_facts and has_sale_total and has_status and has_tms:
|
||||
return _soft_fill_quote_sale_fields(ticket)
|
||||
no = ticket_no(ticket)
|
||||
sales = str(view.get("sales_wecom_id") or view.get("salesWecomId") or "").strip()
|
||||
book = getattr(flow, "ledger", None)
|
||||
if book is None or not no:
|
||||
return ticket
|
||||
return _soft_fill_quote_sale_fields(ticket)
|
||||
full: Any = None
|
||||
getter = getattr(book, "get_for_agent", None)
|
||||
if callable(getter) and sales:
|
||||
@@ -423,13 +427,33 @@ def hydrate_ticket(flow: Any, ticket: object) -> object:
|
||||
if callable(getter):
|
||||
full = getter(work_order_no=no)
|
||||
if full is None:
|
||||
return ticket
|
||||
return _soft_fill_quote_sale_fields(ticket)
|
||||
merged = dict(view)
|
||||
full_view = ticket_view(full)
|
||||
if (not has_facts) and full_view.get("facts"):
|
||||
merged["facts"] = dict(full_view.get("facts") or {})
|
||||
if (not has_quote) and full_view.get("quote"):
|
||||
merged["quote"] = dict(full_view.get("quote") or {})
|
||||
if (not has_sale_total) and full_view.get("quote"):
|
||||
# 薄报价保留已有明细,补上完整快照里的总价/线路。
|
||||
rich = dict(full_view.get("quote") or {})
|
||||
cur = dict(quote)
|
||||
for key in (
|
||||
"total",
|
||||
"salePrice",
|
||||
"totalSalePrice",
|
||||
"airOptions",
|
||||
"air_options",
|
||||
"selected_air_option",
|
||||
"selectedAirOption",
|
||||
"chargeableWeightKg",
|
||||
"chargeable_weight_kg",
|
||||
"currency",
|
||||
"valid_until",
|
||||
):
|
||||
if cur.get(key) in (None, "", "-", [], {}) and rich.get(key) not in (None, "", "-", [], {}):
|
||||
cur[key] = rich[key]
|
||||
if not has_fee_rows and (rich.get("fee_lines") or rich.get("fee_rows")):
|
||||
cur["fee_lines"] = rich.get("fee_lines") or rich.get("fee_rows")
|
||||
merged["quote"] = cur
|
||||
if full_view.get("tms_quote") or full_view.get("tmsQuote"):
|
||||
merged["tms_quote"] = dict(full_view.get("tms_quote") or full_view.get("tmsQuote") or {})
|
||||
if (not has_status) and full_view.get("status"):
|
||||
@@ -449,6 +473,66 @@ def hydrate_ticket(flow: Any, ticket: object) -> object:
|
||||
):
|
||||
if full_view.get(key) and not merged.get(key):
|
||||
merged[key] = full_view.get(key)
|
||||
return _soft_fill_quote_sale_fields(merged)
|
||||
|
||||
|
||||
def _quote_has_usable_sale_total(quote: dict[str, Any] | None) -> bool:
|
||||
"""
|
||||
是否已有可用于出单预估费用的总价。
|
||||
total="-" 不算;仅有 fee_rows 也不算。
|
||||
"""
|
||||
src = dict(quote or {})
|
||||
total = str(src.get("total") or src.get("total_amount") or src.get("salePrice") or "").strip()
|
||||
if total and total != "-":
|
||||
return True
|
||||
selected = src.get("selected_air_option") or src.get("selectedAirOption")
|
||||
if isinstance(selected, dict):
|
||||
sale = str(selected.get("salePrice") or selected.get("sale_price") or "").strip()
|
||||
if sale and sale != "-":
|
||||
return True
|
||||
opts = src.get("airOptions") or src.get("air_options") or []
|
||||
if isinstance(opts, list) and opts and isinstance(opts[0], dict):
|
||||
sale = str(opts[0].get("salePrice") or opts[0].get("sale_price") or "").strip()
|
||||
if sale and sale != "-":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _soft_fill_quote_sale_fields(ticket: object) -> object:
|
||||
"""
|
||||
从 tms_quote 补齐当前 quote 缺失的总销售价 / 线路对象。
|
||||
群 findByCollabChat 常只有薄 latest quote,出单前必须能落到 salePrice。
|
||||
"""
|
||||
view = ticket_view(ticket)
|
||||
cur = dict(view.get("quote") or {})
|
||||
rich = dict(view.get("tms_quote") or view.get("tmsQuote") or {})
|
||||
if not rich:
|
||||
return ticket if isinstance(ticket, dict) else view
|
||||
changed = False
|
||||
for key in (
|
||||
"total",
|
||||
"salePrice",
|
||||
"totalSalePrice",
|
||||
"airOptions",
|
||||
"air_options",
|
||||
"selected_air_option",
|
||||
"selectedAirOption",
|
||||
"chargeableWeightKg",
|
||||
"chargeable_weight_kg",
|
||||
"currency",
|
||||
"valid_until",
|
||||
):
|
||||
if cur.get(key) in (None, "", "-", [], {}) and rich.get(key) not in (None, "", "-", [], {}):
|
||||
cur[key] = rich[key]
|
||||
changed = True
|
||||
if not changed:
|
||||
return ticket if isinstance(ticket, dict) else view
|
||||
if isinstance(ticket, dict):
|
||||
out = dict(ticket)
|
||||
out["quote"] = cur
|
||||
return out
|
||||
merged = dict(view)
|
||||
merged["quote"] = cur
|
||||
return merged
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user