## ADDED Requirements ### Requirement: Step save registers consumption via requisition not direct deduction 对于 **编码存在于** `biz_consumable` / `biz_reagent` 目录中的步骤行,系统 SHALL 要求提供有效 `requisitionUsageId`(指向 `source_type=manual_out` 的 stock_log 记录)。步骤保存时: 1. 写 `source_type=step_save` 变动记录 2. 设置 `parent_usage_id = requisitionUsageId` 3. **不修改** 对应物资 `stock_qty`(`stock_before` SHALL 等于 `stock_after`) 4. `change_qty` SHALL 为负数,绝对值等于 `actual_usage` 解析后的有效用量 #### Scenario: First save with requisition linked - **WHEN** 用户保存步骤,耗材 A(目录内)关联领用记录 R(曾出库 10),actual_usage=2 - **THEN** 耗材 A 的 stock_qty 不变,生成 1 条 step_save 记录(change_qty=-2,parent_usage_id=R) #### Scenario: Save without requisition for catalog material - **WHEN** 用户保存步骤,试剂 B 编码存在于 biz_reagent,但未选 requisitionUsageId - **THEN** 整个步骤保存回滚,提示「请选择领用记录」 #### Scenario: Save with empty actual usage - **WHEN** 用户保存步骤,已选领用记录但 actual_usage 为空或为 0 - **THEN** 该步骤行不生成 step_save 记录(与现网跳过空用量一致) ### Requirement: Custom catalog-absent materials remain record-only 若步骤行 `consumable_code` / `reagent_code` **不存在于** 对应目录表(自定义/legacy 编码),系统 SHALL: - 允许保存步骤子表(编码、名称、standard_usage、actual_usage 等) - **不要求** requisitionUsageId - **不写入** stock_log,**不修改** stock_qty #### Scenario: Custom code without catalog match - **WHEN** 步骤保存包含 consumable_code=`CUSTOM-001` 且 biz_consumable 中无此编码 - **THEN** 子表保存成功,无 stock_log 变动 ### Requirement: Requisition record validation on step save 保存步骤时,对每个需关联领用的行,系统 SHALL 校验: 1. `requisitionUsageId` 对应记录存在、未删除、`source_type=manual_out` 2. 领用记录的 `material_id` 与步骤行所选物料(按编码匹配目录)一致 3. 领用记录 **SHALL** 含有效 `batch_id`(批次领用出库产生);步骤登记继承 parent 的批号/入库编号快照 4. 同一步骤列表内 `requisitionUsageId` 不可重复 #### Scenario: Invalid requisition id rejected - **WHEN** 用户提交不存在的 requisitionUsageId - **THEN** 步骤保存回滚,提示「领用记录不存在或已失效」 #### Scenario: Duplicate requisition in same step - **WHEN** 同一步骤两行均选择同一 requisitionUsageId - **THEN** 步骤保存回滚,提示「物料列表中存在重复领用记录,请检查」 #### Scenario: Requisition material mismatch - **WHEN** 步骤行选择耗材 A,但 requisitionUsageId 指向耗材 B 的领用记录 - **THEN** 步骤保存回滚,提示物料与领用记录不匹配 ### Requirement: Step save diff settlement replaces legacy deduct_for_step `replace_step_reagents()` / `replace_step_consumables()` SHALL 继续采用全量回退 + 重算,但替换 `deduct_for_step()` 的直接扣库逻辑为 `register_step_usage_from_requisition()`(新函数,耗材/试剂各一)。 **回退阶段**(revert step 的全部 step_save 记录): | 旧记录类型 | 库存处理 | |-----------|----------| | `parent_usage_id` 为空(历史直接扣库) | 回加 `\|change_qty\|` 至 stock_qty | | `parent_usage_id` 有值(新流程登记) | **不回加** stock_qty,仅软删记录 | **重算阶段**:按本 spec「Step save registers consumption via requisition」写入新 step_save 记录。 #### Scenario: Re-save step with new requisition flow - **WHEN** 步骤首次保存登记领用 R 用量 2(新流程),第二次改为用量 3 - **THEN** 回退时 stock_qty 不变;重算后仅 1 条 step_save(change_qty=-3);stock_qty 全程不变 #### Scenario: Re-save legacy direct deduction step - **WHEN** 步骤含历史 step_save(无 parent_usage_id,曾扣库 5),用户编辑为领用模式用量 2 - **THEN** 回退时 stock_qty +5;新 step_save 不扣库;净效果 stock_qty +5 #### Scenario: Remove all reagent rows from step - **WHEN** 步骤曾登记 2 条 step_save(新流程),第二次保存清空试剂列表 - **THEN** 回退软删 2 条 step_save,stock_qty 不变 ### Requirement: Step save transaction atomicity 领用登记、步骤子表替换、stock_log 回退/写入 SHALL 在同一数据库事务内完成。任一校验失败 SHALL 整单回滚。 #### Scenario: Invalid requisition rolls back step sub-table - **WHEN** 领用校验失败 - **THEN** 步骤试剂/耗材子表不发生部分更新 ### Requirement: Step save traceability fields 每条新流程 `step_save` 记录 SHALL 包含: - `step_id`、`step_name`(快照) - `task_id`、`task_no`(快照) - `parent_usage_id` - `material_id`、`material_code`、`material_name`(快照) - `usage_unit`(来自步骤行 unit 或领用记录) #### Scenario: Stock log traceability - **WHEN** 步骤保存成功 - **THEN** step_save 记录可通过 task_no、step_name 追溯至【生产工单】任务与步骤;登记人可在【我的耗材领用记录】或【我的试剂领用记录】中查看 ### Requirement: Step usage visible in my requisition menus 【生产工单】步骤保存产生的 `step_save` 记录 SHALL 在对应物料类型的「我的领用记录」菜单中可见:`create_by` 为登记人;`manual_out` 领用记录可通过下钻查看关联的全部 step_save。 #### Scenario: Operator finds own registration in my menu - **WHEN** 用户完成生产工单步骤耗材登记 - **THEN** 无需进入耗材管理页,在【我的耗材领用记录】即可看到该次登记 ## REMOVED Requirements ### Requirement: Step save auto stock deduction **Reason**: 库存扣减前移至 manual_out 领用;步骤保存改为领用关联登记,避免双重扣减。 **Migration**: 新保存步骤 MUST 选领用记录;历史无 parent_usage_id 的 step_save 仍按 Decision 3 回退规则处理。实现上删除 `deduct_for_step()` 中对目录物料的直接扣库分支,替换为 `register_step_usage_from_requisition()`。 ### Requirement: Skip deduction for materials not in catalog **Reason**: 合并入「Custom catalog-absent materials remain record-only」;目录内物料改为 MUST 选领用,不再存在「目录内跳过扣减」语义。 **Migration**: 自定义编码行为不变(仅记录);目录内物料从无领用扣库变为必须领用。 ### Requirement: Step save diff settlement via full revert and re-deduct **Reason**: 「re-deduct」语义变更:重算阶段不再扣总库,仅写关联流水。 **Migration**: 保留 revert + 重算框架;重算函数替换;回退区分历史/新记录(见 ADDED「Step save diff settlement replaces legacy deduct_for_step」)。 #### Scenario: Stock insufficient during step save - **WHEN** 用户保存步骤且某目录内行未选领用 - **THEN** 回滚并提示「请选择领用记录」(**不再**出现「库存不足」类 step_save 扣库错误) > **注**:「库存不足」仍仅发生在 **manual_out 批量出库** 时,不在步骤保存阶段校验总库。