fix(wle): 现场拦截(售后已签收)不再算仓储物流转运异常 #83

Merged
yanhui merged 2 commits from yanhui-wle-intercept-20261023 into main 2026-10-23 08:47:17 +08:00
Collaborator

目的与范围

业务口径(2026-10-23,yanhui 提出):仓储中心物流转运异常里,把「现场拦截」的去掉
—— 也就是发的货被快递当场拦下、最终被售后仓签收的那批,物流环节其实已经结束了,
不该再报「卡在网点发不出去」。

判据(业务原话):售后单有「签收单号」且「实退数量」不为 0。

落地口径

项 字段 说明
签收单号 jst_returnAndRefundInfo.l_id / jst_qmcust_refundlist.l_id 退回那一票的运单号,实测常与原发货单号相同
实退数量 jst_returnAndRefundItem.r_qty / jst_qmcust_refundlist_item.r_qty 申请数量是 qty,只能看 r_qty:货没到 = 0、仅退款/补发恒为 0

店铺互斥,两张售后表都要读。

改动

  • warehouseLogisticsExceptionRegistry.js:新增 INTERCEPT_AFTERSALE_SOURCES(两张表 + 各自的 as_id 关联表达式)。
  • warehouseLogisticsExceptionService.js:新增 loadInterceptedOrders(),在主循环前批量判定;命中即从异常清单摘掉。
  • warehouseLogisticsExceptionNotifyJob.js:钉钉文案补一行「另有 N 个包裹属现场拦截(售后已签收)」。
  • 前端页脚:补口径说明 + 本批实际剔除数(含「原本会算哪一类异常」)。
  • 测试:新增 2 个用例(判据正/反例 + 售后表故障降级),并修正 2 个缓存用例的查询计数。

同步与兼容性

  • 基线 db1185c(PR #82 合并后),无冲突。
  • 接口只新增 exclusions.interceptPackages / interceptOrders / interceptReasons,
    老前端不读这些字段也不会报错。
  • 与既有 a/b/c 三类剔除语义不同:命中现场拦截的单仍计入发货分母(货确实发出去了),
    只从异常里摘掉 —— 否则异常率会被放大。

性能

两张售后表在 rpt 副本里都是堆表(零索引),o_id IN (...) 只能全表扫:
实测 returnAndRefund 4.5s(125 万行)、qmcust 8.5s(176 万行)。因此:

  1. 只查「本来会报异常」的 oId(本批 9800 单 → 36 单);
  2. 两张表并发查,取较慢一条(~8.5s),不是相加的 13s;
  3. 结果进既有 5 分钟缓存,页面自动刷新时命中缓存;
  4. 售后表查询失败 → 降级为「不剔除」,页面照常出数(不会因为售后表挂了整页空)。

验证

  • node --test test/warehouseLogisticsException.test.js test/warehouseLogisticsExceptionNotify.test.js → 47/47 通过
  • 真实库(2026-10-22 批次):异常 36 → 33,剔除 3 单
    • 9854409 / 9850736 / 9858367,全是「拒收退货 + 实退 1 件 + 签收单号=原运单号 + 卖家已收货」
    • 同批 9859198(l_id 有、r_qty=0)与 9871523(仅退款、r_qty=0)正确地没被剔
  • 10-21 批次:剔除 2 单
  • 本地 5173 真渲染:表格 33 行、页脚正确显示「另有 3 单属现场拦截(售后已签收)、仍计入发货分母」、无 pageerror
  • 后端 npm run check:469/471,2 个失败为既有平台差异(resilientSecretStore Windows 权限位、cloudDatabase 负缓存依赖本地 13307)

风险与回退

  • 风险:若某店铺售后单「实退数量」口径与业务理解不同,可能误剔真异常。
    兜底:r_qty 只在货真的签收入库后才 > 0,未签收恒为 0;且 exclusions.interceptOrders 可核对。
  • 回退:revert 本 PR 即恢复原行为(三个文件独立,无数据迁移)。
## 目的与范围 业务口径(2026-10-23,yanhui 提出):**仓储中心物流转运异常里,把「现场拦截」的去掉** —— 也就是发的货被快递当场拦下、最终被售后仓签收的那批,物流环节其实已经结束了, 不该再报「卡在网点发不出去」。 判据(业务原话):**售后单有「签收单号」且「实退数量」不为 0**。 ### 落地口径 | 项 | 字段 | 说明 | |---|---|---| | 签收单号 | `jst_returnAndRefundInfo.l_id` / `jst_qmcust_refundlist.l_id` | 退回那一票的运单号,实测常与原发货单号相同 | | 实退数量 | `jst_returnAndRefundItem.r_qty` / `jst_qmcust_refundlist_item.r_qty` | 申请数量是 `qty`,**只能看 r_qty**:货没到 = 0、仅退款/补发恒为 0 | 店铺互斥,两张售后表都要读。 ### 改动 - `warehouseLogisticsExceptionRegistry.js`:新增 `INTERCEPT_AFTERSALE_SOURCES`(两张表 + 各自的 as_id 关联表达式)。 - `warehouseLogisticsExceptionService.js`:新增 `loadInterceptedOrders()`,在主循环前批量判定;命中即从异常清单摘掉。 - `warehouseLogisticsExceptionNotifyJob.js`:钉钉文案补一行「另有 N 个包裹属现场拦截(售后已签收)」。 - 前端页脚:补口径说明 + 本批实际剔除数(含「原本会算哪一类异常」)。 - 测试:新增 2 个用例(判据正/反例 + 售后表故障降级),并修正 2 个缓存用例的查询计数。 ## 同步与兼容性 - 基线 `db1185c`(PR #82 合并后),无冲突。 - 接口只**新增** `exclusions.interceptPackages / interceptOrders / interceptReasons`, 老前端不读这些字段也不会报错。 - 与既有 a/b/c 三类剔除**语义不同**:命中现场拦截的单**仍计入发货分母**(货确实发出去了), 只从异常里摘掉 —— 否则异常率会被放大。 ## 性能 两张售后表在 rpt 副本里**都是堆表(零索引)**,`o_id IN (...)` 只能全表扫: 实测 returnAndRefund 4.5s(125 万行)、qmcust 8.5s(176 万行)。因此: 1. 只查「本来会报异常」的 oId(本批 9800 单 → 36 单); 2. 两张表**并发**查,取较慢一条(~8.5s),不是相加的 13s; 3. 结果进既有 5 分钟缓存,页面自动刷新时命中缓存; 4. 售后表查询失败 → 降级为「不剔除」,页面照常出数(不会因为售后表挂了整页空)。 ## 验证 - `node --test test/warehouseLogisticsException.test.js test/warehouseLogisticsExceptionNotify.test.js` → **47/47 通过** - 真实库(2026-10-22 批次):异常 **36 → 33**,剔除 3 单 - `9854409` / `9850736` / `9858367`,全是「拒收退货 + 实退 1 件 + 签收单号=原运单号 + 卖家已收货」 - 同批 `9859198`(l_id 有、r_qty=0)与 `9871523`(仅退款、r_qty=0)**正确地没被剔** - 10-21 批次:剔除 2 单 - 本地 5173 真渲染:表格 33 行、页脚正确显示「另有 3 单属现场拦截(售后已签收)、仍计入发货分母」、无 pageerror - 后端 `npm run check`:469/471,2 个失败为既有平台差异(`resilientSecretStore` Windows 权限位、`cloudDatabase` 负缓存依赖本地 13307) ## 风险与回退 - 风险:若某店铺售后单「实退数量」口径与业务理解不同,可能误剔真异常。 兜底:`r_qty` 只在货真的签收入库后才 > 0,未签收恒为 0;且 `exclusions.interceptOrders` 可核对。 - 回退:revert 本 PR 即恢复原行为(三个文件独立,无数据迁移)。
yanhui added 1 commit 2026-10-23 08:44:23 +08:00
业务口径(2026-10-23):发货后被快递当场拦下、货被售后仓签收的单,物流环节
其实已经结束,不该报「转运异常」。判据 = 售后单**签收单号 `l_id` 非空** 且
明细**实退数量 `r_qty` 合计 > 0**。

改动:
- registry 新增 INTERCEPT_AFTERSALE_SOURCES,登记两张互斥的店铺售后表
  (jst_returnAndRefundInfo/Item、jst_qmcust_refundlist/Item);
- service 新增 loadInterceptedOrders(),在主循环前一次性批量判定:
  · 只查「本来会报异常」的 oId(9800 单 → 几十单);
  · 两张表**并发**查(两表在 rpt 副本里都是堆表,全表扫 4.5s + 8.5s,并发后取 8.5s);
  · 售后表查询失败自动降级为「不剔除」,不让整页挂掉;
- 命中即从异常清单摘掉,但**保留发货分母**(货确实发出去了),异常率不被放大;
- exclusions 新增 interceptPackages/Orders/Reasons,页面页脚与钉钉推送各补一行说明。

实测(2026-10-22 批次):异常 36 → 33,剔除 3 单(9854409/9850736/9858367,
全是「拒收退货 + 实退 1 件 + 签收单号=原运单号 + 卖家已收货」);
10-21 批次剔除 2 单;同时 r_qty=0 的 9859198/9871523 正确地没被剔。

验证:
- node --test warehouseLogisticsException(+Notify):47/47 通过;
- 本地 5173 真渲染:表格 33 行、页脚显示「另有 3 单属现场拦截(售后已签收)」、无 pageerror;
- 后端 npm run check:469/471,2 个失败为既有平台差异(secretStore 权限位、cloudDatabase 负缓存)。
yanhui added 1 commit 2026-10-23 08:45:09 +08:00
yanhui merged commit 38b902e35a into main 2026-10-23 08:47:17 +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#83
No description provided.