feat: 完善审批退回流程与报销申请关联

后端优化报销单访问策略和常量定义,增强退回原因和审批状态
流转,前端完善退回对话框和审批交互组件,新增报销申请关联
模型,优化文档中心行数据和审批收件箱工具函数,增强引导
流程和会话模型,补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-27 14:35:17 +08:00
parent 7d32eae74e
commit cbb98f4469
30 changed files with 1794 additions and 250 deletions

View File

@@ -95,35 +95,19 @@ class ExpenseClaimAccessPolicy:
return normalized_status in ARCHIVED_CLAIM_STATUSES and stage in {"", "归档入账", "completed"}
def can_return_claim(self, current_user: CurrentUserContext, claim: ExpenseClaim) -> bool:
if self.has_privileged_claim_access(current_user):
return True
role_codes = self.normalize_role_codes(current_user)
if not (role_codes & APPROVAL_VISIBLE_CLAIM_ROLE_CODES):
return False
if str(claim.status or "").strip().lower() != "submitted":
return False
if str(claim.approval_stage or "").strip() != "直属领导审批":
normalized_status = str(claim.status or "").strip().lower()
if normalized_status != "submitted":
return False
current_employee = self.resolve_current_employee(current_user)
if current_employee is not None and str(claim.employee_id or "").strip() == current_employee.id:
return False
claim_employee = claim.employee
if current_employee is not None and claim_employee is not None:
if claim_employee.manager_id == current_employee.id:
return True
if claim_employee.manager is not None and claim_employee.manager.id == current_employee.id:
return True
approver_name = str(
current_employee.name if current_employee is not None and current_employee.name else current_user.name or ""
).strip()
if not approver_name:
return False
return self.resolve_claim_manager_name(claim) == approver_name
stage = str(claim.approval_stage or "").strip()
if stage == "直属领导审批":
return self.is_current_direct_manager_approver(current_user, claim)
if stage == "财务审批":
return self.has_privileged_claim_access(current_user) and not self.is_claim_owned_by_current_user(
claim,
current_user,
)
return False
def can_approve_claim(self, current_user: CurrentUserContext, claim: ExpenseClaim) -> bool:
stage = str(claim.approval_stage or "").strip()
@@ -131,7 +115,10 @@ class ExpenseClaimAccessPolicy:
return self.is_current_direct_manager_approver(current_user, claim)
if stage == "财务审批":
role_codes = self.normalize_role_codes(current_user)
return current_user.is_admin or "finance" in role_codes
return (
(current_user.is_admin or "finance" in role_codes)
and not self.is_claim_owned_by_current_user(claim, current_user)
)
return False
def is_current_direct_manager_approver(self, current_user: CurrentUserContext, claim: ExpenseClaim) -> bool: