feat: 新增预算费控模型与报销审批流引擎

后端新增预算费控服务和报销单审批流模块,引入申请人费用画像
算法,优化知识库 RAG 运行时和同步逻辑,完善报销单工作流常
量和明细同步,更新差旅报销规则电子表格,前端新增预算分析
组件和数字员工模型,完善审批对话框和洞察面板交互,优化侧
边栏和顶栏样式,补充单元测试。
This commit is contained in:
caoxiaozhu
2026-05-27 17:31:27 +08:00
parent cbb98f4469
commit d4d5d40569
75 changed files with 5393 additions and 686 deletions

View File

@@ -7,6 +7,7 @@ from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from app.api.deps import CurrentUserContext, get_current_user, get_db
from app.schemas.budget import BudgetClaimAnalysisRead
from app.schemas.common import ErrorResponse
from app.schemas.reimbursement import (
ExpenseClaimAttachmentActionResponse,
@@ -25,6 +26,7 @@ from app.schemas.reimbursement import (
TravelReimbursementCalculatorResponse,
)
from app.services.expense_claims import ExpenseClaimService
from app.services.budget import BudgetService
from app.services.reimbursement import ReimbursementService
from app.services.travel_reimbursement_calculator import TravelReimbursementCalculatorService
@@ -126,6 +128,38 @@ def get_expense_claim(claim_id: str, db: DbSession, current_user: CurrentUser) -
return claim
@router.get(
"/claims/{claim_id}/budget-analysis",
response_model=BudgetClaimAnalysisRead,
summary="读取申请单预算分析",
description="根据当前预算池、申请金额和预算管控模型,返回费用申请的预算影响和评分建议。",
responses={
status.HTTP_404_NOT_FOUND: {
"model": ErrorResponse,
"description": "单据不存在。",
},
status.HTTP_403_FORBIDDEN: {
"model": ErrorResponse,
"description": "当前用户无权查看预算分析。",
},
},
)
def get_expense_claim_budget_analysis(
claim_id: str,
db: DbSession,
current_user: CurrentUser,
) -> BudgetClaimAnalysisRead:
service = ExpenseClaimService(db)
if not service.can_view_budget_analysis(current_user):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="只有预算监控员或高级财务人员可以查看预算分析。")
claim = service.get_claim(claim_id, current_user)
if claim is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Claim not found")
if not service.can_view_budget_analysis(current_user, claim):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="只有该部门 P8 预算监控员或高级财务人员可以查看预算分析。")
return BudgetService(db).analyze_claim_budget(claim)
@router.patch(
"/claims/{claim_id}",
response_model=ExpenseClaimRead,
@@ -538,7 +572,7 @@ def return_expense_claim(
"/claims/{claim_id}/approve",
response_model=ExpenseClaimRead,
summary="审批通过单据",
description="费用申请由直属领导审批通过后完成;报销单直属领导审批后流转到财务审批,财务终审通过后进入归档入账",
description="费用申请由直属领导审批后流转到预算管理者审批,预算审核通过后生成报销草稿;报销单直属领导审批后流转到财务审批。",
responses={
status.HTTP_404_NOT_FOUND: {
"model": ErrorResponse,