Refine travel reimbursement steward flow

Align planner, runtime rules, and policy assets so travel guidance
matches the updated reimbursement workflow.
This commit is contained in:
caoxiaozhu
2026-06-15 22:55:18 +08:00
parent 792741709a
commit 9f7b8b46a3
85 changed files with 9496 additions and 2555 deletions

View File

@@ -38,8 +38,14 @@ from app.services.agent_asset_spreadsheet import (
COMPANY_COMMUNICATION_EXPENSE_RULE_FILENAME,
COMPANY_PREAPPROVAL_RULE_CODE,
COMPANY_PREAPPROVAL_RULE_FILENAME,
COMPANY_TRAVEL_GRADE_MAPPING_RULE_CODE,
COMPANY_TRAVEL_GRADE_MAPPING_RULE_FILENAME,
COMPANY_TRAVEL_EXPENSE_RULE_CODE,
COMPANY_TRAVEL_EXPENSE_RULE_FILENAME,
COMPANY_TRAVEL_SEASON_MAPPING_RULE_CODE,
COMPANY_TRAVEL_SEASON_MAPPING_RULE_FILENAME,
COMPANY_TRAVEL_TRANSPORT_ESTIMATE_RULE_CODE,
COMPANY_TRAVEL_TRANSPORT_ESTIMATE_RULE_FILENAME,
FINANCE_RULES_LIBRARY,
)
from app.services.agent_foundation_constants import COMPANY_PREAPPROVAL_RULE_SCENARIO_JSON
@@ -64,6 +70,9 @@ def isolate_rule_file_storage(tmp_path, monkeypatch) -> None:
real_finance_rules = SERVER_DIR / "rules" / FINANCE_RULES_LIBRARY
for file_name in (
COMPANY_TRAVEL_EXPENSE_RULE_FILENAME,
COMPANY_TRAVEL_GRADE_MAPPING_RULE_FILENAME,
COMPANY_TRAVEL_SEASON_MAPPING_RULE_FILENAME,
COMPANY_TRAVEL_TRANSPORT_ESTIMATE_RULE_FILENAME,
COMPANY_COMMUNICATION_EXPENSE_RULE_FILENAME,
COMPANY_PREAPPROVAL_RULE_FILENAME,
):
@@ -197,12 +206,36 @@ def test_finance_rules_use_risk_rule_scenario_categories() -> None:
assert communication_config["scenario_category"] == "通信费"
assert communication_config["ai_review_category"] == "通信费"
assert preapproval_rule.scenario_json == list(COMPANY_PREAPPROVAL_RULE_SCENARIO_JSON)
assert preapproval_config["tag"] == "财务规则"
assert travel_config["tag"] == "基础规则"
assert communication_config["tag"] == "基础规则"
assert preapproval_config["tag"] == "申请规则"
assert preapproval_config["finance_rule_code"] == "expense.preapproval.policy"
assert preapproval_config["finance_rule_sheet"] == "费用申请审批规则"
assert preapproval_config["expense_types"] == ["meal", "entertainment", "office", "all"]
assert preapproval_config["rule_document"]["file_name"] == COMPANY_PREAPPROVAL_RULE_FILENAME
grade_mapping_rule = next(
item for item in rules if item.code == COMPANY_TRAVEL_GRADE_MAPPING_RULE_CODE
)
season_mapping_rule = next(
item for item in rules if item.code == COMPANY_TRAVEL_SEASON_MAPPING_RULE_CODE
)
transport_estimate_rule = next(
item for item in rules if item.code == COMPANY_TRAVEL_TRANSPORT_ESTIMATE_RULE_CODE
)
assert grade_mapping_rule.config_json["tag"] == "基础规则"
assert grade_mapping_rule.config_json["rule_document"]["file_name"] == (
COMPANY_TRAVEL_GRADE_MAPPING_RULE_FILENAME
)
assert season_mapping_rule.config_json["tag"] == "基础规则"
assert season_mapping_rule.config_json["rule_document"]["file_name"] == (
COMPANY_TRAVEL_SEASON_MAPPING_RULE_FILENAME
)
assert transport_estimate_rule.config_json["tag"] == "基础规则"
assert transport_estimate_rule.config_json["rule_document"]["file_name"] == (
COMPANY_TRAVEL_TRANSPORT_ESTIMATE_RULE_FILENAME
)
def test_non_standard_finance_rule_spreadsheets_are_not_seeded() -> None:
with build_session() as db:
@@ -743,15 +776,15 @@ def test_expense_rule_runtime_reads_amount_standards_from_travel_spreadsheet() -
assert catalog.travel_policy is not None
assert catalog.travel_policy.standard_rule_code == COMPANY_TRAVEL_EXPENSE_RULE_CODE
assert catalog.travel_policy.standard_rule_name == "公司差旅费报销规则"
assert catalog.travel_policy.hotel_city_limits["北京"]["mid"] == 450
assert catalog.travel_policy.hotel_city_limits["北京"]["junior"] == 450
assert catalog.travel_policy.hotel_city_limits["北京"]["manager"] == 500
assert catalog.travel_policy.standard_rule_name == "差旅住宿报销标准"
assert catalog.travel_policy.hotel_city_limits["北京"]["P0"] == 450
assert catalog.travel_policy.hotel_city_limits["北京"]["P4"] == 450
assert catalog.travel_policy.hotel_city_limits["北京"]["P8"] == 500
assert catalog.travel_policy.allowance_limits["meal"]["直辖市/特区"] == 65
assert catalog.travel_policy.allowance_limits["meal"]["其他地区"] == 55
assert catalog.travel_policy.allowance_limits["total"]["其他地区"] == 90
assert catalog.travel_policy.transport_limits["senior"]["flight"] == 1
assert catalog.travel_policy.transport_limits["executive"]["train"] == 1
assert catalog.travel_policy.transport_limits["P7"]["flight"] == 1
assert catalog.travel_policy.transport_limits["P8"]["train"] == 2
def test_travel_reimbursement_calculator_uses_finance_spreadsheet_amounts() -> None:
@@ -777,18 +810,23 @@ def test_travel_reimbursement_calculator_uses_finance_spreadsheet_amounts() -> N
),
)
assert result.rule_name == "公司差旅费报销规则"
assert result.rule_name == "差旅住宿报销标准"
assert result.grade == "P4"
assert result.grade_band == "mid"
assert result.grade_band == "P4"
assert result.matched_city == "北京"
assert result.hotel_rate == 450
assert result.hotel_amount == 1350
assert result.allowance_region == "直辖市/特区"
assert result.total_allowance_rate == 100
assert result.allowance_amount == 300
assert result.total_amount == 1650
assert "住宿 450.00 × 3 天 + 补贴 100.00 × 3 天 = 1650.00" == result.formula_text
assert "参考可报销总金额为 1650.00 元" in result.summary_text
assert result.transport_estimated_amount == 1040
assert result.transport_estimate_source == "basic_rule_transport_estimate"
assert result.total_amount == 2690
assert (
"交通 1040.00 + 住宿 450.00 × 3 天 + 补贴 100.00 × 3 天 = 2690.00"
== result.formula_text
)
assert "申请预算占用参考总金额为 2690.00 元" in result.summary_text
def test_travel_reimbursement_calculator_uses_other_region_for_known_unlisted_location() -> None:
@@ -821,7 +859,8 @@ def test_travel_reimbursement_calculator_uses_other_region_for_known_unlisted_lo
assert result.allowance_region == "其他地区"
assert result.total_allowance_rate == 90
assert result.allowance_amount == 180
assert result.total_amount == 940
assert result.transport_estimated_amount == 720
assert result.total_amount == 1660
def test_travel_reimbursement_calculator_rejects_unrecognized_location() -> None: