老系统做法是「入库价填 0 → 出库 → 反审核入库单改价 → 重审」。新系统已审核单据只读、无反审核、流水不可变、库存成本一旦落地无修改接口——强行复刻反审核在「货已出库」时几乎无法回滚干净,且违反现有不可变设计。
故改用会计上的「暂估入库 → 实际成本确认」模型:不反审核,以一次前向调整补齐成本与应付。关键前提是新系统的序列号数据模型让这件事变得精确——
product_id。因此「某次调货的成本」就是「某个 product 的成本」,可凭 product_id 精确回填到它的所有已出库行,无需额外的批次消耗映射表。inventories.unit_price 为 *float64,0 价入库即存 NULL,天然表示「待定价」。用户确认的口径:①不填预估、直接填 0;②确认后补成本 + 补应付流水;③调货不单独建单据类型,复用普通入库单;④利润统计遇到无进价的行须跳过并单独说明。
简化决策:不新增 schema 字段(遵循「禁止为每个业务字段改表结构」)。约定 成本待定 = 成本为 0 / unit_price 为 NULL。调货白酒成本不会真为 0,歧义可忽略。
接口:POST /api/v1/stock-in/orders/:id/confirm-cost,body {"items":[{"item_id":N,"unit_price":50.0}]}。
仅 approved 单可确认(draft 直接编辑即可);权限 管理员/超管;后端实现 StockService.ConfirmStockInCost。
一个事务内,对每个有变化的明细(旧价→新价,差额 diff = (new-old)×qty)前向写补偿:
幂等 / 可重复:以「旧价→新价」差额计算,多次修正各补一条差额流水(如 0→50 补 +500,再 50→60 补 +100)。
应付余额语义:balance 是该往来单位「应收 + 应付」混合的滚动总账(沿用既有 partnerLastBalance),确认流水在此基础上累加差额。
| 数据 | 0 价入库审核后 | 确认进价后 |
|---|---|---|
| 入库明细 unit_price | 0 | → 真实价 |
| 库存批次 unit_price | NULL(待定) | → 真实价 |
| 已出库行 unit_price(成本快照) | 0 | → 真实价(按 product_id) |
| 出库 sale_price / 应收 | 正常 | 不变 |
| 入库单 total_amount | 0 | → Σ 真实小计 |
| 对供应商应付 | +0 | 补一条 +差额 流水 |
product_id 命中。returned_quantity):按现有快照同样回填 unit_price,退货金额逻辑不变;如需特殊冲减再议。product_id=0):不向出库行/参考进价传播(避免误伤),仅改本单明细与库存。- 或 ¥0.00。系统当前无利润/毛利报表,本次不新建(YAGNI)。约定:未来任何利润/毛利统计,须排除成本待定(unit_price ≤ 0 / NULL)的出库行,并单独列「N 笔成本待定,未计入利润」。 本设计的「待定价」标识即为该口径提供可识别依据。
backend/internal/service/stock.go(ConfirmStockInCost + CostConfirmItem)、internal/handler/stock_in.go(ConfirmCost)、internal/router/router.go、internal/handler/stock_cost_confirm_test.go(4 用例:回填+应付 / 403 / 非 approved / 重复确认)。client/lib/repositories/stock_in_repository.dart(confirmCost)、client/lib/screens/stock_in/stock_in_list_screen.dart(确认进价弹窗 + 待定价)、client/lib/screens/inventory/inventory_list_screen.dart(待定价)。