|
|
@@ -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'` 的商品不自持库存,库存检查/扣减穿透到子商品;入库单也只针对子商品,不针对套餐本身
|