落地海运私聊文字询价全流程,海运多项费用改走文本明细,避免企微卡片引用条截断。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -45,11 +45,16 @@ class FlowSession:
|
||||
status: str = ""
|
||||
allowed: tuple[str, ...] = ()
|
||||
immutable_text: str = ""
|
||||
collab_chat_id: str = ""
|
||||
collab_facts: dict[str, str] = field(default_factory=dict)
|
||||
invited_userids: tuple[str, ...] = ()
|
||||
invited_sales_name: str = ""
|
||||
invited_product_names: tuple[str, ...] = ()
|
||||
|
||||
|
||||
class AirTextInquiryFlow:
|
||||
"""
|
||||
空运文字询价 Owner(本轮产品范围);海运/陆运先补问运输方式或陆运二级。
|
||||
空运文字询价 Owner。海运走 SeaTextInquiryFlow,不要再往本文件堆海运。陆运仍补问二级。
|
||||
|
||||
同一 sender 新开询价会覆盖「当前书签」(旧单留在主账)。
|
||||
价格卡按工单号另存一份当时会话:点哪张卡就生成哪张卡当时的报价单。
|
||||
@@ -69,6 +74,25 @@ class AirTextInquiryFlow:
|
||||
with self._lock:
|
||||
return self._by_sender.get(sender_id)
|
||||
|
||||
def session_by_ticket(self, sender_id: str, work_order_no: str) -> Optional[FlowSession]:
|
||||
"""
|
||||
只查进程内该书签,不读主账。
|
||||
|
||||
续办选空运/海运流程用:海运已跳过协同时必须找回 wait_adopt,
|
||||
不能因为主账把已报价海运一律收成 wait_collab 就套空运协同卡。
|
||||
"""
|
||||
no = (work_order_no or "").strip().upper()
|
||||
if not (sender_id or "").strip() or not no:
|
||||
return None
|
||||
with self._lock:
|
||||
hit = self._by_ticket.get(no)
|
||||
if hit and hit.sender_id == sender_id:
|
||||
return hit
|
||||
for key, sess in self._by_ticket.items():
|
||||
if (key or "").upper() == no and sess.sender_id == sender_id:
|
||||
return sess
|
||||
return None
|
||||
|
||||
def session_for_action(
|
||||
self,
|
||||
sender_id: str,
|
||||
@@ -152,6 +176,7 @@ class AirTextInquiryFlow:
|
||||
else:
|
||||
keep = None
|
||||
if keep:
|
||||
self._align_resume_phase(keep)
|
||||
return self._replay_wait(keep, reply, source="session")
|
||||
getter = getattr(self._ledger, "get_for_agent", None)
|
||||
if not callable(getter):
|
||||
@@ -165,6 +190,7 @@ class AirTextInquiryFlow:
|
||||
reply("这张工单不属于当前账号,不能继续。")
|
||||
return "ticket_forbidden"
|
||||
sess = self._session_from_ledger(sender_id=sender_id, view=view)
|
||||
self._align_resume_phase(sess)
|
||||
self._save(sess)
|
||||
return self._replay_wait(sess, reply, source="ledger")
|
||||
|
||||
@@ -204,6 +230,20 @@ class AirTextInquiryFlow:
|
||||
return "wait_adopt"
|
||||
return "tms_miss"
|
||||
|
||||
def _align_resume_phase(self, sess: FlowSession) -> None:
|
||||
"""
|
||||
报价文件已经发给销售,续办必须回到成交跟进。
|
||||
|
||||
主账六态仍是「已报价」,不能据此重放到协同卡或生成报价单。
|
||||
Redis 就绪键由出文件时写入;主账 wait_phase=wait_deal 也认。
|
||||
"""
|
||||
if sess.phase not in {"wait_collab", "wait_adopt", "wait_file"}:
|
||||
return
|
||||
issued = bool((sess.quote or {}).get("quoteFileIssued"))
|
||||
if issued or self._quote_file_already_out(sess.work_order_no):
|
||||
logger.info("resume 报价文件已出,回到成交跟进 wo=%s was=%s", sess.work_order_no, sess.phase)
|
||||
self._promote_wait_deal(sess)
|
||||
|
||||
def _replay_wait(self, sess: FlowSession, reply: ReplyFn, *, source: str) -> str:
|
||||
"""按书签重出当时节点,不改六态。"""
|
||||
logger.info(
|
||||
@@ -213,18 +253,21 @@ class AirTextInquiryFlow:
|
||||
source,
|
||||
)
|
||||
if sess.phase == "wait_adopt":
|
||||
mode = copy.scheme_transport_mode(sess.business_line)
|
||||
reply(
|
||||
copy.scheme_card(
|
||||
work_order_no=sess.work_order_no,
|
||||
status=sess.status or "已报价",
|
||||
facts=sess.facts,
|
||||
quote=sess.quote,
|
||||
transport_mode=mode,
|
||||
),
|
||||
copy.scheme_wecom_payload(
|
||||
work_order_no=sess.work_order_no,
|
||||
facts=sess.facts,
|
||||
quote=sess.quote,
|
||||
status=sess.status or "已报价",
|
||||
transport_mode=mode,
|
||||
),
|
||||
)
|
||||
return "wait_adopt"
|
||||
@@ -349,9 +392,23 @@ class AirTextInquiryFlow:
|
||||
if mode == "LAND":
|
||||
reply(copy.ASK_LAND_SUBTYPE)
|
||||
return "need_land_subtype"
|
||||
# 海运本轮只提示先走空运闭环(不半做海运查价)
|
||||
reply("本轮先开通空运文字询价。请按空运描述需求,或补充为「空运」。")
|
||||
return "sea_deferred"
|
||||
if mode == "SEA":
|
||||
# 海运交给海运 Owner,空运不再回「本轮先开通空运」
|
||||
from agent.policy.sea_text_flow import get_sea_text_flow
|
||||
|
||||
return get_sea_text_flow().on_text(
|
||||
sender_id=sender_id,
|
||||
text=text,
|
||||
reply=reply,
|
||||
injected_facts=facts,
|
||||
injected_mode=mode,
|
||||
b_result=b_result,
|
||||
allow_b=allow_b,
|
||||
chat_fn=chat_fn,
|
||||
inbound_raw=inbound_raw,
|
||||
)
|
||||
reply("请补充运输方式:空运、海运或陆运。")
|
||||
return "need_mode"
|
||||
|
||||
check = validate_required_fields(facts=facts, business_line="AIR")
|
||||
facts = dict(check["facts"])
|
||||
@@ -640,18 +697,21 @@ class AirTextInquiryFlow:
|
||||
sess.allowed = (copy.BTN_ADOPT_EXCEL, copy.BTN_ADOPT_PDF, copy.BTN_REJECT)
|
||||
sess.wait_version += 1
|
||||
self._save(sess)
|
||||
mode = copy.scheme_transport_mode(sess.business_line)
|
||||
reply(
|
||||
copy.scheme_card(
|
||||
work_order_no=sess.work_order_no,
|
||||
status=sess.status or "已报价",
|
||||
facts=sess.facts,
|
||||
quote=sess.quote,
|
||||
transport_mode=mode,
|
||||
),
|
||||
copy.scheme_wecom_payload(
|
||||
work_order_no=sess.work_order_no,
|
||||
facts=sess.facts,
|
||||
quote=sess.quote,
|
||||
status=sess.status or "已报价",
|
||||
transport_mode=mode,
|
||||
),
|
||||
)
|
||||
return "wait_adopt"
|
||||
@@ -763,6 +823,9 @@ class AirTextInquiryFlow:
|
||||
file_extra,
|
||||
)
|
||||
self._wait_outbound_sent(str(out_id or ""), work_order_no=sess.work_order_no, what="报价文件")
|
||||
from agent.redis_coord.quote_file import mark_quote_file_ready
|
||||
|
||||
mark_quote_file_ready(sess.work_order_no)
|
||||
sess.phase = "wait_deal"
|
||||
sess.allowed = (copy.BTN_DEAL, copy.BTN_LOST, copy.BTN_NEGOTIATE)
|
||||
sess.wait_version += 1
|
||||
|
||||
Reference in New Issue
Block a user