refactor: consolidate finance workflow modules

This commit is contained in:
caoxiaozhu
2026-06-23 11:21:18 +08:00
parent 1f40ce3df3
commit 73966b3a7b
52 changed files with 3468 additions and 2865 deletions

View File

@@ -0,0 +1,42 @@
from __future__ import annotations
from datetime import date
from app.services.application_fact_resolver import (
ApplicationFactResolver,
resolve_application_facts,
)
def test_application_fact_resolver_extracts_travel_application_fields() -> None:
facts = resolve_application_facts(
"明天去上海出差3天辅助国网仿生产环境部署高铁往返",
"expense_application",
date(2026, 6, 23),
)
assert facts["expense_type"] == "travel"
assert facts["time_range"] == "2026-06-24"
assert facts["location"] == "上海"
assert facts["reason"] == "辅助国网仿生产环境部署,高铁往返"
assert facts["transport_mode"] == "train"
def test_application_fact_resolver_preserves_reimbursement_transport_semantics() -> None:
facts = resolve_application_facts(
"报销昨天去北京客户现场沟通产生的出租车费用",
"reimbursement",
date(2026, 6, 23),
)
assert facts["expense_type"] == "transport"
assert facts["time_range"] == "2026-06-22"
assert facts["location"] == "北京"
assert facts["reason"] == "去北京客户现场沟通产生的出租车费用"
assert facts["transport_mode"] == "taxi"
def test_application_fact_resolver_keeps_static_wrapper_api() -> None:
assert ApplicationFactResolver.infer_expense_type("打车去客户现场", "expense_application") == "travel"
assert ApplicationFactResolver.infer_expense_type("打车去客户现场", "reimbursement") == "transport"
assert ApplicationFactResolver.extract_time_range("2026-07-01 去深圳", date(2026, 6, 23)) == "2026-07-01"

View File

@@ -0,0 +1,29 @@
from __future__ import annotations
from datetime import UTC, datetime
from decimal import Decimal
from app.models.financial_record import ExpenseClaim
from app.test_helpers.db import build_in_memory_session
def test_build_in_memory_session_creates_isolated_sqlite_schema() -> None:
with build_in_memory_session() as db:
db.add(
ExpenseClaim(
claim_no="CLM-HELPER-001",
employee_name="张三",
department_name="研发部",
expense_type="travel",
reason="测试共享内存数据库夹具",
location="上海",
amount=Decimal("10.00"),
occurred_at=datetime(2026, 6, 23, tzinfo=UTC),
status="draft",
approval_stage="待提交",
risk_flags_json=[],
)
)
db.commit()
assert db.query(ExpenseClaim).count() == 1

View File

@@ -0,0 +1,52 @@
from __future__ import annotations
from types import SimpleNamespace
from app.services.expense_claim_platform_context_tools import (
collect_context_cities,
collect_context_item_ids,
extract_first_known_city_from_text,
unique_text_values,
)
from app.services.expense_rule_runtime_models import build_default_expense_rule_catalog
def test_unique_text_values_trims_and_preserves_order() -> None:
assert unique_text_values([" 上海 ", "", "上海", "北京", None, "北京"]) == [
"上海",
"北京",
]
def test_collect_context_item_ids_skips_empty_and_dedupes() -> None:
contexts = [
{"item": SimpleNamespace(id="item-1")},
{"item": SimpleNamespace(id="item-1")},
{"item": SimpleNamespace(id=" item-2 ")},
{"item": SimpleNamespace(id="")},
{},
]
assert collect_context_item_ids(contexts) == ["item-1", "item-2"]
def test_collect_context_cities_can_include_item_reason() -> None:
policy = build_default_expense_rule_catalog().travel_policy
assert policy is not None
context = {
"ocr_summary": "火车票;武汉-上海",
"ocr_text": "",
"document_info": {
"fields": [
{"key": "route", "label": "路线", "value": "上海-深圳"},
]
},
"item": SimpleNamespace(item_location="", item_reason="深圳-上海"),
}
assert set(collect_context_cities(context, policy, include_item_reason=True)) == {
"武汉",
"上海",
"深圳",
}
assert extract_first_known_city_from_text("预计前往北京客户现场", policy) == "北京"

View File

@@ -5,13 +5,10 @@ from datetime import UTC, date, datetime
from decimal import Decimal
from typing import Any
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.pool import StaticPool
from sqlalchemy.orm import Session
from app.api.deps import CurrentUserContext
from app.core.agent_enums import AgentAssetDomain, AgentAssetStatus, AgentAssetType
from app.db.base import Base
from app.models.agent_asset import AgentAsset
from app.models.financial_record import ExpenseClaim, ExpenseClaimItem
from app.services.agent_asset_rule_library import AgentAssetRuleLibraryManager
@@ -19,17 +16,10 @@ from app.services.agent_asset_spreadsheet import RISK_RULES_LIBRARY
from app.services.expense_claim_attachment_storage import ExpenseClaimAttachmentStorage
from app.services.expense_claims import ExpenseClaimService
from app.services.risk_rule_generation_interpreter import COMPOSITE_RULE_TEMPLATE_KEY
from app.test_helpers.db import build_in_memory_session
def build_session() -> Session:
engine = create_engine(
"sqlite+pysqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
Base.metadata.create_all(bind=engine)
session_factory = sessionmaker(bind=engine, autoflush=False, autocommit=False)
return session_factory()
build_session = build_in_memory_session
def _build_rule_payload(