init
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
---
|
||||
description: 库存模型、库存流水与并发安全规则(任何涉及库存数量变化的代码)
|
||||
globs: backend/app/**/Inventory/**,backend/app/**/Inbound/**,backend/app/**/Outbound/**,backend/app/**/Picking/**,backend/app/**/Return/**
|
||||
alwaysApply: false
|
||||
---
|
||||
# 库存规则
|
||||
|
||||
详见 `docs/05-inventory.md`。库存是整个 WMS 的核心。
|
||||
|
||||
## 模型
|
||||
- 维度:仓库 → 库区 → 库位 → SKU → 批次 → 库存状态,不要简化为 `sku + warehouse + quantity`。
|
||||
- 数量:`available_qty`、`reserved_qty`、`picked_qty`、`hold_qty`、`damaged_qty`、`in_transit_qty`。
|
||||
|
||||
## 流水
|
||||
- 任何库存数量变化,必须在**同一事务**内写入 `wms_stock_log`(变化量、变化前后、业务单据类型与单号、操作人)。
|
||||
- 库存变更只能通过库存领域服务 / Action 完成,业务模块不得直接 update 库存表。
|
||||
- 流水只追加,不修改、不删除。
|
||||
|
||||
## 并发
|
||||
禁止 "先 SELECT → PHP 计算 → UPDATE"。使用事务 + 原子条件更新 / 行锁 / 乐观锁,必要时 Redis 锁。
|
||||
|
||||
```php
|
||||
// ❌ 并发下会超卖
|
||||
$inv = Inventory::find($id);
|
||||
if ($inv->available_qty >= $qty) { $inv->available_qty -= $qty; $inv->save(); }
|
||||
|
||||
// ✅ 原子条件更新,受影响行数为 0 即库存不足
|
||||
$affected = Inventory::whereKey($id)
|
||||
->where('available_qty', '>=', $qty)
|
||||
->update([
|
||||
'available_qty' => DB::raw('available_qty - '.(int) $qty),
|
||||
'reserved_qty' => DB::raw('reserved_qty + '.(int) $qty),
|
||||
]);
|
||||
if ($affected === 0) { throw new InsufficientStockException(); }
|
||||
```
|
||||
|
||||
- 多行扣减按固定顺序(如库存主键升序)加锁,避免死锁。
|
||||
- 必须有并发测试:库存 10,两个请求同时扣 8,只能成功一个,且不会出现负库存。
|
||||
Reference in New Issue
Block a user