协商中再问按后台超时小时顺延并可强制清跟进时刻;工单与账号支持按筛选导出 Excel。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -88,7 +88,7 @@ def shift_workdays(start: date, count: int) -> date:
|
||||
"""
|
||||
从 start 当天之后数 count 个工作日。
|
||||
|
||||
成交选协商中:顺延 3 个工作日后,第四个工作日再问,故 count=4。
|
||||
仍给单测与节假日校验用;协商再问已改走 add_workday_hours。
|
||||
"""
|
||||
if count < 1:
|
||||
return start
|
||||
@@ -101,11 +101,51 @@ def shift_workdays(start: date, count: int) -> date:
|
||||
return cur
|
||||
|
||||
|
||||
def next_followup_at(now: datetime | None = None) -> datetime:
|
||||
"""第四个工作日 Asia/Shanghai 09:00。"""
|
||||
# 协商中再问:主账 timeoutCode;缺配置时默认 48 工作小时。
|
||||
TIMEOUT_CODE_DEAL_NEGOTIATE = "deal_negotiate"
|
||||
DEFAULT_NEGOTIATE_HOURS = 48.0
|
||||
|
||||
|
||||
def add_workday_hours(start: datetime, hours: float) -> datetime:
|
||||
"""
|
||||
从 start 起累加 hours 个工作小时;非工作日整天跳过。
|
||||
|
||||
与 workday_elapsed_hours 互逆:工作日当天 0–24 都算。
|
||||
起点落在休息日:从下一个工作日 00:00 起算。
|
||||
hours≤0 时原样返回(调用方应不排期)。
|
||||
"""
|
||||
base = start.astimezone(SHANGHAI) if start.tzinfo else start.replace(tzinfo=SHANGHAI)
|
||||
remaining = float(hours)
|
||||
if remaining <= 0:
|
||||
return base
|
||||
cur = base
|
||||
if not is_workday(cur.date()):
|
||||
cur = datetime.combine(cur.date() + timedelta(days=1), time(0, 0), tzinfo=SHANGHAI)
|
||||
while not is_workday(cur.date()):
|
||||
cur = datetime.combine(cur.date() + timedelta(days=1), time(0, 0), tzinfo=SHANGHAI)
|
||||
while remaining > 0:
|
||||
if not is_workday(cur.date()):
|
||||
cur = datetime.combine(cur.date() + timedelta(days=1), time(0, 0), tzinfo=SHANGHAI)
|
||||
continue
|
||||
day_end = datetime.combine(cur.date() + timedelta(days=1), time(0, 0), tzinfo=SHANGHAI)
|
||||
room = (day_end - cur).total_seconds() / 3600.0
|
||||
if remaining <= room + 1e-9:
|
||||
return cur + timedelta(hours=remaining)
|
||||
remaining -= room
|
||||
cur = day_end
|
||||
return cur
|
||||
|
||||
|
||||
def next_followup_at(now: datetime | None = None, *, hours: float | None = None) -> datetime:
|
||||
"""
|
||||
距今 hours 个工作小时后的再问时刻(默认 48)。
|
||||
|
||||
非工作日不计入;提醒时刻不再固定 09:00。
|
||||
hours≤0 时返回起点(调用方应把 0 当作不排再问)。
|
||||
"""
|
||||
base = now.astimezone(SHANGHAI) if now else datetime.now(SHANGHAI)
|
||||
day = shift_workdays(base.date(), 4)
|
||||
return datetime.combine(day, time(9, 0), tzinfo=SHANGHAI)
|
||||
h = DEFAULT_NEGOTIATE_HOURS if hours is None else float(hours)
|
||||
return add_workday_hours(base, h)
|
||||
|
||||
|
||||
def workday_elapsed_hours(start: datetime, now: datetime) -> float:
|
||||
|
||||
Reference in New Issue
Block a user