feat(borrow,outbound): 默认免审批改造——命中物料需审批才走原流程

- models/base.py 加 is_approval_required 列及 isApprovalRequired 序列化;field_permissions 登记
- 新增 POST /inbound/base/batch-approval(批量设需审批,仿批量质检)
- borrow_service.submit_approval / outbound_service.create_request:明细含需审批物料→须选审批人走原审批;否则创建即 status=1(待库管执行)、不发审批邮件
- 判定按 (name,spec_model) 反查启用物料
This commit is contained in:
yueli
2026-09-09 09:31:18 +08:00
parent e03c035ee0
commit 4cd3eefdf4
5 changed files with 164 additions and 25 deletions

View File

@ -700,6 +700,33 @@ class OutboundApprovalService:
return f"APR-OUT-{date_str}-{time_str}-{sequence:04d}"
@staticmethod
def _items_require_approval(items):
"""
明细中任一物料命中“出库/借库需审批”→ 需要审批。
申请明细只存 name/spec_model故按 (name, spec_model) 反查启用物料判定。
"""
from app.models.base import MaterialBase
seen = set()
for item in items:
name = str(item.get('name') or '').strip()
spec = str(item.get('spec_model') or '').strip()
if not name:
continue
key = (name, spec)
if key in seen:
continue
seen.add(key)
hit = MaterialBase.query.filter(
MaterialBase.name == name,
MaterialBase.spec_model == spec,
MaterialBase.is_enabled == True,
MaterialBase.is_approval_required == True
).first()
if hit:
return True
return False
@staticmethod
def create_request(applicant_id, items, allowed_approvers, remark=None, approver_id=None, outbound_type=None):
"""
@ -745,33 +772,53 @@ class OutboundApprovalService:
except (TypeError, ValueError) as e:
raise ValueError(f"{idx + 1} 条物品的 quantity 格式无效: {str(e)}")
# ★ 校验 allowed_approvers 非空
if not allowed_approvers:
raise ValueError("必须指定至少一位审批人")
# ★ 需审批判定:明细含“出库/借库需审批”物料 → 走原审批流程;否则默认自动通过
need_approval = OutboundApprovalService._items_require_approval(items)
if need_approval and not approver_id:
raise ValueError("该申请包含需审批的物料,请选择审批人后再提交")
# ★ 指定审批人模式approver_id 覆盖 allowed_approvers
if approver_id:
allowed_approvers = [{"type": "user", "value": int(approver_id)}]
elif not need_approval:
allowed_approvers = [] # 免审批单不绑定审批人
request_no = OutboundApprovalService.generate_request_no()
approval = OutboundApproval(
request_no=request_no,
applicant_id=applicant_id,
remark=remark,
outbound_type=outbound_type, # 申请时确定的出库类型,扫码出库时带出
status=0, # 待审批
)
if need_approval:
approval = OutboundApproval(
request_no=request_no,
applicant_id=applicant_id,
remark=remark,
outbound_type=outbound_type, # 申请时确定的出库类型,扫码出库时带出
status=0, # 待审批
)
else:
# 默认不审批:创建即已通过(status=1),直接进入“待库管执行”
from datetime import datetime, timezone, timedelta
approval = OutboundApproval(
request_no=request_no,
applicant_id=applicant_id,
remark=remark,
outbound_type=outbound_type,
status=1,
actual_approver_id=applicant_id,
approved_at=datetime.now(timezone(timedelta(hours=8))),
)
# 直接存储前端传来的物料信息快照,不查询/不关联具体库存记录
approval.set_items(items)
approval.set_allowed_approvers(allowed_approvers)
if allowed_approvers:
approval.set_allowed_approvers(allowed_approvers)
else:
approval.allowed_approvers = '[]'
db.session.add(approval)
db.session.commit()
# ★ 创建成功后,发送邮件通知审批人(精确通知 approver_id 对应的邮箱)
OutboundApprovalService._notify_new_request(approval, applicant_id, approver_id=approver_id)
# 仅需审批单通知审批人;免审批单静默进入“待库管执行”
if need_approval:
OutboundApprovalService._notify_new_request(approval, applicant_id, approver_id=approver_id)
return approval