feat(claim): 重构报销审批流并收敛风险标记
- 直属领导兼任部门 P8 预算审批人时合并预算审批,直接流转至财务审批 - 预算超过警戒值时强制要求预算管理者填写审批意见 - 新增风险标记去重工具,消除各审核阶段重复风险卡片 - 新增工作流修复 Mixin,纠正重复预算审批阶段的历史数据 - 收紧单据删除权限至 admin,放宽预算分析可见范围至当前审核人 - 提交校验放宽已上传票据条目的 OCR 字段缺失并忽略尾部占位条目
This commit is contained in:
@@ -641,6 +641,12 @@ class ExpenseClaimItemSyncMixin:
|
||||
issues: list[str] = []
|
||||
claim_location_required = self._is_location_required_expense_type(claim.expense_type)
|
||||
claim_min_attachment_count = self._resolve_claim_required_attachment_count(claim)
|
||||
substantive_items = [
|
||||
item
|
||||
for item in list(claim.items or [])
|
||||
if str(item.item_type or "").strip().lower() not in SYSTEM_GENERATED_ITEM_TYPES
|
||||
and not self._is_submission_placeholder_item(item)
|
||||
]
|
||||
|
||||
if self._is_missing_value(claim.employee_name):
|
||||
issues.append("申请人未完善")
|
||||
@@ -658,28 +664,39 @@ class ExpenseClaimItemSyncMixin:
|
||||
issues.append("发生时间未完善")
|
||||
if int(claim.invoice_count or 0) < claim_min_attachment_count:
|
||||
issues.append("票据附件数量不足")
|
||||
if not claim.items:
|
||||
if not substantive_items:
|
||||
issues.append("费用明细不能为空")
|
||||
|
||||
for index, item in enumerate(claim.items, start=1):
|
||||
prefix = f"费用明细第 {index} 条"
|
||||
is_system_generated = str(item.item_type or "").strip().lower() in SYSTEM_GENERATED_ITEM_TYPES
|
||||
if is_system_generated or self._is_submission_placeholder_item(item):
|
||||
continue
|
||||
item_location_required = self._is_location_required_expense_type(item.item_type or claim.expense_type)
|
||||
if item.item_date is None:
|
||||
item_has_attachment = not self._is_missing_value(item.invoice_id)
|
||||
if not item_has_attachment and item.item_date is None:
|
||||
issues.append(f"{prefix}缺少日期")
|
||||
if self._is_missing_value(item.item_type):
|
||||
issues.append(f"{prefix}缺少费用项目")
|
||||
if self._is_missing_value(item.item_reason):
|
||||
if not item_has_attachment and self._is_missing_value(item.item_reason):
|
||||
issues.append(f"{prefix}缺少说明")
|
||||
if item_location_required and self._is_missing_value(item.item_location):
|
||||
if not item_has_attachment and item_location_required and self._is_missing_value(item.item_location):
|
||||
issues.append(f"{prefix}缺少地点")
|
||||
if item.item_amount is None or item.item_amount <= Decimal("0.00"):
|
||||
if not item_has_attachment and (item.item_amount is None or item.item_amount <= Decimal("0.00")):
|
||||
issues.append(f"{prefix}缺少金额")
|
||||
if self._is_attachment_required_item_type(item.item_type) and self._is_missing_value(item.invoice_id):
|
||||
if self._is_attachment_required_item_type(item.item_type) and not item_has_attachment:
|
||||
issues.append(f"{prefix}缺少票据标识")
|
||||
|
||||
return issues
|
||||
|
||||
def _is_submission_placeholder_item(self, item: ExpenseClaimItem) -> bool:
|
||||
if not self._is_missing_value(item.invoice_id):
|
||||
return False
|
||||
missing_reason = self._is_missing_value(item.item_reason)
|
||||
missing_location = self._is_missing_value(item.item_location)
|
||||
missing_amount = item.item_amount is None or item.item_amount <= Decimal("0.00")
|
||||
return missing_reason and missing_location and missing_amount
|
||||
|
||||
def _is_location_required_expense_type(self, expense_type: str | None) -> bool:
|
||||
policy = self._get_expense_scene_policy(expense_type)
|
||||
if policy is None:
|
||||
|
||||
Reference in New Issue
Block a user