refactor: consolidate finance workflow modules
This commit is contained in:
42
server/tests/test_application_fact_resolver.py
Normal file
42
server/tests/test_application_fact_resolver.py
Normal 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"
|
||||
29
server/tests/test_db_test_helpers.py
Normal file
29
server/tests/test_db_test_helpers.py
Normal 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
|
||||
52
server/tests/test_expense_claim_platform_context_tools.py
Normal file
52
server/tests/test_expense_claim_platform_context_tools.py
Normal 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) == "北京"
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user