角色业务范围收紧工单与模板;报价日期不当费用;未选舱不迁已报价;另开一票可清违禁 hold

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-10-15 21:00:01 +08:00
co-authored by Cursor
parent a0c705683f
commit 277cdc1c28
39 changed files with 2083 additions and 217 deletions
+21 -5
View File
@@ -76,7 +76,8 @@ LAND_DISPLAY = {
# 协同补充字段:拉群后可静默写入,不挡首次查价。内部键仍是 HS编码。
SEA_COLLAB_FIELDS = ("货好时间", "HS编码", "是否含油", "是否含电", "是否含磁")
# 空运群只补含电/含磁,摘要不要把海运协同五项搬过去。
# 空运群只补含电/含磁(及报价日期),摘要不要把海运协同五项搬过去。
# 货好时间、贸易条款、客户名称不在群里补(产品口径)。
AIR_COLLAB_FIELDS = ("是否含电", "是否含磁")
# 群摘要对外展示名。内部继续用 HS编码,避免改合同键。
SEA_COLLAB_DISPLAY = {
@@ -222,6 +223,10 @@ _ALIASES = {
"海关编码": "HS编码",
"客户名称": "客户名称",
"货值": "货值",
# 模板/口语常写「是否带电」,合同内部键仍是是否含电。
"是否带电": "是否含电",
"是否含电": "是否含电",
"是否含磁": "是否含磁",
"是否为危险品": "是否为危险品",
"通关口岸": "通关口岸",
"通关口岸(非必填)": "通关口岸",
@@ -253,11 +258,15 @@ def shanghai_today() -> str:
return datetime.now(_SHANGHAI).date().isoformat()
# 销售卡片/摘要占位横杠:等于没写,禁止落进 facts 再当起运地出站(运行证据 WO202610150086)。
_PLACEHOLDER_DASHES = frozenset({"-", "—", "-"})
def normalize_facts(facts: dict[str, Any] | None) -> dict[str, str]:
"""
把展示名/别名折成合同内部键,去掉首尾空白。
空值丢弃;不解释语义。
空值与摘要占位「-」丢弃;不解释语义。
"""
out: dict[str, str] = {}
for raw_key, raw_val in (facts or {}).items():
@@ -268,7 +277,7 @@ def normalize_facts(facts: dict[str, Any] | None) -> dict[str, str]:
if raw_val is None:
continue
val = str(raw_val).strip()
if not val:
if not val or val in _PLACEHOLDER_DASHES:
continue
out[key] = val
_fold_land_vehicle_qty(out)
@@ -527,9 +536,16 @@ def harvest_oral_collab(text: str) -> dict[str, str]:
只认原话里已经说死的词(不含电、随时可提、普货),不猜贸易条款和海关编码。
「(如:随时可提)」这种补问示例行不算销售说了货好时间。
危险品:否词(不是危险品/非危/普货)先于是词,避免「不是危险品」收成是。
「是否带电:否」里的「带电」不能当成肯定(运行证据 session 717349)。
"""
raw = _without_clarify_examples(text or "")
out: dict[str, str] = {}
# 先剥掉「是否带电/含电/含磁:是|否」标签行,再口语匹配,避免标签里的「带电」误判成是。
oral_src = re.sub(
r"是否(?:带电|含电|含磁|含油)\s*[::]\s*[是否]",
" ",
raw,
)
yes_no = (
("是否含电", ("不含电", "不带电", "无电"), ("含电", "带电")),
("是否含油", ("不含油", "不带油", "无油"), ("含油", "带油")),
@@ -541,9 +557,9 @@ def harvest_oral_collab(text: str) -> dict[str, str]:
),
)
for key, no_words, yes_words in yes_no:
if any(w in raw for w in no_words):
if any(w in oral_src for w in no_words):
out[key] = "否"
elif any(w in raw for w in yes_words):
elif any(w in oral_src for w in yes_words):
out[key] = "是"
ready = ("随时可提", "货好随时", "随时货好", "货已好", "已经货好")
for word in ready: