From 32a43cf6bb65b47e4d29a5a5050dee2ae6f7b5a0 Mon Sep 17 00:00:00 2001 From: caoxiaozhu Date: Thu, 14 May 2026 12:34:12 +0000 Subject: [PATCH] =?UTF-8?q?feat(server):=20=E6=96=B0=E5=A2=9E=E7=BC=96?= =?UTF-8?q?=E6=8E=92=E5=99=A8=E6=9C=8D=E5=8A=A1=EF=BC=8C=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E9=97=B4=E6=B5=81=E7=A8=8B=E7=BC=96=E6=8E=92?= =?UTF-8?q?=E5=92=8C=E4=BB=BB=E5=8A=A1=E8=B0=83=E5=BA=A6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/app/services/orchestrator.py | 4 +- server/tests/test_orchestrator_service.py | 59 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/server/src/app/services/orchestrator.py b/server/src/app/services/orchestrator.py index f3a0205..54a6b94 100644 --- a/server/src/app/services/orchestrator.py +++ b/server/src/app/services/orchestrator.py @@ -657,8 +657,8 @@ class OrchestratorService: if ontology.scenario == "expense": tool_type = AgentToolType.DATABASE.value - tool_name = "database.expense_claims.upsert_draft" - executor = lambda: self.expense_claim_service.upsert_draft_from_ontology( + tool_name = "database.expense_claims.save_or_submit" + executor = lambda: self.expense_claim_service.save_or_submit_from_ontology( run_id=run_id, user_id=payload.user_id, message=payload.message or "", diff --git a/server/tests/test_orchestrator_service.py b/server/tests/test_orchestrator_service.py index b187a4a..39e8105 100644 --- a/server/tests/test_orchestrator_service.py +++ b/server/tests/test_orchestrator_service.py @@ -629,6 +629,65 @@ def test_orchestrator_user_agent_draft_returns_structured_payload() -> None: assert claim.items +def test_orchestrator_expense_next_step_submits_claim_to_approval() -> None: + client, session_factory = build_client() + user_id = "zhangsan@example.com" + + with session_factory() as db: + db.add( + Employee( + employee_no="E3001", + name="张三", + email=user_id, + ) + ) + db.commit() + + response = client.post( + "/api/v1/orchestrator/run", + json={ + "source": "user_message", + "user_id": user_id, + "message": "帮我报销昨天去上海出差的交通费680元", + "context_json": { + "role_codes": ["employee"], + "name": "张三", + "department_name": "销售部", + "attachment_names": ["didi-trip.png"], + "attachment_count": 1, + "review_action": "next_step", + "review_form_values": { + "reporter_name": "张三", + "expense_type": "交通费", + "amount": "680", + "occurred_date": "2026-05-13", + "location": "上海", + "reason": "上海客户拜访交通" + }, + }, + }, + ) + + assert response.status_code == 200 + payload = response.json() + assert payload["status"] == "succeeded" + assert payload["result"]["draft_payload"]["claim_no"].startswith("EXP-") + assert payload["result"]["draft_payload"]["status"] == "submitted" + assert payload["result"]["draft_payload"]["approval_stage"] == "AI验审" + assert "已提交审批" in payload["result"]["answer"] + + with session_factory() as db: + claim = db.scalar( + select(ExpenseClaim).where( + ExpenseClaim.id == payload["result"]["draft_payload"]["claim_id"] + ) + ) + assert claim is not None + assert claim.status == "submitted" + assert claim.approval_stage == "AI验审" + assert claim.submitted_at is not None + + def test_orchestrator_blocks_fourth_expense_draft_for_same_user() -> None: client, session_factory = build_client() user_id = "zhangsan@example.com"