补齐成交跟进:按线路推成交通知、收下未成交原因、协商中按工作日再问。
成交走询价消息服务;陆运/海运私聊下一句能记下原因;协商中回执写明顺延三个工作日和下次 9:00。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -322,6 +322,8 @@ class AirTextInquiryFlow:
|
||||
allowed = (copy.BTN_ADOPT_EXCEL, copy.BTN_ADOPT_PDF, copy.BTN_REJECT)
|
||||
elif phase == "wait_deal":
|
||||
allowed = (copy.BTN_DEAL, copy.BTN_LOST, copy.BTN_NEGOTIATE)
|
||||
elif phase == "wait_lost_reason":
|
||||
allowed = ()
|
||||
return FlowSession(
|
||||
sender_id=sender_id,
|
||||
thread_id=sender_id,
|
||||
@@ -333,11 +335,17 @@ class AirTextInquiryFlow:
|
||||
status=status,
|
||||
allowed=allowed,
|
||||
wait_version=1,
|
||||
invited_sales_name=str(view.get("sales_name") or view.get("salesName") or ""),
|
||||
collab_chat_id=str(view.get("collab_chat_id") or ""),
|
||||
)
|
||||
|
||||
def _infer_wait_phase(self, *, status: str, quote: dict[str, Any]) -> str:
|
||||
if status in {"已成交", "未成交", "协商中", "已关闭"}:
|
||||
if status in {"已成交", "已关闭"}:
|
||||
return "done"
|
||||
if status == "未成交":
|
||||
return "wait_lost_reason"
|
||||
if status == "协商中":
|
||||
return "wait_deal"
|
||||
if status == "已报价" and quote:
|
||||
return "wait_adopt"
|
||||
return "tms_miss"
|
||||
@@ -413,6 +421,9 @@ class AirTextInquiryFlow:
|
||||
# 成交卡已经绑在报价文件那条出站上。这里再发一张独立卡,
|
||||
# 会在文件还在上传时被另一条出站线程抢走,销售又先看到成交跟进。
|
||||
return "wait_deal"
|
||||
if sess.phase == "wait_lost_reason":
|
||||
reply(copy.deal_ack("未成交", sess.work_order_no))
|
||||
return "wait_lost_reason"
|
||||
if sess.phase == "done":
|
||||
reply(copy.deal_ack(sess.status or "已关闭", sess.work_order_no))
|
||||
return "done"
|
||||
@@ -462,6 +473,13 @@ class AirTextInquiryFlow:
|
||||
reply=reply,
|
||||
card_meta=inbound_raw,
|
||||
)
|
||||
# 未成交后下一句任意文字即原因;完整新询价(注入字段)则空着原因开新单。
|
||||
if (
|
||||
sess
|
||||
and sess.phase == "wait_lost_reason"
|
||||
and not (injected_facts and injected_mode)
|
||||
):
|
||||
return self._capture_lost_reason(sess, text, reply)
|
||||
|
||||
snap = extract_inquiry_snapshot(
|
||||
text,
|
||||
@@ -1056,15 +1074,48 @@ class AirTextInquiryFlow:
|
||||
) -> str:
|
||||
"""点成交/未成交/协商中:先整卡置灰,再入主账。"""
|
||||
self._grey_clicked_card(reply, card_meta, replace_name=status)
|
||||
result = self._ledger.transition(work_order_no=sess.work_order_no, to_status=status)
|
||||
from agent.policy.deal_outcome import finish_deal_outcome
|
||||
|
||||
result = finish_deal_outcome(
|
||||
ledger=self._ledger,
|
||||
work_order_no=sess.work_order_no,
|
||||
outcome=status,
|
||||
facts=sess.facts,
|
||||
quote=sess.quote,
|
||||
business_line=sess.business_line,
|
||||
sales_name=sess.invited_sales_name,
|
||||
)
|
||||
if not result.get("ok"):
|
||||
reply("主账状态更新失败,成交结果未入账。")
|
||||
return "ledger_fail"
|
||||
phase = str(result.get("phase") or "done")
|
||||
sess.status = status
|
||||
sess.phase = phase
|
||||
if phase == "wait_deal":
|
||||
sess.allowed = (copy.BTN_DEAL, copy.BTN_LOST, copy.BTN_NEGOTIATE)
|
||||
else:
|
||||
sess.allowed = ()
|
||||
sess.wait_version += 1
|
||||
self._save(sess)
|
||||
reply(copy.deal_ack(status, sess.work_order_no, str(result.get("next_followup_at") or "")))
|
||||
return phase
|
||||
|
||||
def _capture_lost_reason(self, sess: FlowSession, text: str, reply: ReplyFn) -> str:
|
||||
"""私聊未成交后收下原因,不再追问。"""
|
||||
from agent.policy.deal_outcome import capture_lost_reason
|
||||
|
||||
result = capture_lost_reason(
|
||||
ledger=self._ledger,
|
||||
work_order_no=sess.work_order_no,
|
||||
reason=text,
|
||||
)
|
||||
if not result.get("ok"):
|
||||
reply("未成交原因没有记下,请再发一句。")
|
||||
return "wait_lost_reason"
|
||||
sess.phase = "done"
|
||||
sess.allowed = ()
|
||||
self._save(sess)
|
||||
reply(copy.deal_ack(status, sess.work_order_no))
|
||||
reply(copy.lost_reason_ack(text))
|
||||
return "done"
|
||||
|
||||
def mark_wait_deal(self, sender_id: str, work_order_no: str) -> None:
|
||||
|
||||
Reference in New Issue
Block a user