feat(approval): 审批单/节点状态机与二次分配接入(开关自动通过)

- approval_orders/approval_steps 服务层:submit_order(不 commit 不嵌套
  audit,业务写路径统一收口)+ act 节点动作 + 分页/详情
- 开关关闭=提单即两级「自动通过」留痕(action=3,operator 记系统);
  开启=财务→领导流转,一驳全驳,驳回必填意见
- 节点准入严格按角色(status=1 仅财务、status=2 仅领导),admin 不代办;
  模块准入 require_roles 依赖工厂(admin/finance/leader,营销后勤待
  澄清 #6 后放开)
- 业务接入:创建/编辑带方案即提单(空方案不提单);再编辑自动撤回旧
  在途单(node=0/action=4 留痕);AP 编号冲突 create 内可重取(外层
  重试兜底)、update 直接抛出防静默丢失
- conftest 兜底清理增审批单(AP 前缀)与开关参数种子基线恢复
- 集成 11 例:自动通过/两节点流转/驳回留痕/缺意见 400/节点准入 403/
  admin 不代办/重复操作 400/撤旧建新/模块准入

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
liuwenxinandClaude Code committed 2026-10-15 18:50:38 +08:00
1 parent 680661a80b
commit 8ef26e22fb
10 files changed
+842 -1

No files matched your search

+25 -1
View File
@@ -45,6 +45,7 @@ from app.models import (
Shipment,
User,
)
from app.models.approval import APPROVAL_TYPE_SECONDARY_ALLOCATION
from app.models.business import (
BUSINESS_STATUS_ACTIVE,
BUSINESS_STATUS_DONE,
@@ -69,7 +70,7 @@ from app.schemas.business import (
SecondaryAllocationIn,
SecondaryAllocationOut,
)
from app.services import audit_service, param_service, personnel_service
from app.services import approval_service, audit_service, param_service, personnel_service
from app.services.audit_service import AuditRecord, RequestMeta
from app.services.formula import converted_profit, profit_rate
from app.services.no_generator import next_no
@@ -389,6 +390,18 @@ def create_business(
business.id,
_build_allocation_rows(session, business.id, payload.secondary_allocations),
)
# 方案非空才提单:开关关闭=自动通过留痕,开启=待财务复核。
# retry_on_conflict=True:AP 编号撞键可内部重取(外层编号
# 重试循环兜底整体重来)
if payload.secondary_allocations:
approval_service.submit_order(
session,
order_type=APPROVAL_TYPE_SECONDARY_ALLOCATION,
ref_id=business.id,
refer_no=business.business_no,
submitter=operator,
retry_on_conflict=True,
)
customer = customer_repository.get_by_id(session, business.customer_id)
out = _to_out((business, customer.company_name if customer else None, None, None))
new_id, new_no = business.id, business.business_no # 固化:commit 后不碰 ORM
@@ -469,6 +482,17 @@ def update_business(
business_id,
_build_allocation_rows(session, business_id, payload.secondary_allocations),
)
# 方案非空提单(自动撤回旧在途单);retry_on_conflict=False:
# 本路径无外层重试,内部 rollback 会回掉业务行修改造成静默丢失
if payload.secondary_allocations:
approval_service.submit_order(
session,
order_type=APPROVAL_TYPE_SECONDARY_ALLOCATION,
ref_id=business_id,
refer_no=business.business_no,
submitter=operator,
retry_on_conflict=False,
)
_recalc_totals(session, business)
# 锁定行上已赋值,同一身份映射实例的 _to_out 即反映新值;名称字段
# 从首查 row 取(换客户时 _ensure_customer 已给出新公司名)