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

@ -0,0 +1,46 @@
# inventory-backend/app/api/v1/common/users.py
from flask import jsonify
from flask_jwt_extended import jwt_required
from . import common_bp
def active_user_options():
"""
在职人员名单(id + 姓名)——「选择某人」类下拉框的**共用实现**。
★ 为什么单独开一条中性路径,而不是复用 /transactions/borrow/users:
那条路径在语义上属于借库模块,出库补发、报废执行等处若直接复用,
后人读代码时会困惑「出库为什么在调借库的接口」。这里提供统一入口,
借库那条路径改为调本函数,实现只有一份。
★ 公司隔离与业务台账同口径(get_current_company_filter):
否则 A 公司的人能在选择器里看到 B 公司人员。
★ 只返回 id 与姓名:不含邮箱 / 角色 / 部门,最小披露。
"""
from app.utils.decorators import get_current_company_filter
from app.models.system import SysUser
from app.services.trans_service import user_display_name
company_limit = get_current_company_filter()
query = SysUser.query.filter(SysUser.status == 'active')
if company_limit is not None:
# 与 borrow_service.get_request_list 一致:SysUser.department 即公司维度
query = query.filter(SysUser.department == company_limit)
return [{'id': u.id, 'name': user_display_name(u)}
for u in query.order_by(SysUser.username).all()]
@common_bp.route('/active-users', methods=['GET'])
@jwt_required()
def get_active_users():
"""
在职人员名单,供借出 / 转交 / 归还 / 出库补发等多个页面的选择器共用。
★ 无 permission_required,仅要求登录:
同一份名单要被多个页面共用,绑定其中任一权限码都会让其他页面 403;
且只暴露 id 与姓名(与 /auth/users/approvers 同一处理方式)。
"""
return jsonify({'code': 200, 'msg': 'success', 'data': active_user_options()})