132 lines
6.7 KiB
Markdown
132 lines
6.7 KiB
Markdown
## Context
|
||
|
||
生产部门当前仅有耗材目录表(`biz_consumable`)和试剂目录表(`biz_reagent`),管理编码、名称、规格、标准用量等基础信息,无库存管理。市场部门和质检部门已有完整的库存管理体系,采用「主表含库存字段 + 变动记录表」的双表模式。
|
||
|
||
现有耗材/试剂被 10 张下游关联表(耗材包、工艺、工艺路线、生产任务步骤)引用,但全部使用快照复制(denormalized code/name),无 FK 依赖,对主表加字段零影响。
|
||
|
||
### 现有参照实现
|
||
|
||
- **市场物料**:`biz_material`(含 stock_qty)+ `biz_material_stock_log`(变动记录,rk/ck,正数)
|
||
- **质检物料**:`biz_qc_material`(含 stock_qty)+ `biz_qc_material_usage`(变动记录,in/use,正负数,含 task_complete 自动扣减 + revert 回退)
|
||
|
||
### 步骤保存挂钩点
|
||
|
||
生产任务步骤的耗材/试剂保存入口:
|
||
- `PUT /production-tasks/{task_id}/steps/{step_id}/reagents` → `replace_step_reagents()`
|
||
- `PUT /production-tasks/{task_id}/steps/{step_id}/consumables` → `replace_step_consumables()`
|
||
|
||
这两个函数使用"软删旧 + 插入新"模式,需在此处加入 diff 结算逻辑。
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
- 为耗材和试剂增加库存管理能力(库存量、预警量、出入库操作)
|
||
- 支持手动单个/批量入库出库,参照质检物料模式
|
||
- 支持生产任务步骤保存时按 actual_usage 自动 diff 结算库存
|
||
- 变动记录在耗材/试剂页面内以子弹窗和 Tab 形式展示
|
||
|
||
**Non-Goals:**
|
||
- 不新建独立菜单页面(变动记录嵌入现有页面)
|
||
- 不修改现有耗材/试剂目录字段(只加库存字段)
|
||
- 不修改下游 10 张关联表
|
||
- 不实现仓库/库位管理(单库存维度)
|
||
- 不实现库存预警通知(仅记录 warning_qty 字段)
|
||
- 不统一耗材/试剂为统一物料表(保持两个独立目录)
|
||
|
||
## Decisions
|
||
|
||
### Decision 1: 在现有目录表上加库存字段,不新建库存主表
|
||
|
||
**选择**:ALTER TABLE `biz_consumable` / `biz_reagent` 新增 `stock_qty`、`warning_qty`、`status` 字段。
|
||
|
||
**理由**:
|
||
- 下游 10 张关联表全是快照复制,加字段零影响
|
||
- 与市场/质检物料的「主表含库存字段」模式一致
|
||
- 避免引入目录表→库存表的间接层和数据同步问题
|
||
- 改动最小:复用现有 CRUD/API/前端,只需扩展
|
||
|
||
**替代方案**:新建 `biz_consumable_stock` 表,通过 consumable_id 关联。放弃原因:多一层间接、需维护目录-库存同步、与已有模式不一致。
|
||
|
||
### Decision 2: 新建独立的变动记录表
|
||
|
||
**选择**:新建 `biz_consumable_stock_log` 和 `biz_reagent_stock_log`,参照 `biz_material_stock_log` 结构。
|
||
|
||
**理由**:
|
||
- 变动记录是独立的关注点,不应混在目录表中
|
||
- 需要快照字段(code/name)和 before/after 库存
|
||
- 需要溯源字段(source_type、step_id、task_id、task_no)
|
||
- 参照 `biz_qc_material_usage` 的 source_type 模式:manual_in / manual_out / step_save
|
||
|
||
**关键设计**:参照质检物料采用正负数表示方向(入库正、出库负),同时保留 `change_type` 字段(in/use)。
|
||
|
||
### Decision 3: 步骤保存 diff 结算算法
|
||
|
||
**选择**:全量回退 + 重算模式(参照质检物料的 revert + deduct 模式)。
|
||
|
||
**算法**:
|
||
1. 查出该步骤当前所有 source_type=step_save 的变动记录
|
||
2. 按变动记录逐条回退库存(加回扣减量),软删变动记录
|
||
3. 遍历新的步骤耗材/试剂列表,按 actual_usage 扣减库存,生成新变动记录
|
||
4. 整体在同一事务中
|
||
|
||
**理由**:
|
||
- 步骤保存频率不高,全量回退+重算简单可靠
|
||
- 避免复杂的逐项 diff 计算(需处理编码变更等边界情况)
|
||
- 与质检物料 deduct_for_task() 模式一致,代码可复用
|
||
|
||
**替代方案**:逐项 diff(旧用量 - 新用量 = 差额)。放弃原因:需处理编码变更(物料A改成物料B)、处理删除、新增等复杂场景,容易出 bug。全量回退更简单且已验证。
|
||
|
||
### Decision 4: 变动记录子弹窗 + Tab 双入口
|
||
|
||
**选择**:
|
||
- 每行操作列「变动记录」按钮 → Dialog 弹窗,按 material_id 筛选
|
||
- 页面顶部 Tab「全部变动记录」→ Tab 切换视图,展示所有物料的汇总记录
|
||
|
||
**理由**:
|
||
- 不新增菜单位,保持生产管理菜单简洁
|
||
- 行按钮满足"看某个物料历史"的快速需求
|
||
- Tab 视图满足"看所有变动流水"的审计需求
|
||
|
||
### Decision 5: 挂钩点在 replace_step_reagents/consumables
|
||
|
||
**选择**:在 `replace_step_reagents()` 和 `replace_step_consumables()` 函数中,在 soft delete 旧记录之后、insert 新记录之前,执行库存 diff 结算。
|
||
|
||
**调用链**:
|
||
```
|
||
API: PUT /production-tasks/{task_id}/steps/{step_id}/consumables
|
||
→ replace_step_consumables(db, step_id, tenant_no, user_id, items)
|
||
→ 1. 查出步骤信息(step_id → task_id, task_no)
|
||
→ 2. 调用 diff_settle_step_consumables(db, step_id, task_id, task_no, tenant_no, user_id)
|
||
→ revert step 的所有 step_save 变动记录(回退库存)
|
||
→ 3. soft delete 旧步骤耗材子记录
|
||
→ 4. insert 新步骤耗材子记录
|
||
→ 5. 调用 deduct_step_consumables(db, step_id, task_id, task_no, tenant_no, user_id, new_items)
|
||
→ 按 actual_usage 扣减库存,生成 step_save 变动记录
|
||
→ 6. commit
|
||
```
|
||
|
||
## Risks / Trade-offs
|
||
|
||
### Risk: 步骤保存时库存不足
|
||
**影响**:任务执行保存步骤时,若耗材/试剂库存不足,保存会失败。
|
||
**缓解**:提供清晰的错误提示("物料「XX」库存不足,当前库存 N,需使用 M"),让用户先去入库。同时前端可在步骤编辑时显示当前库存量供参考。
|
||
|
||
### Risk: actual_usage 为空或非数字
|
||
**影响**:步骤保存时 actual_usage 字段可能为空字符串或非数字。
|
||
**缓解**:diff 结算时跳过 actual_usage 为空或无法转为正数的条目,仅处理有效数据。
|
||
|
||
### Risk: 并发保存同一物料库存
|
||
**影响**:多个步骤同时保存涉及同一耗材/试剂。
|
||
**缓解**:使用 `with_for_update()` 行锁,与质检物料一致。
|
||
|
||
### Trade-off: 全量回退 vs 逐项 diff
|
||
**选择**全量回退,牺牲少量性能换取代码简洁性和正确性保证。步骤保存频率低,性能影响可忽略。
|
||
|
||
## Migration Plan
|
||
|
||
1. **数据库迁移**:ALTER TABLE 加字段(有默认值) + CREATE TABLE 建变动记录表
|
||
2. **后端部署**:模型 → CRUD → API 顺序部署
|
||
3. **前端部署**:扩展现有页面
|
||
4. **无需数据迁移**:现有耗材/试剂的 stock_qty 默认为 0,warning_qty 默认为 0,status 默认为 '1'
|
||
5. **回滚方案**:ALTER TABLE 删除新增字段,DROP TABLE 变动记录表,回滚代码
|