落地海运私聊文字询价全流程,海运多项费用改走文本明细,避免企微卡片引用条截断。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-15 14:26:09 +08:00
co-authored by Cursor
parent 58b3c2f3e6
commit 0a3c74e3a1
41 changed files with 3702 additions and 48 deletions
@@ -32,6 +32,21 @@ AIR_REQUIRED_FIELDS = (
)
AIR_DISPLAY = {key: label for key, label in AIR_REQUIRED_FIELDS}
# 海运询价必填 7 项:销售侧名称。内部键「货量」对外叫「货物数量」。
SEA_REQUIRED_FIELDS = (
("起运港", "起运港"),
("目的港", "目的港"),
("品名", "品名"),
("货量", "货物数量"),
("整柜或拼柜", "整柜或拼柜"),
("箱型箱量", "箱型箱量"),
("报价日期", "报价日期"),
)
SEA_DISPLAY = {key: label for key, label in SEA_REQUIRED_FIELDS}
# 协同补充字段:拉群后可静默写入,不挡首次查价。
SEA_COLLAB_FIELDS = ("贸易条款", "货好时间", "HS编码", "是否含油", "是否含电", "是否含磁")
# 口语里已经带上 TMS 文档规定的单位时,补进空字段。
# 只认「数字+单位」,不猜港口,不把长宽高换算成立方。
_RE_PIECES = re.compile(r"(?<![\d.])(\d+)\s*(件|pcs)\b", re.I)
@@ -63,6 +78,8 @@ _ALIASES = {
"重量": "毛重",
"体积(CBM)": "体积",
"车型/数量": "车型数量",
"HS": "HS编码",
"HS CODE": "HS编码",
}
@@ -161,6 +178,20 @@ def harvest_oral_measures(text: str, facts: dict[str, str] | None = None) -> dic
return harvest_named_air_route(raw, merged)
def project_sea_cargo_qty(facts: dict[str, str] | None) -> dict[str, str]:
"""
海运货物数量投影:原话「15件」常被抽成空运「件数」。
货量已有则不覆盖。件数有、货量空时,货量用件数。不猜吨位、不改空运校验。
"""
merged = dict(facts or {})
qty = (merged.get("货量") or merged.get("货物数量") or "").strip()
pieces = (merged.get("件数") or "").strip()
if not qty and pieces:
merged["货量"] = pieces
return merged
def apply_quote_date_default(facts: dict[str, str]) -> dict[str, str]:
"""销售未提供报价日期时填当天;已有则不覆盖。"""
merged = dict(facts)
@@ -192,6 +223,8 @@ def display_name(internal_key: str, business_line: str = "AIR") -> str:
line = (business_line or "").upper()
if line == "AIR":
return AIR_DISPLAY.get(internal_key, internal_key)
if line == "SEA":
return SEA_DISPLAY.get(internal_key, internal_key)
return internal_key
@@ -212,6 +245,8 @@ def validate_required_fields(
contract = require_formal_contract("inquiry-required-fields-v1")
normalized = apply_quote_date_default(normalize_facts(facts))
line = (business_line or "").strip().upper()
if line == "SEA":
normalized = project_sea_cargo_qty(normalized)
if line not in {"SEA", "AIR", "LAND"}:
return {
"ok": False,