From 3bc7668f6ceef4a70b303886fe98279ce0afc4e6 Mon Sep 17 00:00:00 2001 From: caoxiaozhu Date: Thu, 14 May 2026 12:34:54 +0000 Subject: [PATCH] =?UTF-8?q?feat(server):=20=E4=BC=98=E5=8C=96=E8=B4=B9?= =?UTF-8?q?=E7=94=A8=E6=8A=A5=E9=94=80=E6=9C=8D=E5=8A=A1=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E6=8A=A5=E9=94=80=E5=8D=95=E6=95=B0=E6=8D=AE=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E5=92=8C=E7=8A=B6=E6=80=81=E6=B5=81=E8=BD=AC=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/app/services/expense_claims.py | 65 +++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/server/src/app/services/expense_claims.py b/server/src/app/services/expense_claims.py index a03bd07..81c4b10 100644 --- a/server/src/app/services/expense_claims.py +++ b/server/src/app/services/expense_claims.py @@ -510,6 +510,71 @@ class ExpenseClaimService: return claim + def save_or_submit_from_ontology( + self, + *, + run_id: str, + user_id: str | None, + message: str, + ontology: OntologyParseResult, + context_json: dict[str, Any], + ) -> dict[str, Any]: + result = self.upsert_draft_from_ontology( + run_id=run_id, + user_id=user_id, + message=message, + ontology=ontology, + context_json=context_json, + ) + + review_action = str(context_json.get("review_action") or "").strip() + if review_action != "next_step": + return result + + claim_id = str(result.get("claim_id") or "").strip() + if not claim_id or result.get("draft_limit_reached"): + return result + + current_user = CurrentUserContext( + username=str(user_id or context_json.get("name") or "anonymous").strip() or "anonymous", + name=str(context_json.get("name") or user_id or "anonymous").strip() or "anonymous", + role_codes=[ + str(item).strip() + for item in list(context_json.get("role_codes") or []) + if str(item).strip() + ], + is_admin=bool(context_json.get("is_admin")), + ) + + try: + claim = self.submit_claim(claim_id, current_user) + except ValueError as exc: + return { + **result, + "message": str(exc), + "submission_blocked": True, + "draft_only": False, + } + + if claim is None: + return { + **result, + "message": "未找到可提交的报销单,请刷新后重试。", + "submission_blocked": True, + "draft_only": False, + } + + return { + "message": f"报销单 {claim.claim_no} 已提交审批,当前节点为 {claim.approval_stage or '审批中'}。", + "draft_only": False, + "claim_id": claim.id, + "claim_no": claim.claim_no, + "status": claim.status, + "approval_stage": claim.approval_stage, + "amount": float(claim.amount), + "invoice_count": int(claim.invoice_count or 0), + } + def delete_claim(self, claim_id: str, current_user: CurrentUserContext) -> ExpenseClaim | None: claim = self.get_claim(claim_id, current_user) if claim is None: