feat(server): 申请单支持草稿保存并统一删除权限口径

- user_agent_application 新增草稿分支:识别'保存草稿/存草稿/先保存'等意图,复用可编辑记录更新或建草稿,提交前单据重叠仍拦截
- 草稿态返回单号与待提交提示,submit 仅在确认提交分支触发,避免草稿进入审批流
- reimbursements 删除接口文案与判定统一为系统管理员可删、申请人删自有草稿/退回单,申请单判定改用 is_application_claim_no
- 更新财务规则表与 reimbursement 端点测试
This commit is contained in:
caoxiaozhu
2026-06-20 21:44:12 +08:00
parent 47c6a4bb73
commit 81e990ab72
9 changed files with 221 additions and 30 deletions

View File

@@ -10,16 +10,17 @@ from app.api.deps import CurrentUserContext, get_current_user, get_db
from app.api.pagination import PageNumber, PageSize, page_payload, wants_page
from app.schemas.budget import BudgetClaimAnalysisRead
from app.schemas.common import ErrorResponse, PaginatedResponse
from app.schemas.ontology import OntologyParseResult, OntologyPermission
from app.schemas.reimbursement import (
ExpenseApplicationPreviewActionPayload,
ExpenseApplicationPreviewActionResponse,
ExpenseApplicationPreviewActionResult,
ExpenseClaimAttachmentActionResponse,
ExpenseClaimActionResponse,
ExpenseClaimAttachmentRead,
ExpenseClaimApprovalPayload,
ExpenseClaimItemCreate,
ExpenseClaimAttachmentActionResponse,
ExpenseClaimAttachmentRead,
ExpenseClaimItemActionResponse,
ExpenseClaimItemCreate,
ExpenseClaimItemUpdate,
ExpenseClaimRead,
ExpenseClaimReturnPayload,
@@ -30,9 +31,9 @@ from app.schemas.reimbursement import (
TravelReimbursementCalculatorRequest,
TravelReimbursementCalculatorResponse,
)
from app.schemas.ontology import OntologyParseResult, OntologyPermission
from app.schemas.user_agent import UserAgentRequest
from app.services.budget import BudgetService
from app.services.document_numbering import is_application_claim_no
from app.services.expense_claims import ExpenseClaimService
from app.services.reimbursement import ReimbursementService
from app.services.travel_reimbursement_calculator import TravelReimbursementCalculatorService
@@ -119,7 +120,10 @@ def _build_application_preview_action_context(
"/application-preview-action",
response_model=ExpenseApplicationPreviewActionResponse,
summary="按申请核对预览快速保存或提交申请单",
description="用于 AI 工作台已完成表格核对后的轻量建单/提交流程,避免重复进入通用 Orchestrator 编排。",
description=(
"用于 AI 工作台已完成表格核对后的轻量建单/提交流程,"
"避免重复进入通用 Orchestrator 编排。"
),
)
def run_application_preview_action(
payload: ExpenseApplicationPreviewActionPayload,
@@ -831,7 +835,7 @@ def pay_expense_claim(
"/claims/{claim_id}",
response_model=ExpenseClaimActionResponse,
summary="删除报销单",
description="申请人可删除自己的草稿、待补充或退回单据(含申请单和报销单);高级财务人员可删除可见的非归档报销单;已归档单据仅高级管理员可删除,财务人员没有删除权限",
description="申请人可删除自己的草稿、待补充或退回单据(含申请单和报销单);系统管理员可删除单据;已归档单据仅系统管理员可删除。",
responses={
status.HTTP_404_NOT_FOUND: {
"model": ErrorResponse,
@@ -855,7 +859,11 @@ def delete_expense_claim(claim_id: str, db: DbSession, current_user: CurrentUser
claim_no = str(claim.claim_no or "").strip()
expense_type = str(claim.expense_type or "").strip().lower()
document_label = "申请单" if claim_no.upper().startswith(("AP-", "APP-")) or expense_type.endswith("_application") else "报销单"
document_label = (
"申请单"
if is_application_claim_no(claim_no) or expense_type.endswith("_application")
else "报销单"
)
return ExpenseClaimActionResponse(
message=f"{claim.claim_no} {document_label}已删除。",
claim_id=claim.id,