Files
InboundVerify/docs/2026-07-29-指定日期下载接口-design.md
2026-07-29 12:58:08 +08:00

6.8 KiB
Raw Permalink Blame History

指定日期下载接口(开发者)— 设计文档

日期2026-07-29 定位:面向开发者的 HTTP 接口,不进前端。提供"指定一个具体日期,下载该日应到 / 实到数据"的能力,用于补下历史数据。 前置:中通跨月导航已实现并验证(见 feat(zto): cross-month calendar navigation)。

一、背景与目标

现状:下载日期由各站 offset 偏移0=今天1=昨天…,存 state.db,上限 MAX_DATE_OFFSET=30)决定,周期调度与手动触发都用 offset。无法指定一个具体日期。

目标:新增"指定日期"入口(开发者用),传一个 YYYY-MM-DD 日期,下载该日应到 / 实到数据。不替换 offset 机制,与之并存:传 date 用 date不传走 offset。

二、范围

站点 支持指定日期 说明
顺心 / 中通 / 韵达 / 安能 应到、实到均支持
百世 固定下载当天,传 date 返回 400

三、接口契约

复用 POST /tasksbody 新增可选字段 date(与 force 并列):

{ "site": "中通", "kind": "expected", "date": "2026-06-14" }
  • date: Optional[str] = None,格式 YYYY-MM-DD
  • 优先级:传 date 则本次用 date不传则走站点 offset 配置(默认行为完全不变)。
  • dateforce 可共存(指定日期 + 强制重下)。

合法性校验(仅在传了 date 时执行,失败返回 400

  1. 格式datetime.strptime(date, "%Y-%m-%d") 解析成功,否则 400。
  2. 范围今天 - 90 天 ≤ date ≤ 今天
    • date > 今天 → 400未来日期日历未来格子 invalid 物理上点不动,且不应下未来数据)。
    • date < 今天 - 90 天 → 400回溯上限 90 天)。
  3. 百世site=百世 且传 date → 400固定当天

合法性校验落在 POST /tasksserver.py create_task),入队前拦截,非法请求不产生任务。

四、透传链路(与现有 force 完全对称)

POST /tasks {site, kind, force, date}
  → task_queue.put((tid, {site, kind, force, date}))
  → dispatch_task(ctx, task_spec)        # 读 task_spec["date"]
  → handler(ctx, force, date)            # _web_handler / 安能 lambda / _site_undelivered_handler
  → impl(page, force, date)              # 各站 download_impl
  • _web_handlerhandler(ctx, force=False, date=None),透传 download_func(pg, force, date);顺心双账号透传 (pages, foreground, force, date)
  • _site_undelivered_handler(未到):连下 expected + actual两个子任务共用同一个 date
  • 安能 lambda(ctx, force=False, date=None) → anneng_xxx_download(force=force, date=date)
  • 周期调度 _enqueue_fetch 投递的 task_spec 只有 {site, kind}(不带 date→ 恒走 offset无需改动

五、各站 impl 改造(核心)

统一模式:target = parse(date) if date else (today offset)

中通zto—— 复用跨月算法

把 date 折算成 effective offset复用现有 target_time = today_time offset*86400000 与跨月翻页(_zto_flip_to_target_month),零额外 UI 逻辑:

def zto_expected_download_impl(page, force=False, date=None):
    ...
    offset = state_store.get_offset("中通")
    if date:
        target_date = datetime.strptime(date, "%Y-%m-%d").date()
        offset = (datetime.now().date() - target_date).days
    # 后续 today_time / target_time / 跨月翻页 逻辑完全不变

zto_actual_download_impl 同理(用 ("中通","actual") offset。expected / actual 两个 impl 都加 date=None 形参,zto_expected_download / zto_actual_download 公开入口同步加形参并透传。

韵达 / 顺心 / 安能 —— date 直接当 target

这三站 offset→日期是 target = today timedelta(days=offset) 后填字符串到日期控件(非日历格子),指定日期只需替换 target 来源:

if date:
    target = datetime.strptime(date, "%Y-%m-%d")
else:
    target = today - timedelta(days=offset)

后接的"填起始/截止日期字符串"逻辑完全不变。各站 expected / actual 入口与 impl 都加 date=None 形参。

  • 韵达:yunda_expected_download(_impl) / yunda_actual_download(_impl)
  • 顺心:shunxin_expected_download(_impl) / shunxin_actual_download(_impl)(双账号入口透传 date 到各账号 impl
  • 安能:anneng_expected_download / anneng_actual_download

百世baishi—— 签名兼容

baishi_download_undelivered_data(page, date=None)date=None 形参(忽略),仅为对齐 _web_handler 的统一透传签名;百世任务实际不会带 dateserver 已拦截)。

六、业务日期快照

_record_business_date(site, kind, date=None):有 date 则业务日期 = date否则维持现状 today offsetdispatch_tasktask_spec["date"] 透传进去,保证状态盘 / 报告显示的"是哪天的数据"准确(不被 offset 算错)。

七、改动文件清单

文件 改动
inbound_verify/cli/server.py TaskRequest.date + create_task 合法性校验 + task_spec 透传 date
inbound_verify/runtime.py _web_handler / _site_undelivered_handler / 安能 lambda 透传 datedispatch_task 读 date 透传给 handler 与 _record_business_date_record_business_date 加 date
inbound_verify/sites/zto.py expected/actual 入口+impl 加 datedate→effective offset 复用跨月
inbound_verify/sites/yunda.py expected/actual 入口+impl 加 datedate→target
inbound_verify/sites/shunxin.py 同上(双账号透传 date
inbound_verify/sites/anneng.py expected/actual 加 datedate→target
inbound_verify/sites/baishi.py date=None 形参兼容(忽略)

八、验证计划

  1. 接口校验curl/python urllib
    • 合法 date过去某日→ 202任务成功。
    • 未来日期 / 超 90 天 / 格式错 → 400。
    • 百世 + date → 400。
    • 不传 date → 走 offset行为不变
  2. 各站实测(指定一个过去日期触发任务):
    • 中通:跨月日期(已知 OK复用已验证的跨月导航
    • 顺心 / 韵达 / 安能:实测其日期控件是否接受任意过去日期字符串;若控件是日历选择器需翻月,则按中通同法扩展(本轮发现则记录、必要时追加改动)。
  3. 业务日期快照:下载后 GET /status*_business_date == 指定 date。
  4. 改完跑 Black + py_compile

九、非目标YAGNI

  • 前端 UIcheckbox / 日期选择器)——开发者接口,不进前端。
  • 周期调度指定日期——周期恒走 offset。
  • 批量日期 / 日期范围下载——单次单日。