Files
InboundVerify/docs/站点统计逻辑审查报告.md
Misaka 8f79cbc5d7 修复安能实到日期设定 + 站点统计口径重构
- site_anneng.py: set_scan_date 改用 execCommand 全选替换+回车(修复 Ant DatePicker 受控组件未写入导致实到下成当天); wait_scan_form_ready 增加 settle 与 DatePicker 预热,消除首设竞态
- expected_undelivered.py: 应到口径改交接件数、实到改单号去重、未到明细列已到单号(不再编子单号),百世排除
- docs: 补充站点统计逻辑审查报告与韵达/安能计算逻辑梳理
2026-07-19 13:16:01 +08:00

9.0 KiB
Raw Blame History

后端各站点「应到件数 / 已到件数」统计逻辑审查报告

审查范围:InboundVerify 后端 核心模块:expected_undelivered.py(比对统计)、runtime.py(调度/下载路由)、site_*.py(各站数据采集)、server.py(对外接口) 审查重点:每个站点的「应到件数」和「已到件数」如何统计、数据来源、口径与潜在歧义。


一、总体架构(两层)

统计逻辑分两层,前端看到的「应到/已到/未到」计数最终都来自第二层,且只在跑比对时才生成。

模块 职责 产物
① 数据采集层 site_顺心/中通/韵达/安能.pysite_百世.py 用 Playwright安能用 CDP登录各承运商后台导出 Excel 到 downloads/ downloads/<站>-应到货物数据.xlsxdownloads/<站>-实到货物数据.xlsxdownloads/<站>-未到数据.xlsx
② 比对统计层 expected_undelivered.py downloads/ 源文件,两表比对,算出应到/已到/未到件数并出报表 output/应到未到数据.xlsx(汇总+各站明细)

调度入口:runtime.pyTASK_HANDLERS

  • 4 站:expected 下载 + actual 下载 + undelivered(先下应到+实到,再调 write_site_file 算出未到)。
  • 百世:只有 undelivered(直接导「当日未扫」明细,无应到/实到两份基表)。
  • __compare__(菜单[9]):调 expected_undelivered.main(),用 downloads/ 现有文件生成全站汇总报表。

二、核心统计公式4 站统一口径)

expected_undelivered.process(name) 是 4 站统计的唯一实现:

对每一条应到运单(按运单号去重,保留首条):
  应到件数 N  = 应到数据中的「录单件数」(输出列名「总件数」)
  应到序号集  = {1, 2, …, N}
  已到序号集  = 从「实到货物数据.xlsx」解析该运单实际到货的子单序号
  未到序号集  = {1…N}  已到序号集
  未到件数   += len(未到序号集)        # 每缺 1 个子单 → 1 行未到明细
  应到件数   += N

站点级:
  应到件数 = Σ N所有应到运单
  未到件数 = Σ len(未到序号集)
  已到件数 = 应到件数  未到件数        ← 注意:是「减出来」的,不是直接数实到
  未到率   = 未到件数 ÷ 应到件数
  完全未到运单 = 未到序号集 == {1…N} 的运单数
  部分未到运单 = 0 < 未到 < N 的运单数

关键事实已到件数应到件数 未到件数 推算出来的(exp_pieces - len(rows)),并非独立去数实到表。它等价于 Σ|已到序号集|,前提是实到解析正确且已到序号 ⊆ 应到序号。


三、各站点统计明细

站点 应到件数来源 已到件数来源 实到序号解析规则(arrived 源文件(downloads/
中通 中通-应到货物数据.xlsx 的「录单件数」 应到−未到(推算) 运单号列是复合串 = 运单号 + 总数(4位) + 顺序号(4位);取右 8 位,前 4 为总数、后 4 为顺序号 中通-应到货物数据.xlsx / 中通-实到货物数据.xlsx
顺心 顺心-应到货物数据.xlsx 的「录单件数」 应到−未到(推算) 运单号(干净) + 子单号 = 运单号 + 顺序号(3位);后缀(3位)即顺序号 顺心-应到货物数据.xlsx / 顺心-实到货物数据.xlsx
韵达 韵达-应到货物数据.xlsx 的「录单件数」 应到−未到(推算) 主单号=运单号,子单号=主单号 + 顺序号(4位);后缀(4位)即顺序号 韵达-应到货物数据.xlsx / 韵达-实到货物数据.xlsx
安能 安能-应到货物数据.xlsx 的「录单件数」 应到−未到(推算) 所属单号=运单号,扫描单号=所属单号 + 总数(4位) + 顺序号(4位)has_total=True,取末 4 位为顺序号 安能-应到货物数据.xlsx / 安能-实到货物数据.xlsx
百世 (站点只给未到) 无(显示「—」) 不适用(无实到基表) 百世-应到未到货物数据.xlsx= 当日未扫明细,本身就是未到结果)

4 站合计/图表口径:expected_undelivered.build_summary 只累加 4 站(应到−实到口径),百世不计入合计(无应到基数)。百世在表中单列,未到件数 = 其明细行数。


四、百世的特殊口径(务必注意)

百世是唯一「无应到/实到基数」的站点:

  • 它的数据来自后台「扫描综合查询 → 到/接件扫描 → 当日 → 未扫」,导出即「当日未扫」明细(site_baishi.py)。
  • 因此 process_baishi() 只能给 未到件数 = 行数应到件数 = None已到件数 = None、完全/部分未到 = None。
  • 报表里百世的应到/已到列显示「—」,未到率无法计算。
  • 含义:百世统计的是「今天还没扫到的件」,不是「相对应到总量的缺件率」。与 4 站口径不可直接相加比较。

五、数据日期与偏移(潜在口径不一致风险)

runtime._record_business_date 在下载成功后把业务日期写进状态库:

  • 业务日期 = 下载当天 日期偏移
  • 各站 expected_offset / actual_offset 独立配置(前端 /config 可改;百世偏移恒 0锁定当天
  • 韵达默认 expected_offset=1(取前一日应到)。

风险点4 站的「应到」和「实到」是两次独立下载,各自可能带不同偏移。若 expected_offset ≠ actual_offset,则「应到件数」和「已到件数」来自不同业务日期,比对会变成「拿昨天的应到对比今天的实到」,未到率失真。报表「数据日期」列分别标注各站,但汇总合计不标注,肉眼难发现。


六、统计结果如何暴露给前端

接口 返回内容 是否含应到/已到计数
GET /status 各站 login_state + expected/actual/undelivered_ready + business_date + worker_ready 不含计数,只给就绪标志
GET /report FileResponse(output/应到未到数据.xlsx) 计数只在 xlsx 里
GET /data/{filename} 下载 downloads/ 下某源文件 原始数据,非统计值

结论:后端没有把应到/已到件数以 JSON 形式实时返回前端。计数仅物化在 output/应到未到数据.xlsx。任何前端界面显示的应到/已到数字,都是解析这份 xlsx 得到的——即**「截至上次跑比对」的快照**,不是实时值。


七、潜在歧义与风险点(审查结论)

  1. 已到件数是减出来的,不是数出来的:依赖实到子单号解析正确。一旦某站 子单号 格式与解析规则(arrived_*)不匹配,该序号进不了「已到序号集」→ 误判为未到 → 已到件数被低估、未到率虚高。解析规则是硬编码的,承运商改版号段即失准。
  2. 应到件数依赖「录单件数」:若应到数据某运单 录单件数 缺失/为 0/非数字,该运单被 continue 跳过,既不计入应到也不计入未到 → 静默漏统(应到总量被低估,但该运单若出现在实到中也因不在应到循环而永不计入已到,方向一致)。
  3. 应到按运单号去重keep first:同一运单多条交接记录只取首条 录单件数。若重复行的件数不同,取首条,可能与实际不符。
  4. 百世不可并入合计4 站合计的「已到总件数」不含百世;跨站看「已到」时别把百世当成有应到基数的站。
  5. 应到/实到业务日期可能错位(见第五节):两表不同步下载或偏移不一致时,比对口径失真。
  6. 计数是比对产物,非实时:前端若要「实时件数」需先触发比对任务;/statusready 仅表示「下载成功」,不代表「已比对出数」。
  7. 子单号是程序现拼的4 站缺件的「子单号/扫描单号」由 code_* 按各站编号规则生成(code_shunxin 等),并非实到原始记录——明细里的缺件单号是推算值,用于人工核对,不是系统回执。

八、关键文件索引

文件 角色
expected_undelivered.py 统计核心:process()4站比对process_baishi()(百世)、build_summary()(汇总报表)、STATIONS(各站解析配置)
runtime.py TASK_HANDLERS(下载/比对路由)、_site_undelivered_handler4站先下应到+实到再算未到)、_record_business_date(业务日期/偏移写入)
site_中通/顺心/韵达/安能.py 各站 expected_download / actual_downloadPlaywright/CDP 导出源表)
site_百世.py baishi_download_undelivered_data(直接导「当日未扫」)
state_store.py site_statusready/business_datesite_configoffset/scheduleget_offset
server.py /status/report/data/{filename} 接口