|
|
@@ -28,15 +28,42 @@ haha 平台的职责是 AI 识别(开关门事件 + 商品识别结果)和
|
|
|
|
|
|
### 1.4 库存初始化机制
|
|
|
|
|
|
-库存数据**没有自动初始化**,唯一的入口是人工上货操作:
|
|
|
+库存数据有**两个入口**进入系统:
|
|
|
+
|
|
|
+#### 入口一:人工上货(主要,创建实际库存)
|
|
|
|
|
|
```
|
|
|
管理员/补货员手动上货 → DeviceInventoryService.increaseStock()
|
|
|
- → 首次上货该商品 → 新建 t_device_inventory 记录
|
|
|
+ → 首次上货该商品 → 新建 t_device_inventory 记录(stock > 0)
|
|
|
→ 再次上货 → 累加 stock
|
|
|
```
|
|
|
|
|
|
-以下流程**不创建库存**:
|
|
|
+人工上货创建的记录带有 **实际库存数量**(`stock > 0`),是唯一的物理库存来源。
|
|
|
+
|
|
|
+#### 入口二:层模版同步(辅助,创建占位记录)
|
|
|
+
|
|
|
+```
|
|
|
+设备层模版同步 → syncFromHaha(deviceId) → initInventoryFromTemplate(deviceId, apiData)
|
|
|
+ → 解析层模版中的商品编码
|
|
|
+ → 查本地 Product 表确认商品存在
|
|
|
+ → 查 t_device_inventory 确认记录不存在
|
|
|
+ → 新建 t_device_inventory 记录(stock = 0)
|
|
|
+```
|
|
|
+
|
|
|
+层模版同步创建的记录 **stock 初始化为 0**,目的是:
|
|
|
+- 让设备在库存列表中**提前可见**所有理论货道商品
|
|
|
+- 为 `recalculateStandardStock` 提供记录载体(标准库存值写入已有记录)
|
|
|
+- 已存在的人工上货记录**不受影响**
|
|
|
+
|
|
|
+**创建条件**:
|
|
|
+
|
|
|
+| 条件 | 行为 |
|
|
|
+|------|------|
|
|
|
+| 商品编码在本地 Product 表中不存在 | 跳过 |
|
|
|
+| 该设备+商品已有库存记录 | 跳过(不覆盖已有 stock) |
|
|
|
+| 该设备+商品无库存记录 | 新建,stock=0, warningThreshold=5 |
|
|
|
+
|
|
|
+#### 不会创建库存的流程
|
|
|
|
|
|
| 流程 | 做了什么 | 为什么不创建库存 |
|
|
|
|------|---------|-----------------|
|
|
|
@@ -44,7 +71,45 @@ haha 平台的职责是 AI 识别(开关门事件 + 商品识别结果)和
|
|
|
| 商品同步 | 拉取商品目录写入 `t_product` | 商品信息不绑定设备和数量 |
|
|
|
| 商品上架 | 调用 haha API 设置可售卖商品 | 只是标记可售卖,不涉及数量 |
|
|
|
|
|
|
-> **未来扩展**:如果 haha 平台升级 API 在设备同步时回传库存数据,策略是 **首次同步用 haha 数据初始化,后续同步以本地为准**。因为首次时本地无数据,哈哈的数据可作为初始值;之后本地实时扣减/补货,本地数据才是最新真相源。
|
|
|
+> **初始化策略总结**:人工上货是唯一写入实际库存(stock>0)的途径,层模版同步提供占位能力让运营平台提前看到设备货道商品列表。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 1.5 标准库存重算(recalculateStandardStock)
|
|
|
+
|
|
|
+层模版同步完成后,会根据层模版中的货道商品配置**重新计算**每台设备每个商品的 `standard_stock`(理论满柜库存量)。
|
|
|
+
|
|
|
+**触发时机**:层模版创建 / 更新 / 删除 / 同步 操作完成后自动调用。
|
|
|
+
|
|
|
+**计算逻辑**:
|
|
|
+
|
|
|
+```
|
|
|
+查询该设备所有层模版 (t_layer_template by deviceId)
|
|
|
+ │
|
|
|
+ ├─ 无层模版 → 所有库存记录的 standard_stock 置 0
|
|
|
+ │
|
|
|
+ └─ 有层模版 → 遍历每个 LayerTemplate:
|
|
|
+ │
|
|
|
+ ├─ 解析 leftFloors JSON → 遍历每层每个货道 → goodsItem.stock
|
|
|
+ └─ 解析 rightFloors JSON → 遍历每层每个货道 → goodsItem.stock
|
|
|
+ │
|
|
|
+ └─ 按 productCode 累加 → standardMap.merge(code, stock, Integer::sum)
|
|
|
+ (同一商品跨层/跨门配置数量叠加)
|
|
|
+ │
|
|
|
+ └─ 遍历设备所有 t_device_inventory 记录:
|
|
|
+ standard_stock = standardMap 中的累计值(无则为 0)
|
|
|
+ → updateById()
|
|
|
+```
|
|
|
+
|
|
|
+**关键规则**:
|
|
|
+- 同一商品在多个楼层或左右门都有配置 → **累加**各货道的摆放数量
|
|
|
+- 层模版有但库存表没有的商品 → 不处理(由 `initInventoryFromTemplate` 预先建好记录)
|
|
|
+- 库存表有但层模版没有的商品 → `standard_stock = 0`
|
|
|
+- 每次全量覆盖,非增量更新
|
|
|
+
|
|
|
+**用途**:standard_stock 作为理论满柜值,用于库存管理页面展示库存占比(`stock / standard_stock`),帮助运营判断缺货程度。
|
|
|
+
|
|
|
+> **为什么不在同步时直接写入 stock?** 物理库存必须由实际补货操作确认,层模版是"应该放什么商品"的配置,不代表当前柜内真实存量。standard_stock 记录的是"满柜时应该有多少",与实际 stock 分离。
|
|
|
|
|
|
---
|
|
|
|
|
|
@@ -64,6 +129,7 @@ haha 平台的职责是 AI 识别(开关门事件 + 商品识别结果)和
|
|
|
| `product_code` | VARCHAR(100) | haha 平台商品编码 |
|
|
|
| `product_name` | VARCHAR(200) | 商品名称快照 |
|
|
|
| `stock` | INT | **当前库存数量** |
|
|
|
+| `standard_stock` | INT | **标准库存**(满柜理论值,由层模版同步自动重算) |
|
|
|
| `shelf_num` | INT | 货架层位置 |
|
|
|
| `position` | VARCHAR(50) | 通道位置(left/right) |
|
|
|
| `warning_threshold` | INT | 低库存预警阈值(默认 5) |
|
|
|
@@ -335,7 +401,8 @@ if (deducted > 0) {
|
|
|
| 幂等性通过日志表实现 | 不在订单表增加 `stock_deducted` 字段,避免侵入;日志表本身就是审计需求 |
|
|
|
| 退款恢复用 `adjustStock` | 相比 `increaseStock`,不需要补货所需的 shelf_num/position 等字段 |
|
|
|
| 库存纯本地管理 | haha 平台不提供库存 API,且本地管理可灵活控制预警阈值、统计维度 |
|
|
|
-| **无自动初始化** | 库存数据完全由人工上货创建,设备/商品同步不创建库存记录 |
|
|
|
+| **层模版同步自动初始化** | 层模版同步时为设备中配置的商品自动创建 stock=0 的库存占位记录,已存在的人工上货记录不受影响 |
|
|
|
+| **标准库存自动重算** | 层模版创建/更新/同步后自动调用 `recalculateStandardStock`,根据货道配置重算每个商品的理论满柜库存值 |
|
|
|
| **哈哈库存首次导入策略** | 如哈哈后续提供设备库存数据:首次同步做初始化,后续同步丢弃以本地为准 |
|
|
|
|
|
|
---
|