hl-api-changelog/changelogs-v2/2026-07/29_5342_核单报表取消中间确认并由finalize固化-修改接口-管理后台.md
Mimingguang 3851666575
一些检查失败了
changelog-filename-gate / validate (push) Failing after 1s
chore(changelog): 回写核单接口消费结果
修改原因:#5310、#5320、#5342、#5343 已由管理后台完成消费并通过最终验证。

修改内容:将四份 changelog 标记为 implemented,记录 v2.1 业务提交、目标版本、验证时间和最终契约说明。

实际验证:业务仓库 pnpm checkpoint 全部通过;业务提交 1444fc7f0bf34efaec0ee9f775f7d529b609b847 已推送 origin/v2.1。

Changelog:changelogs-v2/2026-07/28_5310_*;changelogs-v2/2026-07/29_5320_*、5342_*、5343_*。
2026-07-29 20:57:05 +08:00

36 KiB

schema, ticket, title, consumer, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 5342 核单报表取消中间确认并由 finalize 固化 admin 修改接口 deployed verified implemented pi:019fadb7-dac9-74bf-9581-058835251208 1444fc7f0bf34efaec0ee9f775f7d529b609b847 v2.1 2026-07-29T20:43:00+08:00 管理后台已删除两张报表的中间确认调用;finalize 请求结构按后续 #5343 最终契约收口,pnpm checkpoint 全部通过。 2026-07-29 dev-v3

【修改接口·管理后台】核单报表取消中间确认并由 finalize 固化 (#5342)

PR: #5345 | 服务: hl-order-service-v3 | 更新时间: 2026-07-29 13:28

1. 接口背景

核单流程不再要求用户分别确认“主报账人报账表”和“单团核算表”。核单未完成时,两张报表查询接口按当前业务数据实时返回;点击完成核单时,前端一次性提交转账、垫资结清和签字凭证信息,服务端按提交时的当前数据重新计算并固化终态。核单完成后,两张报表查询接口只返回该次完成核单时固化的内容,后续来源数据变化不会改写该终态结果。

变更接口2. 变更清单)

# 接口 方法 路径 变更类型 说明
1 查询主报账人报账表 GET /v3/admin/order/:orderId/settlement/reports/reimbursement 行为修改 未完成核单时实时计算;完成核单后读取终态结果
2 查询单团核算表 GET /v3/admin/order/:orderId/settlement/reports/group 行为修改 未完成核单时实时计算;完成核单后读取终态结果
3 确认主报账人报账表 POST /v3/admin/order/:orderId/settlement/reports/reimbursement/confirm 删除 接口下线,调用返回业务码 404
4 确认单团核算表 POST /v3/admin/order/:orderId/settlement/reports/group/confirm 删除 接口下线,调用返回业务码 404
5 完成核单 POST /v3/admin/order/:orderId/settlement/finalize 请求与行为修改 请求体改为必填;删除两个客户端指纹;新增转账、垫资和签字凭证字段;提交时实时重算并固化终态

3. 接口详情

3.1 查询主报账人报账表

  • 方法 + 路径: GET /v3/admin/order/:orderId/settlement/reports/reimbursement
  • 使用场景: 打开核单报账表或刷新核单数据
  • 认证: 管理后台 JWT;房务角色不可访问
  • 幂等性: 幂等,只读
  • 请求体: 无

路径参数

字段 类型 必填 说明
orderId String/Long 订单 ID,必须大于 0

响应字段

字段 类型 可空 说明
id String 报账表记录 ID;实时报表和终态快照中可为 null
orderId String 订单 ID
reportStatus String 报表状态,见 §6.1
sourceFingerprint String 当前报表来源指纹,仅用于识别数据版本;前端不再回传
primaryReporterId String 主报账人 ID
primaryReporterName String 主报账人姓名
primaryReporterRole String 主报账人角色
reportVersion Integer 报账表结构版本
driverCollectedTailAmount Decimal 主报账人代收尾款
approvedAdvanceAmount Decimal 已审批垫资金额
reportablePaidCostAmount Decimal 可报账的已付成本
reporterNetAmount Decimal 报账人净额;大于 0 表示报账人应转给公司,小于 0 表示公司应转给报账人
primaryReporterCollectedAmount Decimal 主报账人代收金额
publicPrepaidAmount Decimal 公共预支金额
primaryReporterDueAmount Decimal 主报账人应报账金额
advanceOutstandingAmount Decimal 未结清垫资金额
reconNetAmount Decimal 报账净额
transferDirection String 转账方向,见 §6.2
transferAmount Decimal 应转账金额的绝对值
incomeLines Array<Object> 主报账人代收明细,字段见下表
expenseLines Array<Object> 现金已付成本明细,字段随费用分类变化,字段见下表
advanceLines Array<Object> 已审批垫资明细,字段见下表
vehicleLines Array<Object> 车辆独立明细;当前返回空数组,车辆金额已进入费用分类和汇总金额
transferStatus String 未完成核单时为 null;终态为 COMPLETED
transferDate String/date 转账日期,格式 YYYY-MM-DD
transferRef String 转账流水号
advanceSettledFlag Boolean 垫资是否结清
signedVoucher Object 签字凭证;结构同 finalize 请求的 signedVoucher
generatedBy String 历史生成操作人 ID;实时/终态模式下可为 null
generatedByName String 历史生成操作人姓名;实时/终态模式下可为 null
generatedAt String/date-time 历史生成时间;实时/终态模式下可为 null
confirmedBy String 完成核单操作人 ID;未完成核单时为 null
confirmedByName String 完成核单操作人姓名;未完成核单时为 null
confirmedAt String/date-time 完成核单时间;未完成核单时为 null

incomeLines[] 字段

字段 类型 说明
type String 固定为 DRIVER_CASH_RECEIPT
receiptId String 收款记录 ID
amount Decimal 收款金额
channel String 收款渠道;当前参与报账的值为 DRIVER_CASH
payType String/null 支付类型
collectorStaffId String/null 收款人员 ID
collectorName String/null 收款人员姓名
collectorRole String/null 收款人员角色
receivedAt String/date-time/null 收款时间
remark String/null 备注

advanceLines[] 字段

字段 类型 说明
type String 固定为 APPROVED_ADVANCE
advanceId String 垫资记录 ID
payeeStaffId String/null 收款人员 ID
payeeName String/null 收款人员姓名
payeeRole String/null 收款人员角色
advanceType String/null 垫资类型
amount Decimal 已审批金额
purpose String/null 用途
voucherUrl String/null 垫资凭证地址
status String 垫资状态
submittedAt String/date-time/null 提交时间
approvedAt String/date-time/null 审批时间
approvedBy String/null 审批人 ID

expenseLines[] 公共字段

字段 类型 说明
category String 费用分类,见 §6.3
kind String 明细类型,例如 HOTELTICKETMEALVEHICLE_FEESTAFF:DRIVER
amount Decimal 当前行实际成本
paymentMethod String 当前仅包含 CASH_PAID

expenseLines[] 会按 kind 追加以下分类字段:

  • HOTEL: hotelAssignmentIdhotelIdroomTypeIddayNumberstayDatehotelNameroomTyperoomTypeNameroomCountunitPriceplannedCostsourceTypesourceIdvoucherUrlsremark
  • TICKET: sourceTypescenicAssignmentIddayNumberdayDatescenicNamespecNameticketCountticketUnitPricesellPricetotalAmountplannedCostvoucherUrlsremark
  • MEAL: mealTypemealDatemealNamequantityunitPricevoucherUrlsremark
  • VEHICLE_FEE: sourceRecordTypesourceDetailIdserviceDatevehicleIdvehiclePlatevehicleModelIdvehicleModelNamedriverIddriverNamestartDateendDatedailyPricepaymentTypeCodepaymentTypeName
  • STAFF:*: staffRolestaffIdstaffNametotalPlannedCostvoucherUrlsreimbursesettleStatussettledDatetransferRefdetailremark
  • EXPENSE:*: expenseTypeprojectNameexpenseDatevoucherUrlsremark
  • SUBSIDY:*: subsidyTypeprojectNameexpenseDatevoucherUrlsremark

行为

  • 订单不存在当前终态快照时,每次请求均按当前核单数据计算,reportStatus=GENERATED
  • 订单存在当前终态快照时,返回完成核单时固化的报账表,reportStatus=CONFIRMED
  • sourceFingerprint 继续返回,但不再作为任何前端确认或 finalize 入参。

3.2 查询单团核算表

  • 方法 + 路径: GET /v3/admin/order/:orderId/settlement/reports/group
  • 使用场景: 打开单团核算表或刷新核算结果
  • 认证: 管理后台 JWT;房务角色不可访问
  • 幂等性: 幂等,只读
  • 请求体: 无

路径参数

字段 类型 必填 说明
orderId String/Long 订单 ID,必须大于 0

响应字段

字段 类型 可空 说明
id String 单团核算表记录 ID;实时报表和终态快照中可为 null
orderId String 订单 ID
reportStatus String 报表状态,见 §6.1
sourceFingerprint String 当前报表来源指纹,仅用于识别数据版本;前端不再回传
baseOrderAmount Decimal 订单基础金额
otherIncomeAmount Decimal 其他收入金额
discountAmount Decimal 优惠金额
adjustedReceivableAmount Decimal 调整后应收金额
paidAmount Decimal 已收金额
actualRefundedAmount Decimal 实际退款金额
netRevenueAmount Decimal 净收入
netReceivedAmount Decimal 净已收
outstandingAmount Decimal 待收金额
hotelCost Decimal 住宿成本
ticketCost Decimal 门票/游玩项目成本
mealCost Decimal 餐食成本
vehicleCost Decimal 车辆成本
guideCost Decimal 导游/领队成本
photographerCost Decimal 摄影成本
otherExpenseCost Decimal 其他支出成本
insurancePremium Decimal 保险保费
totalCost Decimal 总成本
paidCost Decimal 已付成本
unpaidCost Decimal 未付成本
grossProfit Decimal 毛利
grossProfitRate Decimal 毛利率,小数形式
travelerCount Integer 出行人数
perCapitaRevenue Decimal 人均收入
perCapitaCost Decimal 人均成本
perCapitaProfit Decimal 人均利润
incomeLines Array<Object> 收入汇总行,固定结构见下表
costCategories Array<Object> 成本分类汇总,固定结构见下表
generatedBy String 历史生成操作人 ID;实时/终态模式下可为 null
generatedByName String 历史生成操作人姓名;实时/终态模式下可为 null
generatedAt String/date-time 历史生成时间;实时/终态模式下可为 null
confirmedBy String 完成核单操作人 ID;未完成核单时为 null
confirmedByName String 完成核单操作人姓名;未完成核单时为 null
confirmedAt String/date-time 完成核单时间;未完成核单时为 null

incomeLines[] 字段

字段 类型 说明
type String BASE_ORDEROTHER_INCOMEDISCOUNTACTUAL_REFUND
amount Decimal 金额;优惠和实际退款以负数返回

costCategories[] 字段

字段 类型 说明
category String HOTELTICKETMEALVEHICLEGUIDEPHOTOGRAPHEROTHER_EXPENSEINSURANCE
amount Decimal 分类成本

行为

  • 订单不存在当前终态快照时,每次请求均按当前核单数据计算,reportStatus=GENERATED
  • 订单存在当前终态快照时,返回完成核单时固化的单团核算表,reportStatus=CONFIRMED
  • sourceFingerprint 继续返回,但不再作为任何前端确认或 finalize 入参。

3.3 完成核单

  • 方法 + 路径: POST /v3/admin/order/:orderId/settlement/finalize
  • 使用场景: 用户检查实时主报账表和单团核算表后,点击完成核单
  • 认证: 管理后台 JWT;需要核单资金写权限;房务角色不可访问
  • 幂等性: 已存在当前终态快照时,重复请求返回已有终态结果,不重新生成新终态
  • 限流: 无接口级特殊限流

路径参数

字段 类型 必填 说明
orderId String/Long 订单 ID,必须大于 0

请求体字段

字段 类型 必填 说明 校验规则
remark String 核单整体备注 最多 500 字符
transferDate String/date 条件必填 转账日期 reporterNetAmount != 0 时必填;格式 YYYY-MM-DD
transferRef String 条件必填 转账流水号 reporterNetAmount != 0 时必须为非空字符串;最多 128 字符
advanceSettledFlag Boolean 垫资是否结清;必须明确传 truefalse 不可为 null
signedVoucher Object 签字凭证 不可为 null
signedVoucher.files Array<Object> 签字凭证文件 19 项;重复 URL 按规范化后的 URL 去重并保留首项
signedVoucher.files[].name String 文件名 最多 255 字符
signedVoucher.files[].url String 文件地址 非空;最多 1024 字符;必须是带有效主机名的绝对 http/https URL
signedVoucher.note String 签字凭证备注 最多 500 字符

以下字段已经删除,前端不得继续发送:

删除字段 原类型 迁移方式
reimbursementExpectedSourceFingerprint String 删除本地缓存和提交逻辑;完成核单时不再回传报账表指纹
groupExpectedSourceFingerprint String 删除本地缓存和提交逻辑;完成核单时不再回传单团核算表指纹

响应字段

字段 类型 说明
summaryId String 核单汇总 ID
finalSnapshotId String 核单终态快照 ID
finalSnapshotVersionNo Integer 终态快照版本号,从 1 开始
finalSnapshotStatus String 当前终态固定为 FINALIZED
orderId String 订单 ID
settledAt String/date-time 核单完成时间
totalAmount String/Decimal 订单总金额快照
paidAmount String/Decimal 已付金额快照
balanceAmount String/Decimal 尾款金额快照
roomCost String/Decimal 住宿实际成本
ticketCost String/Decimal 门票实际成本
staffCost String/Decimal 人员费用实际成本
subsidyCost String/Decimal 补助实际成本
mealCost String/Decimal 餐食实际成本
vehicleCost String/Decimal 车辆基础服务总车费
otherExpenseCost String/Decimal 其他支出实际成本
insurancePremium String/Decimal 保险实际保费
totalActualCost String/Decimal 总实际成本
driverTransferAmount String/Decimal 给司机/主报账人转回金额
profitAmount String/Decimal 公司毛利
profitRate Decimal 毛利率;订单总金额为 0 时返回 0
orderStatusAfter String 当前返回 待财务复核
mqTriggered Boolean 当前固定返回 false;完成核单不发布结算 MQ
warnings Array<String> 软预警列表;不阻塞完成核单

提交行为

  1. 前端不再先调用任何报表“确认”接口。
  2. 服务端按提交时的当前核单数据重新计算两张报表和所有汇总金额,不采信前端缓存的金额或指纹。
  3. transferDatetransferRefadvanceSettledFlagsignedVoucher 与本次完成核单结果一并固化。
  4. 成功后,两张 GET 报表接口返回本次固化结果。

3.4 已删除的报表确认接口

以下接口不再有可用请求契约:

原接口 原请求字段 当前结果
POST /v3/admin/order/:orderId/settlement/reports/reimbursement/confirm expectedSourceFingerprinttransferStatustransferDatetransferRefadvanceSettledFlagsignedVoucher 业务码 404
POST /v3/admin/order/:orderId/settlement/reports/group/confirm expectedSourceFingerprint 业务码 404

前端必须删除这两个请求,不要用忽略 404、重试或降级继续调用的方式兼容。

4. 接口入参

4.1 通用路径参数

接口 字段 类型 必填 规则
两张 GET 报表、finalize orderId String/Long 必须大于 0

4.2 请求体变化总览

接口 修改前 修改后
主报账表确认 独立 POST 提交报账表指纹及凭证 接口删除
单团核算表确认 独立 POST 提交单团核算表指纹 接口删除
finalize 请求体可缺省;主要提交两个报告指纹和可选 remark 请求体必填;提交 remarktransferDatetransferRefadvanceSettledFlagsignedVoucher;不再提交任何指纹

5. 出参

5.1 报表查询

  • 两张 GET 接口的字段结构保持不变。
  • 未完成核单时返回最新实时计算结果。
  • 完成核单后返回完成核单时固化的结果。
  • 报表 sourceFingerprint 仍存在于出参,但只表示数据版本,前端不得再将其用于确认或 finalize。

5.2 完成核单

  • finalize 响应字段结构保持 SettlementSubmitRespVO
  • finalSnapshotIdfinalSnapshotVersionNofinalSnapshotStatus 标识本次固化结果。
  • mqTriggered 的当前契约为固定 false,前端不得用该字段判断是否需要等待 MQ。

6. 枚举 / 数据字典

6.1 reportStatus

所属字段: 两张报表响应 reportStatus | 类型: String

中文 当前语义
GENERATED 实时结果 订单未完成核单,响应按当前数据实时计算
CONFIRMED 已固化 订单已完成核单,响应来自终态结果
STALE 历史过期状态 仅兼容历史报表数据;新实时查询流程不要求前端据此重新生成或确认

6.2 transferDirection

所属字段: 主报账人报账表 transferDirection | 类型: String

中文 说明
REPORTER_TO_COMPANY 报账人转给公司 reporterNetAmount > 0
COMPANY_TO_REPORTER 公司转给报账人 reporterNetAmount < 0
BALANCED 已平衡 reporterNetAmount = 0

6.3 报账费用分类

所属字段: expenseLines[].categorycostCategories[].category | 类型: String

中文 说明
HOTEL 住宿 住宿成本
TICKET 门票/游玩项目 门票及游玩项目成本
MEAL 餐食 餐食成本
VEHICLE 车辆 车辆成本
GUIDE 导游/领队 导游及领队成本
PHOTOGRAPHER 摄影 摄影成本
OTHER_EXPENSE 其他支出 其他支出成本
INSURANCE 保险 保险保费;仅用于单团核算表成本分类

6.4 finalSnapshotStatus

所属字段: finalize 响应 finalSnapshotStatus | 类型: String

中文 说明
FINALIZED 已固化 当前核单终态有效

6.5 transferStatus

所属字段: 主报账人报账表 transferStatus | 类型: String/null

中文 说明
COMPLETED 已完成 finalize 成功后固化到终态报账表
null 未固化 尚未完成核单的实时报表

7. 错误码

code 含义 触发场景
400 请求参数校验失败 orderId <= 0、finalize 缺请求体/必填字段、字段超长、凭证文件数量不在 19
403 无访问权限 房务角色或无权访问当前订单
404 接口不存在 继续调用两个已删除的 /confirm 接口
584051 当前核单状态不允许提交结算 review 状态不是待核单或核单中
584056 订单已结算,不能重复提交 已存在结算汇总但缺少可返回的当前终态
584071 无权访问该订单(公司隔离) 当前管理员不能查看该订单
584077 存在未确认的其他收入 finalize 前其他收入未确认
584078 其他收入关联附加费已失效或金额不一致 finalize 前其他收入与当前附加费不一致
584079 存在未纳入核单分类的有效附加费 finalize 前还有有效附加费未进入核单
584081 对账数据不一致 已付金额与有效支付、线下收款合计不一致
584082 存在待收尾款 单团核算 outstandingAmount != 0
584085 存在辅助人员结算未完成 辅助人员未全部完成结算或缺转账流水
584092 存在未确认的人员费用 人员费用确认状态未全部完成
584097 凭证 URL 格式或数量不合法 URL 不是有效绝对 http/https 地址、为空、过长或数量超限
584100 车辆总车费暂时不可用 报表查询或 finalize 暂时无法取得车辆费用
584101 存在未完结派车或未确认车辆总车费 当前车辆数据尚不能用于核单
584102 当前用车需求没有可核单的车辆总车费 有用车需求但没有可用车辆费用
584315 核单来源数据已变化,请刷新后重新确认 finalize 提交期间当前用车需求发生变化
584316 核单报告发生并发变化,请刷新后重试 同一订单并发完成核单发生冲突
584317 当前报告状态不允许执行该操作 报账人净额非 0 但缺转账日期/流水,或签字凭证不可用
584320 核单分类明细尚未保存完整 当前分类数据不能用于报账和 finalize

验证证据8. 示例)

8.1 典型成功:查询实时主报账人报账表

请求

GET /v3/admin/order/1914050000000001/settlement/reports/reimbursement
Authorization: Bearer <admin-jwt>

无请求体。

响应

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": null,
    "orderId": "1914050000000001",
    "reportStatus": "GENERATED",
    "sourceFingerprint": "7a0e84a9f9d0cb411f9cff8d6a0d1c047726bb05b68c8e23af5629afdbdd67c1",
    "primaryReporterId": "3001",
    "primaryReporterName": "示例报账人",
    "primaryReporterRole": "DRIVER",
    "reportVersion": 1,
    "driverCollectedTailAmount": 2000.00,
    "approvedAdvanceAmount": 500.00,
    "reportablePaidCostAmount": 1200.00,
    "reporterNetAmount": 1300.00,
    "primaryReporterCollectedAmount": 2000.00,
    "publicPrepaidAmount": 1200.00,
    "primaryReporterDueAmount": 800.00,
    "advanceOutstandingAmount": 500.00,
    "reconNetAmount": 1300.00,
    "transferDirection": "REPORTER_TO_COMPANY",
    "transferAmount": 1300.00,
    "incomeLines": [
      {
        "type": "DRIVER_CASH_RECEIPT",
        "receiptId": "9100000000001",
        "amount": 2000.00,
        "channel": "DRIVER_CASH",
        "payType": "CASH",
        "collectorStaffId": "3001",
        "collectorName": "示例报账人",
        "collectorRole": "DRIVER",
        "receivedAt": "2026-07-28T15:30:00",
        "remark": "示例代收尾款"
      }
    ],
    "expenseLines": [
      {
        "category": "HOTEL",
        "kind": "HOTEL",
        "hotelAssignmentId": "9200000000001",
        "hotelId": "1001",
        "roomTypeId": "2001",
        "dayNumber": 1,
        "stayDate": "2026-07-20",
        "hotelName": "示例酒店",
        "roomType": "STANDARD",
        "roomTypeName": "标准间",
        "roomCount": 2,
        "unitPrice": 300.00,
        "plannedCost": 600.00,
        "amount": 600.00,
        "paymentMethod": "CASH_PAID",
        "sourceType": "HOUSE_ASSIGNMENT",
        "sourceId": "9200000000001",
        "voucherUrls": ["https://oss.example.com/vouchers/hotel-1.pdf"],
        "remark": null
      }
    ],
    "advanceLines": [
      {
        "type": "APPROVED_ADVANCE",
        "advanceId": "9300000000001",
        "payeeStaffId": "3001",
        "payeeName": "示例报账人",
        "payeeRole": "DRIVER",
        "advanceType": "PUBLIC",
        "amount": 500.00,
        "purpose": "行程公共支出",
        "voucherUrl": "https://oss.example.com/vouchers/advance-1.pdf",
        "status": "APPROVED",
        "submittedAt": "2026-07-19T10:00:00",
        "approvedAt": "2026-07-19T11:00:00",
        "approvedBy": "10001"
      }
    ],
    "vehicleLines": [],
    "transferStatus": null,
    "transferDate": null,
    "transferRef": null,
    "advanceSettledFlag": null,
    "signedVoucher": null,
    "generatedBy": null,
    "generatedByName": null,
    "generatedAt": null,
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  }
}

8.2 典型成功:查询实时单团核算表

请求

GET /v3/admin/order/1914050000000001/settlement/reports/group
Authorization: Bearer <admin-jwt>

无请求体。

响应

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": null,
    "orderId": "1914050000000001",
    "reportStatus": "GENERATED",
    "sourceFingerprint": "651cb6708a49f169e2ccb1b455267def9cc1a69d06935f9d9eeb41919897e0fb",
    "baseOrderAmount": 24800.00,
    "otherIncomeAmount": 500.00,
    "discountAmount": 300.00,
    "adjustedReceivableAmount": 25000.00,
    "paidAmount": 25000.00,
    "actualRefundedAmount": 0.00,
    "netRevenueAmount": 25000.00,
    "netReceivedAmount": 25000.00,
    "outstandingAmount": 0.00,
    "hotelCost": 4280.00,
    "ticketCost": 3680.00,
    "mealCost": 860.00,
    "vehicleCost": 1260.00,
    "guideCost": 800.00,
    "photographerCost": 600.00,
    "otherExpenseCost": 300.00,
    "insurancePremium": 180.00,
    "totalCost": 11960.00,
    "paidCost": 11960.00,
    "unpaidCost": 0.00,
    "grossProfit": 13040.00,
    "grossProfitRate": 0.521600,
    "travelerCount": 5,
    "perCapitaRevenue": 5000.00,
    "perCapitaCost": 2392.00,
    "perCapitaProfit": 2608.00,
    "incomeLines": [
      {
        "type": "BASE_ORDER",
        "amount": 24800.00
      },
      {
        "type": "OTHER_INCOME",
        "amount": 500.00
      },
      {
        "type": "DISCOUNT",
        "amount": -300.00
      },
      {
        "type": "ACTUAL_REFUND",
        "amount": 0.00
      }
    ],
    "costCategories": [
      {
        "category": "HOTEL",
        "amount": 4280.00
      },
      {
        "category": "TICKET",
        "amount": 3680.00
      },
      {
        "category": "MEAL",
        "amount": 860.00
      },
      {
        "category": "VEHICLE",
        "amount": 1260.00
      },
      {
        "category": "GUIDE",
        "amount": 800.00
      },
      {
        "category": "PHOTOGRAPHER",
        "amount": 600.00
      },
      {
        "category": "OTHER_EXPENSE",
        "amount": 300.00
      },
      {
        "category": "INSURANCE",
        "amount": 180.00
      }
    ],
    "generatedBy": null,
    "generatedByName": null,
    "generatedAt": null,
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  }
}

8.3 典型成功:完成核单并固化

请求

POST /v3/admin/order/1914050000000001/settlement/finalize
Authorization: Bearer <admin-jwt>
Content-Type: application/json

{
  "remark": "核单完成",
  "transferDate": "2026-07-29",
  "transferRef": "BANK-20260729-001",
  "advanceSettledFlag": true,
  "signedVoucher": {
    "files": [
      {
        "name": "签字单.pdf",
        "url": "https://oss.example.com/vouchers/signed-20260729.pdf"
      }
    ],
    "note": "签字凭证已回收"
  }
}

响应

{
  "code": 200,
  "msg": "success",
  "data": {
    "summaryId": "9400000000001",
    "finalSnapshotId": "9400000000002",
    "finalSnapshotVersionNo": 1,
    "finalSnapshotStatus": "FINALIZED",
    "orderId": "1914050000000001",
    "settledAt": "2026-07-29T13:28:22",
    "totalAmount": "25000.00",
    "paidAmount": "25000.00",
    "balanceAmount": "0.00",
    "roomCost": "4280.00",
    "ticketCost": "3680.00",
    "staffCost": "1400.00",
    "subsidyCost": "0.00",
    "mealCost": "860.00",
    "vehicleCost": "1260.00",
    "otherExpenseCost": "300.00",
    "insurancePremium": "180.00",
    "totalActualCost": "11960.00",
    "driverTransferAmount": "11780.00",
    "profitAmount": "13040.00",
    "profitRate": 0.5216,
    "orderStatusAfter": "待财务复核",
    "mqTriggered": false,
    "warnings": []
  }
}

8.4 边界:报账人净额为 0

当最新 reporterNetAmount=0 时,transferDatetransferRef 可以省略;advanceSettledFlagsignedVoucher 仍必须提交。

请求

POST /v3/admin/order/1914050000000002/settlement/finalize
Authorization: Bearer <admin-jwt>
Content-Type: application/json

{
  "remark": "收支已平衡",
  "advanceSettledFlag": false,
  "signedVoucher": {
    "files": [
      {
        "name": "签字单.jpg",
        "url": "https://oss.example.com/vouchers/signed-balanced.jpg"
      }
    ]
  }
}

响应

{
  "code": 200,
  "msg": "success",
  "data": {
    "summaryId": "9400000000011",
    "finalSnapshotId": "9400000000012",
    "finalSnapshotVersionNo": 1,
    "finalSnapshotStatus": "FINALIZED",
    "orderId": "1914050000000002",
    "settledAt": "2026-07-29T13:40:00",
    "totalAmount": "0.00",
    "paidAmount": "0.00",
    "balanceAmount": "0.00",
    "roomCost": "0.00",
    "ticketCost": "0.00",
    "staffCost": "0.00",
    "subsidyCost": "0.00",
    "mealCost": "0.00",
    "vehicleCost": "0.00",
    "otherExpenseCost": "0.00",
    "insurancePremium": "0.00",
    "totalActualCost": "0.00",
    "driverTransferAmount": "0.00",
    "profitAmount": "0.00",
    "profitRate": 0,
    "orderStatusAfter": "待财务复核",
    "mqTriggered": false,
    "warnings": []
  }
}

8.5 异常:仍调用已删除的确认接口

请求

POST /v3/admin/order/1914050000000001/settlement/reports/group/confirm
Authorization: Bearer <admin-jwt>
Content-Type: application/json

{
  "expectedSourceFingerprint": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}

响应

{
  "code": 404,
  "msg": "请求地址不存在",
  "data": null
}

8.6 异常:车辆费用尚未可核单

请求

POST /v3/admin/order/1914050000000001/settlement/finalize
Authorization: Bearer <admin-jwt>
Content-Type: application/json

{
  "transferDate": "2026-07-29",
  "transferRef": "BANK-20260729-001",
  "advanceSettledFlag": true,
  "signedVoucher": {
    "files": [
      {
        "name": "签字单.pdf",
        "url": "https://oss.example.com/vouchers/signed-20260729.pdf"
      }
    ]
  }
}

响应

{
  "code": 584101,
  "msg": "存在未完结派车或未确认车辆总车费,暂不能核单",
  "data": null
}

9. 业务边界

  • 报表 GET 的“实时”以每次请求时可用于核单的当前数据为准,前端不要把上一次响应当作提交凭据。
  • 完成核单前,前端可以重复查询两张报表;无需执行任何“生成”或“确认”步骤。
  • finalize 不接收前端金额。页面展示金额与提交时权威数据发生变化时,以提交时重新计算结果为准。
  • 报账人净额不为 0 时,必须同时提交 transferDate 和非空 transferRef
  • signedVoucher.files 原始数组必须为 19 项;URL 会去除首尾空格、规范化并按 URL 去重。
  • 完成核单成功后,两张报表进入终态读取;只有业务上的核单反确认使当前终态失效后,查询才重新进入实时模式。
  • finalize 成功响应中的 warnings 是软预警,不表示提交失败。
  • 已有当前终态时重复调用 finalize 返回已有终态,不会依据本次请求改写已固化的转账或凭证信息。

10. 修改前后对比

10.1 字段级对比

接口/字段 修改前 修改后
finalize 请求体 可缺省 必填
remark 可选,最多 500 字符 保持不变
reimbursementExpectedSourceFingerprint finalize 必填 删除
groupExpectedSourceFingerprint finalize 必填 删除
transferDate 在主报账表确认接口提交 移至 finalize;报账人净额非 0 时必填
transferRef 在主报账表确认接口提交 移至 finalize;报账人净额非 0 时必填,最多 128 字符
advanceSettledFlag 在主报账表确认接口提交 移至 finalize,必填
signedVoucher 在主报账表确认接口提交 移至 finalize,必填
signedVoucher.files 原确认接口字段 finalize 中要求 19 项
signedVoucher.files[].name 原确认接口未明确长度 最多 255 字符
signedVoucher.files[].url 原确认接口未明确长度 必填;最多 1024 字符;绝对 http/https URL
signedVoucher.note 原确认接口未明确长度 最多 500 字符
mqTriggered 示例和历史说明可能按 true 理解 当前固定 false

10.2 行为级对比

行为 修改前 修改后
主报账表 先读取,再调用独立 confirm GET 实时读取;不再确认
单团核算表 主报账表确认后再读取并 confirm GET 实时读取;不再确认
数据变化处理 前端携带两张报表指纹,指纹过期时刷新重试 前端不携带指纹;finalize 按提交时数据重算
转账/垫资/签字信息 主报账表 confirm 时提交 finalize 时一次提交
完成核单后查询 依赖已确认报表记录 返回完成核单时固化的终态结果
重复 finalize 依赖旧报告确认门禁 已有当前终态时返回已有结果

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容: 是。两个 POST 确认接口删除,finalize 请求字段和必填规则改变。
  • 前端是否必须同步调整: 是。旧页面继续调用 /confirm 会收到业务码 404;旧 finalize 请求缺少新必填字段会收到业务码 400
  • 查询字段兼容性: 两张 GET 报表的顶层字段结构保持不变,但数据时效语义变为“未终态实时、终态固定”。

11.2 回滚说明

  • 如果接口契约回滚,前端需要同步恢复两次确认请求和两个指纹字段。
  • 前后端不能混用新旧流程:新版前端不再保留报表确认指纹,旧版后端仍会要求指纹和独立确认。

12. 注意事项

  • 删除“确认主报账表”“确认单团核算表”按钮、请求封装、loading 状态、重试逻辑和指纹缓存。
  • 页面展示仍调用两个 GET 接口;无需在详情加载时调用任何写接口。
  • “完成核单”按钮直接提交 finalize 新请求体。
  • 不要把 GET 返回的 sourceFingerprint 填回 finalize。
  • 不要继续发送已删除字段;即使服务端当前可能忽略未知 JSON 字段,前端类型和请求对象也应删除。
  • signedVoucher 不是可选附件:至少需要一个有效 URL。
  • mqTriggered=false 是当前固定契约,不要显示“MQ 触发失败”或据此轮询。

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人: @yst
  • 消费端: v3 管理后台