Ver Fonte

docs: 更新库存管理文档 — 补充初始化机制 + 设备选择器标注门店

1. 新增 1.4 库存初始化机制:说明无自动初始化,唯一入口是人工上货;
   未来如哈哈回传库存数据,首次导入初始化、后续丢弃以本地为准
2. 新增设计决策:无自动初始化、哈哈库存首次导入策略
3. 库存列表页设备选择器显示格式改为「deviceId — shopName」,
   方便快速区分不同门店设备

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline há 1 semana atrás
pai
commit
b4dc478153

+ 22 - 0
docs/库存管理模块.md

@@ -26,6 +26,26 @@
 
 haha 平台的职责是 AI 识别(开关门事件 + 商品识别结果)和设备管理。其 SDK 提供的 `GoodsApi` 和 `OrderApi` 均无库存查询/更新端点,商品 API 仅管理产品目录和上架状态。
 
+### 1.4 库存初始化机制
+
+库存数据**没有自动初始化**,唯一的入口是人工上货操作:
+
+```
+管理员/补货员手动上货 → DeviceInventoryService.increaseStock()
+    → 首次上货该商品 → 新建 t_device_inventory 记录
+    → 再次上货 → 累加 stock
+```
+
+以下流程**不创建库存**:
+
+| 流程 | 做了什么 | 为什么不创建库存 |
+|------|---------|-----------------|
+| 设备同步 | 拉取设备信息写入 `t_device` | haha 的 `DeviceInfo` 不含库存字段 |
+| 商品同步 | 拉取商品目录写入 `t_product` | 商品信息不绑定设备和数量 |
+| 商品上架 | 调用 haha API 设置可售卖商品 | 只是标记可售卖,不涉及数量 |
+
+> **未来扩展**:如果 haha 平台升级 API 在设备同步时回传库存数据,策略是 **首次同步用 haha 数据初始化,后续同步以本地为准**。因为首次时本地无数据,哈哈的数据可作为初始值;之后本地实时扣减/补货,本地数据才是最新真相源。
+
 ---
 
 ## 二、数据库设计
@@ -315,6 +335,8 @@ if (deducted > 0) {
 | 幂等性通过日志表实现 | 不在订单表增加 `stock_deducted` 字段,避免侵入;日志表本身就是审计需求 |
 | 退款恢复用 `adjustStock` | 相比 `increaseStock`,不需要补货所需的 shelf_num/position 等字段 |
 | 库存纯本地管理 | haha 平台不提供库存 API,且本地管理可灵活控制预警阈值、统计维度 |
+| **无自动初始化** | 库存数据完全由人工上货创建,设备/商品同步不创建库存记录 |
+| **哈哈库存首次导入策略** | 如哈哈后续提供设备库存数据:首次同步做初始化,后续同步丢弃以本地为准 |
 
 ---
 

+ 1 - 1
haha-admin-web/src/views/inventory/index.vue

@@ -50,7 +50,7 @@ const {
           <el-option
             v-for="item in deviceOptions"
             :key="item.deviceId"
-            :label="item.deviceName"
+            :label="item.shopName ? `${item.deviceId} — ${item.shopName}` : item.deviceId"
             :value="item.deviceId"
           />
         </el-select>

+ 1 - 1
haha-admin-web/src/views/inventory/utils/hook.tsx

@@ -166,7 +166,7 @@ export function useInventory(tableRef: Ref) {
           <ElFormItem label="设备" prop="deviceId" rules={[{ required: true, message: "请选择设备", trigger: "change" }]}>
             <ElSelect v-model={stockInForm.deviceId} placeholder="请选择设备" class="w-full!">
               {deviceOptions.value.map(item => (
-                <ElOption key={item.deviceId} label={item.deviceName} value={item.deviceId} />
+                <ElOption key={item.deviceId} label={item.shopName ? `${item.deviceId} — ${item.shopName}` : item.deviceId} value={item.deviceId} />
               ))}
             </ElSelect>
           </ElFormItem>