将未到统计从实到驱动(实到锚点反推批次)改为应到驱动(batch_out_date 归属日直接取应到批次),以吸收应到任务提前 1~2 天提交的扰动(韵达固定 +1、中通偶发 +1)。 - expected_record 新增 out_date / batch_out_date + 索引;入库解析出库时间并聚合批次归属日,支持历史回填 - 新增 compare_site_outdate 应到驱动入口,保留 compare_site_date 实到驱动作对照 - 未到任务 / POST /compare / 全站汇总切换到应到驱动 - 附现状梳理、设计、实现总结三篇文档
5.7 KiB
5.7 KiB
应到驱动差缺统计重构 · 实现总结(备忘录)
完成日期:2026-08-03 分支:
refactor/undelivered-by-expected关联文档:docs/2026-08-02-未到差缺统计逻辑现状梳理.md、docs/2026-08-03-应到驱动差缺统计重构-design.md状态:已完成并验证,待提交
一、背景
原差缺统计为实到驱动:以目标日实到扫描为锚点 → 反推交接批次 → 展开批次全量应到 → 逐单比对。
业务部门日常以应到数据为依据,且应到任务可能被提前提交 1~2 天(韵达固定提前 1 天),导致:
- 完全按应到统计会出现假差缺;
- 实到驱动会把历史批次混入当天报表(1 单命中即整批展开)。
重构目标:改为应到驱动,并用「出库日」作为批次归属日,自动吸收提前提交。
二、核心口径
- 批次归属日 = 批次内运单「出库时间」日期众数,并列取较早(字段:
expected_record.batch_out_date)。 - 统计 D 日差缺 = 取所有
batch_out_date = D的应到批次,展开全量应到 → 查全量实到 → 逐运单比对。 - 无论批次在 D / D-1 / D-2 哪天下载(
business_date为何),只要出库日 = D 即纳入 D 日统计。
三、数据实证(7 月全量)
| 站点 | 下载日=出库大头日 | 出库大头日=下载日+1 |
|---|---|---|
| 顺心 | 83/83(100%) | 0 |
| 中通 | 28/30(93%) | 2(071402、071902) |
| 韵达 | 0 | 29/29(100%,固定提前) |
| 安能 | 31/31(100%) | 0 |
关键结论:
- 出库大头日 ≈ 实到峰值日(154/158 一致,97.5%)——"出库日"基本等于"这批货实际到的那天"。
- "提前提交"的批次(中通
071402出库 7/15、071902出库 7/20)在出库时间上如实体现真实归属日。 - 四站应到文件的「出库时间」字段非空率 100%,且已完整保留在 PG
expected_record.rawJSONB 中。
四、代码改动
4.1 数据层
schema.sql:expected_record新增out_date DATE(运单出库日)、batch_out_date DATE(批次归属日)+idx_expected_out_date/idx_expected_batch_out_date索引。store.py:_ingest_expected:解析「出库时间」写out_date;按交接单号聚合出库日众数(并列取较早)写batch_out_date。- 新增
_batch_out_date_map()辅助函数。 - 新增
backfill_out_date()+ CLI 子命令backfill-out-date,历史数据一次性回填。
4.2 比对层
db_compare.py:- 新增
compare_site_outdate(site, target_date):应到驱动入口,WHERE batch_out_date = target_date取批次 → 展开 → 比对。 - 保留
compare_site_date()(实到驱动)作对照,不删除。 _target_date_for()改为默认取今天(不再依赖 actual_offset)。build_full_report()改用compare_site_outdate。
- 新增
runtime.py:_site_undelivered_handler切到应到驱动,锚点日期默认今天。cli/server.py:POST /compare切到应到驱动。
五、实施与验证
5.1 数据迁移
python -m inbound_verify.store init # 建表/补列(幂等)
python -m inbound_verify.store backfill-out-date # 历史回填
回填结果:
out_date:顺心 3290 / 中通 5419 / 韵达 1640 / 安能 3459 条,共 13808 条。batch_out_date:顺心 93 / 中通 35 / 韵达 32 / 安能 35 个批次。- 抽样核对 PG
out_datevs 归档 Excel 出库日一致率 96~100%。
5.2 批次归属验证
| 批次 | 下载日 | batch_out_date | 预期 |
|---|---|---|---|
中通 ...071401 |
7/14 | 7/14 | 正常 |
中通 ...071402 |
7/14 | 7/15 | 提前提交归位 |
中通 ...071901 |
7/19 | 7/19 | 正常 |
中通 ...071902 |
7/19 | 7/20 | 提前提交归位 |
韵达 ...07312001 |
7/31 | 8/1 | 固定 +1 |
| 顺心/安能 | — | = 下载日 | 无扰动 |
5.3 回溯对照(7/02~7/31)
新应到驱动 vs 旧实到驱动,差异方向符合设计:
- 旧驱动混入历史批次(如中通 7/12 旧 236 件 vs 新 11 件;顺心 7/13 旧 59 vs 新 1)。
- 新驱动只统计出库日=当天批次,数字更聚焦。
- 个别日期新驱动未到偏大(如韵达 7/03、安能 7/29),属"当天出库、次日扫描"的真实差缺口径。
5.4 接口联调(真实后端)
| 用例 | 结果 |
|---|---|
POST /compare 韵达 2026-08-02 |
批次 1 个(...08012001),差缺 2 件/2 单(988350756、988415586),历史批次不再混入 |
POST /compare 中通 2026-07-15 |
提前提交批次 ...071402 正确归位到 7/15 |
__compare__/compare 全站汇总 2026-08-01 |
顺心 17 件 / 中通 23 件 / 韵达 0 件 / 安能 0 件,合计 40 件,报表正常生成 |
六、待确认 / 遗留事项
out_date/batch_out_date依赖站点「出库时间」字段语义(当前按"货物实际发出时间"处理,已与业务确认)。- 批次内出库日并列众数取较早(已确认)。
- "无应到"时报表直接写(如实呈现,无特殊文案,已确认)。
- 实到驱动入口保留作对照(已确认)。
docs/2026-08-02-未到统计重构讨论纪要与下一步.md中记录的 18:28 直入入库等链路疑点,本重构未处理,留待后续。
七、附:涉及文件
| 文件 | 说明 |
|---|---|
schema.sql |
表结构:新增 out_date / batch_out_date |
inbound_verify/store.py |
入库解析 + 历史回填 |
inbound_verify/db_compare.py |
应到驱动比对入口(保留实到驱动对照) |
inbound_verify/runtime.py |
未到任务切到应到驱动 |
inbound_verify/cli/server.py |
/compare API 切到应到驱动 |