hl-api-changelog/changelogs-v2/2026-07/29_5343_核单确认收口到完成核单-修改接口-管理后台.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

35 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 5343 核单确认收口到完成核单 admin 修改接口 deployed verified implemented pi:019fadb7-dac9-74bf-9581-058835251208 1444fc7f0bf34efaec0ee9f775f7d529b609b847 v2.1 2026-07-29T20:43:00+08:00 管理后台已删除旧报表 confirm 流程,完成核单改为提交双指纹与嵌套 reimbursementConfirmation;pnpm checkpoint 全部通过。 2026-07-29 dev-v3

⚠️【修改接口·管理后台】核单确认收口到完成核单 (#5343)

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

1. 接口背景

主报账表和单团核算表不再各自提供“确认”写操作。页面先通过两张 GET 报表取得同一轮核单事实对应的两个 sourceFingerprint,再由“完成核单”一次提交双指纹、转账信息、预支处理标志和签字凭证。

本文纠正并取代 29_5342_核单报表取消中间确认并由finalize固化-修改接口-管理后台.md 中关于 finalize 请求的说明:双指纹没有删除,仍是 finalize 必填字段;转账与凭证字段必须放在必填的 reimbursementConfirmation 对象内。

2. 变更清单

# 接口 方法 路径 变更类型 说明
1 查询主报账表 GET /v3/admin/order/{orderId}/settlement/reports/reimbursement 行为明确 返回主报账数据及 sourceFingerprint,该指纹必须回传给 finalize
2 查询单团核算表 GET /v3/admin/order/{orderId}/settlement/reports/group 行为明确 返回单团核算数据及 sourceFingerprint,该指纹必须回传给 finalize
3 完成核单 POST /v3/admin/order/{orderId}/settlement/finalize 请求与行为修改 必填双指纹和嵌套 reimbursementConfirmation;成功后一次完成核单
4 确认主报账表 POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/confirm 删除接口 路由继续保持删除,不得调用
5 确认单团核算表 POST /v3/admin/order/{orderId}/settlement/reports/group/confirm 删除接口 路由继续保持删除,不得调用

3. 接口详情

3.1 查询主报账表

  • 方法与路径GET /v3/admin/order/{orderId}/settlement/reports/reimbursement
  • 使用场景:展示主报账表,并在调用 finalize 前取得最新主报账指纹
  • 认证:管理后台 JWT;房务角色不可访问
  • 幂等性:幂等,只读
  • 限流:无接口级特殊限流

路径参数

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

请求体

无。

响应字段

data 字段 JSON 类型 可空 说明
id string 报账表记录 ID
orderId string 订单 ID
reportStatus string 报表状态,见 §6.1
sourceFingerprint string 64 位小写十六进制 SHA-256;传给 finalize 的 reimbursementExpectedSourceFingerprint
primaryReporterId string 主报账人 ID
primaryReporterName string 主报账人姓名
primaryReporterRole string 主报账人角色
reportVersion integer 报账表结构版本
driverCollectedTailAmount number 主报账人代收尾款
approvedAdvanceAmount number 已审批预支金额
reportablePaidCostAmount number 可报账的已付成本
reporterNetAmount number 主报账人净额;决定转账日期和流水是否必填
primaryReporterCollectedAmount number 主报账人代收金额
publicPrepaidAmount number 公共预支金额
primaryReporterDueAmount number 主报账人应报账金额
advanceOutstandingAmount number 未结清预支金额
reconNetAmount number 报账净额
transferDirection string 转账方向,见 §6.2
transferAmount number 应转账金额的绝对值
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 的凭证一致
generatedBy string 历史生成操作人 ID
generatedByName string 历史生成操作人姓名
generatedAt string(date-time) 历史生成时间
confirmedBy string 完成核单操作人 ID
confirmedByName string 完成核单操作人姓名
confirmedAt string(date-time) 完成核单时间

incomeLines[] 字段

字段 类型 说明
type string 当前为 DRIVER_CASH_RECEIPT
receiptId string 收款记录 ID
amount number 收款金额
channel string 收款渠道
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 number 已审批金额
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 number 当前行实际成本
paymentMethod string 当前报账明细使用 CASH_PAID

不同 kind 还会携带相应业务字段:

  • HOTELhotelAssignmentIdhotelIdroomTypeIddayNumberstayDatehotelNameroomTyperoomTypeNameroomCountunitPriceplannedCostsourceTypesourceIdvoucherUrlsremark
  • TICKETsourceTypescenicAssignmentIddayNumberdayDatescenicNamespecNameticketCountticketUnitPricesellPricetotalAmountplannedCostvoucherUrlsremark
  • MEALmealTypemealDatemealNamequantityunitPricevoucherUrlsremark
  • VEHICLE_FEEsourceRecordTypesourceDetailIdserviceDatevehicleIdvehiclePlatevehicleModelIdvehicleModelNamedriverIddriverNamestartDateendDatedailyPricepaymentTypeCodepaymentTypeName
  • STAFF:*staffRolestaffIdstaffNametotalPlannedCostvoucherUrlsreimbursesettleStatussettledDatetransferRefdetailremark
  • EXPENSE:*expenseTypeprojectNameexpenseDatevoucherUrlsremark
  • SUBSIDY:*subsidyTypeprojectNameexpenseDatevoucherUrlsremark

错误与业务边界

  • orderId <= 0 返回 400
  • 房务角色或无订单访问权限返回 403/对应订单访问错误。
  • 未完成核单时返回当前核单事实的实时视图和当前指纹。
  • 已完成核单时返回当前有效终态版本中的报账表和该版本指纹。
  • 管理员反确认后再次 GET 会回到实时视图;前端必须重新取得指纹。

典型请求

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

无请求体。

典型响应

{
  "code": 200,
  "message": "成功",
  "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": [],
    "expenseLines": [],
    "advanceLines": [],
    "vehicleLines": [],
    "transferStatus": null,
    "transferDate": null,
    "transferRef": null,
    "advanceSettledFlag": null,
    "signedVoucher": null,
    "generatedBy": null,
    "generatedByName": null,
    "generatedAt": null,
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  },
  "traceId": "a1b2c3d4-e5f6-7890",
  "success": true
}

3.2 查询单团核算表

  • 方法与路径GET /v3/admin/order/{orderId}/settlement/reports/group
  • 使用场景:展示单团核算表,并在调用 finalize 前取得最新单团指纹
  • 认证:管理后台 JWT;房务角色不可访问
  • 幂等性:幂等,只读
  • 限流:无接口级特殊限流

路径参数

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

请求体

无。

响应字段

data 字段 JSON 类型 可空 说明
id string 单团核算表记录 ID
orderId string 订单 ID
reportStatus string 报表状态,见 §6.1
sourceFingerprint string 64 位小写十六进制 SHA-256;传给 finalize 的 groupExpectedSourceFingerprint
baseOrderAmount number 订单基础金额
otherIncomeAmount number 其他收入金额
discountAmount number 优惠金额
adjustedReceivableAmount number 调整后应收金额
paidAmount number 已收金额
actualRefundedAmount number 实际退款金额
netRevenueAmount number 净收入
netReceivedAmount number 净已收
outstandingAmount number 待收金额;不为 0 时不能 finalize
hotelCost number 住宿成本
ticketCost number 门票/游玩项目成本
mealCost number 餐食成本
vehicleCost number 车辆成本
guideCost number 导游/领队成本
photographerCost number 摄影成本
otherExpenseCost number 其他支出成本
insurancePremium number 保险保费
totalCost number 总成本
paidCost number 已付成本
unpaidCost number 未付成本
grossProfit number 毛利
grossProfitRate number 毛利率,小数形式
travelerCount integer 出行人数
perCapitaRevenue number 人均收入
perCapitaCost number 人均成本
perCapitaProfit number 人均利润
incomeLines array<object> 收入汇总行
costCategories array<object> 成本分类汇总
generatedBy string 历史生成操作人 ID
generatedByName string 历史生成操作人姓名
generatedAt string(date-time) 历史生成时间
confirmedBy string 完成核单操作人 ID
confirmedByName string 完成核单操作人姓名
confirmedAt string(date-time) 完成核单时间

incomeLines[] 字段

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

costCategories[] 字段

字段 类型 说明
category string HOTELTICKETMEALVEHICLEGUIDEPHOTOGRAPHEROTHER_EXPENSEINSURANCE
amount number 分类成本

错误与业务边界

  • orderId <= 0 返回 400
  • 房务角色或无订单访问权限返回 403/对应订单访问错误。
  • 未完成核单时返回实时视图;已完成核单时返回当前有效终态版本。
  • 管理员反确认后,下一次 GET 会生成新的实时结果和指纹。

典型请求

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

无请求体。

典型响应

{
  "code": 200,
  "message": "成功",
  "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": 5200.00,
    "guideCost": 800.00,
    "photographerCost": 600.00,
    "otherExpenseCost": 1200.00,
    "insurancePremium": 180.00,
    "totalCost": 16800.00,
    "paidCost": 16800.00,
    "unpaidCost": 0.00,
    "grossProfit": 8200.00,
    "grossProfitRate": 0.328,
    "travelerCount": 5,
    "perCapitaRevenue": 5000.00,
    "perCapitaCost": 3360.00,
    "perCapitaProfit": 1640.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": 5200.00},
      {"category": "GUIDE", "amount": 800.00},
      {"category": "PHOTOGRAPHER", "amount": 600.00},
      {"category": "OTHER_EXPENSE", "amount": 1200.00},
      {"category": "INSURANCE", "amount": 180.00}
    ],
    "generatedBy": null,
    "generatedByName": null,
    "generatedAt": null,
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  },
  "traceId": "a1b2c3d4-e5f6-7890",
  "success": true
}

3.3 完成核单

  • 方法与路径POST /v3/admin/order/{orderId}/settlement/finalize
  • 使用场景:两张报表核对完成后,一次提交双指纹和主报账凭据
  • 认证:管理后台 JWT;房务角色不可访问
  • 幂等性:严格幂等,比较双指纹、规范化后的凭据和 remark
  • 限流:无接口级特殊限流

路径参数

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

请求体字段

字段 JSON 类型 必填 校验与规范化
remark string/null 最长 500;去除首尾空格,空串按 null 比较
reimbursementExpectedSourceFingerprint string 必须等于主报账 GET 返回的 64 位小写十六进制 sourceFingerprint
groupExpectedSourceFingerprint string 必须等于单团 GET 返回的 64 位小写十六进制 sourceFingerprint
reimbursementConfirmation object 主报账转账、预支和签字凭据
reimbursementConfirmation.transferDate string(date)/null 条件必填 reporterNetAmount != 0 时必填;净额为 0 时可为 null
reimbursementConfirmation.transferRef string/null 条件必填 去除首尾空格后最长 128;净额非 0 时长度必须为 1128
reimbursementConfirmation.advanceSettledFlag boolean 必须明确传值,false 合法
reimbursementConfirmation.signedVoucher object 缺失返回 400
reimbursementConfirmation.signedVoucher.files array<object> 业务必填 19 项;为 null、空数组、超过 9 项或含 null 项返回 584317
reimbursementConfirmation.signedVoucher.files[].url string 业务必填 去除首尾空格后长度 11024;不符合返回 584317
reimbursementConfirmation.signedVoucher.files[].name string/null 去除首尾空格;空串归一化为 null;非空最长 255
reimbursementConfirmation.signedVoucher.note string/null 去除首尾空格;空串归一化为 null;非空最长 500

transferStatus 不得提交。finalize 成功后,报账终态中的 transferStatus 固定为 COMPLETED

签字凭证文件按规范化后的 urlname 升序稳定保存。不得依赖请求数组原顺序进行严格幂等判断。

响应字段

data 字段 JSON 类型 说明
summaryId string 核单汇总 ID
finalSnapshotId string 核单终态快照 ID
finalSnapshotVersionNo integer 终态版本号;首次为 1,反确认后再次 finalize 为上一版本 + 1
finalSnapshotStatus string 成功固定为 FINALIZED
orderId string 订单 ID
settledAt string(date-time) ISO-8601 核单完成时间
totalAmount string 订单总金额快照
paidAmount string 已付金额快照
balanceAmount string 尾款金额快照
roomCost string 住宿实际成本
ticketCost string 门票实际成本
staffCost string 人员费用实际成本
subsidyCost string 补助实际成本
mealCost string 餐食实际成本
vehicleCost string 车辆成本
otherExpenseCost string 其他支出实际成本
insurancePremium string 保险实际保费
totalActualCost string 总实际成本
driverTransferAmount string 给司机/主报账人转回金额
profitAmount string 公司毛利
profitRate number 毛利率;订单总金额为 0 时为 0
orderStatusAfter string 成功后为 待财务复核
mqTriggered boolean 当前固定为 false
warnings array<string> 软预警列表;无预警为 []

错误与业务边界

  • 缺 body、非法 JSON、remark 超长、双指纹格式错误,或缺少 reimbursementConfirmationadvanceSettledFlagsignedVoucher:返回 400
  • 双指纹任一与当前冻结事实不一致:返回 584315,须重新 GET 两张报表。
  • transferRef 条件不满足或超过 128,凭证 files/文件项/url 无效,或 name/note 超长:返回 584317
  • 单团核算的 outstandingAmount != 0:返回 584082,不能完成核单。
  • 完全相同的终态请求重试返回原 summaryIdfinalSnapshotId 和版本号,不产生新版本。
  • 已有当前终态时,双指纹、规范化凭据或 remark 任一不同:返回 584316
  • 任一失败不留下部分完成结果。

典型请求:净报账金额非 0

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

{
  "remark": "主报账人与单团核算均已核对",
  "reimbursementExpectedSourceFingerprint": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "groupExpectedSourceFingerprint": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
  "reimbursementConfirmation": {
    "transferDate": "2026-07-29",
    "transferRef": "FT202607290001",
    "advanceSettledFlag": false,
    "signedVoucher": {
      "files": [
        {
          "name": "司机签字报账单.pdf",
          "url": "https://oss.example.com/settlement/driver-signed-20260729.pdf"
        }
      ],
      "note": "司机现场签字后上传"
    }
  }
}

典型响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "summaryId": "9600000000001",
    "finalSnapshotId": "9600000000002",
    "finalSnapshotVersionNo": 1,
    "finalSnapshotStatus": "FINALIZED",
    "orderId": "1914050000000001",
    "settledAt": "2026-07-29T10:30:25",
    "totalAmount": "24800.00",
    "paidAmount": "24800.00",
    "balanceAmount": "0.00",
    "roomCost": "4280.00",
    "ticketCost": "3680.00",
    "staffCost": "7000.00",
    "subsidyCost": "720.00",
    "mealCost": "860.00",
    "vehicleCost": "5200.00",
    "otherExpenseCost": "1200.00",
    "insurancePremium": "180.00",
    "totalActualCost": "23120.00",
    "driverTransferAmount": "22940.00",
    "profitAmount": "1680.00",
    "profitRate": 0.0677,
    "orderStatusAfter": "待财务复核",
    "mqTriggered": false,
    "warnings": []
  },
  "traceId": "a1b2c3d4-e5f6-7890",
  "success": true
}

边界请求:reporterNetAmount = 0

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

{
  "remark": null,
  "reimbursementExpectedSourceFingerprint": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "groupExpectedSourceFingerprint": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
  "reimbursementConfirmation": {
    "transferDate": null,
    "transferRef": null,
    "advanceSettledFlag": false,
    "signedVoucher": {
      "files": [
        {
          "name": null,
          "url": "https://oss.example.com/settlement/zero-net-signed.jpg"
        }
      ],
      "note": null
    }
  }
}

边界响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "summaryId": "9600000000011",
    "finalSnapshotId": "9600000000012",
    "finalSnapshotVersionNo": 1,
    "finalSnapshotStatus": "FINALIZED",
    "orderId": "1914050000000002",
    "settledAt": "2026-07-29T10:35: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": []
  },
  "traceId": "a1b2c3d4-e5f6-7890",
  "success": true
}

异常请求:凭证包含空 URL

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

{
  "reimbursementExpectedSourceFingerprint": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "groupExpectedSourceFingerprint": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
  "reimbursementConfirmation": {
    "transferDate": "2026-07-29",
    "transferRef": "FT202607290001",
    "advanceSettledFlag": true,
    "signedVoucher": {
      "files": [
        {"name": "签字单.pdf", "url": "   "}
      ]
    }
  }
}

异常响应

{
  "code": 584317,
  "message": "当前报告状态不允许执行该操作",
  "data": null,
  "traceId": "a1b2c3d4-e5f6-7890",
  "success": false
}

异常请求:缺少 signedVoucher

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

{
  "reimbursementExpectedSourceFingerprint": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "groupExpectedSourceFingerprint": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
  "reimbursementConfirmation": {
    "transferDate": "2026-07-29",
    "transferRef": "FT202607290001",
    "advanceSettledFlag": true
  }
}

异常响应

{
  "code": 400,
  "message": "参数校验失败",
  "data": null,
  "traceId": "a1b2c3d4-e5f6-7890",
  "success": false
}

3.4 已删除:确认主报账表

  • 原方法与路径POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/confirm
  • 当前契约:接口已删除,无有效请求体或成功响应。
  • 前端动作删除请求封装、按钮、loading、重试和错误忽略逻辑。

请求示例

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

{}

响应示例

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

3.5 已删除:确认单团核算表

  • 原方法与路径POST /v3/admin/order/{orderId}/settlement/reports/group/confirm
  • 当前契约:接口已删除,无有效请求体或成功响应。
  • 前端动作删除请求封装、按钮、loading、重试和错误忽略逻辑。

请求示例

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

{}

响应示例

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

4. 接口入参汇总

接口 入参
主报账 GET 路径参数 orderId;无请求体
单团 GET 路径参数 orderId;无请求体
finalize 路径参数 orderId;请求体必须包含两个指纹及 reimbursementConfirmation
两个旧 confirm 已删除,无有效入参

双指纹映射必须严格如下:

来源 finalize 字段
主报账 GET 的 data.sourceFingerprint reimbursementExpectedSourceFingerprint
单团 GET 的 data.sourceFingerprint groupExpectedSourceFingerprint

5. 出参汇总

  • 两张 GET 均返回 Result<报表对象>,其中 sourceFingerprint 是 finalize 的提交凭据。
  • finalize 返回 Result<SettlementSubmitRespVO>,完整字段见 §3.3。
  • 两个旧 confirm 不再返回业务成功响应,只会命中不存在的路由。
  • 金额序列化以各字段表和示例为准finalize 的金额字段为字符串,两张 GET 的金额字段为 JSON number。

6. 枚举 / 数据字典

6.1 reportStatus

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

中文 说明
GENERATED 实时结果 当前不存在有效终态,按当前核单事实计算
CONFIRMED 已固化 返回当前有效终态版本中的报表
STALE 历史过期 兼容历史报表状态,不用于当前 finalize

6.2 transferDirection

所属字段:主报账响应 transferDirection | 类型string

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

6.3 category

所属字段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 尚未固化 实时报表可为空

transferStatus 只出现在响应中,不是 finalize 入参。

7. 错误码

code 含义 触发场景
400 请求/参数校验失败 orderId <= 0、缺请求体、非法 JSON、双指纹格式错误、缺 reimbursementConfirmation/advanceSettledFlag/signedVoucherremark 超长
403 无访问权限 房务角色或无权访问当前订单
404 路由不存在 调用两个已删除的报表 confirm 接口
584082 存在待收尾款 单团核算 outstandingAmount != 0
584100 车辆费用暂时不可用 报表查询或 finalize 当前无法取得可核单车辆费用
584101 车辆事实未完成 存在未完结派车或未确认车辆费用
584102 缺少车辆费用 有用车需求但没有可核单车辆费用
584315 核单来源数据已变化 车辆候选与冻结事实不一致,或任一双指纹过期
584316 并发或严格幂等冲突 终态重试请求不同、并发完成/反确认冲突
584317 转账条件或签字凭证不合法 净额非 0 缺日期/流水、流水超长、files/文件项/url 无效、name/note 超长
584320 核单明细未准备好 当前分类数据不能用于报账或 finalize
584321 缺少当前终态 后续财务复核缺少 current FINALIZED 终态
584325 双指纹兜底校验失败 finalize 发现双指纹不完整或不合法
584326 终态组合不一致 当前终态、关联汇总或订单终态不匹配

8. 示例索引

场景 位置
主报账 GET 典型请求与响应 §3.1
单团 GET 典型请求与响应 §3.2
finalize 净额非 0 典型成功 §3.3
finalize 净额为 0 合法边界 §3.3
finalize 凭证 URL 非法返回 584317 §3.3
finalize 缺 signedVoucher 返回 400 §3.3
两个旧 confirm 返回 404 §3.4、§3.5

9. 业务边界

  • 必须先分别 GET 两张报表,再把两个 sourceFingerprint 一一映射到 finalize;不能复用旧指纹、互换字段或只传一个。
  • 任一核单事实变化后,旧双指纹都会失效;收到 584315 后必须重新 GET 两张表。
  • outstandingAmount 必须为 0 才能 finalize。
  • reporterNetAmount != 0 时,transferDate 和非空 transferRef 同时必填;净额为 0 时二者可为 null
  • advanceSettledFlag=false 是有效业务值,不等同于缺失。
  • signedVoucher 始终必填,且 files 必须有 19 个合法文件项。
  • 完全相同请求重试严格幂等;任何双指纹、规范化凭据或 remark 差异均返回 584316
  • 管理员反确认使当前终态失效后,两张 GET 重新返回实时结果;再次 finalize 必须使用新双指纹,成功响应的 finalSnapshotVersionNo 为上一版本 + 1。
  • finalize 成功后订单进入“待财务复核”。既有财务复核接口 POST /v3/admin/order/{orderId}/settlement/confirm 的请求/响应结构未在本次变更:请求仅含可选 confirmRemark;当前没有独立财务角色校验;成功 dataorderIdsettlementStatus=COMPLETEDsettledAtflowStatus=SETTLED。其复核前提为当前有效 FINALIZED 终态及其关联汇总,旧报表 confirm 状态不参与判断。

10. 修改前后对比

10.1 字段级对比

接口/字段 修改前或错误说明 当前正确契约
finalize 双指纹 #5342 通知误写为删除 两个字段均必填
reimbursementExpectedSourceFingerprint 误写为不再回传 来自主报账 GET 的 sourceFingerprint
groupExpectedSourceFingerprint 误写为不再回传 来自单团 GET 的 sourceFingerprint
reimbursementConfirmation #5342 把内部字段错误提升到 finalize 顶层 必填嵌套对象
transferDate 误写为 finalize 顶层 位于 reimbursementConfirmation
transferRef 误写为 finalize 顶层 位于 reimbursementConfirmation,trim 后最长 128
advanceSettledFlag 误写为 finalize 顶层 位于 reimbursementConfirmation,必填 boolean
signedVoucher 误写为 finalize 顶层 位于 reimbursementConfirmation,必填 object
transferStatus 可能沿用旧 confirm 传值 finalize 不接收,成功后固定为 COMPLETED

10.2 行为级对比

行为 修改前 当前
主报账确认 独立 POST confirm 接口删除,由 finalize 一次完成
单团确认 独立 POST confirm 接口删除,由 finalize 一次完成
finalize 前的数据校验 分散在两个 confirm 两张 GET 取双指纹,finalize 一次校验
重复 finalize 旧流程语义不明确 完全相同返回原结果,任一差异返回 584316
反确认后再次核单 可能沿用旧报表结果 重新 GET 新指纹,再 finalize 生成版本号 + 1

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容:是。两个 POST confirm 已删除,finalize 的双指纹及嵌套凭据均为必填。
  • 前端是否必须同步上线:是。按 #5342 错误契约提交会因缺双指纹或缺 reimbursementConfirmation 返回 400/业务错误。
  • 查询兼容性:两张 GET 的字段结构保持,sourceFingerprint 的用途明确为 finalize 必填凭据。

11.2 回滚说明

  • 前后端必须使用同一版核单流程;不能混用“独立 confirm”和“finalize 双指纹”两套调用顺序。
  • 若后端契约回滚,前端也需同步恢复对应请求模型与调用链,不能只单独回滚一端。

12. 注意事项

  • 删除两个报表确认按钮及对应请求、loading、重试、错误忽略代码。
  • 保留两个 GET 返回的 sourceFingerprint,并在点击完成核单前保存当前两份值。
  • finalize 请求模型必须新增必填 reimbursementConfirmation,其余凭据字段不得放在顶层。
  • 不要发送 transferStatus;页面在 finalize 成功后按响应/重新 GET 展示终态。
  • 不要继续沿用 #5342 通知中的“删除双指纹”“finalize 顶层凭据字段”实现。
  • 584315 进行刷新两张报表后重试;对 584316 不要静默覆盖终态。

13. 关联 / 联系人

13.1 链接

13.2 联系人

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