空运人工价锁舱现拉补全舱位并拦清缺参;成交/报价填表与工单陆运费率展示同步收紧。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -210,7 +210,11 @@ def finish_deal_outcome(
|
||||
writer = getattr(ledger, "transition", None)
|
||||
if not callable(writer):
|
||||
return {"ok": False, "error": "no_transition", "phase": "ledger_fail"}
|
||||
result = writer(work_order_no=no, to_status=status, **extra) or {}
|
||||
# 报价文件已出、会话已进入成交跟进,但主账仍停在「询价中」时,
|
||||
# 直接迁「未成交/已成交/协商中」会被六态拒绝。先补「已报价」再迁目标态。
|
||||
result = _transition_deal_status(
|
||||
writer, work_order_no=no, to_status=status, extra=extra, ledger=ledger
|
||||
)
|
||||
if not result.get("ok"):
|
||||
return {"ok": False, "error": result.get("error") or "transition_failed", "phase": "ledger_fail"}
|
||||
from agent.policy.event_exception import WAIT_LOST_REASON, clear_wait, start_wait
|
||||
@@ -241,6 +245,79 @@ def finish_deal_outcome(
|
||||
}
|
||||
|
||||
|
||||
def _transition_deal_status(
|
||||
writer: Callable[..., dict[str, Any]],
|
||||
*,
|
||||
work_order_no: str,
|
||||
to_status: str,
|
||||
extra: dict[str, Any],
|
||||
ledger: Any = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
写入成交三态。若主账仍停在询价中,先迁已报价再迁目标态。
|
||||
|
||||
运行证据:
|
||||
- WO022/WO023:文件已发仍停询价中,直迁未成交被六态拒绝;
|
||||
- HTTP 500 时 http_ledger 常只回 http_500(正文里的「询价中」丢失),
|
||||
不能只靠错误文案判断,要以工单当前状态为准。
|
||||
"""
|
||||
no = (work_order_no or "").strip()
|
||||
status = (to_status or "").strip()
|
||||
result = writer(work_order_no=no, to_status=status, **extra) or {}
|
||||
if result.get("ok"):
|
||||
return result
|
||||
if status not in {"已成交", "未成交", "协商中"}:
|
||||
return result
|
||||
err = str(result.get("error") or result.get("message") or "")
|
||||
cur = ""
|
||||
getter = getattr(ledger, "get_for_agent", None) if ledger is not None else None
|
||||
if callable(getter):
|
||||
try:
|
||||
snap = getter(work_order_no=no, sender_id="") or {}
|
||||
cur = str(snap.get("status") or "").strip()
|
||||
except Exception:
|
||||
cur = ""
|
||||
# 状态确认询价中,或错误文案带询价中,或仅有 http_5xx 时仍尝试补已报价。
|
||||
should_promote = (
|
||||
cur == "询价中"
|
||||
or "询价中" in err
|
||||
or err.startswith("http_5")
|
||||
or err in {"transition_failed", "ledger_error"}
|
||||
)
|
||||
if not should_promote:
|
||||
return result
|
||||
promoted = writer(
|
||||
work_order_no=no,
|
||||
to_status="已报价",
|
||||
remark="成交跟进前补已报价",
|
||||
) or {}
|
||||
if not promoted.get("ok"):
|
||||
return result
|
||||
return writer(work_order_no=no, to_status=status, **extra) or {}
|
||||
|
||||
|
||||
def ensure_ticket_quoted(ledger: Any, *, work_order_no: str) -> dict[str, Any]:
|
||||
"""
|
||||
报价文件发出 / 进入成交跟进时,保证主账至少是「已报价」。
|
||||
|
||||
幂等:已离开「询价中」则不再迁态(已报价→已报价会被六态拒绝)。
|
||||
"""
|
||||
no = (work_order_no or "").strip()
|
||||
writer = getattr(ledger, "transition", None)
|
||||
if not no or not callable(writer):
|
||||
return {"ok": False, "error": "no_transition"}
|
||||
getter = getattr(ledger, "get_for_agent", None)
|
||||
if callable(getter):
|
||||
try:
|
||||
snap = getter(work_order_no=no, sender_id="") or {}
|
||||
except Exception:
|
||||
snap = {}
|
||||
st = str(snap.get("status") or "").strip()
|
||||
if st and st != "询价中":
|
||||
return {"ok": True, "status": st, "skipped": True}
|
||||
return writer(work_order_no=no, to_status="已报价", remark="报价文件已出") or {}
|
||||
|
||||
|
||||
def capture_lost_reason(*, ledger: Any, work_order_no: str, reason: str) -> dict[str, Any]:
|
||||
"""把销售下一句写进未成交原因。@询价小助手 不是原因。"""
|
||||
text = strip_bot_mentions(reason or "")
|
||||
|
||||
Reference in New Issue
Block a user