89 lines
3.0 KiB
Python
89 lines
3.0 KiB
Python
"""
|
|
意图:询价卡片按钮(复制工单号 / 拉产品进群 / 跳过协同 / 采用 / 不采用 / 成交)。
|
|
|
|
本文件职责:校验当前会话允许的动作后交给流程执行。
|
|
禁止:不校验 wait/允许集合就改主账;禁止一个函数处理未声明的新按钮。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from agent.channel.queue import get_message_store
|
|
from agent.policy import inquiry_copy as copy
|
|
from agent.policy.air_text_flow import get_air_text_flow
|
|
from agent.policy.land_text_flow import get_land_text_flow
|
|
from agent.policy.sea_text_flow import get_sea_text_flow
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _pick_card_flow(sender_id: str, payload: dict | None):
|
|
"""点卡:海运/陆运书签能找回工单就走对应流程,否则空运。"""
|
|
sea = get_sea_text_flow()
|
|
sess = sea.session_for_action(sender_id, payload)
|
|
if sess and (sess.business_line or "").upper() == "SEA":
|
|
return sea
|
|
land = get_land_text_flow()
|
|
land_sess = land.session_for_action(sender_id, payload)
|
|
if land_sess and (land_sess.business_line or "").upper() == "LAND":
|
|
return land
|
|
return get_air_text_flow()
|
|
|
|
|
|
def handle_card_action(
|
|
*,
|
|
sender_id: str,
|
|
thread_id: str,
|
|
wait_version: int,
|
|
action: str,
|
|
payload: dict[str, Any] | None = None,
|
|
flow=None,
|
|
store=None,
|
|
) -> str:
|
|
"""
|
|
处理一次卡片动作。
|
|
|
|
wait_version:会话书签版本;错版本丢弃,不重放副作用。
|
|
payload 须带 task_id / event_key,才能找回点卡当时的工单。
|
|
"""
|
|
_ = thread_id
|
|
if not (sender_id or "").strip():
|
|
return "reject_no_sender"
|
|
engine = flow or _pick_card_flow(sender_id, payload)
|
|
sess = engine.session_for_action(sender_id, payload)
|
|
if sess and wait_version and sess.wait_version != wait_version:
|
|
logger.info("card waitVersion 不匹配 expect=%s got=%s", sess.wait_version, wait_version)
|
|
return "card_discard"
|
|
|
|
msg_store = store or get_message_store()
|
|
|
|
def reply(text: str, extra: dict | None = None) -> str:
|
|
# 销售询价正文不加 [test];[test] 只给运维告警
|
|
body = text
|
|
extra = dict(extra or {})
|
|
wo = ""
|
|
if sess is not None:
|
|
wo = (sess.work_order_no or "").strip()
|
|
if not wo:
|
|
wo = copy.work_order_from_card_meta(payload)
|
|
code = str((payload or {}).get("response_code") or extra.get("response_code") or "")[:24]
|
|
ok, info = msg_store.enqueue_outbound(
|
|
touser=sender_id,
|
|
content=body,
|
|
dedupe_key=(
|
|
f"card:{sender_id}:{wo}:{code}:"
|
|
f"{sess.wait_version if sess else 0}:{action}:{body[:20]}"
|
|
),
|
|
payload=extra,
|
|
)
|
|
if not ok:
|
|
logger.warning("card 出站被去重 sender=%s wo=%s info=%s", sender_id, wo or "-", info)
|
|
return ""
|
|
return info
|
|
|
|
return engine.on_button(
|
|
sender_id=sender_id, action=action, reply=reply, card_meta=payload
|
|
)
|