refactor(backend): update services and tests
- services/expense_claims.py: update expense claims service - services/user_agent.py: update user agent service - tests/test_orchestrator_service.py: update orchestrator service tests - tests/test_user_agent_service.py: update user agent service tests
This commit is contained in:
@@ -12,6 +12,7 @@ from app.api.deps import get_db
|
||||
from app.db.base import Base
|
||||
from app.main import create_app
|
||||
from app.models.agent_conversation import AgentConversation, AgentConversationMessage
|
||||
from app.models.employee import Employee
|
||||
from app.models.financial_record import ExpenseClaim
|
||||
from app.schemas.settings import SettingsWrite
|
||||
from app.services.agent_assets import AgentAssetService
|
||||
@@ -183,6 +184,153 @@ def test_orchestrator_user_agent_draft_returns_structured_payload() -> None:
|
||||
assert claim.items
|
||||
|
||||
|
||||
def test_orchestrator_blocks_fourth_expense_draft_for_same_user() -> None:
|
||||
client, session_factory = build_client()
|
||||
user_id = "zhangsan@example.com"
|
||||
|
||||
with session_factory() as db:
|
||||
db.add(
|
||||
Employee(
|
||||
employee_no="E1001",
|
||||
name="张三",
|
||||
email=user_id,
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
|
||||
for amount, city in ((120, "上海"), (240, "北京"), (360, "深圳")):
|
||||
response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": user_id,
|
||||
"message": f"帮我生成报销草稿,我昨天去{city}出差,交通费{amount}元",
|
||||
"context_json": {
|
||||
"role_codes": ["finance"],
|
||||
"name": "张三",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["result"]["draft_payload"]["claim_no"].startswith("EXP-")
|
||||
|
||||
blocked_response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": user_id,
|
||||
"message": "帮我生成报销草稿,我昨天去杭州出差,交通费480元",
|
||||
"context_json": {
|
||||
"role_codes": ["finance"],
|
||||
"name": "张三",
|
||||
"review_action": "save_draft",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert blocked_response.status_code == 200
|
||||
blocked_payload = blocked_response.json()
|
||||
assert blocked_payload["status"] == "succeeded"
|
||||
assert "你当前已保存 3 个草稿" in blocked_payload["result"]["answer"]
|
||||
assert blocked_payload["result"]["draft_payload"]["claim_id"] is None
|
||||
assert blocked_payload["result"]["draft_payload"]["claim_no"] is None
|
||||
assert blocked_payload["result"]["draft_payload"]["status"] == "blocked"
|
||||
|
||||
with session_factory() as db:
|
||||
draft_count = db.scalar(
|
||||
select(func.count())
|
||||
.select_from(ExpenseClaim)
|
||||
.where(ExpenseClaim.status == "draft")
|
||||
)
|
||||
assert draft_count == 3
|
||||
|
||||
|
||||
def test_orchestrator_allows_existing_draft_update_when_user_already_has_three_drafts() -> None:
|
||||
client, session_factory = build_client()
|
||||
user_id = "lisi@example.com"
|
||||
|
||||
with session_factory() as db:
|
||||
db.add(
|
||||
Employee(
|
||||
employee_no="E1002",
|
||||
name="李四",
|
||||
email=user_id,
|
||||
)
|
||||
)
|
||||
db.commit()
|
||||
|
||||
first_response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": user_id,
|
||||
"message": "帮我生成报销草稿,我昨天去上海出差,交通费120元",
|
||||
"context_json": {
|
||||
"role_codes": ["finance"],
|
||||
"name": "李四",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert first_response.status_code == 200
|
||||
first_payload = first_response.json()
|
||||
claim_id = first_payload["result"]["draft_payload"]["claim_id"]
|
||||
conversation_id = first_payload["conversation_id"]
|
||||
assert claim_id
|
||||
assert conversation_id
|
||||
|
||||
for amount, city in ((240, "北京"), (360, "深圳")):
|
||||
response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": user_id,
|
||||
"message": f"帮我生成报销草稿,我昨天去{city}出差,交通费{amount}元",
|
||||
"context_json": {
|
||||
"role_codes": ["finance"],
|
||||
"name": "李四",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["result"]["draft_payload"]["claim_no"].startswith("EXP-")
|
||||
|
||||
update_response = client.post(
|
||||
"/api/v1/orchestrator/run",
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": user_id,
|
||||
"conversation_id": conversation_id,
|
||||
"message": "金额改成888元",
|
||||
"context_json": {
|
||||
"role_codes": ["finance"],
|
||||
"name": "李四",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert update_response.status_code == 200
|
||||
update_payload = update_response.json()
|
||||
assert update_payload["result"]["draft_payload"]["claim_id"] == claim_id
|
||||
|
||||
with session_factory() as db:
|
||||
claim = db.scalar(select(ExpenseClaim).where(ExpenseClaim.id == claim_id))
|
||||
assert claim is not None
|
||||
assert float(claim.amount) == 888.0
|
||||
|
||||
draft_count = db.scalar(
|
||||
select(func.count())
|
||||
.select_from(ExpenseClaim)
|
||||
.where(ExpenseClaim.employee_id == claim.employee_id)
|
||||
.where(ExpenseClaim.status == "draft")
|
||||
)
|
||||
assert draft_count == 3
|
||||
|
||||
|
||||
def test_orchestrator_persists_conversation_and_reuses_expense_draft_context() -> None:
|
||||
client, session_factory = build_client()
|
||||
|
||||
|
||||
@@ -246,6 +246,36 @@ def test_user_agent_draft_returns_structured_payload() -> None:
|
||||
assert response.answer == response.review_payload.body_message
|
||||
|
||||
|
||||
def test_user_agent_returns_draft_limit_message_when_save_is_blocked() -> None:
|
||||
session_factory = build_session_factory()
|
||||
with session_factory() as db:
|
||||
ontology = SemanticOntologyService(db).parse(
|
||||
OntologyParseRequest(
|
||||
query="请按当前识别信息保存报销草稿",
|
||||
user_id="pytest",
|
||||
)
|
||||
)
|
||||
response = UserAgentService(db).respond(
|
||||
UserAgentRequest(
|
||||
run_id=ontology.run_id,
|
||||
user_id="pytest",
|
||||
message="请按当前识别信息保存报销草稿",
|
||||
ontology=ontology,
|
||||
context_json={"review_action": "save_draft"},
|
||||
tool_payload={
|
||||
"draft_limit_reached": True,
|
||||
"message": "你当前已保存 3 个草稿,请先完成已保存的草稿,才能再次新建草稿。",
|
||||
"status": "blocked",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
assert (
|
||||
response.answer
|
||||
== "你当前已保存 3 个草稿,请先完成已保存的草稿,才能再次新建草稿。"
|
||||
)
|
||||
|
||||
|
||||
def test_user_agent_builds_review_payload_for_multi_document_expense_flow() -> None:
|
||||
session_factory = build_session_factory()
|
||||
with session_factory() as db:
|
||||
|
||||
Reference in New Issue
Block a user