fix(wle): 正文写明物流快照是否覆盖核验时刻 / 是否过旧 #97

Merged
yanhui merged 1 commits from yanhui-wle-notify-freshness-1111 into main 2026-11-14 09:51:25 +08:00
Collaborator

目的

11-11 09:10 那批:物流镜像表停在 11-10 11:53,算出 990 单全部异常,
钉钉正文却只有一句「已发货 990 单 / 990 个包裹,异常 990 个包裹(100%)」。

群里没法分辨这是真异常还是数据没更新 —— 而这恰恰决定当天要不要去催快递。

PR #94 只修了「0 单」这一种情形(freshness.emptyWindow)。有异常、但快照降级的情形仍然是哑的,
11-11 就是这一类。

改动范围

只动 backend/src/jobs/warehouseLogisticsExceptionNotifyJob.js 与对应单测。

  • 新增 buildFreshnessWarning(freshness, batch):
    • coversDeadline === false → ⚠️ 数据未覆盖核验时刻:物流快照最新只到 …,本轮核验 … —— 之后的揽收/中转轨迹没进库,异常量会偏大。请以聚水潭实时物流为准,别按这个数去催快递。
    • stale === true → ⚠️ 物流快照偏旧:最新只到 …(已 X 小时未刷新)—— 状态可能滞后,异常量仅供参考…
    • 插在数字行 / 类型行下面,抬头仍带「异常」关键词(钉钉自定义关键词安全设置要求)。
  • 新增 formatSnapshotMoment:快照时刻跨天必须带 MM-DD。
    11-11 那批的 snapshotAt 是前一天的,只写「11:53」会被读成当天上午的新鲜数据
    (与 WST「历史单审核时间必须带 MM-DD」是同一个坑)。
  • 只在 totalPackages > 0 时告警;0 单走原有 emptyWindow 分支,不叠加两条。
  • 字段缺失(老缓存 / 接口未返回)静默跳过 —— 不崩、不瞎报警。

11-11 场景改后的实际正文:

【仓储物流转运异常】11-11 09:00 核验 · 11-10 发货
已发货 990 单 / 990 个包裹,异常 990 个包裹(100%)
类型:已揽收未中转 990
⚠️ 数据未覆盖核验时刻:物流快照最新只到 11-10 11:53,本轮核验 09:00 —— 之后的揽收/中转轨迹没进库,异常量会偏大。请以聚水潭实时物流为准,别按这个数去催快递。

同步与兼容性

  • 纯正文拼装,不读新接口、不加新字段:用的都是 getLogisticsExceptionExportRows 已返回的
    freshness.{snapshotAt, ageMinutes, stale, coversDeadline}。
  • 服务层字段缺失时静默降级 → 与改造前正文一致。
  • 不影响页面、不影响接口、不影响其它 job。

验证

  • node --test backend/test/warehouseLogisticsExceptionNotify.test.js → 26 / 26 通过
    (新增 5 条:未覆盖核验时刻且跨天带日期 / 同日不写日期 / stale 带未刷新时长 /
    正常批次无告警 / 字段缺失不崩不报警)
  • 另用真实字段(snapshotAt=2026-11-10 11:53:00、coversDeadline=false、990 单全异常)
    渲染过一遍正文,见上面的样例。
  • node --check 通过。

风险与回退

  • 风险:正文会多 12 行,字节数增加约 100150(上限 20000,当前典型 650~12KB,量级无影响)。
  • 回退:回退本提交即恢复原正文;不影响任何数据与状态。
## 目的 11-11 09:10 那批:物流镜像表停在 **11-10 11:53**,算出 **990 单全部异常**, 钉钉正文却只有一句「已发货 990 单 / 990 个包裹,异常 990 个包裹(100%)」。 群里没法分辨这是**真异常**还是**数据没更新** —— 而这恰恰决定当天要不要去催快递。 PR #94 只修了「0 单」这一种情形(`freshness.emptyWindow`)。**有异常、但快照降级**的情形仍然是哑的, 11-11 就是这一类。 ## 改动范围 只动 `backend/src/jobs/warehouseLogisticsExceptionNotifyJob.js` 与对应单测。 - 新增 `buildFreshnessWarning(freshness, batch)`: - `coversDeadline === false` → `⚠️ 数据未覆盖核验时刻:物流快照最新只到 …,本轮核验 … —— 之后的揽收/中转轨迹没进库,异常量会偏大。请以聚水潭实时物流为准,别按这个数去催快递。` - `stale === true` → `⚠️ 物流快照偏旧:最新只到 …(已 X 小时未刷新)—— 状态可能滞后,异常量仅供参考…` - 插在数字行 / 类型行下面,抬头仍带「异常」关键词(钉钉自定义关键词安全设置要求)。 - 新增 `formatSnapshotMoment`:快照时刻**跨天必须带 `MM-DD`**。 11-11 那批的 `snapshotAt` 是**前一天**的,只写「11:53」会被读成当天上午的新鲜数据 (与 WST「历史单审核时间必须带 MM-DD」是同一个坑)。 - 只在 `totalPackages > 0` 时告警;0 单走原有 `emptyWindow` 分支,不叠加两条。 - 字段缺失(老缓存 / 接口未返回)静默跳过 —— 不崩、不瞎报警。 11-11 场景改后的实际正文: ``` 【仓储物流转运异常】11-11 09:00 核验 · 11-10 发货 已发货 990 单 / 990 个包裹,异常 990 个包裹(100%) 类型:已揽收未中转 990 ⚠️ 数据未覆盖核验时刻:物流快照最新只到 11-10 11:53,本轮核验 09:00 —— 之后的揽收/中转轨迹没进库,异常量会偏大。请以聚水潭实时物流为准,别按这个数去催快递。 ``` ## 同步与兼容性 - 纯正文拼装,不读新接口、不加新字段:用的都是 `getLogisticsExceptionExportRows` 已返回的 `freshness.{snapshotAt, ageMinutes, stale, coversDeadline}`。 - 服务层字段缺失时静默降级 → 与改造前正文一致。 - 不影响页面、不影响接口、不影响其它 job。 ## 验证 - `node --test backend/test/warehouseLogisticsExceptionNotify.test.js` → **26 / 26 通过** (新增 5 条:未覆盖核验时刻且跨天带日期 / 同日不写日期 / stale 带未刷新时长 / 正常批次无告警 / 字段缺失不崩不报警) - 另用真实字段(`snapshotAt=2026-11-10 11:53:00`、`coversDeadline=false`、990 单全异常) 渲染过一遍正文,见上面的样例。 - `node --check` 通过。 ## 风险与回退 - **风险**:正文会多 1~2 行,字节数增加约 100~150(上限 20000,当前典型 650~12KB,量级无影响)。 - **回退**:回退本提交即恢复原正文;不影响任何数据与状态。
yanhui added 1 commit 2026-11-11 11:15:59 +08:00
11-11 09:10 那批:物流镜像表停在 11-10 11:53,算出 990 单**全部异常**,
钉钉正文却只有「已发货 990 单,异常 990 个包裹(100%)」。群里没法分辨
这是真异常还是数据没更新 —— 而这恰恰决定当天要不要去催快递。

PR #94 只修了「0 单」这一种(emptyWindow),有异常但快照降级的情形仍然是哑的。

- 新增 `buildFreshnessWarning`:`coversDeadline === false` 或 `stale === true`
  时,在数字行下面插一条 ⚠️ 告警,写明快照最新时刻、本轮核验时刻、未刷新时长,
  并明确「请以聚水潭实时物流为准,别按这个数去催快递」。
- 新增 `formatSnapshotMoment`:快照时刻**跨天必须带 MM-DD**。
  11-11 那批的 snapshotAt 是前一天的,只写「11:53」会被读成当天上午的新鲜数据
  (与 WST「历史单审核时间必须带 MM-DD」是同一个坑)。
- 只在「算出异常」时告警;0 单走原有 emptyWindow 分支,不叠加两条。
- 字段缺失(老缓存 / 接口未返回)静默跳过,不能把推送搞崩,也不能瞎报警。

测试:新增 5 条(未覆盖核验时刻含跨天日期 / 同日不写日期 / stale 带时长 /
正常批次无告警 / 字段缺失不崩),26/26 通过。
yanhui merged commit 936d391142 into main 2026-11-14 09:51:25 +08:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: lunanting/cangku#97
No description provided.