docs/00-overview.md
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# 05 库存设计
|
||||
|
||||
**库存设计是整个 WMS 的核心。**
|
||||
|
||||
## 库存模型
|
||||
|
||||
不要简单设计 `sku + warehouse + quantity`,必须建立完整库存模型。
|
||||
|
||||
### 数量维度
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| available_qty | 可用数量 |
|
||||
| reserved_qty | 预占 / 锁定数量 |
|
||||
| picked_qty | 已拣货数量 |
|
||||
| hold_qty | 冻结数量 |
|
||||
| damaged_qty | 残损数量 |
|
||||
| in_transit_qty | 在途数量 |
|
||||
|
||||
### 位置与属性维度
|
||||
|
||||
- 仓库
|
||||
- 库区
|
||||
- 库位
|
||||
- SKU
|
||||
- 批次
|
||||
- 库存状态
|
||||
|
||||
### 核心关系
|
||||
|
||||
```
|
||||
SKU
|
||||
↓
|
||||
Warehouse
|
||||
↓
|
||||
Zone
|
||||
↓
|
||||
Location
|
||||
↓
|
||||
Batch
|
||||
↓
|
||||
Inventory
|
||||
```
|
||||
|
||||
## 库存流水必须是核心数据
|
||||
|
||||
必须设计 `wms_stock_log`,任何库存变化必须能够追溯。例如:
|
||||
|
||||
```
|
||||
入库 +100
|
||||
锁定 -20
|
||||
拣货 -5
|
||||
出库 -5
|
||||
盘点 +2
|
||||
调整 -1
|
||||
```
|
||||
|
||||
需要能够回答:**为什么这个 SKU 的库存从昨天的 100 变成今天的 76?**
|
||||
|
||||
- 库存余额是结果。
|
||||
- 库存流水是事实。
|
||||
|
||||
不要只修改 `inventory.quantity` 而不留下完整流水。库存余额更新与流水写入必须在同一事务中完成,流水需记录业务单据类型与单号(如 inbound_no / outbound_no)。
|
||||
|
||||
## 库存并发安全
|
||||
|
||||
库存扣减必须考虑并发。
|
||||
|
||||
**禁止:** 先 SELECT → PHP 计算 → UPDATE。这种方式容易产生超卖。
|
||||
|
||||
根据实际业务采用:
|
||||
|
||||
- 数据库事务
|
||||
- 行锁(`SELECT ... FOR UPDATE`)
|
||||
- 乐观锁(version 字段)
|
||||
- 原子更新
|
||||
- Redis 分布式锁(必要时)
|
||||
|
||||
原子更新示例:
|
||||
|
||||
```sql
|
||||
UPDATE wms_inventory
|
||||
SET available_qty = available_qty - :qty,
|
||||
reserved_qty = reserved_qty + :qty
|
||||
WHERE tenant_code = :tenant_code
|
||||
AND id = :id
|
||||
AND available_qty >= :qty;
|
||||
-- 受影响行数为 0 即库存不足,必须抛出业务异常
|
||||
```
|
||||
|
||||
必须保证:
|
||||
|
||||
- `available_qty >= 扣减数量`
|
||||
- 多个并发请求不能导致负库存或重复扣减
|
||||
|
||||
## 并发验收用例
|
||||
|
||||
两个请求同时扣减 8 个库存,而实际只有 10 个库存。必须保证:
|
||||
|
||||
- 不会出现 `available_qty = -6`
|
||||
- 不能出现两个订单都成功扣减 8
|
||||
Reference in New Issue
Block a user