Просмотр исходного кода

docs: 库存管理设计文档(入库单+流水+盘点+预警+套餐拆库存)

Xiaogang Liao 3 месяцев назад
Родитель
Сommit
b846acb2de

+ 2 - 0
docs/superpowers/PROJECT-OVERVIEW.md

@@ -189,6 +189,7 @@
 | 供应商销售体系(体系账期+留利) | Phase 2 | 🟡 设计稿 | `specs/2026-07-05-supply-distribution-system-design.md` + `plans/2026-07-05-supply-distribution-system.md` |
 | 商品规格最小购买数限制 | Phase 4 | ✅ 已实施(ProductSku.minQuantity + ProductOrderService校验 + schema.sql同步) | `plans/2026-07-13-supplier-system-gap-fix.md` |
 | 供应商订单修复 | Phase 4 | 🟡 计划中 | `plans/2026-06-20-danshop-order-fix.md` |
+| 库存管理(入库单+流水+盘点+预警+套餐拆库存) | Phase 4 | 🟡 设计稿 | `specs/2026-08-05-inventory-management-design.md` |
 
 ---
 
@@ -334,6 +335,7 @@
 | `2026-08-04-registration-profile-backfill-design.md` | 🟡 设计稿 | 新用户注册引导 + 个人信息按需补充/回写 |
 | `2026-08-04-report-confirm-member-selector-design.md` | 🟡 设计稿 | 健康报告确认页被检测人选择面板整合(基本信息内选/添被检人) |
 | `2026-08-04-family-challenge-custom.md` | 🟢 已实施 | 家庭挑战自定义管理(创建/编辑/删除/模板) |
+| `2026-08-05-inventory-management-design.md` | 🟡 设计稿 | 库存管理(入库单+流水+盘点+预警+套餐拆库存) |
 
 ### 实施计划(plans/)
 

+ 244 - 0
docs/superpowers/specs/2026-08-05-inventory-management-design.md

@@ -0,0 +1,244 @@
+# 库存管理设计
+
+## 概述
+
+为商品管理模块增加完整的库存管理功能,记录实物商品的入库、出库(订单)、盘点及预警,支持 SKU 级别库存。
+
+## 数据库设计
+
+### 1. inventory_transactions — 库存流水
+
+```sql
+CREATE TABLE IF NOT EXISTS inventory_transactions (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    product_id BIGINT NOT NULL COMMENT '商品ID',
+    sku_id BIGINT COMMENT 'SKU ID,NULL=商品级库存',
+    type VARCHAR(20) NOT NULL COMMENT '类型: inbound/outbound/adjustment/counting/refund',
+    direction TINYINT NOT NULL COMMENT '方向: 1=入库 -1=出库',
+    quantity INT NOT NULL COMMENT '变动数量(正数)',
+    before_stock INT NOT NULL COMMENT '变动前库存',
+    after_stock INT NOT NULL COMMENT '变动后库存',
+    reference_type VARCHAR(32) COMMENT '关联类型: inbound_order/order/counting/adjustment',
+    reference_id BIGINT COMMENT '关联ID',
+    operator_id BIGINT COMMENT '操作人ID,关联 users.id',
+    remark VARCHAR(500) COMMENT '备注',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+    INDEX idx_product (product_id),
+    INDEX idx_sku (sku_id),
+    INDEX idx_type (type),
+    INDEX idx_reference (reference_type, reference_id),
+    INDEX idx_created_at (created_at)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存流水表';
+```
+
+### 2. inventory_inbound_orders — 入库单
+
+```sql
+CREATE TABLE IF NOT EXISTS inventory_inbound_orders (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    order_no VARCHAR(64) NOT NULL UNIQUE COMMENT '入库单号',
+    supplier_id BIGINT COMMENT '供应商ID,关联 ecom_supplier.id',
+    supplier_name VARCHAR(200) COMMENT '供应商名称(冗余)',
+    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/completed/cancelled',
+    total_items INT NOT NULL DEFAULT 0 COMMENT '商品总数',
+    operator_id BIGINT COMMENT '操作人ID,关联 users.id',
+    remark VARCHAR(500) COMMENT '备注',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    INDEX idx_status (status),
+    INDEX idx_operator (operator_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='入库单表';
+```
+
+### 3. inventory_inbound_items — 入库单明细
+
+```sql
+CREATE TABLE IF NOT EXISTS inventory_inbound_items (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    inbound_order_id BIGINT NOT NULL COMMENT '入库单ID',
+    product_id BIGINT NOT NULL COMMENT '商品ID',
+    sku_id BIGINT COMMENT 'SKU ID',
+    quantity INT NOT NULL COMMENT '入库数量',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+    INDEX idx_inbound_order (inbound_order_id),
+    INDEX idx_product (product_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='入库单明细表';
+```
+
+### 4. inventory_counting_records — 盘点记录
+
+```sql
+CREATE TABLE IF NOT EXISTS inventory_counting_records (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    product_id BIGINT NOT NULL COMMENT '商品ID',
+    sku_id BIGINT COMMENT 'SKU ID',
+    expected_stock INT NOT NULL COMMENT '系统库存',
+    actual_stock INT NOT NULL COMMENT '实际库存',
+    difference INT NOT NULL COMMENT '差异(actual - expected)',
+    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/confirmed',
+    operator_id BIGINT COMMENT '操作人ID',
+    remark VARCHAR(500) COMMENT '备注',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+    INDEX idx_product (product_id),
+    INDEX idx_status (status)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='盘点记录表';
+```
+
+### 5. product_bundle_items — 套餐商品组成(零进整出)
+
+```sql
+CREATE TABLE IF NOT EXISTS product_bundle_items (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    bundle_product_id BIGINT NOT NULL COMMENT '套餐商品ID,关联 products.id',
+    child_product_id BIGINT NOT NULL COMMENT '子商品ID,关联 products.id',
+    child_sku_id BIGINT COMMENT '子商品SKU ID,NULL=商品级',
+    quantity INT NOT NULL DEFAULT 1 COMMENT '子商品数量',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+    INDEX idx_bundle (bundle_product_id),
+    INDEX idx_child (child_product_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='套餐商品组成表';
+```
+
+**套餐库存逻辑:**
+- 套餐商品 `product_type='bundle'`,**自身不管理库存**(零进)
+- 卖出时从各子商品扣减库存(整出)
+- 库存检查:遍历所有子商品,任一子商品库存不足则套餐不可售
+- 出库流水:每个子商品各生成一条 `type=outbound` 记录
+
+### 6. 现有表扩展
+
+- `products` 表增加列:`min_stock_alert INT DEFAULT 10 COMMENT '库存预警下限'`
+- `product_skus` 表增加列:`min_stock_alert INT DEFAULT 10 COMMENT '库存预警下限'`
+
+## 后端架构
+
+### 新增文件
+
+```
+entity/
+├── InventoryTransaction.java
+├── InventoryInboundOrder.java
+├── InventoryInboundItem.java
+├── InventoryCountingRecord.java
+
+mapper/
+├── InventoryTransactionMapper.java
+├── InventoryInboundOrderMapper.java
+├── InventoryInboundItemMapper.java
+├── InventoryCountingRecordMapper.java
+
+service/
+└── InventoryService.java
+
+controller/admin/
+└── AdminInventoryController.java
+```
+
+### API 接口
+
+| 方法 | 接口 | 说明 |
+|------|------|------|
+| POST | `/api/admin/inventory/inbound/create` | 创建入库单(含明细,事务提交) |
+| POST | `/api/admin/inventory/inbound/list` | 入库单列表(分页+筛选) |
+| POST | `/api/admin/inventory/inbound/detail` | 入库单详情(含明细) |
+| POST | `/api/admin/inventory/inbound/confirm` | 确认入库(状态→completed,触发库存增加+流水) |
+| POST | `/api/admin/inventory/inbound/cancel` | 取消入库单 |
+| POST | `/api/admin/inventory/transactions/list` | 库存流水(按商品/时间/类型筛选) |
+| POST | `/api/admin/inventory/counting/create` | 创建盘点记录 |
+| POST | `/api/admin/inventory/counting/confirm` | 确认盘点(差异自动调账+流水) |
+| POST | `/api/admin/inventory/counting/list` | 盘点列表 |
+| POST | `/api/admin/inventory/product/stock` | 商品库存详情(含预警状态) |
+| POST | `/api/admin/inventory/alert/list` | 库存预警商品列表 |
+
+### 库存自动出库集成
+
+| 位置 | 事件 | 操作 |
+|------|------|------|
+| `ProductOrderService.handlePaymentSuccess()` | 支付成功扣减库存后 | 追加 `direction=-1, type=outbound` 流水 |
+| `ProductOrderService.cancel()` | 取消订单恢复库存后 | 追加 `direction=1, type=refund` 流水 |
+| `ProductOrderService.approveRefund()` | 退款恢复库存后 | 追加 `direction=1, type=refund` 流水 |
+
+### InventoryService 核心职责
+
+- `createInboundOrder()` — 创建入库单(状态 pending)
+- `confirmInbound()` — 确认入库:逐条增加 products.stock / product_skus.stock,写入流水
+- `recordOutbound()` — 供订单服务调用,记录出库流水
+- `getStockAlerts()` — 查询所有库存低于预警线的商品/SKU
+- `createCounting()` — 创建盘点并自动计算差异
+- `confirmCounting()` — 确认盘点结果,差异自动调账
+
+### 套餐商品(Bundle)库存逻辑
+
+**新增 Entity / Mapper / Service:**
+- `entity/ProductBundleItem.java` — 套餐组成实体
+- `mapper/ProductBundleItemMapper.java` — 套餐组成 Mapper
+- `InventoryService` 中新增 bundle 相关方法
+
+**新增 API:**
+```
+POST /api/admin/inventory/bundle/items   — 配置套餐商品组成(子商品+数量)
+POST /api/admin/inventory/bundle/items/list — 查询套餐组成
+```
+
+**订单集成逻辑:**
+- `ProductOrderService.create()` / `createMultiItem()`: 库存检查时,若商品为 `product_type='bundle'`,遍历 `product_bundle_items` 检查每个子商品库存
+- `ProductOrderService.handlePaymentSuccess()`: 若商品为 bundle,不扣主商品库存,改为逐条扣减子商品库存+记录流水
+- `ProductOrderService.cancel()` / `approveRefund()`: 恢复各子商品库存+记录流水
+
+**库存查询:**
+- `GET /api/admin/inventory/product/stock` 返回 bundle 商品时,`stock` 字段返回各子商品的最低库存,并附带子商品明细
+
+## 管理端 UI
+
+### 新增页面
+
+**InventoryManage.vue** — 库存管理主页,Tabs 布局:
+
+| 标签页 | 内容 |
+|--------|------|
+| 库存流水 | 筛选(商品名/SKU/类型/时间范围),表格展示流水 |
+| 入库单 | 列表 + 查看/确认/取消操作 |
+| 库存预警 | 低于预警线的商品列表,红色高亮 |
+| 盘点记录 | 盘点列表 + 确认操作 |
+
+**InventoryInboundCreate.vue** — 创建入库单:
+- 供应商搜索选择
+- 动态明细行(商品选择器 → 规格选择 → 数量)
+- 备注
+
+### 修改现有页面
+
+**ProductManage.vue** — 商品列表每行增加「库存」按钮,点击弹窗显示:
+- 当前库存、预警下限、最近 10 条流水
+- SKU 列表及各自库存
+- 快捷入库按钮
+
+### 路由
+
+```js
+{ path: 'inventory', component: InventoryManage, meta: { perm: 'commerce:inventory' } }
+{ path: 'inventory/inbound-create', component: InventoryInboundCreate, meta: { perm: 'commerce:inventory' } }
+```
+
+### 侧边栏
+
+在「商品管理」菜单下新增「库存管理」子菜单项。
+
+## 数据库迁移
+
+迁移编号: 168(当前最新 167),在 `DatabaseInitializer.runMigrations()` 末尾追加。
+
+## 范围说明
+
+- 库存预警仅对 `product_type='physical'` 的实物商品生效
+- `min_stock_alert` 默认值为 10,通过管理端 UI 可逐商品/SKU 调整
+- 非实物商品(digital/assessment/coupon/virtual)不参与库存管理
+- 套餐商品 `product_type='bundle'` 零进整出:自身不管理库存,通过子商品扣减实现
+
+## 设计决策
+
+1. **库存快照字段**:流水记录 `before_stock` 和 `after_stock`,即使后续修改,流水也能反映当时库存状态
+2. **入库单两阶段提交**:创建(pending)→ 确认(completed),确认时才实际修改库存,支持撤销
+3. **盘点差异自动调账**:确认盘点时,差异自动生成一条 `type=adjustment` 的流水
+4. **SKU 级 vs 商品级**:有 SKU 的商品按 SKU 管理库存,无 SKU 的直接按商品管理
+5. **套餐零进整出**:`product_type='bundle'` 的商品不自持库存,库存检查/扣减穿透到子商品;入库单也只针对子商品,不针对套餐本身