落地海运协同群:测服靠会话存档听群话,报价单能带上协同字段。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,7 +13,12 @@ import time
|
||||
import uuid
|
||||
from typing import Any, Iterable
|
||||
|
||||
from agent.schema.field_validate import AIR_REQUIRED_FIELDS, SEA_COLLAB_FIELDS, SEA_REQUIRED_FIELDS
|
||||
from agent.schema.field_validate import (
|
||||
AIR_REQUIRED_FIELDS,
|
||||
SEA_COLLAB_DISPLAY,
|
||||
SEA_COLLAB_FIELDS,
|
||||
SEA_REQUIRED_FIELDS,
|
||||
)
|
||||
|
||||
# 空运补问:与合同 8 项一致。报价日期默认当天,不进待补充。
|
||||
_AIR_EXAMPLES = {
|
||||
@@ -379,6 +384,20 @@ def work_order_from_card_meta(
|
||||
return ""
|
||||
|
||||
|
||||
def deal_card_version(card_meta: dict[str, Any] | None = None, *, text: str = "") -> int:
|
||||
"""从成交卡 EventKey 取出 vN;没有则 0(旧私聊卡)。"""
|
||||
src = card_meta or {}
|
||||
for raw in (
|
||||
str(src.get("event_key") or ""),
|
||||
str(src.get("task_id") or ""),
|
||||
text or "",
|
||||
):
|
||||
hit = re.search(r":v(\d+)\s*$", raw)
|
||||
if hit:
|
||||
return int(hit.group(1))
|
||||
return 0
|
||||
|
||||
|
||||
def _work_order_in_token(raw: str) -> str:
|
||||
"""从 TaskId / EventKey 里抽出 WO 工单号;没有则空。"""
|
||||
text = (raw or "").strip()
|
||||
@@ -505,19 +524,18 @@ def sea_quote_detail_text(
|
||||
history_work_order_no: str = "",
|
||||
status: str = "已报价",
|
||||
) -> str:
|
||||
"""海运完整价格明细文本。不受卡片引用条字数限制。"""
|
||||
"""
|
||||
海运完整价格明细文本:来源、工单号、费用行、合计。
|
||||
|
||||
时效、报价有效期只在卡片上出现,这里不写,避免和卡重复。
|
||||
不受卡片引用条字数限制。first_or_same 只兼容调用方。
|
||||
"""
|
||||
_ = first_or_same, history_work_order_no, status
|
||||
src = dict(quote or {})
|
||||
source = str(src.get("source_label") or "TMS标准报价").replace(" ", "")
|
||||
lines = [source, f"{work_order_no}价格明细"]
|
||||
lines.extend(
|
||||
quote_detail_lines(
|
||||
src,
|
||||
first_or_same=first_or_same,
|
||||
history_work_order_no=history_work_order_no,
|
||||
status=status,
|
||||
)
|
||||
return "\n".join(
|
||||
[source, f"{work_order_no}价格明细", quote_area_fee_text(src)]
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def collab_hint(work_order_no: str) -> str:
|
||||
@@ -957,6 +975,11 @@ def sea_group_no_staff() -> str:
|
||||
return "没有可拉的产品人员。请先在后台「员工管理」维护本线路的海运产品岗后再试。"
|
||||
|
||||
|
||||
def group_sheet_send_fail() -> str:
|
||||
"""模板已填好但没发进群。"""
|
||||
return "报价单已生成,发到群里失败,请稍后重试。"
|
||||
|
||||
|
||||
def sea_group_create_fail(*, reason: str = "") -> str:
|
||||
"""建群失败,按钮保持可点。"""
|
||||
extra = (reason or "").strip()
|
||||
@@ -978,7 +1001,8 @@ def sea_group_brief(
|
||||
"""
|
||||
群里自动摘要:@销售 @产品 + 工单号 + 询价字段 + 协同字段 + TMS 报价。
|
||||
|
||||
协同没填写 -。无价写明暂无匹配报价。
|
||||
三段之间空一行,方便群里扫。协同没填写 -。
|
||||
HS编码对外写成商品海关编码。无价只写「TMS 暂无匹配报价」。
|
||||
"""
|
||||
no = (work_order_no or "").strip()
|
||||
sales = (sales_name or "").strip() or "销售"
|
||||
@@ -988,16 +1012,19 @@ def sea_group_brief(
|
||||
lines.extend(
|
||||
inquiry_field_lines(work_order_no=no, facts=facts, transport_mode="海运")[1:]
|
||||
)
|
||||
lines.append("")
|
||||
lines.append("协同补充字段:")
|
||||
collab = dict(collab_facts or {})
|
||||
for key in SEA_COLLAB_FIELDS:
|
||||
val = (collab.get(key) or "").strip() or "-"
|
||||
lines.append(f"{key}:{val}")
|
||||
label = SEA_COLLAB_DISPLAY.get(key, key)
|
||||
val = (collab.get(key) or collab.get(label) or "").strip() or "-"
|
||||
lines.append(f"{label}:{val}")
|
||||
lines.append("")
|
||||
lines.append("TMS报价:")
|
||||
if has_price and quote:
|
||||
lines.extend(quote_detail_lines(quote))
|
||||
else:
|
||||
lines.append("TMS 暂无匹配报价 / 未查到合适报价")
|
||||
lines.append("TMS 暂无匹配报价")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
@@ -1244,6 +1271,7 @@ def deal_wecom_payload(
|
||||
work_order_no: str,
|
||||
quote: dict[str, Any] | None = None,
|
||||
facts: dict[str, str] | None = None,
|
||||
card_version: int = 0,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
成交跟进卡:对齐现网 button_interaction。
|
||||
@@ -1254,6 +1282,8 @@ def deal_wecom_payload(
|
||||
src = dict(quote or {})
|
||||
source = str(src.get("source_label") or "TMS标准报价").replace(" ", "")
|
||||
no = (work_order_no or "").strip()
|
||||
ver = int(card_version or 0)
|
||||
suffix = f":v{ver}" if ver > 0 else ""
|
||||
return {
|
||||
"msgtype": "template_card",
|
||||
"template_card": {
|
||||
@@ -1270,23 +1300,75 @@ def deal_wecom_payload(
|
||||
{
|
||||
"text": BTN_DEAL,
|
||||
"style": 1,
|
||||
"key": f"{BTN_DEAL_KEY}:{no}",
|
||||
"key": f"{BTN_DEAL_KEY}:{no}{suffix}",
|
||||
},
|
||||
{
|
||||
"text": BTN_LOST,
|
||||
"style": 1,
|
||||
"key": f"{BTN_LOST_KEY}:{no}",
|
||||
"key": f"{BTN_LOST_KEY}:{no}{suffix}",
|
||||
},
|
||||
{
|
||||
"text": BTN_NEGOTIATE,
|
||||
"style": 1,
|
||||
"key": f"{BTN_NEGOTIATE_KEY}:{no}",
|
||||
"key": f"{BTN_NEGOTIATE_KEY}:{no}{suffix}",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def ticket_locked(*, work_order_no: str, status: str) -> str:
|
||||
"""已成交/未成交/已关闭后,群里改字段或再报价。"""
|
||||
no = (work_order_no or "").strip() or "该工单"
|
||||
st = (status or "").strip() or "已关闭"
|
||||
return f"工单{no}{st},不能修改工单信息"
|
||||
|
||||
|
||||
def ticket_locked_file(*, work_order_no: str, status: str) -> str:
|
||||
"""终态工单再发 Excel/PDF。"""
|
||||
no = (work_order_no or "").strip() or "该工单"
|
||||
st = (status or "").strip() or "已关闭"
|
||||
return f"工单{no}{st},不能再上传附件"
|
||||
|
||||
|
||||
def group_only_excel_pdf() -> str:
|
||||
return "群里只收 Excel 和 PDF,其它文件不会存入工单"
|
||||
|
||||
|
||||
def group_quote_not_recognized() -> str:
|
||||
return "没有识别到报价,请产品再发一次价格或 Excel/PDF"
|
||||
|
||||
|
||||
def group_fields_not_recognized() -> str:
|
||||
return "听到了。请直接说贸易条款、货好时间、商品海关编码、是否含油/含电/含磁。"
|
||||
|
||||
|
||||
def group_deal_stale(*, work_order_no: str) -> str:
|
||||
"""点了上一版成交卡。"""
|
||||
no = (work_order_no or "").strip()
|
||||
return f"这张成交确认已过期。工单{no}已有更新的报价,请点击群里最新一条成交跟进。"
|
||||
|
||||
|
||||
def group_deal_sales_only() -> str:
|
||||
return "只有负责该工单的销售可以确认成交状态。"
|
||||
|
||||
|
||||
def group_dissolved(*, work_order_no: str) -> str:
|
||||
no = (work_order_no or "").strip()
|
||||
return f"群已解散。工单{no}协同已结束。"
|
||||
|
||||
|
||||
def group_cannot_recreate(*, work_order_no: str) -> str:
|
||||
"""解散后再点拉群。"""
|
||||
no = (work_order_no or "").strip() or "该工单"
|
||||
return f"工单{no}协同已结束,不能再拉群。"
|
||||
|
||||
|
||||
def group_deal_mention(*, sales_name: str, work_order_no: str) -> str:
|
||||
name = (sales_name or "").strip() or "销售"
|
||||
return f"@{name}\n{deal_card(work_order_no=work_order_no)}"
|
||||
|
||||
|
||||
def deal_ack(outcome: str, work_order_no: str) -> str:
|
||||
if outcome == "已成交":
|
||||
return f"已记录为「已成交」。工单 {work_order_no} 已关闭智能体跟进。"
|
||||
|
||||
Reference in New Issue
Block a user