海运补问保留贸易条款;陆运多车型价表按列回填,车型码不进起始地

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-10-29 10:53:30 +08:00
co-authored by Cursor
parent 56ba8e93b5
commit eca0a7ad93
10 changed files with 809 additions and 18 deletions
+80 -2
View File
@@ -967,13 +967,18 @@ def apply_product_quote(
send_group_text(client, chat_id, copy.group_quote_not_recognized())
return "quote_not_recognized"
quote = _attach_land_weight_band_segment(quote, view)
quote = _attach_land_vehicle_rates_segment(quote, view)
if _has_tms_quote(base):
_park_pending_quote(no, quote, sess, flow)
send_group_text(client, chat_id, copy.group_ask_tms_or_product())
return "wait_tms_choice"
# 分档单价是完整人工价(含费率),禁止和旧错误行(如燃油附加费=2)相加。
# 分档单价 / 多车型价表是完整人工价,禁止和旧错误行相加。
# 旧错默认「海运费」的陆运产品价:重报时按本单默认运费对齐后再盖,避免海运费+陆运费并排。
if _quote_fee_rows(base) and not (quote.get("weightPrices") or []):
if (
_quote_fee_rows(base)
and not (quote.get("weightPrices") or [])
and not (quote.get("vehicleRates") or quote.get("vehicle_rates") or [])
):
base = _align_wrong_default_freight(base, quote, business_line=line)
quote = merge_quote_fees(base, quote)
_save_product_quote(flow, no, quote, sess)
@@ -2009,6 +2014,79 @@ def _attach_land_weight_band_segment(
return src
def _land_od_from_view(view: dict[str, Any]) -> tuple[str, str]:
"""
工单询价事实里的起运/目的。
合同归一后陆运常用「起运港/目的港」「提货地址/收货地址」;
「目的地→目的港」「送货地址→收货地址」。产品口语「太原富士康--春疆」不当目的港。
"""
facts = dict((view or {}).get("facts") or {})
origin = str(
facts.get("起运港")
or facts.get("始发站")
or facts.get("始发地")
or facts.get("起运地")
or facts.get("提货地址")
or facts.get("origin")
or (view or {}).get("origin")
or ""
).strip()
dest = str(
facts.get("目的港")
or facts.get("目的地")
or facts.get("收货地址")
or facts.get("送货地址")
or facts.get("destination")
or (view or {}).get("destination")
or ""
).strip()
return origin, dest
def _attach_land_vehicle_rates_segment(
quote: dict[str, Any], view: dict[str, Any]
) -> dict[str, Any]:
"""
陆运产品多车型价:把 vehicleRates 挂到 landSegments,出单才能填 5T/10T/40HQ 列。
无车型价表时原样返回。OD 取工单询价事实;备注进段上 remark(含0点税等)。
不写裸 salePrice 冒充单车型,避免多列表头误灌同一价。
"""
src = dict(quote or {})
rates = src.get("vehicleRates") or src.get("vehicle_rates")
if not isinstance(rates, dict) or not rates:
return src
clean = {
str(k).strip(): str(v).strip()
for k, v in rates.items()
if str(k).strip() and str(v).strip()
}
if not clean:
return src
origin, dest = _land_od_from_view(view)
remark = str(src.get("remark") or "").strip()
seg: dict[str, Any] = {
"origin": origin,
"destination": dest,
"vehicleRates": dict(clean),
"vehicle_rates": dict(clean),
"currency": str(src.get("currency") or "CNY"),
}
if remark:
seg["remark"] = remark
# 展示合计用第一档,不写入 salePrice,防止 resolve 在无 map 匹配时乱灌。
src["landSegments"] = [seg]
src["route_rows"] = [seg]
src["vehicleRates"] = dict(clean)
src["vehicle_rates"] = dict(clean)
# 多车型价只走 vehicleRates 矩阵列;fee_rows 若仍是「10T/40HQ」会被出单当成费目名
# 写进国内段「起始地」(运行证据:国内段出现 10T/40HQ/45HQ 行)。挂段后清空费目行。
src["fee_rows"] = []
src["fee_lines"] = []
return src
def _save_product_quote(
flow: Any,
no: str,