feat: 新增员工行为画像算法与费用风险标签体系
后端新增员工行为画像算法模块,支持标签规则引擎和评分计算, 完善员工模型、银行信息、序列化和导入逻辑,优化报销审批流 和工作流常量,增强 Hermes 同步和知识同步能力,前端新增费 用画像详情弹窗、雷达图和风险卡片组件,完善登录页和工作台 样式,优化文档中心和归档中心交互,补充单元测试。
This commit is contained in:
@@ -17,6 +17,8 @@ from app.services.expense_claim_workflow_constants import (
|
||||
BUDGET_MANAGER_APPROVAL_STAGE,
|
||||
DIRECT_MANAGER_APPROVAL_STAGE,
|
||||
FINANCE_APPROVAL_STAGE,
|
||||
PAYMENT_PAID_STAGE,
|
||||
PAYMENT_PENDING_STATUS,
|
||||
)
|
||||
|
||||
|
||||
@@ -29,6 +31,7 @@ BUDGET_MONITOR_APPROVAL_GRADE = "P8"
|
||||
CLAIM_DELETE_ROLE_CODES = {"executive"}
|
||||
ARCHIVED_CLAIM_STATUSES = ("approved", "completed", "paid")
|
||||
APPLICATION_ARCHIVED_STAGES = (APPROVAL_DONE_STAGE, "申请归档", "completed")
|
||||
ARCHIVED_REIMBURSEMENT_STAGES = (ARCHIVE_ACCOUNTING_STAGE, PAYMENT_PAID_STAGE, "completed")
|
||||
|
||||
|
||||
class ExpenseClaimAccessPolicy:
|
||||
@@ -60,7 +63,7 @@ class ExpenseClaimAccessPolicy:
|
||||
normalized_type.like("%\\_application", escape="\\"),
|
||||
)
|
||||
return or_(
|
||||
stage == ARCHIVE_ACCOUNTING_STAGE,
|
||||
stage.in_(ARCHIVED_REIMBURSEMENT_STAGES),
|
||||
stage == "completed",
|
||||
and_(
|
||||
application_condition,
|
||||
@@ -72,7 +75,7 @@ class ExpenseClaimAccessPolicy:
|
||||
or_(
|
||||
stage == "",
|
||||
stage.is_(None),
|
||||
stage == ARCHIVE_ACCOUNTING_STAGE,
|
||||
stage.in_(ARCHIVED_REIMBURSEMENT_STAGES),
|
||||
stage == "completed",
|
||||
),
|
||||
),
|
||||
@@ -88,7 +91,7 @@ class ExpenseClaimAccessPolicy:
|
||||
def is_archived_claim(claim: ExpenseClaim) -> bool:
|
||||
normalized_status = str(claim.status or "").strip().lower()
|
||||
stage = str(claim.approval_stage or "").strip()
|
||||
if stage in {ARCHIVE_ACCOUNTING_STAGE, "completed"}:
|
||||
if stage in set(ARCHIVED_REIMBURSEMENT_STAGES):
|
||||
return True
|
||||
normalized_type = str(claim.expense_type or "").strip().lower()
|
||||
claim_no = str(claim.claim_no or "").strip().upper()
|
||||
@@ -103,7 +106,7 @@ class ExpenseClaimAccessPolicy:
|
||||
and stage in APPLICATION_ARCHIVED_STAGES
|
||||
):
|
||||
return True
|
||||
return normalized_status in ARCHIVED_CLAIM_STATUSES and stage in {"", ARCHIVE_ACCOUNTING_STAGE, "completed"}
|
||||
return normalized_status in ARCHIVED_CLAIM_STATUSES and stage in {"", *ARCHIVED_REIMBURSEMENT_STAGES}
|
||||
|
||||
def can_return_claim(self, current_user: CurrentUserContext, claim: ExpenseClaim) -> bool:
|
||||
normalized_status = str(claim.status or "").strip().lower()
|
||||
@@ -136,6 +139,15 @@ class ExpenseClaimAccessPolicy:
|
||||
)
|
||||
return False
|
||||
|
||||
def can_mark_claim_paid(self, current_user: CurrentUserContext, claim: ExpenseClaim) -> bool:
|
||||
if str(claim.status or "").strip().lower() != PAYMENT_PENDING_STATUS:
|
||||
return False
|
||||
if self.is_claim_owned_by_current_user(claim, current_user):
|
||||
return False
|
||||
if current_user.is_admin:
|
||||
return True
|
||||
return bool(self.normalize_role_codes(current_user) & PRIVILEGED_CLAIM_ROLE_CODES)
|
||||
|
||||
def is_current_direct_manager_approver(self, current_user: CurrentUserContext, claim: ExpenseClaim) -> bool:
|
||||
role_codes = self.normalize_role_codes(current_user)
|
||||
if not (role_codes & APPROVAL_VISIBLE_CLAIM_ROLE_CODES):
|
||||
|
||||
Reference in New Issue
Block a user