feat(outbound,common): 补发可指定「补发给谁」+ 抽出通用人员名单接口

一、补发申请人可选择(原单退回)
   退回接口新增 reissue_applicant_id:
     ① 前端指定 → 校验用户存在后落库;
     ② 未指定 → 回退为**当前操作人**(原行为不变,向后兼容)。
   为何不自动推断原申请人:trans_outbound **没有申请人字段,也没有指回原审批单
   的关联**(扫码出库时只把审批单状态置为 3),按 consumer_name 反查会重蹈
   「重名错绑」的覆辙(借用人姓名回填那轮刚踩过)。故把选择权交给现场,不猜。

二、抽出中性人员名单 GET /api/v1/common/active-users
   实现抽到 common.active_user_options(),借库的 /transactions/borrow/users
   改为调同一函数 —— 实现只有一份,但出库补发走**中性路径**,不再出现
   「出库为什么在调借库的接口」这种跨模块语义错位。
   仅要求登录、只返回 id 与姓名(与 /auth/users/approvers 同一处理)。

★ 本次无需 DB 迁移:未新增任何列,补发申请人是复用已有的
  outbound_approval.applicant_id。

验证(打桩/真实 token 直连接口,12 项断言全通过)
  · 名单只含 id/name,无邮箱/角色/部门;借库原路径返回值与新路径完全一致
  · 指定「补发给谁」→ 补发单申请人 = 指定的人;备注仍含原领用人
  · 不指定 → 回退为当前操作人
  ★ 指定不存在的用户 → 被拒,且整笔退回回滚(流水未落库)
  库存与数据零残留。
This commit is contained in:
yueli
2026-09-17 12:01:11 +08:00
parent 9d187593eb
commit 27e5589a5e
4 changed files with 77 additions and 26 deletions

View File

@ -2768,7 +2768,8 @@ def return_from_outbound():
"is_defective": false, # 必填true=不良品退回false=良品退回
"reason": "错领退回", # 可选
"need_reissue": true, # 可选,退回后是否自动生成补发单
"reissue_qty": 2 # 可选,补发数量,默认 = return_qty
"reissue_qty": 2, # 可选,补发数量,默认 = return_qty
"reissue_applicant_id": 12 # 可选,补发给谁;不传则=当前操作人
}
两条分支的差异:
@ -2790,6 +2791,8 @@ def return_from_outbound():
# 补发(可选):退回后申请人往往仍需这件东西。勾选则自动生成一张免审批出库单。
need_reissue = bool(data.get('need_reissue'))
reissue_qty = data.get('reissue_qty')
# 补发给谁:不传则回退为当前操作人(见下方补发块)
reissue_applicant_id = data.get('reissue_applicant_id')
# ---- 1. 入参校验(脏值一律挡在入口)----
if not outbound_id:
@ -2940,17 +2943,27 @@ def return_from_outbound():
strict=True,
)
# ★ 申请人取**当前操作人**(办理退回的库管)。
# 为什么不是「原申请人」trans_outbound **没有申请人字段,也没有
# 指回原审批单的关联**(扫码出库时只把审批单状态置为 3因此
# 无法可靠判定原申请人是谁 —— 按 consumer_name 反查会重蹈「重名
# 错绑」的覆辙(借用人姓名回填那轮刚踩过)。
# 原领用人写入备注,便于人工追溯。
_applicant = get_jwt_identity()
try:
_applicant = int(_applicant)
except (TypeError, ValueError):
raise ValueError('无法确定补发单申请人:当前登录用户缺失')
# ★ 申请人(补发给谁)优先级:
# ① 前端显式指定 reissue_applicant_id —— 现场最清楚该给谁;
# ② 未指定则回退到**当前操作人**(办理退回的库管)。
# 为什么不自动推断成「原申请人」trans_outbound **没有申请人字段,
# 也没有指回原审批单的关联**(扫码出库时只把审批单状态置为 3
# 按 consumer_name 反查会重蹈「重名错绑」的覆辙(借用人姓名回填
# 那轮刚踩过)。故把选择权交给现场,而不是猜。
if reissue_applicant_id:
try:
_applicant = int(reissue_applicant_id)
except (TypeError, ValueError):
raise ValueError('补发申请人ID格式无效')
from app.models.system import SysUser
if not SysUser.query.get(_applicant):
raise ValueError(f'补发申请人不存在ID:{reissue_applicant_id}')
else:
_applicant = get_jwt_identity()
try:
_applicant = int(_applicant)
except (TypeError, ValueError):
raise ValueError('无法确定补发单申请人:当前登录用户缺失')
reissue = OutboundApproval(
request_no=OutboundApprovalService.generate_request_no(),