hl-api-changelog/changelogs-v2/2026-07/28_5324_删除旧核单兼容接口-删除接口-管理后台.md
Mimingguang a2ab2f20e7
一些检查失败了
changelog-filename-gate / validate (push) Failing after 1s
chore(changelog): 完成 5324 管理后台消费
修改原因:#5324 的旧 category-checks、报告 generate、Step6 与无双指纹 finalize 前端兼容路径已移除。

修改内容:将 changelogs-v2/2026-07/28_5324_删除旧核单兼容接口-删除接口-管理后台.md 迁移为 implemented,记录业务提交 2ab427c62a8d44155e740f4abfcc5c812a5b63ad 与验证时间。

实际验证:主仓库全量 checkpoint 通过;source 46 项测试和 git diff --check 通过。
2026-07-29 10:23:46 +08:00

33 KiB

schema, ticket, title, consumer, change_type, backend_status, backend_ref, deployment_status, deployment_ref, gateway_status, verification_status, verification_ref, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base, generated
schema ticket title consumer change_type backend_status backend_ref deployment_status deployment_ref gateway_status verification_status verification_ref frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base generated
hl-changelog/v2 5324 删除旧核单兼容接口 admin 删除接口 deployed PR #5328 · merge 709105c1a1d26ae1c867fcc998286781f499faf2 deployed deploy-panel task ad042377 verified verified D:/work/project-doc/PRPs/reports/5328-deploy-qa-report.md · D:/work/project-doc/test/5328/evidence.json implemented hl-ui-pi 2ab427c62a8d44155e740f4abfcc5c812a5b63ad 2026-07-29T10:21:44+08:00 部署 task ad042377 成功;8086/8186 正常;网关 20/20 HTTP 200、0 网络错误、0 个 5xx、RST 0;3 个删除路由均返回业务 404,4 个保留路由进入业务门禁且零写入。管理后台待迁移到双报表确认后调用 finalize 的五步流程。 2026-07-29 dev-v3 2026-07-28T18:04:49+08:00

【删除接口·管理后台】删除旧核单兼容接口 (#5324)

PR: #5328 | 服务: hl-order-service-v3 | 更新时间: 2026-07-28 18:04

1. 接口背景

核单完成入口统一为“双报表确认后完成核单”:管理后台先读取并确认主报账人报账表,再读取并确认单团核算表,最后携带两份报告的当前来源指纹调用 finalize。旧分类确认兼容接口和旧 Step6 提交入口不再提供。

2. 变更清单

2.1 删除的接口

# 接口 方法 路径 变更类型 前端动作
1 查询核单分类确认状态 GET /v3/admin/order/{orderId}/settlement/category-checks 删除 删除调用及分类确认状态门禁
2 确认单个核单分类 POST /v3/admin/order/{orderId}/settlement/category-checks/{category}/confirm 删除 删除调用及“本分类已确认”交互
3 旧 Step6 提交核单 POST /v3/admin/order/{orderId}/settlement/step6/submit 删除 改为下表五步流程

2.2 唯一替代流程

顺序 接口 方法 路径 用途
1 查询主报账人报账表 GET /v3/admin/order/{orderId}/settlement/reports/reimbursement 获取实时数据和主报账表 sourceFingerprint
2 确认主报账人报账表 POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/confirm 确认转账、预支结清标志和签字凭证
3 查询单团核算表 GET /v3/admin/order/{orderId}/settlement/reports/group 获取实时数据和单团核算表 sourceFingerprint
4 确认单团核算表 POST /v3/admin/order/{orderId}/settlement/reports/group/confirm 确认当前单团核算结果
5 完成核单 POST /v3/admin/order/{orderId}/settlement/finalize 携带两份已确认报告的当前指纹完成核单

3. 接口详情

以下五个接口都需要管理后台登录态,房务角色不可访问;orderId 为必填路径参数,类型为 Long/String,值必须大于 0。

3.1 查询主报账人报账表

  • 方法 + 路径GET /v3/admin/order/{orderId}/settlement/reports/reimbursement
  • 使用场景:进入报账报表页面、确认前刷新、来源数据变化后重新获取。
  • 幂等性:幂等,只读。
  • 请求体:无。
  • 成功响应Result<SettlementReimbursementReportRespVO>,完整字段见 §5.2。
  • 关键规则:前端必须保存本次响应的 data.sourceFingerprint;确认请求不得使用缓存的旧指纹。

请求示例

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

响应示例

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": null,
    "orderId": "1914050000000001",
    "reportStatus": "GENERATED",
    "sourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "primaryReporterId": "3001",
    "primaryReporterName": "王司机",
    "primaryReporterRole": "DRIVER",
    "reportVersion": 1,
    "driverCollectedTailAmount": 2000.00,
    "approvedAdvanceAmount": 500.00,
    "reportablePaidCostAmount": 1000.00,
    "reporterNetAmount": 1500.00,
    "primaryReporterCollectedAmount": 2000.00,
    "publicPrepaidAmount": 1000.00,
    "primaryReporterDueAmount": 1000.00,
    "advanceOutstandingAmount": 500.00,
    "reconNetAmount": 1500.00,
    "transferDirection": "REPORTER_TO_COMPANY",
    "transferAmount": 1500.00,
    "incomeLines": [
      {
        "type": "DRIVER_CASH_RECEIPT",
        "receiptId": "9100000000001",
        "amount": 2000.00,
        "channel": "DRIVER_CASH",
        "payType": "CASH",
        "collectorStaffId": "3001",
        "collectorName": "王司机",
        "collectorRole": "DRIVER",
        "receivedAt": "2026-07-27T18:30:00",
        "remark": "司机代收尾款"
      }
    ],
    "expenseLines": [
      {
        "category": "HOTEL",
        "kind": "HOTEL",
        "hotelAssignmentId": "9200000000001",
        "hotelName": "示例酒店",
        "stayDate": "2026-07-20",
        "amount": 1000.00,
        "paymentMethod": "CASH_PAID",
        "remark": null
      }
    ],
    "advanceLines": [
      {
        "type": "APPROVED_ADVANCE",
        "advanceId": "9300000000001",
        "payeeStaffId": "3001",
        "payeeName": "王司机",
        "payeeRole": "DRIVER",
        "advanceType": "PUBLIC",
        "amount": 500.00,
        "purpose": "途中费用",
        "voucherUrl": "https://oss.example.com/advance.jpg",
        "status": "APPROVED",
        "submittedAt": "2026-07-18T10:00:00",
        "approvedAt": "2026-07-18T11:00:00",
        "approvedBy": "10001"
      }
    ],
    "vehicleLines": [],
    "transferStatus": null,
    "transferDate": null,
    "transferRef": null,
    "advanceSettledFlag": false,
    "signedVoucher": null,
    "generatedBy": null,
    "generatedByName": null,
    "generatedAt": null,
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  }
}

3.2 确认主报账人报账表

  • 方法 + 路径POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/confirm
  • 使用场景:已核对主报账表,且转账、预支标记和签字凭证已经填写完毕。
  • 幂等性:同一当前指纹和完全相同的确认内容可重复提交;确认后改传其它内容返回 584317
  • 请求体:见 §4.2。
  • 成功响应:与 §3.1 相同,reportStatus=CONFIRMED,并返回确认信息。

请求示例

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

{
  "expectedSourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "transferStatus": "COMPLETED",
  "transferDate": "2026-07-28",
  "transferRef": "BANK-20260728-001",
  "advanceSettledFlag": true,
  "signedVoucher": {
    "files": [
      {
        "name": "司机签字单.pdf",
        "url": "https://oss.example.com/signed-voucher.pdf"
      }
    ],
    "note": "签字凭证已回收"
  }
}

响应示例

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": "9400000000001",
    "orderId": "1914050000000001",
    "reportStatus": "CONFIRMED",
    "sourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "primaryReporterId": "3001",
    "primaryReporterName": "王司机",
    "primaryReporterRole": "DRIVER",
    "reportVersion": 1,
    "driverCollectedTailAmount": 2000.00,
    "approvedAdvanceAmount": 500.00,
    "reportablePaidCostAmount": 1000.00,
    "reporterNetAmount": 1500.00,
    "primaryReporterCollectedAmount": 2000.00,
    "publicPrepaidAmount": 1000.00,
    "primaryReporterDueAmount": 1000.00,
    "advanceOutstandingAmount": 500.00,
    "reconNetAmount": 1500.00,
    "transferDirection": "REPORTER_TO_COMPANY",
    "transferAmount": 1500.00,
    "incomeLines": [],
    "expenseLines": [],
    "advanceLines": [],
    "vehicleLines": [],
    "transferStatus": "COMPLETED",
    "transferDate": "2026-07-28",
    "transferRef": "BANK-20260728-001",
    "advanceSettledFlag": true,
    "signedVoucher": {
      "files": [
        {
          "name": "司机签字单.pdf",
          "url": "https://oss.example.com/signed-voucher.pdf"
        }
      ],
      "note": "签字凭证已回收"
    },
    "generatedBy": null,
    "generatedByName": null,
    "generatedAt": null,
    "confirmedBy": "10001",
    "confirmedByName": "财务管理员",
    "confirmedAt": "2026-07-28T18:10:00"
  }
}

3.3 查询单团核算表

  • 方法 + 路径GET /v3/admin/order/{orderId}/settlement/reports/group
  • 使用场景:主报账表确认后查看单团收入、成本、毛利和人均指标。
  • 幂等性:幂等,只读。
  • 请求体:无。
  • 成功响应Result<SettlementGroupReportRespVO>,完整字段见 §5.3。
  • 关键规则:前端必须保存本次响应的 data.sourceFingerprint;确认请求不得使用缓存的旧指纹。

请求示例

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

响应示例

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": null,
    "orderId": "1914050000000001",
    "reportStatus": "GENERATED",
    "sourceFingerprint": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
    "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.5216,
    "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
  }
}

3.4 确认单团核算表

  • 方法 + 路径POST /v3/admin/order/{orderId}/settlement/reports/group/confirm
  • 使用场景:主报账表已经确认,且已核对当前单团收入、成本和利润。
  • 幂等性:相同当前指纹重复确认返回已确认结果。
  • 请求体:见 §4.3。
  • 成功响应:与 §3.3 相同,reportStatus=CONFIRMED,并返回确认人和确认时间。

请求示例

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

{
  "expectedSourceFingerprint": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}

响应示例

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": "9500000000001",
    "orderId": "1914050000000001",
    "reportStatus": "CONFIRMED",
    "sourceFingerprint": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
    "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.5216,
    "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": "10001",
    "confirmedByName": "财务管理员",
    "confirmedAt": "2026-07-28T18:12:00"
  }
}

3.5 完成核单

  • 方法 + 路径POST /v3/admin/order/{orderId}/settlement/finalize
  • 使用场景:两份报告均已确认且来源仍为当前版本时,点击“完成核单”。
  • 幂等性:已完成且存在当前终态结果时,重复提交返回当前终态结果。
  • 请求体:见 §4.4;请求体在业务上必填。
  • 成功响应Result<SettlementSubmitRespVO>,完整字段见 §5.4。

请求示例

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

{
  "remark": "双报表已核对完成",
  "reimbursementExpectedSourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "groupExpectedSourceFingerprint": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}

响应示例

{
  "code": 200,
  "msg": "success",
  "data": {
    "summaryId": "9600000000001",
    "finalSnapshotId": "9600000000002",
    "finalSnapshotVersionNo": 1,
    "finalSnapshotStatus": "FINALIZED",
    "orderId": "1914050000000001",
    "settledAt": "2026-07-28T18:15:00",
    "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": 1000.00,
    "profitAmount": 13040.00,
    "profitRate": 0.5216,
    "orderStatusAfter": "待财务复核",
    "mqTriggered": true,
    "warnings": []
  }
}

4. 接口入参

4.1 五个替代接口共用路径参数

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

两个 GET 接口没有 Query 参数和请求体。

4.2 主报账表确认请求体

字段 类型 必填 说明 校验规则
expectedSourceFingerprint String §3.1 最新响应的 data.sourceFingerprint 64 位小写十六进制
transferStatus String 转账处理状态 固定传 COMPLETED
transferDate String/date 条件必填 转账日期 reporterNetAmount != 0 时必填;格式 YYYY-MM-DD
transferRef String 条件必填 转账流水号或可追溯凭证号 reporterNetAmount != 0 时不得为空白
advanceSettledFlag Boolean 预支款项是否已处理完毕 不得为 null
signedVoucher Object 签字凭证 不得为 null
signedVoucher.files Array 签字凭证文件列表 至少 1 项
signedVoucher.files[].name String 文件名 可为空
signedVoucher.files[].url String 文件地址 不得为空白
signedVoucher.note String 凭证备注 可为空

reporterNetAmount = 0 时,transferDatetransferRef 可不传;transferStatus 仍必须是 COMPLETED,签字凭证仍必须至少包含一个有效文件。

4.3 单团核算表确认请求体

字段 类型 必填 说明 校验规则
expectedSourceFingerprint String §3.3 最新响应的 data.sourceFingerprint 64 位小写十六进制

4.4 完成核单请求体

字段 类型 必填 说明 校验规则
remark String 本次完成核单的整体备注 最长 500 字
reimbursementExpectedSourceFingerprint String 已确认主报账表的当前 sourceFingerprint 64 位小写十六进制
groupExpectedSourceFingerprint String 已确认单团核算表的当前 sourceFingerprint 64 位小写十六进制

4.5 指纹传递关系

来源 确认接口字段 完成核单字段
GET .../reports/reimbursementdata.sourceFingerprint POST .../reports/reimbursement/confirmexpectedSourceFingerprint POST .../finalizereimbursementExpectedSourceFingerprint
GET .../reports/groupdata.sourceFingerprint POST .../reports/group/confirmexpectedSourceFingerprint POST .../finalizegroupExpectedSourceFingerprint

5. 出参

5.1 统一响应外层

字段 类型 说明
code Integer 200 表示成功;其它值见 §7
msg String 结果说明
data Object/null 成功时为业务数据,失败时通常为 null

所有 Long ID 以 JSON 字符串消费,避免前端数字精度损失;金额字段为十进制数。

5.2 主报账人报账表响应

字段 类型 说明
id String/null 报账表记录 ID;仅实时预览、尚未确认时可为 null
orderId String 订单 ID
reportStatus String GENERATED / CONFIRMED / STALE,见 §6.1
sourceFingerprint String 当前来源指纹,64 位小写十六进制
primaryReporterId String/null 主报账人 ID
primaryReporterName String/null 主报账人姓名
primaryReporterRole String/null 主报账人角色
reportVersion Integer/null 报账表版本
driverCollectedTailAmount Decimal 司机代收尾款
approvedAdvanceAmount Decimal 已审批预支合计
reportablePaidCostAmount Decimal 主报账人已支付、可报账成本合计
reporterNetAmount Decimal 报账净额:司机代收尾款 + 已审批预支 - 可报账已支付成本
primaryReporterCollectedAmount Decimal 主报账人代收金额
publicPrepaidAmount Decimal 公共预支金额
primaryReporterDueAmount Decimal 主报账人应报账金额
advanceOutstandingAmount Decimal 待处理预支金额
reconNetAmount Decimal 报账净额兼容字段
transferDirection String 转账方向,见 §6.2
transferAmount Decimal 需转账金额,取 reporterNetAmount 绝对值
incomeLines Array 司机代收尾款明细
expenseLines Array 主报账人现金支付成本明细
advanceLines Array 已审批预支明细
vehicleLines Array 车辆逐日明细;允许空数组
transferStatus String/null 未确认时可为空;确认后为 COMPLETED
transferDate String/date/null 转账日期
transferRef String/null 转账流水号或凭证号
advanceSettledFlag Boolean 预支是否已处理完毕
signedVoucher Object/null 签字凭证,结构同 §4.2
generatedBy String/null 历史生成操作人 ID
generatedByName String/null 历史生成操作人姓名
generatedAt String/date-time/null 历史生成时间
confirmedBy String/null 确认人 ID
confirmedByName String/null 确认人姓名
confirmedAt String/date-time/null 确认时间

incomeLines[] 的固定字段为 typereceiptIdamountchannelpayTypecollectorStaffIdcollectorNamecollectorRolereceivedAtremark

advanceLines[] 的固定字段为 typeadvanceIdpayeeStaffIdpayeeNamepayeeRoleadvanceTypeamountpurposevoucherUrlstatussubmittedAtapprovedAtapprovedBy

expenseLines[] 至少包含 categorykindamountpaymentMethod;按分类还会包含对应的名称、日期、数量、单价、人员或车辆标识、凭证和备注字段。前端列表应按字段是否存在展示,不依赖固定列宽。

5.3 单团核算表响应

字段 类型 说明
id String/null 单团核算表记录 ID;仅实时预览、尚未确认时可为 null
orderId String 订单 ID
reportStatus String GENERATED / CONFIRMED / STALE
sourceFingerprint String 当前来源指纹,64 位小写十六进制
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 毛利率;收入为 0 时为 0
travelerCount Integer 出行人数
perCapitaRevenue Decimal 人均收入
perCapitaCost Decimal 人均成本
perCapitaProfit Decimal 人均利润
incomeLines Array 收入构成;元素字段为 typeamount
costCategories Array 成本构成;元素字段为 categoryamount
generatedBy String/null 历史生成操作人 ID
generatedByName String/null 历史生成操作人姓名
generatedAt String/date-time/null 历史生成时间
confirmedBy String/null 确认人 ID
confirmedByName String/null 确认人姓名
confirmedAt String/date-time/null 确认时间

5.4 完成核单响应

字段 类型 说明
summaryId String 核单汇总 ID
finalSnapshotId String 核单终态版本 ID
finalSnapshotVersionNo Integer 核单终态版本号
finalSnapshotStatus String 核单终态状态,成功时为 FINALIZED
orderId String 订单 ID
settledAt String/date-time 核单完成时间
totalAmount Decimal 订单总金额
paidAmount Decimal 已收金额
balanceAmount Decimal 待收金额;完成核单时必须为 0
roomCost Decimal 住宿实际成本
ticketCost Decimal 门票实际成本
staffCost Decimal 人员实际成本
subsidyCost Decimal 补助实际成本
mealCost Decimal 餐食实际成本
vehicleCost Decimal 车辆实际成本
otherExpenseCost Decimal 其他支出实际成本
insurancePremium Decimal 保险保费
totalActualCost Decimal 总实际成本
driverTransferAmount Decimal 需与司机/主报账人结算的金额
profitAmount Decimal 公司毛利
profitRate Decimal 公司毛利率
orderStatusAfter String 完成核单后的订单状态
mqTriggered Boolean 核单完成事件是否已触发
warnings Array 软提示列表;不阻塞成功结果

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 transferStatus

所属字段:主报账表确认请求和响应 transferStatus | 类型String

中文 说明
COMPLETED 已完成 确认主报账表时唯一允许值

6.4 单团收入行 type

中文 金额符号
BASE_ORDER 订单基础收入 正数
OTHER_INCOME 其他收入 正数
DISCOUNT 优惠 负数
ACTUAL_REFUND 实际退款 负数或 0

6.5 单团成本行 category

中文
HOTEL 住宿
TICKET 门票/游玩项目
MEAL 餐食
VEHICLE 车辆
GUIDE 导游
PHOTOGRAPHER 摄影
OTHER_EXPENSE 其他支出
INSURANCE 保险

7. 错误码

code 含义 触发场景
400 参数校验失败 orderId <= 0、请求体缺字段、指纹格式错误等
403 无访问或写入权限 房务角色访问,或操作人没有核单写权限
404 接口不存在 调用本次删除的 3 个旧接口
584082 存在待收尾款,请收齐后再提交核单 finalize 时单团核算表 outstandingAmount != 0
584312 主报账表尚未确认或数据已变化 单团核算表确认前,主报账表未确认或已失效
584314 单团核算表尚未确认或数据已变化 finalize 时单团核算表未确认、已失效或指纹不匹配
584315 核单来源数据已变化,请刷新后重新确认 确认报告时提交的 expectedSourceFingerprint 不是当前值
584316 核单报告发生并发变化,请刷新后重试 多人同时确认同一报告发生冲突
584317 当前报告状态不允许执行该操作 确认内容不合法,或报告当前状态不允许重复变更
584325 完成核单必须提交主报账和单团核算的当前指纹 finalize 缺少任一指纹或指纹不是 64 位小写十六进制

8. 示例(典型 / 边界 / 异常)

8.1 典型成功:五步完成核单

  1. 调用 GET .../reports/reimbursement,保存响应 sourceFingerprint=aaaa...
  2. 调用 POST .../reports/reimbursement/confirmexpectedSourceFingerprintaaaa...,响应状态为 CONFIRMED
  3. 调用 GET .../reports/group,保存响应 sourceFingerprint=bbbb...
  4. 调用 POST .../reports/group/confirmexpectedSourceFingerprintbbbb...,响应状态为 CONFIRMED
  5. 调用 POST .../finalize,两个指纹分别传 aaaa...bbbb...,响应 finalSnapshotStatus=FINALIZED

各步完整请求和响应见 §3.1§3.5。

8.2 边界:报账净额为 0

当最新主报账表返回 reporterNetAmount=0transferDirection=BALANCED 时:

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

{
  "expectedSourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "transferStatus": "COMPLETED",
  "advanceSettledFlag": true,
  "signedVoucher": {
    "files": [
      {
        "name": "司机签字单.pdf",
        "url": "https://oss.example.com/signed-voucher.pdf"
      }
    ],
    "note": null
  }
}
{
  "code": 200,
  "msg": "success",
  "data": {
    "orderId": "1914050000000001",
    "reportStatus": "CONFIRMED",
    "sourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "reporterNetAmount": 0.00,
    "transferDirection": "BALANCED",
    "transferAmount": 0.00,
    "transferStatus": "COMPLETED",
    "transferDate": null,
    "transferRef": null,
    "advanceSettledFlag": true,
    "signedVoucher": {
      "files": [
        {
          "name": "司机签字单.pdf",
          "url": "https://oss.example.com/signed-voucher.pdf"
        }
      ],
      "note": null
    }
  }
}

8.3 异常:来源数据变化

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

{
  "expectedSourceFingerprint": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
}
{
  "code": 584315,
  "msg": "核单来源数据已变化,请刷新后重新确认",
  "data": null
}

收到该错误后重新执行对应 GET,使用新的 data.sourceFingerprint 重新确认;不得继续用旧指纹调用 finalize

8.4 异常:仍有待收尾款

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

{
  "reimbursementExpectedSourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "groupExpectedSourceFingerprint": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}
{
  "code": 584082,
  "msg": "存在待收尾款,请收齐后再提交核单",
  "data": null
}

9. 业务边界

  • 必须按“查询主报账表 → 确认主报账表 → 查询单团核算表 → 确认单团核算表 → 完成核单”的顺序执行。
  • 两份报告的指纹互不通用;禁止把主报账表指纹传到单团核算字段,或反向混用。
  • 每次确认前都应重新 GET;当 reportStatus=STALE 或收到 584315 时,必须刷新数据并使用新指纹。
  • 单团核算表确认依赖当前有效的主报账表确认,否则返回 584312
  • finalize 同时校验两份报告已确认、指纹仍为当前值,以及 outstandingAmount=0
  • 主报账表 reporterNetAmount != 0 时,确认请求必须提供 transferDate 和非空 transferRef
  • 主报账表确认始终要求至少一个含有效 url 的签字凭证文件。

10. 修改前后对比

10.1 接口级对比

功能 修改前 修改后
分类状态 调用 GET .../category-checks 不再查询分类确认状态
分类确认 调用 POST .../category-checks/{category}/confirm 保存各核单明细即可,不再单独确认分类
报账与单团核算 可能绕过双报表直接提交旧 Step6 必须分别 GET、confirm 两份报告
完成核单 POST .../step6/submit POST .../finalize,请求体必须携带两个当前指纹

10.2 请求体对比

入口 修改前 修改后
step6/submit 旧提交请求 接口删除
finalize 不适用 remark 可选;reimbursementExpectedSourceFingerprintgroupExpectedSourceFingerprint 必填

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容是。3 个旧接口已删除。
  • 前端是否必须同步上线:是。仍调用任一旧接口的管理后台将收到 404;旧 Step6 提交必须迁移为五步流程。

11.2 回滚原则

  • 后端回退时,前端仍可保留五步新流程。
  • 前端不得因为短期回退重新新增分类确认入口或恢复旧 Step6 调用;如需临时兼容,应单独确认接口契约后再处理。

12. 注意事项

  • 删除 category-checks 查询、分类确认 API 封装、分类确认按钮和相关状态门禁。
  • 删除 step6/submit API 封装及所有调用点。
  • “完成核单”按钮改为调用 finalize,并在调用前确保两份报告都为 CONFIRMED
  • 页面状态中分别保存两份 sourceFingerprint,不要只保存一个通用指纹。
  • 主报账表确认成功后再开放单团核算确认;单团核算确认成功后再开放“完成核单”。
  • 收到 584312584314584315584316 时刷新对应报告,不得自动使用旧数据重试。

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人: @yst
  • 前端负责人: 待认领