From 191724a176acc4ddb5e59536d8f4c1b37073d3ef Mon Sep 17 00:00:00 2001 From: yueli Date: Thu, 17 Sep 2026 13:35:47 +0800 Subject: [PATCH] =?UTF-8?q?fix(outbound):=20=E4=BF=AE=E5=A4=8D=E6=89=AB?= =?UTF-8?q?=E7=A0=81=E5=87=BA=E5=BA=93=20500=20=E2=80=94=E2=80=94=20applic?= =?UTF-8?q?ant=5Fid=20=E7=94=A8=E4=BA=86=E5=B0=9A=E6=9C=AA=E8=B5=8B?= =?UTF-8?q?=E5=80=BC=E7=9A=84=20approval?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象 ---- 所有扫码出库报 500(前端 create.vue 提交即失败)。 根因 ---- 上一个提交把 'applicant_id': approval.applicant_id 写进了 common_data, 但 common_data 构造在第 234 行,而 approval 直到第 269 行(「强制按单出库」 那一段)才查询赋值 —— 典型的变量先用后赋,直接 UnboundLocalError。 它影响的是**每一条**出库请求,属于必然复现而非偶发。 修复 ---- 把赋值移到 approval 取出并校验**之后**:common_data['applicant_id'] = ... 并在原处留注释说明为什么不能写在字典字面量里,避免后人搬回去。 ★ 我的测试为什么没抓到 上一轮只测了「退回 → 补发」这条路径,而 applicant_id 的写入在**扫码出库** 路径上 —— 两条路径不重合,所以漏了。本次补测了完整的 「出库申请(预占) → 扫码出库(扣减)」链路。 验证(6 项断言全通过,走真实接口链路) 申请单创建(status=1,申请人=12,预占 stock_buy#2058 两件) → 扫码出库不再抛 500 → 出库明细生成且 applicant_id = 12(不再是 NULL) → consumer_name 照常写入 → 审批单置为已完成 → 库存实际扣减 2 清理后库存与数据零残留。 ★ 顺带在真实数据上得到印证:生产库中已有一笔由业务方重试成功的出库 (OUT-20260917-1333-0001),其 applicant_id 正确等于所关联申请单的申请人。 --- inventory-backend/app/services/outbound_service.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/inventory-backend/app/services/outbound_service.py b/inventory-backend/app/services/outbound_service.py index 1a14fe0..6b86b92 100644 --- a/inventory-backend/app/services/outbound_service.py +++ b/inventory-backend/app/services/outbound_service.py @@ -238,10 +238,9 @@ class OutboundService: 'signature_path': data.get('signature_path'), 'operator_name': operator_name, 'remark': data.get('remark'), - # ★ 申请人从**关联审批单**带出。落这一列是为了让后续「退回 → 补发」 - # 能把补发单挂回真正该拿东西的人名下 —— consumer_name 是自由文本 - # (可能是客户名),不能作为依据。 - 'applicant_id': approval.applicant_id, + # ⚠ applicant_id 不在这里赋值 —— 此刻 approval 尚未查询(见下方 + # 第 2 步「强制按单出库」),在这里引用它会直接 UnboundLocalError。 + # 待 approval 取出并校验后再补进本字典。 } beijing_tz = timezone(timedelta(hours=8)) @@ -279,6 +278,13 @@ class OutboundService: f"仅已通过的审批单方可执行出库" ) + # ★ 申请人从**关联审批单**带出。落这一列是为了让后续「退回 → 补发」能把 + # 补发单挂回真正该拿东西的人名下 —— consumer_name 是扫码时自由填写的 + # 领用人/客户名,不能作为依据。 + # ⚠ 必须放在 approval 取出并校验**之后**:common_data 在上面就已构造, + # 在那里引用 approval 会直接 UnboundLocalError(上线时踩过)。 + common_data['applicant_id'] = approval.applicant_id + model_map = { 'stock_buy': StockBuy, 'stock_semi': StockSemi,