Files
X-Financial/server/tests/test_steward_flow_state.py
caoxiaozhu 9f7b8b46a3 Refine travel reimbursement steward flow
Align planner, runtime rules, and policy assets so travel guidance
matches the updated reimbursement workflow.
2026-06-15 22:55:18 +08:00

139 lines
5.2 KiB
Python

from __future__ import annotations
from app.schemas.steward import (
StewardCandidateFlow,
StewardFlowStatePatch,
StewardPendingFlowConfirmation,
StewardPlanResponse,
)
from app.services.steward_flow_state import StewardFlowStateService
def test_state_merge_keeps_application_and_reimbursement_flows() -> None:
service = StewardFlowStateService()
state = service.merge_state(
{},
StewardFlowStatePatch(
active_flow="travel_application",
flow_id="travel_application",
intent="travel_application_create",
fields={"expense_type": "travel", "location": "上海", "reason": "客户现场支撑"},
missing_fields=["transport_mode"],
),
)
state = service.merge_state(
state,
StewardFlowStatePatch(
active_flow="travel_reimbursement",
flow_id="travel_reimbursement",
intent="travel_reimbursement_draft",
fields={"amount": "708.00", "invoice_no": "NO-1"},
linked_application_claim_id="claim-app-001",
),
)
assert state["active_flow"] == "travel_reimbursement"
assert state["flows"]["travel_application"]["fields"]["location"] == "上海"
assert state["flows"]["travel_application"]["missing_fields"] == ["transport_mode"]
assert state["flows"]["travel_reimbursement"]["fields"]["amount"] == "708.00"
assert state["flows"]["travel_reimbursement"]["linked_application_claim_id"] == "claim-app-001"
def test_state_merge_filters_non_ontology_fields() -> None:
service = StewardFlowStateService()
state = service.merge_state(
{},
StewardFlowStatePatch(
active_flow="travel_application",
flow_id="travel_application",
intent="travel_application_create",
fields={
"location": "上海",
"invented_field": "x",
"occurred_date": "2026-06-15",
},
),
)
assert state["flows"]["travel_application"]["fields"] == {
"location": "上海",
"time_range": "2026-06-15",
}
def test_state_merge_appends_traceable_events() -> None:
service = StewardFlowStateService()
state = service.merge_state(
{},
StewardFlowStatePatch(
active_flow="travel_application",
flow_id="travel_application",
intent="travel_application_create",
fields={"location": "北京"},
evidence=[{"source": "user_message", "field": "location", "text": "去北京出差"}],
),
)
assert len(state["events"]) == 1
assert state["events"][0]["flow_id"] == "travel_application"
assert state["events"][0]["intent"] == "travel_application_create"
assert state["events"][0]["fields"] == {"location": "北京"}
assert state["events"][0]["evidence"][0]["text"] == "去北京出差"
def test_state_merge_plan_keeps_pending_flow_confirmation() -> None:
service = StewardFlowStateService()
state = service.merge_plan(
{},
StewardPlanResponse(
plan_id="steward_plan_pending",
plan_status="needs_flow_confirmation",
planning_source="llm_function_call",
next_action="confirm_flow",
summary="需要先确认是申请还是报销。",
pending_flow_confirmation=StewardPendingFlowConfirmation(
status="pending",
source_message="2月20-23日去上海出差辅助国网仿生产环境部署",
reason="缺少申请或报销动作词。",
candidate_flows=[
StewardCandidateFlow(
flow_id="travel_application",
label="补办出差申请",
confidence=0.52,
reason="可能是补办申请。",
ontology_fields={
"time_range": "2026-02-20",
"location": "上海",
"expense_type": "travel",
"reason": "辅助国网仿生产环境部署",
},
missing_fields=["transport_mode"],
),
StewardCandidateFlow(
flow_id="travel_reimbursement",
label="发起费用报销",
confidence=0.48,
reason="可能是发起报销。",
ontology_fields={
"time_range": "2026-02-20",
"location": "上海",
"expense_type": "travel",
"reason": "辅助国网仿生产环境部署",
},
),
],
),
),
)
assert state["active_flow"] == ""
assert state["pending_flow_confirmation"]["status"] == "pending"
assert state["flows"]["travel_application"]["status"] == "pending_flow_confirmation"
assert state["flows"]["travel_application"]["fields"]["location"] == "上海"
assert state["flows"]["travel_application"]["missing_fields"] == ["transport_mode"]
assert state["flows"]["travel_reimbursement"]["fields"]["time_range"] == "2026-02-20"