落地陆运群内协同:按填写样例拉群并只列本单协同项,进群把私聊已抽到的字段带上。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,7 +14,12 @@ from typing import Any, Optional
|
||||
from agent.llm.extract_text import extract_collab_fields, extract_product_quote
|
||||
from agent.policy.quote_overlay import overlay_labeled_facts
|
||||
from agent.policy import inquiry_copy as copy
|
||||
from agent.schema.field_validate import SEA_COLLAB_DISPLAY, SEA_COLLAB_FIELDS
|
||||
from agent.schema.field_validate import (
|
||||
SEA_COLLAB_DISPLAY,
|
||||
SEA_COLLAB_FIELDS,
|
||||
collab_display_name,
|
||||
collab_fields_for_ticket,
|
||||
)
|
||||
|
||||
# 主账填表按英文码取格子;中文键必须同时带上,否则货好时间/条款写不进表。
|
||||
_COLLAB_FILL_ALIASES = {
|
||||
@@ -24,6 +29,10 @@ _COLLAB_FILL_ALIASES = {
|
||||
"是否含油": ("是否含油", "has_oil"),
|
||||
"是否含电": ("是否含电", "has_battery"),
|
||||
"是否含磁": ("是否含磁", "has_magnet"),
|
||||
"客户名称": ("客户名称", "customer_name"),
|
||||
"货值": ("货值", "cargo_value"),
|
||||
"是否为危险品": ("是否为危险品", "is_dangerous"),
|
||||
"包装方式": ("包装方式", "包装类型"),
|
||||
}
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -91,6 +100,24 @@ def ticket_no(ticket: object) -> str:
|
||||
return str(ticket_view(ticket).get("work_order_no") or "").strip()
|
||||
|
||||
|
||||
def _collab_keys_of(ticket: object, sess: Any = None) -> tuple[str, tuple[str, ...]]:
|
||||
"""本单业务线 + 允许写入的协同内部键。"""
|
||||
view = ticket_view(ticket)
|
||||
facts = dict(view.get("facts") or {})
|
||||
if sess is not None and getattr(sess, "facts", None):
|
||||
facts.update(dict(sess.facts or {}))
|
||||
line = str(
|
||||
view.get("business_line")
|
||||
or view.get("businessLine")
|
||||
or (getattr(sess, "business_line", "") if sess is not None else "")
|
||||
or "SEA"
|
||||
).strip().upper() or "SEA"
|
||||
keys = collab_fields_for_ticket(facts, line)
|
||||
if not keys and line != "LAND":
|
||||
keys = SEA_COLLAB_FIELDS
|
||||
return line, keys
|
||||
|
||||
|
||||
def is_terminal(ticket: object) -> bool:
|
||||
return ticket_status(ticket) in TERMINAL
|
||||
|
||||
@@ -378,6 +405,13 @@ def send_brief_and_sheet(
|
||||
quote = dict(override or sess_q or view_q or tms or manual)
|
||||
sales_name, products, mention_ids = resolve_group_mentions(flow, ticket, sess)
|
||||
has_tms = bool(tms.get("total") or _quote_fee_rows(tms))
|
||||
line = str(
|
||||
view.get("business_line")
|
||||
or view.get("businessLine")
|
||||
or (sess.business_line if sess is not None else "")
|
||||
or "SEA"
|
||||
).strip().upper()
|
||||
mode = "陆运" if line == "LAND" else "海运"
|
||||
brief = copy.sea_group_brief(
|
||||
work_order_no=no,
|
||||
facts=facts,
|
||||
@@ -388,9 +422,16 @@ def send_brief_and_sheet(
|
||||
has_price=has_tms,
|
||||
tms_quote=tms,
|
||||
product_quote=manual,
|
||||
transport_mode=mode,
|
||||
)
|
||||
send_group_text(client, chat_id, brief, mention_userids=mention_ids)
|
||||
send_filled_sheet(flow=flow, ticket=ticket, sess=sess, quote_override=quote)
|
||||
send_filled_sheet(
|
||||
flow=flow,
|
||||
ticket=ticket,
|
||||
sess=sess,
|
||||
quote_override=quote,
|
||||
business_line=line,
|
||||
)
|
||||
return "brief_and_sheet"
|
||||
|
||||
|
||||
@@ -400,7 +441,7 @@ def send_filled_sheet(
|
||||
ticket: object,
|
||||
sess: Any = None,
|
||||
quote_override: Optional[dict[str, Any]] = None,
|
||||
business_line: str = "SEA",
|
||||
business_line: str = "",
|
||||
chat_id: str = "",
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
@@ -429,7 +470,7 @@ def send_filled_sheet(
|
||||
flow=flow,
|
||||
chat_id=room,
|
||||
work_order_no=no,
|
||||
facts=_facts_for_fill(facts, collab),
|
||||
facts=_facts_for_fill(facts, collab, business_line=line or "SEA"),
|
||||
quote=quote,
|
||||
sales_id=str(
|
||||
(sess.sender_id if sess else "")
|
||||
@@ -441,15 +482,20 @@ def send_filled_sheet(
|
||||
)
|
||||
|
||||
|
||||
def _collab_value(collab: dict[str, str], key: str) -> str:
|
||||
"""协同六项:内部键、对外展示名都能取到。"""
|
||||
def _collab_value(collab: dict[str, str], key: str, business_line: str = "SEA") -> str:
|
||||
"""协同项:内部键、对外展示名都能取到。"""
|
||||
src = dict(collab or {})
|
||||
val = str(src.get(key) or "").strip()
|
||||
if val:
|
||||
return val
|
||||
label = SEA_COLLAB_DISPLAY.get(key, "")
|
||||
label = collab_display_name(key, business_line)
|
||||
if label:
|
||||
val = str(src.get(label) or "").strip()
|
||||
if val:
|
||||
return val
|
||||
sea_label = SEA_COLLAB_DISPLAY.get(key, "")
|
||||
if sea_label:
|
||||
val = str(src.get(sea_label) or "").strip()
|
||||
return val
|
||||
|
||||
|
||||
@@ -466,15 +512,22 @@ def _oil_elec_mag_text(collab: dict[str, str]) -> str:
|
||||
return f"油:{oil or '-'};电:{elec or '-'};磁:{mag or '-'}"
|
||||
|
||||
|
||||
def _facts_for_fill(facts: dict[str, str], collab: dict[str, str]) -> dict[str, str]:
|
||||
def _facts_for_fill(
|
||||
facts: dict[str, str],
|
||||
collab: dict[str, str],
|
||||
business_line: str = "SEA",
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
询价七项 + 协同六项。中文键和填表英文码一起带上。
|
||||
询价字段 + 本单协同项。中文键和填表英文码一起带上。
|
||||
主账 writeFactsByLabel 只认 cargo_ready_date / trade_terms,只传「货好时间」会空着。
|
||||
模板没有格子的新项照样带上,overlay 找不到标签就跳过。
|
||||
"""
|
||||
merged = dict(facts or {})
|
||||
src = dict(collab or {})
|
||||
for key in SEA_COLLAB_FIELDS:
|
||||
val = _collab_value(src, key)
|
||||
line = (business_line or "SEA").strip().upper() or "SEA"
|
||||
keys = collab_fields_for_ticket(facts, line) or SEA_COLLAB_FIELDS
|
||||
for key in keys:
|
||||
val = _collab_value(src, key, line)
|
||||
if not val:
|
||||
continue
|
||||
for alias in _COLLAB_FILL_ALIASES.get(key, (key,)):
|
||||
@@ -549,7 +602,7 @@ def apply_collab_update(
|
||||
sender_id: str,
|
||||
sess: Any = None,
|
||||
) -> str:
|
||||
"""补协同六项。终态要说明原因。"""
|
||||
"""补本单协同项。终态要说明原因。不该有的项当没补到。"""
|
||||
ticket = hydrate_ticket(flow, ticket)
|
||||
no = ticket_no(ticket)
|
||||
chat_id = str((sess.collab_chat_id if sess else "") or ticket_view(ticket).get("collab_chat_id") or "")
|
||||
@@ -557,11 +610,21 @@ def apply_collab_update(
|
||||
if is_terminal(ticket):
|
||||
send_group_text(client, chat_id, copy.ticket_locked(work_order_no=no, status=ticket_status(ticket)))
|
||||
return "ticket_locked"
|
||||
fields = extract_collab_fields(text, allow_b=True)
|
||||
line, keys = _collab_keys_of(ticket, sess)
|
||||
fields = extract_collab_fields(text, allow_b=True, allowed_keys=keys)
|
||||
if not fields:
|
||||
send_group_text(client, chat_id, copy.group_fields_not_recognized())
|
||||
send_group_text(
|
||||
client,
|
||||
chat_id,
|
||||
copy.group_fields_not_recognized(keys=keys or None, business_line=line),
|
||||
)
|
||||
return "collab_not_recognized"
|
||||
flow.apply_collab_facts(work_order_no=no, facts=fields, sender_id=sender_id)
|
||||
flow.apply_collab_facts(
|
||||
work_order_no=no,
|
||||
facts=fields,
|
||||
sender_id=sender_id,
|
||||
allowed_keys=keys,
|
||||
)
|
||||
if sess is not None:
|
||||
merged = dict(sess.collab_facts)
|
||||
merged.update(fields)
|
||||
@@ -603,9 +666,15 @@ def apply_product_quote(
|
||||
if not is_product(ticket, sender_id, flow=flow):
|
||||
send_group_text(client, chat_id, copy.group_only_product_can_quote())
|
||||
return "quote_not_product"
|
||||
fields = extract_collab_fields(text)
|
||||
fields = extract_collab_fields(text, allowed_keys=_collab_keys_of(ticket, sess)[1])
|
||||
if fields:
|
||||
flow.apply_collab_facts(work_order_no=no, facts=fields, sender_id=sender_id)
|
||||
line, keys = _collab_keys_of(ticket, sess)
|
||||
flow.apply_collab_facts(
|
||||
work_order_no=no,
|
||||
facts=fields,
|
||||
sender_id=sender_id,
|
||||
allowed_keys=keys,
|
||||
)
|
||||
if sess is not None:
|
||||
merged = dict(sess.collab_facts)
|
||||
merged.update(fields)
|
||||
@@ -772,7 +841,7 @@ def _persist_quote_sheet(
|
||||
result = renderer(
|
||||
work_order_no=no,
|
||||
business_line=line,
|
||||
facts=_facts_for_fill(facts, collab),
|
||||
facts=_facts_for_fill(facts, collab, business_line=line or "SEA"),
|
||||
quote=quote,
|
||||
format="xlsx",
|
||||
sales_wecom_id=str(
|
||||
|
||||
Reference in New Issue
Block a user