feat: 新增预算后端服务与差旅风险规则库
后端新增预算模型、端点和服务模块,支持预算 CRUD 和余额 查询,清理旧生成规则文件并替换为按严重等级分类的差旅风 险规则库,优化认证权限和报销单访问策略,新增财务规则目 录和演示数据构建脚本,前端预算中心增加对话框交互,完善 审计页面运行时模型和元数据展示,补充单元测试。
This commit is contained in:
96
server/src/app/services/expense_claim_budget_flow.py
Normal file
96
server/src/app/services/expense_claim_budget_flow.py
Normal file
@@ -0,0 +1,96 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from app.api.deps import CurrentUserContext
|
||||
from app.models.financial_record import ExpenseClaim
|
||||
from app.services.budget import BudgetService
|
||||
|
||||
|
||||
class ExpenseClaimBudgetFlowMixin:
|
||||
def _reserve_budget_for_submission(
|
||||
self,
|
||||
claim: ExpenseClaim,
|
||||
current_user: CurrentUserContext,
|
||||
*,
|
||||
is_application_claim: bool,
|
||||
) -> list[dict[str, Any]]:
|
||||
source_type = "application" if is_application_claim else "claim"
|
||||
return BudgetService(self.db).reserve_for_claim(
|
||||
claim,
|
||||
source_type=source_type,
|
||||
operator=self._resolve_budget_operator(current_user),
|
||||
)
|
||||
|
||||
def _release_budget_for_return(
|
||||
self,
|
||||
claim: ExpenseClaim,
|
||||
current_user: CurrentUserContext,
|
||||
*,
|
||||
reason: str,
|
||||
) -> list[dict[str, Any]]:
|
||||
is_application_claim = self._is_expense_application_claim(claim)
|
||||
source_type = "application" if is_application_claim else "claim"
|
||||
return BudgetService(self.db).release_for_claim(
|
||||
claim,
|
||||
source_type=source_type,
|
||||
operator=self._resolve_budget_operator(current_user),
|
||||
reason=reason,
|
||||
)
|
||||
|
||||
def _release_budget_for_delete(
|
||||
self,
|
||||
claim: ExpenseClaim,
|
||||
current_user: CurrentUserContext,
|
||||
) -> None:
|
||||
is_application_claim = self._is_expense_application_claim(claim)
|
||||
source_type = "application" if is_application_claim else "claim"
|
||||
BudgetService(self.db).release_for_claim(
|
||||
claim,
|
||||
source_type=source_type,
|
||||
operator=self._resolve_budget_operator(current_user),
|
||||
reason="单据删除释放预算预占",
|
||||
)
|
||||
|
||||
def _consume_budget_for_finance_approval(
|
||||
self,
|
||||
claim: ExpenseClaim,
|
||||
current_user: CurrentUserContext,
|
||||
) -> dict[str, Any] | None:
|
||||
return BudgetService(self.db).consume_for_claim(
|
||||
claim,
|
||||
operator=self._resolve_budget_operator(current_user),
|
||||
reason="财务终审通过核销预算",
|
||||
)
|
||||
|
||||
def _transfer_application_budget_to_reimbursement(
|
||||
self,
|
||||
*,
|
||||
application_claim: ExpenseClaim,
|
||||
draft_claim: ExpenseClaim,
|
||||
current_user: CurrentUserContext,
|
||||
) -> dict[str, Any] | None:
|
||||
return BudgetService(self.db).transfer_application_reservation(
|
||||
application_claim=application_claim,
|
||||
draft_claim=draft_claim,
|
||||
operator=self._resolve_budget_operator(current_user),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _append_budget_flags(
|
||||
risk_flags: list[Any] | None,
|
||||
budget_flags: list[dict[str, Any]] | dict[str, Any] | None,
|
||||
) -> list[Any]:
|
||||
if budget_flags is None:
|
||||
return list(risk_flags or [])
|
||||
if isinstance(budget_flags, dict):
|
||||
next_flags = [budget_flags]
|
||||
else:
|
||||
next_flags = list(budget_flags or [])
|
||||
if not next_flags:
|
||||
return list(risk_flags or [])
|
||||
return [*list(risk_flags or []), *next_flags]
|
||||
|
||||
@staticmethod
|
||||
def _resolve_budget_operator(current_user: CurrentUserContext) -> str:
|
||||
return current_user.name or current_user.username or "system"
|
||||
Reference in New Issue
Block a user