海运补问保留贸易条款;陆运多车型价表按列回填,车型码不进起始地
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -237,13 +237,27 @@ class SeaTextInquiryFlow(AirTextInquiryFlow):
|
||||
|
||||
# 刚选定海运时,贸易条款、运输分类要对照定方式前的全部原话,不只看「海运」两个字。
|
||||
source = waiting_mode_source(sess, text)
|
||||
# 补问阶段 waiting_mode_source 只给本句;首句里的「港到港」必须拼回去,
|
||||
# 否则 apply_spoken 会把会话已有条款当成模型冒充删掉(只补货量时再问贸易条款)。
|
||||
trade_source = source
|
||||
if sess and getattr(sess, "phase", "") in {"clarify", "wait_confirm", "sensitive_block"}:
|
||||
trade_source = stack_user_text(getattr(sess, "immutable_text", "") or "", text)
|
||||
# 整句只回「港到港」是贸易条款举例,不要改写成运输分类。
|
||||
class_source = "" if short_sea_trade_reply(source) == "港到港" else source
|
||||
facts = harvest_sea_class(class_source, facts)
|
||||
# 贸易条款标签行原样优先;整句回复或长句里写了门到门/港到港都要收下。
|
||||
# 原话没出现这两个词时,模型冒充的门到门、港到港继续丢掉。
|
||||
facts = apply_spoken_sea_trade_reply(source, facts)
|
||||
spoken = harvest_spoken_trade_term(source)
|
||||
# 补问用 trade_source(首句+本句),避免只补货量时丢掉已确认的港到港。
|
||||
facts = apply_spoken_sea_trade_reply(trade_source, facts)
|
||||
# 本句显式改条款时覆盖历史(短回门到门/港到港,或写出 FOB/CIF 等)。
|
||||
short_now = short_sea_trade_reply(text)
|
||||
if short_now:
|
||||
facts["贸易条款"] = short_now
|
||||
else:
|
||||
spoken_now = harvest_spoken_trade_term(text)
|
||||
if spoken_now.get("贸易条款"):
|
||||
facts["贸易条款"] = spoken_now["贸易条款"]
|
||||
spoken = harvest_spoken_trade_term(trade_source)
|
||||
if spoken.get("贸易条款") and not str(facts.get("贸易条款") or "").strip():
|
||||
facts["贸易条款"] = spoken["贸易条款"]
|
||||
check = validate_required_fields(facts=facts, business_line="SEA")
|
||||
|
||||
Reference in New Issue
Block a user