@@ -39,14 +39,14 @@ def poll_due_negotiate(*, ledger: Any = None, settings: Optional[Settings] = Non
|
|||||||
if not isinstance(row, dict):
|
if not isinstance(row, dict):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
if _reask_one(row, settings=cfg):
|
if _reask_one(row, settings=cfg, ledger=book):
|
||||||
sent += 1
|
sent += 1
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("协商再问失败 wo=%s", row.get("work_order_no") or row.get("workOrderNo"))
|
logger.exception("协商再问失败 wo=%s", row.get("work_order_no") or row.get("workOrderNo"))
|
||||||
return sent
|
return sent
|
||||||
|
|
||||||
|
|
||||||
def _reask_one(row: dict[str, Any], *, settings: Settings) -> bool:
|
def _reask_one(row: dict[str, Any], *, settings: Settings, ledger: Any = None) -> bool:
|
||||||
no = str(row.get("work_order_no") or row.get("workOrderNo") or "").strip()
|
no = str(row.get("work_order_no") or row.get("workOrderNo") or "").strip()
|
||||||
if not no:
|
if not no:
|
||||||
return False
|
return False
|
||||||
@@ -68,7 +68,9 @@ def _reask_one(row: dict[str, Any], *, settings: Settings) -> bool:
|
|||||||
)
|
)
|
||||||
if not ok:
|
if not ok:
|
||||||
logger.warning("协商再问原群失败且不补发私聊 wo=%s chat=%s", no, chat_id)
|
logger.warning("协商再问原群失败且不补发私聊 wo=%s chat=%s", no, chat_id)
|
||||||
return ok
|
return False
|
||||||
|
_start_deal_wait(ledger, no)
|
||||||
|
return True
|
||||||
if not sales:
|
if not sales:
|
||||||
logger.warning("协商再问无销售 userid wo=%s", no)
|
logger.warning("协商再问无销售 userid wo=%s", no)
|
||||||
return False
|
return False
|
||||||
@@ -84,7 +86,16 @@ def _reask_one(row: dict[str, Any], *, settings: Settings) -> bool:
|
|||||||
)
|
)
|
||||||
if not ok:
|
if not ok:
|
||||||
logger.warning("协商再问私聊入队失败 wo=%s info=%s", no, info)
|
logger.warning("协商再问私聊入队失败 wo=%s info=%s", no, info)
|
||||||
return bool(ok)
|
return False
|
||||||
|
_start_deal_wait(ledger, no)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _start_deal_wait(ledger: Any, work_order_no: str) -> None:
|
||||||
|
"""再问发出后重新盯成交跟进。ledger 可空。"""
|
||||||
|
from agent.policy.event_exception import WAIT_DEAL, start_wait
|
||||||
|
|
||||||
|
start_wait(ledger, work_order_no=work_order_no, wait_kind=WAIT_DEAL)
|
||||||
|
|
||||||
|
|
||||||
def _send_group_reask(
|
def _send_group_reask(
|
||||||
|
|||||||
@@ -163,7 +163,14 @@ def _deliver_quote_file(data: dict[str, Any], result: LibreOfficeResult) -> None
|
|||||||
if wo:
|
if wo:
|
||||||
try:
|
try:
|
||||||
from agent.policy.air_text_flow import get_air_text_flow
|
from agent.policy.air_text_flow import get_air_text_flow
|
||||||
|
from agent.policy.event_exception import WAIT_DEAL, start_wait
|
||||||
|
|
||||||
|
flow = get_air_text_flow()
|
||||||
|
start_wait(
|
||||||
|
getattr(flow, "_ledger", None) or getattr(flow, "ledger", None),
|
||||||
|
work_order_no=wo,
|
||||||
|
wait_kind=WAIT_DEAL,
|
||||||
|
)
|
||||||
get_air_text_flow().mark_wait_deal(touser, wo)
|
get_air_text_flow().mark_wait_deal(touser, wo)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("PDF 出文件后未能切到成交跟进 inquiry=%s", wo)
|
logger.exception("PDF 出文件后未能切到成交跟进 inquiry=%s", wo)
|
||||||
|
|||||||
@@ -138,6 +138,9 @@ def activate_ticket(
|
|||||||
if speak:
|
if speak:
|
||||||
send_air_brief_and_sheet(flow=flow, ticket=ticket, chat_id=chat_id)
|
send_air_brief_and_sheet(flow=flow, ticket=ticket, chat_id=chat_id)
|
||||||
_watch_archive_room(chat_id, no)
|
_watch_archive_room(chat_id, no)
|
||||||
|
from agent.policy.event_exception import WAIT_AIR_QUOTE, start_wait
|
||||||
|
|
||||||
|
start_wait(flow.ledger, work_order_no=no, wait_kind=WAIT_AIR_QUOTE)
|
||||||
return ticket, "activated"
|
return ticket, "activated"
|
||||||
|
|
||||||
|
|
||||||
@@ -447,6 +450,9 @@ def apply_air_file(
|
|||||||
return "ledger_fail"
|
return "ledger_fail"
|
||||||
view["collab_chat_id"] = chat_id
|
view["collab_chat_id"] = chat_id
|
||||||
view["quote"] = quote
|
view["quote"] = quote
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(flow.ledger, work_order_no=no)
|
||||||
emit_group_deal(flow=flow, ticket=view, quote=quote)
|
emit_group_deal(flow=flow, ticket=view, quote=quote)
|
||||||
return "airline_file_quote"
|
return "airline_file_quote"
|
||||||
|
|
||||||
@@ -532,6 +538,9 @@ def apply_air_confirm_tms(*, flow: Any, ticket: object, sender_id: str, chat_id:
|
|||||||
business_line="AIR",
|
business_line="AIR",
|
||||||
)
|
)
|
||||||
notify_quote_attachment_saved(flow, chat_id, no, count=1)
|
notify_quote_attachment_saved(flow, chat_id, no, count=1)
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(flow.ledger, work_order_no=no)
|
||||||
emit_group_deal(flow=flow, ticket=view, quote=quote)
|
emit_group_deal(flow=flow, ticket=view, quote=quote)
|
||||||
return "quote_confirmed"
|
return "quote_confirmed"
|
||||||
|
|
||||||
@@ -802,6 +811,9 @@ def _commit_quote(
|
|||||||
if not up.get("ok"):
|
if not up.get("ok"):
|
||||||
send_group_text(group_client_of(flow), chat_id, "主账写入报价失败。")
|
send_group_text(group_client_of(flow), chat_id, "主账写入报价失败。")
|
||||||
return "ledger_fail"
|
return "ledger_fail"
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(flow.ledger, work_order_no=no)
|
||||||
ticket2 = current_ticket(flow, chat_id) or ticket
|
ticket2 = current_ticket(flow, chat_id) or ticket
|
||||||
view = ticket_view(ticket2)
|
view = ticket_view(ticket2)
|
||||||
view["collab_chat_id"] = chat_id
|
view["collab_chat_id"] = chat_id
|
||||||
|
|||||||
@@ -1076,6 +1076,9 @@ class AirTextInquiryFlow:
|
|||||||
return self._skip_collab(sess, reply, card_meta=card_meta)
|
return self._skip_collab(sess, reply, card_meta=card_meta)
|
||||||
if action == copy.BTN_REJECT:
|
if action == copy.BTN_REJECT:
|
||||||
self._grey_clicked_card(reply, card_meta)
|
self._grey_clicked_card(reply, card_meta)
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(self._ledger, work_order_no=sess.work_order_no)
|
||||||
sess.phase = "wait_adjust"
|
sess.phase = "wait_adjust"
|
||||||
sess.allowed = ()
|
sess.allowed = ()
|
||||||
sess.wait_version += 1
|
sess.wait_version += 1
|
||||||
@@ -1128,6 +1131,9 @@ class AirTextInquiryFlow:
|
|||||||
transport_mode=mode,
|
transport_mode=mode,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
from agent.policy.event_exception import WAIT_ADOPT, start_wait
|
||||||
|
|
||||||
|
start_wait(self._ledger, work_order_no=sess.work_order_no, wait_kind=WAIT_ADOPT)
|
||||||
return "wait_adopt"
|
return "wait_adopt"
|
||||||
|
|
||||||
def _grey_clicked_card(
|
def _grey_clicked_card(
|
||||||
@@ -1186,6 +1192,9 @@ class AirTextInquiryFlow:
|
|||||||
reply(str(result.get("message") or copy.quote_template_missing()))
|
reply(str(result.get("message") or copy.quote_template_missing()))
|
||||||
return "wait_adopt"
|
return "wait_adopt"
|
||||||
filename = str(result.get("fileName") or f"{sess.work_order_no}_quote.{fmt}")
|
filename = str(result.get("fileName") or f"{sess.work_order_no}_quote.{fmt}")
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(self._ledger, work_order_no=sess.work_order_no)
|
||||||
file_extra = self._quote_file_payload(result, filename=filename)
|
file_extra = self._quote_file_payload(result, filename=filename)
|
||||||
if kind == "PDF" and result.get("needsPdf"):
|
if kind == "PDF" and result.get("needsPdf"):
|
||||||
queued = self._enqueue_quote_pdf(
|
queued = self._enqueue_quote_pdf(
|
||||||
@@ -1264,6 +1273,9 @@ class AirTextInquiryFlow:
|
|||||||
sess.allowed = (copy.BTN_DEAL, copy.BTN_LOST, copy.BTN_NEGOTIATE)
|
sess.allowed = (copy.BTN_DEAL, copy.BTN_LOST, copy.BTN_NEGOTIATE)
|
||||||
sess.wait_version += 1
|
sess.wait_version += 1
|
||||||
self._save(sess)
|
self._save(sess)
|
||||||
|
from agent.policy.event_exception import WAIT_DEAL, start_wait
|
||||||
|
|
||||||
|
start_wait(self._ledger, work_order_no=sess.work_order_no, wait_kind=WAIT_DEAL)
|
||||||
return "wait_deal"
|
return "wait_deal"
|
||||||
|
|
||||||
def _emit_deal(self, reply: ReplyFn, sess: FlowSession) -> None:
|
def _emit_deal(self, reply: ReplyFn, sess: FlowSession) -> None:
|
||||||
@@ -1423,6 +1435,9 @@ class AirTextInquiryFlow:
|
|||||||
sess.allowed = (copy.BTN_DEAL, copy.BTN_LOST, copy.BTN_NEGOTIATE)
|
sess.allowed = (copy.BTN_DEAL, copy.BTN_LOST, copy.BTN_NEGOTIATE)
|
||||||
sess.wait_version += 1
|
sess.wait_version += 1
|
||||||
self._save(sess)
|
self._save(sess)
|
||||||
|
from agent.policy.event_exception import WAIT_DEAL, start_wait
|
||||||
|
|
||||||
|
start_wait(self._ledger, work_order_no=sess.work_order_no, wait_kind=WAIT_DEAL)
|
||||||
|
|
||||||
def _refresh_wait_file(self, sess: FlowSession) -> None:
|
def _refresh_wait_file(self, sess: FlowSession) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -133,12 +133,17 @@ def finish_deal_outcome(
|
|||||||
result = writer(work_order_no=no, to_status=status, **extra) or {}
|
result = writer(work_order_no=no, to_status=status, **extra) or {}
|
||||||
if not result.get("ok"):
|
if not result.get("ok"):
|
||||||
return {"ok": False, "error": result.get("error") or "transition_failed", "phase": "ledger_fail"}
|
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
|
||||||
|
|
||||||
if status == "未成交":
|
if status == "未成交":
|
||||||
phase = "wait_lost_reason"
|
phase = "wait_lost_reason"
|
||||||
|
start_wait(ledger, work_order_no=no, wait_kind=WAIT_LOST_REASON)
|
||||||
elif status == "协商中":
|
elif status == "协商中":
|
||||||
phase = "wait_deal"
|
phase = "wait_deal"
|
||||||
|
clear_wait(ledger, work_order_no=no)
|
||||||
else:
|
else:
|
||||||
phase = "done"
|
phase = "done"
|
||||||
|
clear_wait(ledger, work_order_no=no)
|
||||||
return {
|
return {
|
||||||
"ok": True,
|
"ok": True,
|
||||||
"phase": phase,
|
"phase": phase,
|
||||||
@@ -157,4 +162,9 @@ def capture_lost_reason(*, ledger: Any, work_order_no: str, reason: str) -> dict
|
|||||||
patcher = getattr(ledger, "patch_lost_reason", None)
|
patcher = getattr(ledger, "patch_lost_reason", None)
|
||||||
if not callable(patcher):
|
if not callable(patcher):
|
||||||
return {"ok": False, "error": "no_patch"}
|
return {"ok": False, "error": "no_patch"}
|
||||||
return patcher(work_order_no=no, lost_reason=text) or {"ok": False}
|
out = patcher(work_order_no=no, lost_reason=text) or {"ok": False}
|
||||||
|
if out.get("ok"):
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(ledger, work_order_no=no)
|
||||||
|
return out
|
||||||
|
|||||||
@@ -273,6 +273,9 @@ def try_commit_air_group_handoff(flow: Any, *, chat_id: str, work_order_no: str)
|
|||||||
else copy.HANDOFF_INTENT_REASON,
|
else copy.HANDOFF_INTENT_REASON,
|
||||||
)
|
)
|
||||||
sess.status = HANDOFF_STATUS
|
sess.status = HANDOFF_STATUS
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(book, work_order_no=real)
|
||||||
sess.handoff_committed = True
|
sess.handoff_committed = True
|
||||||
sess.handoff_offer = ""
|
sess.handoff_offer = ""
|
||||||
sess.phase = "handoff_done"
|
sess.phase = "handoff_done"
|
||||||
|
|||||||
@@ -1028,6 +1028,9 @@ def emit_group_deal(
|
|||||||
)
|
)
|
||||||
if callable(carder):
|
if callable(carder):
|
||||||
carder(chat_id=chat_id, template_card=payload.get("template_card") or {})
|
carder(chat_id=chat_id, template_card=payload.get("template_card") or {})
|
||||||
|
from agent.policy.event_exception import WAIT_DEAL, start_wait
|
||||||
|
|
||||||
|
start_wait(getattr(flow, "ledger", None), work_order_no=no, wait_kind=WAIT_DEAL)
|
||||||
|
|
||||||
|
|
||||||
def apply_group_deal(
|
def apply_group_deal(
|
||||||
@@ -1485,6 +1488,10 @@ def _save_product_quote(
|
|||||||
saved = writer(work_order_no=no, quote=persist, to_status="已报价") or {}
|
saved = writer(work_order_no=no, quote=persist, to_status="已报价") or {}
|
||||||
if not saved.get("ok") and saved.get("error"):
|
if not saved.get("ok") and saved.get("error"):
|
||||||
logger.warning("产品报价未入主账 wo=%s err=%s", no, saved.get("error"))
|
logger.warning("产品报价未入主账 wo=%s err=%s", no, saved.get("error"))
|
||||||
|
elif (kind or "").strip() != "adjust":
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(flow.ledger, work_order_no=no)
|
||||||
if sess is not None:
|
if sess is not None:
|
||||||
sess.quote = dict(quote)
|
sess.quote = dict(quote)
|
||||||
sess.status = "已报价"
|
sess.status = "已报价"
|
||||||
|
|||||||
@@ -670,6 +670,10 @@ class SeaTextInquiryFlow(AirTextInquiryFlow):
|
|||||||
sess.wait_version += 1
|
sess.wait_version += 1
|
||||||
self._save(sess)
|
self._save(sess)
|
||||||
self._grey_clicked_card(reply, card_meta)
|
self._grey_clicked_card(reply, card_meta)
|
||||||
|
from agent.policy.event_exception import WAIT_PRODUCT_QUOTE, start_wait
|
||||||
|
|
||||||
|
# 系统建群成功:开始盯产品正式报价。
|
||||||
|
start_wait(self._ledger, work_order_no=no, wait_kind=WAIT_PRODUCT_QUOTE)
|
||||||
reply(
|
reply(
|
||||||
copy.sea_group_created(
|
copy.sea_group_created(
|
||||||
work_order_no=no,
|
work_order_no=no,
|
||||||
@@ -811,6 +815,9 @@ class SeaTextInquiryFlow(AirTextInquiryFlow):
|
|||||||
product_ids=product_ids,
|
product_ids=product_ids,
|
||||||
)
|
)
|
||||||
sess.status = HANDOFF_STATUS
|
sess.status = HANDOFF_STATUS
|
||||||
|
from agent.policy.event_exception import clear_wait
|
||||||
|
|
||||||
|
clear_wait(self._ledger, work_order_no=real)
|
||||||
sess.collab_chat_id = chat_id
|
sess.collab_chat_id = chat_id
|
||||||
sess.handoff_committed = True
|
sess.handoff_committed = True
|
||||||
sess.handoff_offer = ""
|
sess.handoff_offer = ""
|
||||||
|
|||||||
@@ -205,6 +205,9 @@ class AirGroupCollabTests(unittest.TestCase):
|
|||||||
ledger=self.ledger,
|
ledger=self.ledger,
|
||||||
)
|
)
|
||||||
self.assertEqual(phase, "activated")
|
self.assertEqual(phase, "activated")
|
||||||
|
ticket = self.ledger.get_ticket(work_order_no=wo1)
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "air_quote")
|
||||||
|
self.assertTrue(ticket.event_wait_started_at)
|
||||||
joined = "\n".join(self._texts())
|
joined = "\n".join(self._texts())
|
||||||
self.assertIn(f"工单号:{wo1}", joined)
|
self.assertIn(f"工单号:{wo1}", joined)
|
||||||
self.assertIn("询价字段:", joined)
|
self.assertIn("询价字段:", joined)
|
||||||
@@ -386,6 +389,8 @@ class AirGroupCollabTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(phase, "quoted")
|
self.assertEqual(phase, "quoted")
|
||||||
ticket = self.ledger.get_ticket(work_order_no=wo)
|
ticket = self.ledger.get_ticket(work_order_no=wo)
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "deal")
|
||||||
|
self.assertTrue(ticket.event_wait_started_at)
|
||||||
self.assertEqual(ticket.status, "已报价")
|
self.assertEqual(ticket.status, "已报价")
|
||||||
self.assertEqual(ticket.quote.get("total"), "USD 900")
|
self.assertEqual(ticket.quote.get("total"), "USD 900")
|
||||||
joined = "\n".join(self._texts())
|
joined = "\n".join(self._texts())
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class TestDealOutcome(unittest.TestCase):
|
|||||||
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
||||||
self.assertEqual(ticket.status, "已成交")
|
self.assertEqual(ticket.status, "已成交")
|
||||||
self.assertEqual(ticket.next_followup_at, "")
|
self.assertEqual(ticket.next_followup_at, "")
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "")
|
||||||
|
|
||||||
def test_deal_notify_card_omits_sales_label(self) -> None:
|
def test_deal_notify_card_omits_sales_label(self) -> None:
|
||||||
"""成交通知不要「销售」二字:标题副标和正文都不写。"""
|
"""成交通知不要「销售」二字:标题副标和正文都不写。"""
|
||||||
@@ -126,6 +127,7 @@ class TestDealOutcome(unittest.TestCase):
|
|||||||
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
||||||
self.assertEqual(ticket.status, "未成交")
|
self.assertEqual(ticket.status, "未成交")
|
||||||
self.assertEqual(ticket.lost_reason, "")
|
self.assertEqual(ticket.lost_reason, "")
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "lost_reason")
|
||||||
view = self.ledger.get_for_agent(work_order_no=self.wo, sender_id="sales1")
|
view = self.ledger.get_for_agent(work_order_no=self.wo, sender_id="sales1")
|
||||||
self.assertEqual(view.get("wait_phase"), "wait_lost_reason")
|
self.assertEqual(view.get("wait_phase"), "wait_lost_reason")
|
||||||
captured = capture_lost_reason(
|
captured = capture_lost_reason(
|
||||||
@@ -134,6 +136,7 @@ class TestDealOutcome(unittest.TestCase):
|
|||||||
self.assertTrue(captured.get("ok"))
|
self.assertTrue(captured.get("ok"))
|
||||||
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
||||||
self.assertEqual(ticket.lost_reason, "客人比价了")
|
self.assertEqual(ticket.lost_reason, "客人比价了")
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "")
|
||||||
view = self.ledger.get_for_agent(work_order_no=self.wo, sender_id="sales1")
|
view = self.ledger.get_for_agent(work_order_no=self.wo, sender_id="sales1")
|
||||||
self.assertEqual(view.get("wait_phase"), "done")
|
self.assertEqual(view.get("wait_phase"), "done")
|
||||||
|
|
||||||
@@ -150,6 +153,7 @@ class TestDealOutcome(unittest.TestCase):
|
|||||||
self.assertNotIn("跟进周期已顺延", text)
|
self.assertNotIn("跟进周期已顺延", text)
|
||||||
|
|
||||||
def test_negotiate_keeps_wait_deal(self) -> None:
|
def test_negotiate_keeps_wait_deal(self) -> None:
|
||||||
|
self.ledger.start_event_wait(work_order_no=self.wo, wait_kind="deal")
|
||||||
out = finish_deal_outcome(
|
out = finish_deal_outcome(
|
||||||
ledger=self.ledger,
|
ledger=self.ledger,
|
||||||
work_order_no=self.wo,
|
work_order_no=self.wo,
|
||||||
@@ -161,6 +165,7 @@ class TestDealOutcome(unittest.TestCase):
|
|||||||
self.assertEqual(out.get("phase"), "wait_deal")
|
self.assertEqual(out.get("phase"), "wait_deal")
|
||||||
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
||||||
self.assertEqual(ticket.status, "协商中")
|
self.assertEqual(ticket.status, "协商中")
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "")
|
||||||
self.assertTrue(ticket.next_followup_at)
|
self.assertTrue(ticket.next_followup_at)
|
||||||
view = self.ledger.get_for_agent(work_order_no=self.wo, sender_id="sales1")
|
view = self.ledger.get_for_agent(work_order_no=self.wo, sender_id="sales1")
|
||||||
self.assertEqual(view.get("wait_phase"), "wait_deal")
|
self.assertEqual(view.get("wait_phase"), "wait_deal")
|
||||||
@@ -245,3 +250,39 @@ class TestDealOutcome(unittest.TestCase):
|
|||||||
self.assertEqual(len(rows), 1)
|
self.assertEqual(len(rows), 1)
|
||||||
self.assertEqual(rows[0]["work_order_no"], self.wo)
|
self.assertEqual(rows[0]["work_order_no"], self.wo)
|
||||||
self.assertEqual(self.ledger.get_ticket(work_order_no=self.wo).next_followup_at, "")
|
self.assertEqual(self.ledger.get_ticket(work_order_no=self.wo).next_followup_at, "")
|
||||||
|
|
||||||
|
def test_reask_starts_deal_wait(self) -> None:
|
||||||
|
"""协商再问发出后,重新盯销售成交跟进。"""
|
||||||
|
import importlib.util
|
||||||
|
import os
|
||||||
|
|
||||||
|
path = os.path.join(
|
||||||
|
os.path.dirname(__file__), "..", "agent", "jobs", "deal_followup_poll.py"
|
||||||
|
)
|
||||||
|
spec = importlib.util.spec_from_file_location("deal_followup_poll_ee", path)
|
||||||
|
self.assertIsNotNone(spec)
|
||||||
|
self.assertIsNotNone(spec.loader)
|
||||||
|
mod = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(mod)
|
||||||
|
|
||||||
|
class Cfg:
|
||||||
|
wecom_corp_id = ""
|
||||||
|
wecom_secret = ""
|
||||||
|
wecom_agent_id = "0"
|
||||||
|
|
||||||
|
mod._send_group_reask = lambda **kwargs: True
|
||||||
|
ok = mod._reask_one(
|
||||||
|
{
|
||||||
|
"work_order_no": self.wo,
|
||||||
|
"collab_chat_id": "wr1",
|
||||||
|
"sales_name": "吴吉林",
|
||||||
|
"facts": {},
|
||||||
|
"quote": {},
|
||||||
|
"business_line": "SEA",
|
||||||
|
},
|
||||||
|
settings=Cfg(),
|
||||||
|
ledger=self.ledger,
|
||||||
|
)
|
||||||
|
self.assertTrue(ok)
|
||||||
|
ticket = self.ledger.get_ticket(work_order_no=self.wo)
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "deal")
|
||||||
|
|||||||
@@ -676,6 +676,9 @@ class SeaSkipAndPullTests(unittest.TestCase):
|
|||||||
card_meta={"response_code": "rc-sea-1"},
|
card_meta={"response_code": "rc-sea-1"},
|
||||||
)
|
)
|
||||||
self.assertEqual(phase, "wait_adopt")
|
self.assertEqual(phase, "wait_adopt")
|
||||||
|
ticket = self.ledger.get_ticket(work_order_no=self.flow.session_of("s1").work_order_no)
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "adopt")
|
||||||
|
self.assertTrue(ticket.event_wait_started_at)
|
||||||
self.assertIn("已跳过内部协同", "\n".join(self.replies))
|
self.assertIn("已跳过内部协同", "\n".join(self.replies))
|
||||||
scheme = "\n".join(x for x in self.replies if "报价方案" in x)
|
scheme = "\n".join(x for x in self.replies if "报价方案" in x)
|
||||||
self.assertIn("运输方式:海运", scheme)
|
self.assertIn("运输方式:海运", scheme)
|
||||||
@@ -722,6 +725,9 @@ class SeaSkipAndPullTests(unittest.TestCase):
|
|||||||
card_meta={"response_code": "rc-pull-1"},
|
card_meta={"response_code": "rc-pull-1"},
|
||||||
)
|
)
|
||||||
self.assertEqual(phase, "collab_group")
|
self.assertEqual(phase, "collab_group")
|
||||||
|
ticket = self.ledger.get_ticket(work_order_no=wo)
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "product_quote")
|
||||||
|
self.assertTrue(ticket.event_wait_started_at)
|
||||||
joined = "\n".join(self.replies)
|
joined = "\n".join(self.replies)
|
||||||
self.assertIn("协同群已创建", joined)
|
self.assertIn("协同群已创建", joined)
|
||||||
self.assertIn(wo, joined)
|
self.assertIn(wo, joined)
|
||||||
@@ -1587,6 +1593,8 @@ class SeaGroupOpsTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(phase, "product_file_quote")
|
self.assertEqual(phase, "product_file_quote")
|
||||||
ticket = self.ledger.get_ticket(work_order_no=wo)
|
ticket = self.ledger.get_ticket(work_order_no=wo)
|
||||||
|
self.assertEqual(ticket.event_wait_kind, "deal")
|
||||||
|
self.assertTrue(ticket.event_wait_started_at)
|
||||||
self.assertEqual(ticket.attachments[0]["file_name"], "产品报价.pdf")
|
self.assertEqual(ticket.attachments[0]["file_name"], "产品报价.pdf")
|
||||||
self.assertEqual(ticket.status, "已报价")
|
self.assertEqual(ticket.status, "已报价")
|
||||||
texts = [x.get("content") or "" for x in self.groups.sent if x.get("kind") == "text"]
|
texts = [x.get("content") or "" for x in self.groups.sent if x.get("kind") == "text"]
|
||||||
|
|||||||
Reference in New Issue
Block a user