test: 同步报销审批流与预算分析测试

- 新增预算审批合并、风险标记去重与占位条目校验用例
- 补充预算分析对当前审核人与财务的可见性断言
- 调整单据删除权限测试以匹配 admin 限制
This commit is contained in:
caoxiaozhu
2026-06-17 14:39:26 +08:00
parent 0fac8b615f
commit 4199feb681
10 changed files with 907 additions and 42 deletions

View File

@@ -4,6 +4,7 @@ import uuid
from datetime import UTC, datetime
from decimal import Decimal
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.pool import StaticPool
@@ -236,7 +237,7 @@ def test_budget_warning_application_still_skips_budget_manager_when_not_over_bud
def test_application_routes_to_budget_manager_when_usage_reaches_90_percent() -> None:
with build_session() as db:
department, manager, _budget_manager, employee = _seed_people(db, suffix="OVER-90-APP")
department, manager, budget_manager, employee = _seed_people(db, suffix="OVER-90-APP")
_seed_budget_allocation(
db,
department_id=department.id,
@@ -288,6 +289,18 @@ def test_application_routes_to_budget_manager_when_usage_reaches_90_percent() ->
for flag in routed.risk_flags_json
)
with pytest.raises(ValueError, match="预算已超过警戒值"):
ExpenseClaimService(db).approve_claim(
claim.id,
CurrentUserContext(
username=budget_manager.email,
name=budget_manager.name,
role_codes=["budget_monitor"],
is_admin=False,
),
opinion=" ",
)
def test_application_stage_risk_under_90_percent_does_not_route_to_budget_manager() -> None:
with build_session() as db:
@@ -496,3 +509,57 @@ def test_risky_reimbursement_routes_to_budget_then_finance() -> None:
and flag.get("next_approval_stage") == FINANCE_APPROVAL_STAGE
for flag in budget_approved.risk_flags_json
)
def test_budget_manager_blank_opinion_defaults_to_agree_when_budget_under_warning() -> None:
with build_session() as db:
department, _manager, budget_manager, employee = _seed_people(db, suffix="BUDGET-NORMAL")
_seed_budget_allocation(
db,
department_id=department.id,
department_name=department.name,
amount=Decimal("10000.00"),
)
claim = ExpenseClaim(
claim_no="RE-20260530-BUDGET-NORMAL",
employee_id=employee.id,
employee_name=employee.name,
department_id=department.id,
department_name=department.name,
project_code=None,
expense_type="travel",
reason="客户现场沟通",
location="上海",
amount=Decimal("500.00"),
currency="CNY",
invoice_count=1,
occurred_at=datetime(2026, 5, 30, 9, 0, tzinfo=UTC),
submitted_at=datetime(2026, 5, 30, 10, 0, tzinfo=UTC),
status="submitted",
approval_stage=BUDGET_MANAGER_APPROVAL_STAGE,
risk_flags_json=[],
)
db.add(claim)
db.commit()
approved = ExpenseClaimService(db).approve_claim(
claim.id,
CurrentUserContext(
username=budget_manager.email,
name=budget_manager.name,
role_codes=["budget_monitor"],
is_admin=False,
),
opinion=" ",
)
assert approved is not None
assert approved.status == "submitted"
assert approved.approval_stage == FINANCE_APPROVAL_STAGE
assert any(
isinstance(flag, dict)
and flag.get("source") == "budget_approval"
and flag.get("event_type") == "expense_claim_budget_approval"
and flag.get("opinion") == "同意"
for flag in approved.risk_flags_json
)