协商中再问按后台超时小时顺延并可强制清跟进时刻;工单与账号支持按筛选导出 Excel。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-10-13 12:34:03 +08:00
co-authored by Cursor
parent 97f0219dfd
commit 0b2f0b76c4
36 changed files with 867 additions and 64 deletions
@@ -50,6 +50,10 @@ def _reask_one(row: dict[str, Any], *, settings: Settings, ledger: Any = None) -
no = str(row.get("work_order_no") or row.get("workOrderNo") or "").strip()
if not no:
return False
# 进程/双 Worker 防重:同一工单同一天只发一轮(主账 next_followup 清不掉时曾连发 WO024)
if _already_sent_reask(no, settings):
logger.warning("协商再问去重跳过 wo=%s", no)
return False
chat_id = str(row.get("collab_chat_id") or row.get("collabChatId") or "").strip()
sales = str(row.get("sales_wecom_id") or row.get("salesWecomId") or "").strip()
name = str(row.get("sales_name") or row.get("salesName") or "").strip() or "销售"
@@ -69,6 +73,7 @@ def _reask_one(row: dict[str, Any], *, settings: Settings, ledger: Any = None) -
if not ok:
logger.warning("协商再问原群失败且不补发私聊 wo=%s chat=%s", no, chat_id)
return False
_mark_sent_reask(no, settings)
_start_deal_wait(ledger, no)
return True
if not sales:
@@ -87,10 +92,47 @@ def _reask_one(row: dict[str, Any], *, settings: Settings, ledger: Any = None) -
if not ok:
logger.warning("协商再问私聊入队失败 wo=%s info=%s", no, info)
return False
_mark_sent_reask(no, settings)
_start_deal_wait(ledger, no)
return True
def _already_sent_reask(work_order_no: str, settings: Settings) -> bool:
"""
跨进程去重:Redis SET NX。
返回 True=今天已发过应跳过;False=抢到发送权。
主账 next_followup 若因 updateById 清不掉 null,没有这层会每分钟连发。
"""
from datetime import datetime
from agent.policy.deal_followup import SHANGHAI
from agent.redis_coord import get_redis_runtime
from agent.redis_coord.idempotency import try_acquire
day = datetime.now(SHANGHAI).strftime("%Y-%m-%d")
try:
runtime = get_redis_runtime(settings)
client = getattr(runtime, "client", None)
if client is None:
return False
first = try_acquire(
client,
scope="deal_reask",
idempotency_key=f"{work_order_no}:{day}",
ttl_seconds=86400,
)
return not first
except Exception:
logger.exception("协商再问 Redis 去重失败 wo=%s", work_order_no)
return False
def _mark_sent_reask(work_order_no: str, settings: Settings) -> None:
"""兼容旧调用点;去重键已在发送前 SET NX。"""
_ = (work_order_no, settings)
def _start_deal_wait(ledger: Any, work_order_no: str) -> None:
"""再问发出后重新盯成交跟进。ledger 可空。"""
from agent.policy.event_exception import WAIT_DEAL, start_wait