fix(reservation): 实扫来源不可识别时整单失败,避免预占永久锁死
出库与借库两条执行路径原先写作:
_scanned = [i for i in items if i.get('source_table') != 'trans_repair']
if _scanned:
verify_scanned(...); restore_then_deduct(...)
`if _scanned:` 为假时校验与释放被整体跳过,而下方仍无条件把单据置为
status=3(已完成)。此时申请阶段 reserve_for_items() 扣掉的 available_quantity
无人归还,且 status=3 之后 /close(要求 status==1)与 /withdraw(要求
status∈(0,1))都拒绝再释放 —— 预占就此永久锁死,成为谁也领不走的幽灵库存,
且没有流水可供追溯。
改为 Fail-Closed:实扫明细的来源必须全部落在 model_map 内,否则整单失败。
事务回滚后单据保持 status=1、预占原样保留,库管可重试执行,或走驳回/撤回 ——
任一路径都能正常归还预占。
- outbound_service.create_outbound_batch:以 model_map 白名单过滤,
并要求 _scanned 非空
- trans_service.execute_dispatch:先显式校验来源合法性并列出非法值,
再要求 _scanned 非空
This commit is contained in:
@ -258,11 +258,22 @@ class OutboundService:
|
||||
verify_scanned, restore_then_deduct,
|
||||
)
|
||||
_approved = approval.get_items()
|
||||
# 仅处理库存类来源;维修单(trans_repair)不走库存预占
|
||||
_scanned = [i for i in items if i.get('source_table') != 'trans_repair']
|
||||
if _scanned:
|
||||
verify_scanned(_scanned, _approved)
|
||||
restore_then_deduct(_scanned, _approved)
|
||||
|
||||
# ★ Fail-Closed:只认库存类来源。只要一条库存物料都没扫到就整单失败。
|
||||
#
|
||||
# 旧代码写作 `_scanned = [... if source_table != 'trans_repair']`
|
||||
# 再 `if _scanned:` —— 一旦为假,校验与释放被整体跳过,而下方仍
|
||||
# 无条件执行 approval.status = 3。此时申请阶段 reserve_for_items()
|
||||
# 扣掉的 available_quantity 无人归还,且 status=3 没有任何释放入口
|
||||
# (/close 要求 status==1、/withdraw 要求 status∈(0,1)),预占即
|
||||
# 永久锁死 —— 幽灵库存。
|
||||
# 现在直接要求 _scanned 非空:维修单等非库存来源一并被挡在门外。
|
||||
_scanned = [i for i in items if i.get('source_table') in model_map]
|
||||
if not _scanned:
|
||||
raise ValueError("未扫描到有效的库存物料,出库失败,请检查扫码内容")
|
||||
|
||||
verify_scanned(_scanned, _approved)
|
||||
restore_then_deduct(_scanned, _approved)
|
||||
|
||||
try:
|
||||
for item in items:
|
||||
|
||||
Reference in New Issue
Block a user