feat(server): 新增申请核对预览快速建单接口与平台管理员判定统一
- reimbursements 新增 POST /application-preview-action,AI 工作台表格核对后直接走 UserAgentService 建单/提交,免去通用 Orchestrator 编排 - 平台管理员判定统一抽取 PLATFORM_ADMIN_IDENTITIES 常量,identity 与 role_codes 均支持 admin/superadmin,含 header 开关 - docker-compose 镜像补装 openssh-server - 同步更新差旅/交通/通信等财务规则表与 reimbursements 端点测试
This commit is contained in:
@@ -765,7 +765,7 @@ def test_claim_item_delete_removes_item_and_attachment(monkeypatch, tmp_path) ->
|
||||
assert deleted_meta_response.status_code == 404
|
||||
|
||||
|
||||
def test_claim_delete_allows_draft_owner_by_employee_id_without_employee_no_header(monkeypatch, tmp_path) -> None:
|
||||
def test_claim_delete_allows_admin_and_cleans_risk_observations(monkeypatch, tmp_path) -> None:
|
||||
monkeypatch.setattr(ExpenseClaimAttachmentStorage, "root", lambda self: tmp_path)
|
||||
|
||||
client, session_factory = build_client()
|
||||
@@ -800,7 +800,7 @@ def test_claim_delete_allows_draft_owner_by_employee_id_without_employee_no_head
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1/reimbursements/claims/{claim_id}",
|
||||
headers={"x-auth-username": "emp-1", "x-auth-name": "Browser Session User"},
|
||||
headers={"x-auth-username": "admin", "x-auth-name": "Admin User"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
@@ -812,3 +812,90 @@ def test_claim_delete_allows_draft_owner_by_employee_id_without_employee_no_head
|
||||
assert db.get(ExpenseClaim, claim_id) is None
|
||||
assert db.get(RiskObservation, "risk-observation-delete-1") is None
|
||||
assert db.get(RiskObservationFeedback, "risk-observation-feedback-delete-1") is None
|
||||
|
||||
|
||||
def test_claim_delete_allows_legacy_superadmin_without_is_admin_header(monkeypatch, tmp_path) -> None:
|
||||
monkeypatch.setattr(ExpenseClaimAttachmentStorage, "root", lambda self: tmp_path)
|
||||
|
||||
client, session_factory = build_client()
|
||||
with session_factory() as db:
|
||||
claim, _ = seed_claim(db)
|
||||
claim_id = claim.id
|
||||
|
||||
response = client.delete(
|
||||
f"/api/v1/reimbursements/claims/{claim_id}",
|
||||
headers={
|
||||
"x-auth-username": "superadmin",
|
||||
"x-auth-name": "superadmin",
|
||||
"x-auth-role-codes": "manager",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["claim_id"] == claim_id
|
||||
assert payload["status"] == "deleted"
|
||||
|
||||
with session_factory() as db:
|
||||
assert db.get(ExpenseClaim, claim_id) is None
|
||||
|
||||
|
||||
def test_application_preview_action_submits_without_orchestrator_run(monkeypatch, tmp_path) -> None:
|
||||
monkeypatch.setattr(ExpenseClaimAttachmentStorage, "root", lambda self: tmp_path)
|
||||
|
||||
client, session_factory = build_client()
|
||||
with session_factory() as db:
|
||||
seed_claim(db)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/reimbursements/application-preview-action",
|
||||
headers={
|
||||
"x-auth-username": "zhangsan@example.com",
|
||||
"x-auth-name": "Zhang San",
|
||||
"x-auth-employee-no": "E10001",
|
||||
"x-auth-role-codes": "user",
|
||||
},
|
||||
json={
|
||||
"source": "user_message",
|
||||
"user_id": "zhangsan@example.com",
|
||||
"conversation_id": "conversation-fast-submit",
|
||||
"message": "差旅费用申请提交审批\n申请类型:差旅费用申请\n申请时间:2026-07-01 至 2026-07-03\n地点:北京\n事由:项目实施\n天数:3天\n出行方式:火车\n申请金额:1000元\n直接提交",
|
||||
"context_json": {
|
||||
"session_type": "application",
|
||||
"entry_source": "workbench_ai_inline",
|
||||
"document_type": "expense_application",
|
||||
"application_stage": "expense_application",
|
||||
"application_preview": {
|
||||
"fields": {
|
||||
"applicationType": "差旅费用申请",
|
||||
"time": "2026-07-01 至 2026-07-03",
|
||||
"location": "北京",
|
||||
"reason": "项目实施",
|
||||
"days": "3天",
|
||||
"transportMode": "火车",
|
||||
"amount": "1000元",
|
||||
"applicant": "张三",
|
||||
"department": "市场部",
|
||||
"position": "招商主管",
|
||||
"grade": "P4",
|
||||
"managerName": "李总",
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["status"] == "succeeded"
|
||||
draft_payload = payload["result"]["draft_payload"]
|
||||
assert draft_payload["draft_type"] == "expense_application"
|
||||
assert draft_payload["status"] == "submitted"
|
||||
assert draft_payload["approval_stage"] == "直属领导审批"
|
||||
assert draft_payload["claim_no"].startswith("AP-")
|
||||
|
||||
with session_factory() as db:
|
||||
claim = db.get(ExpenseClaim, draft_payload["claim_id"])
|
||||
assert claim is not None
|
||||
assert claim.status == "submitted"
|
||||
assert claim.employee_name == "张三"
|
||||
|
||||
Reference in New Issue
Block a user