空运协同里手工改费用、有起运地、锁舱失败或缺参会被误判,报价单已出后再激活又重发模板。按销售侧口径收紧这些分支,并让价格卡和未成交回执带上真实工单号。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -45,10 +45,55 @@ def parse_air_options(quote: dict[str, Any] | None) -> list[dict[str, Any]]:
|
||||
|
||||
|
||||
def needs_route_pick(quote: dict[str, Any] | None) -> bool:
|
||||
"""多于一条线路才进 H5 选。"""
|
||||
"""没写起运地、且多于一条线路,才进 H5 选。有起运地时由调用方先按起运地收口。"""
|
||||
return len(parse_air_options(quote)) > 1
|
||||
|
||||
|
||||
def options_matching_origin(
|
||||
options: list[dict[str, Any]],
|
||||
origin_text: str,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""
|
||||
销售已经写了起运地时,只留起运机场对得上的线路。
|
||||
|
||||
杭州对 HGH,珠海对 ZUH。回包里的南京/深圳/郑州不能拿来给这张单选。
|
||||
对不上返回空列表。不改入参。
|
||||
"""
|
||||
text = (origin_text or "").strip()
|
||||
if not text:
|
||||
return list(options)
|
||||
code = resolve_airport_code(text).upper()
|
||||
raw = text.upper()
|
||||
matched: list[dict[str, Any]] = []
|
||||
for opt in options:
|
||||
origin = str(opt.get("originAirportCode") or opt.get("origin") or "").strip().upper()
|
||||
if not origin:
|
||||
continue
|
||||
if code and origin == code:
|
||||
matched.append(opt)
|
||||
elif origin == raw:
|
||||
matched.append(opt)
|
||||
return matched
|
||||
|
||||
|
||||
def choose_stated_origin_option(
|
||||
options: list[dict[str, Any]],
|
||||
quote: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
起运地已指定时直接用一条,不再让销售选线。
|
||||
|
||||
只有一条就用它。多条时优先和报价总价相同的那条,否则用第一条。
|
||||
"""
|
||||
if len(options) == 1:
|
||||
return options[0]
|
||||
total = (quote or {}).get("total")
|
||||
for opt in options:
|
||||
if _same_amount(opt.get("salePrice"), total):
|
||||
return opt
|
||||
return options[0]
|
||||
|
||||
|
||||
def _place_name(code: str, fallback: str = "") -> str:
|
||||
"""三字码能对上就用中文,否则用原文或 fallback。"""
|
||||
raw = (code or "").strip()
|
||||
@@ -331,14 +376,14 @@ def _same_amount(left: Any, right: Any) -> bool:
|
||||
|
||||
def drop_air_freight_total_alias(quote: dict[str, Any] | None) -> dict[str, Any]:
|
||||
"""
|
||||
整单兜底「空运费=总价」不是线路分项,群摘要禁止再写。
|
||||
已经有其它费用分项时,去掉「空运费=总价」这一行兜底。
|
||||
|
||||
真有空运费且金额不等于总价(例如另有附加费)则保留。
|
||||
舱位上有运输费、提送货费时,主账快照常再塞一行空运费,金额就是总价,不能和分项叠在一起。
|
||||
只有空运费这一项时必须留下:TMS 经常只回这一项,金额自然等于总价,群里仍要写出费用名。
|
||||
不写库。群摘要投影之后调用。
|
||||
"""
|
||||
src = dict(quote or {})
|
||||
total = src.get("total")
|
||||
if _same_amount(src.get("freight"), total):
|
||||
src["freight"] = "-"
|
||||
raw = src.get("fee_lines") or src.get("fee_rows")
|
||||
parsed: Any = raw
|
||||
if isinstance(raw, str) and raw.strip():
|
||||
@@ -348,17 +393,26 @@ def drop_air_freight_total_alias(quote: dict[str, Any] | None) -> dict[str, Any]
|
||||
parsed = None
|
||||
if not isinstance(parsed, list):
|
||||
return src
|
||||
kept: list[Any] = []
|
||||
others: list[Any] = []
|
||||
alias: list[Any] = []
|
||||
for item in parsed:
|
||||
if not isinstance(item, dict):
|
||||
kept.append(item)
|
||||
others.append(item)
|
||||
continue
|
||||
name = str(item.get("name") or item.get("label") or "").strip()
|
||||
name = str(item.get("name") or item.get("label") or item.get("feeName") or "").strip()
|
||||
amount = item.get("amount") or item.get("value")
|
||||
if name == "空运费" and _same_amount(amount, total):
|
||||
alias.append(item)
|
||||
continue
|
||||
kept.append(item)
|
||||
src["fee_lines"] = kept
|
||||
others.append(item)
|
||||
if others:
|
||||
# 分项已经在,空运费=总价是重复兜底。运费字段同值也不再补一行。
|
||||
src["fee_lines"] = others
|
||||
if _same_amount(src.get("freight"), total):
|
||||
src["freight"] = "-"
|
||||
return src
|
||||
# 明细就是这一条空运费,群摘要要显示费用名,不能只剩费用合计。
|
||||
src["fee_lines"] = alias
|
||||
return src
|
||||
|
||||
|
||||
|
||||
@@ -493,6 +493,40 @@ def effective_quote(tms: dict[str, Any] | None, overlay: dict[str, Any] | None)
|
||||
return out
|
||||
|
||||
|
||||
def text_has_relative_adjust(text: str) -> bool:
|
||||
"""
|
||||
这句话是在按比例改价:加10%、减5%、上调、上浮、加一成。
|
||||
|
||||
这种是销售调价,不是航线/产品报一个新金额。不打模型。
|
||||
"""
|
||||
raw = text or ""
|
||||
if _PERCENT_UP.search(raw) or _PERCENT_DOWN.search(raw):
|
||||
return True
|
||||
blob = raw.replace(" ", "").replace(" ", "")
|
||||
return any(phrase in blob for phrase in ("加一成", "减一成", "往上抬", "往下压", "上浮", "下浮"))
|
||||
|
||||
|
||||
def text_has_total_only_adjust(text: str) -> bool:
|
||||
"""
|
||||
只动总价/总销售价/费用合计,没有点名某一项费用。
|
||||
|
||||
「总销售价改为180」仍是销售调价。点了「空运费」「报关费」则不是。不打模型。
|
||||
"""
|
||||
raw = text or ""
|
||||
if not (_TARGET.search(raw) or _PERCENT_UP.search(raw) or _PERCENT_DOWN.search(raw)):
|
||||
return False
|
||||
if not any(word in raw for word in _TOTAL_WORDS) and "报价" not in raw:
|
||||
return False
|
||||
real: list[str] = []
|
||||
for name in _FEE_TOKEN.findall(raw):
|
||||
if name in {"费用", "费用合计"}:
|
||||
continue
|
||||
if any(word in name for word in ("合计", "总价", "汇总")):
|
||||
continue
|
||||
real.append(name)
|
||||
return not real
|
||||
|
||||
|
||||
def extract_adjust(
|
||||
text: str,
|
||||
*,
|
||||
|
||||
@@ -35,6 +35,9 @@ _AIRPORTS = {
|
||||
"南京": "NKG",
|
||||
"吉隆坡": "KUL",
|
||||
"北京": "PEK",
|
||||
"杭州": "HGH",
|
||||
"萧山": "HGH",
|
||||
"杭州萧山": "HGH",
|
||||
}
|
||||
|
||||
# 历史字典:只给对照,空运出站不再编成 1/2/3。
|
||||
@@ -199,7 +202,7 @@ def assemble_air_query(facts: dict[str, Any] | None) -> dict[str, Any]:
|
||||
包装只看销售是否说了,散货等原文原样保留。
|
||||
"""
|
||||
src = dict(facts or {})
|
||||
origin = str(src.get("起运港") or "").strip()
|
||||
origin = str(src.get("起运港") or src.get("起运地") or "").strip()
|
||||
dest = str(src.get("目的港") or "").strip()
|
||||
cargo = str(src.get("品名") or "").strip()
|
||||
pieces = _first_number(str(src.get("件数") or ""))
|
||||
|
||||
Reference in New Issue
Block a user