Files
jiu/docs/review/inventory-qty-packsize-report.md
T

94 lines
4.6 KiB
Markdown

# 库存「装箱数被当成数量」脏数据排查报告
> 排查日期:2026-06-22 · 只读核查,**未修改任何生产数据**
> 明细清单:`docs/review/inventory-qty-packsize-dirty.csv`(820 行)
## 一、起因
用户反馈「商品编号 P1297 有 12 个库存,正常只有一个」,并认为「库存都是 1,quantity 字段可以删」。排查后两个判断都需要修正。
## 二、P1297 真相
P1297 = product `4830`(shop 8),**只有 1 条库存行**(inventory id 9412),不是 12 条:
| 字段 | 值 |
|---|---|
| 商品名称 | 茅台公斤大件2005原件 |
| 规格 | `1.00L*12/件`(一件装 12 瓶) |
| 单位 | (空) |
| 当前数量 | **12.000** |
| 来源 | 入库明细 32353 / 入库单 7976,**录入数量本身就是 12** |
即 inventory 忠实快照了入库单的 12,不是代码 bug。问题在于**导入时把规格里的「装箱数 12」当成了库存数量**,用户预期是「1 件」。
## 三、系统性结论:装箱数泄漏
这不是个例。全库 **9412 条活跃库存中,820 条 quantity > 1**,其中 **784 条的数量恰好等于规格里的装箱数**(`*N/件` → 数量 N):
- qty=12 的行:82 条里 80 条规格含 `*12`
- qty=6 的行:641 条里绝大多数规格含 `*6`
- 判定规则:规格 `\*(\d+)` 捕获的装箱数 == 当前数量 → 标记 `dirty_pack_eq_qty=Y`
### 按门店分布(疑似脏 dirty=Y)
| shop_id | 脏行数 | 备注 |
|---|---|---|
| 8 | 279 | 主力门店 |
| 7 | 239 | |
| 1 | 142 | 疑似 seed/demo(商品信息多为 NULL) |
| 6 | 124 | |
| **合计** | **784** | |
### 另有 36 行 quantity>1 但装箱数≠数量(`dirty=N`)
需**人工复核**,不能机械归 1。典型:
- shop 1 的 seed 数据:数量 108/54/36/24…,商品编码/规格全 NULL(demo,可忽略)。
- `ZXZ026602 茅台小白条2023原件` 规格 `500ml*5/件`,数量却是 12 / 10 —— 装箱数 5,数量非整箱倍数,真实库存存疑。
## 四、quantity 字段能否删除
**不能删**(用户原设想不成立):
1. 数据层面:并非「都是 1」,真有 820 行多单位(其中 784 是脏数据,但删字段前必须先治脏,且仍有真实多单位场景)。
2. 代码层面:`quantity` 被 FIFO 扣减、出库库存校验、库存流水 `inventory_logs`、财务对账、公开商品在库量、盘点全链路依赖,删列等于重构整个库存系统。
本轮已按决策**仅在前端隐藏库存数量列**(库存列表表格 + 手机卡片),DB 字段与后端逻辑保留;缺货/预警/流水不动。
## 五、建议(待决策,本轮不执行)
1. **784 行脏数据按「件」归正为 1**:把「规格装箱数 == 数量」的行,数量统一改为 1(视作 1 件);同步修对应入库明细 `stock_in_items.quantity`,保持单据与库存一致。执行前**先备份**,并对照 CSV 的 `suggest_qty` 列逐店确认。
2. **36 行 dirty=N 单独人工核对**:shop 1 demo 可忽略;`*5/件` 却数量 12/10 等异常逐条问业务。
3. **根治导入器**:库存/入库导入时,遇到 `规格含 *N` 且「数量列恰好等于 N」的情况给出告警或按件折算,避免再次把装箱数写进数量。
> 是否执行第 1 项数据归正,请确认后另行单独处理(需备份 + 逐店复核 + 影响行数预览)。
---
## 六、全量数据质量审计(2026-06-22 补充)
对全部活跃库存(9412 行 / 7282 distinct product)逐类核查:
| 类别 | 行数 | 说明 |
|---|---|---|
| 数量 ≤ 0 | 0 | 干净 |
| product_id=0(无主数据) | 0 | 干净 |
| 孤儿(product_id 指向不存在 product) | 0 | 干净 |
| 快照商品编码为空 | 24 | 轻微,无法定位编号 |
| **快照编码 ≠ 所指 product.code(错指)** | **2130** | **重大,全在 shop 7** |
| 装箱数=数量(脏数量) | 784 | 见上文,跨 shop 8/7/6/1 |
### 重大:shop 7 的 product_id 错指(与 shop 8 旧损坏同款)
`shop 7`**2130 条库存行错指**,涉及 **514 个被多编码共享的 product**(每个 product 名下挂多个不同商品编号)。典型:product `234` 名下有 **130 条库存行、130 个不同商品编码**——即 130 个真实商品编号的库存全部指向了同一个 product。这正是上次给 shop 8 修过的「按名称合并导致 product_id 搞混」根因。
各店对比:
| shop | 活跃库存行 | 错指行 | 状态 |
|---|---|---|---|
| 1 | 1213 | 0 | 干净 |
| 6 | 1134 | 0 | 干净 |
| 7 | 3286 | **2130** | ❌ 未修复 |
| 8 | 3779 | 0 | 已修复(本次之前) |
**建议**:对 shop 7 跑既有的 `backend/cmd/fix-inventory-products` 工具(按库存快照编码重建 per-code product),流程同 shop 8——**先备份** → dry-run 预览 → 执行 → 复核「错指=0、distinct product 数=活跃行去重数」。需你确认后单独执行。