feat(approval): add safe risk disposition workflow
This commit is contained in:
@@ -4,7 +4,10 @@ from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
from app.models.financial_record import ExpenseClaim
|
||||
from app.services.expense_claim_risk_stage import risk_business_stage_for_claim, with_risk_business_stage
|
||||
from app.services.expense_claim_risk_stage import (
|
||||
risk_business_stage_for_claim,
|
||||
with_risk_business_stage,
|
||||
)
|
||||
from app.services.expense_claim_workflow_constants import (
|
||||
BUDGET_MANAGER_APPROVAL_STAGE,
|
||||
DIRECT_MANAGER_APPROVAL_STAGE,
|
||||
@@ -13,18 +16,17 @@ from app.services.expense_claim_workflow_constants import (
|
||||
|
||||
|
||||
class ExpenseClaimWorkflowRepairMixin:
|
||||
def _repair_duplicate_budget_approval_stages(self, claims: list[ExpenseClaim]) -> None:
|
||||
repaired_claims = [
|
||||
def _repair_duplicate_budget_approval_stages(
|
||||
self,
|
||||
claims: list[ExpenseClaim],
|
||||
) -> list[ExpenseClaim]:
|
||||
"""只修改当前事务中的对象,不在底层辅助方法里提交事务。"""
|
||||
|
||||
return [
|
||||
claim
|
||||
for claim in claims
|
||||
if claim is not None and self._repair_duplicate_budget_approval_stage(claim)
|
||||
]
|
||||
if not repaired_claims:
|
||||
return
|
||||
|
||||
self.db.commit()
|
||||
for claim in repaired_claims:
|
||||
self.db.refresh(claim)
|
||||
|
||||
def _repair_duplicate_budget_approval_stage(self, claim: ExpenseClaim) -> bool:
|
||||
if self._is_expense_application_claim(claim):
|
||||
@@ -54,7 +56,8 @@ class ExpenseClaimWorkflowRepairMixin:
|
||||
if isinstance(flag, dict)
|
||||
and str(flag.get("source") or "").strip() == "manual_approval"
|
||||
and str(flag.get("event_type") or "").strip() == "expense_claim_approval"
|
||||
and str(flag.get("previous_approval_stage") or "").strip() == DIRECT_MANAGER_APPROVAL_STAGE
|
||||
and str(flag.get("previous_approval_stage") or "").strip()
|
||||
== DIRECT_MANAGER_APPROVAL_STAGE
|
||||
and str(flag.get("next_approval_stage") or "").strip() == BUDGET_MANAGER_APPROVAL_STAGE
|
||||
]
|
||||
for flag in reversed(flags):
|
||||
@@ -74,11 +77,14 @@ class ExpenseClaimWorkflowRepairMixin:
|
||||
return any(
|
||||
isinstance(flag, dict)
|
||||
and str(flag.get("source") or "").strip() == "approval_flow_repair"
|
||||
and str(flag.get("event_type") or "").strip() == "duplicate_budget_approval_stage_repaired"
|
||||
and str(flag.get("event_type") or "").strip()
|
||||
== "duplicate_budget_approval_stage_repaired"
|
||||
for flag in list(claim.risk_flags_json or [])
|
||||
)
|
||||
|
||||
def _build_duplicate_budget_stage_repair_flag(self, approval_event: dict[str, Any]) -> dict[str, Any]:
|
||||
def _build_duplicate_budget_stage_repair_flag(
|
||||
self, approval_event: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
return with_risk_business_stage(
|
||||
{
|
||||
"source": "approval_flow_repair",
|
||||
|
||||
Reference in New Issue
Block a user