hl-api-changelog/changelogs-v2/2026-07/25_5219_核单原型流迁移-修改接口-管理后台.md
Mimingguang 12a331d7c7
所有检测均成功
changelog-filename-gate / validate (push) Successful in 1s
chore(changelog): 标记前端已实现 #5219
修改原因:hl-ui changelog loop 需要把前端消费进度回写到契约源,避免领取、实现状态与实际交付脱节。

修改内容:将 frontend_status 与已有 legacy frontend 同步为 implemented,记录负责人 hl-ui-codex,并关联 mmg/hl-ui@00ea8e2ad187b6b91626f069fc3a4a5ba5a76e06;发布和验收字段保持不变。

实际验证:回写器已校验目标文件、状态单调性、提交范围和 Front Matter 内容,提交只包含当前 changelog。

Frontend-Status: tools/mcp-api-sync/.changelog-repo/changelogs-v2/2026-07/25_5219_核单原型流迁移-修改接口-管理后台.md
2026-07-25 16:37:46 +08:00

34 KiB

frontend_status, frontend_owner, frontend_ref, updated_at
frontend_status frontend_owner frontend_ref updated_at
implemented hl-ui-codex mmg/hl-ui@00ea8e2ad1 2026-07-25T08:37:46.681Z

【修改接口·管理后台】核单原型流迁移 (#5219)

PR: #5243 | 服务: hl-order-service-v3 | 更新时间: 2026-07-25 16:08

1. 接口背景

核单流程从旧的“财务总览/优惠逐条确认后直接 Step6 提交”调整为原型流:先确认 8 个核单分类,再生成并确认主报账人报账表,再生成并确认单团核算表,最后完成核单。

2. 变更清单

# 接口 方法 路径 变更类型 说明
1 查询八分类确认状态 GET /v3/admin/order/{orderId}/settlement/category-checks 新增 返回 8 个核单分类的确认状态、行数和来源指纹
2 确认单个核单分类 POST /v3/admin/order/{orderId}/settlement/category-checks/{category}/confirm 新增 用最近读取的分类指纹确认单个分类
3 查询主报账人报账表 GET /v3/admin/order/{orderId}/settlement/reports/reimbursement 新增 查询主报账表当前快照
4 生成主报账人报账表 POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/generate 新增 8 分类全部确认后生成
5 确认主报账人报账表 POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/confirm 新增 确认转账、预支和签字单
6 查询单团核算表 GET /v3/admin/order/{orderId}/settlement/reports/group 新增 查询单团核算表当前快照
7 生成单团核算表 POST /v3/admin/order/{orderId}/settlement/reports/group/generate 新增 主报账表确认后生成
8 确认单团核算表 POST /v3/admin/order/{orderId}/settlement/reports/group/confirm 新增 用最近读取的报告指纹确认
9 完成核单 POST /v3/admin/order/{orderId}/settlement/finalize 新增 单团核算表确认后提交核单
10 查询核单应收财务总览 GET /v3/admin/order/{orderId}/settlement/financial-overview 修改 仍保留查询,但不再返回确认状态/指纹
11 确认财务总览 POST /v3/admin/order/{orderId}/settlement/financial-overview/confirm 删除 旧 POST 契约下线
12 确认单条优惠 POST /v3/admin/order/{orderId}/settlement/financial-overview/discounts/{discountId}/confirm 删除 旧 POST 契约下线

3. 接口详情

3.1 查询八分类确认状态

  • 方法 + 路径: GET /v3/admin/order/{orderId}/settlement/category-checks
  • 接口名: 查询原型八个核单分类确认状态
  • 认证: 管理后台 JWT;房务角色不可访问
  • 幂等性: 幂等,只读
  • 限流: 无接口级特殊限流

路径参数

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

请求体: 无

响应字段

字段 类型 说明
orderId String 订单 ID
allConfirmed Boolean 8 个分类是否全部已确认
items Array 分类确认项
items[].category String 分类枚举,见 §6.1
items[].categoryName String 分类中文名
items[].rowCount Integer 当前分类参与核单的行数
items[].empty Boolean 当前分类是否为空
items[].sourceFingerprint String 当前分类来源事实 SHA-256
items[].confirmStatus String UNCONFIRMED / CONFIRMED
items[].confirmedBy String/null 确认人 ID
items[].confirmedByName String/null 确认人名称
items[].confirmedAt String/null 确认时间,未确认时为 null

错误码

code 含义 触发场景
400 参数校验失败 orderId <= 0
403 无访问权限 房务角色访问

典型成功示例

请求:

GET /v3/admin/order/1914050000000001/settlement/category-checks
Authorization: Bearer <token>

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "orderId": "1914050000000001",
    "allConfirmed": false,
    "items": [
      {
        "category": "HOTEL",
        "categoryName": "住宿",
        "rowCount": 2,
        "empty": false,
        "sourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
        "confirmStatus": "CONFIRMED",
        "confirmedBy": "10001",
        "confirmedByName": "张三",
        "confirmedAt": "2026-07-25T15:20:00"
      },
      {
        "category": "OTHER_EXPENSE",
        "categoryName": "其他支出",
        "rowCount": 0,
        "empty": true,
        "sourceFingerprint": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
        "confirmStatus": "UNCONFIRMED",
        "confirmedBy": null,
        "confirmedByName": null,
        "confirmedAt": null
      }
    ]
  }
}

边界示例

请求:

GET /v3/admin/order/1914050000000001/settlement/category-checks
Authorization: Bearer <token>

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "orderId": "1914050000000001",
    "allConfirmed": false,
    "items": [
      {
        "category": "MEAL",
        "categoryName": "餐食",
        "rowCount": 0,
        "empty": true,
        "sourceFingerprint": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
        "confirmStatus": "UNCONFIRMED",
        "confirmedBy": null,
        "confirmedByName": null,
        "confirmedAt": null
      }
    ]
  }
}

异常示例

请求:

GET /v3/admin/order/0/settlement/category-checks
Authorization: Bearer <token>

响应:

{
  "code": 400,
  "msg": "订单 ID 必须大于 0",
  "data": null
}

业务边界

  • 适用:进入核单流程后读取 8 个分类状态。
  • 不适用:房务角色不可查看。
  • 特殊边界:空分类仍需要走显式确认,不能因为 rowCount=0 自动通过。

3.2 确认单个核单分类

  • 方法 + 路径: POST /v3/admin/order/{orderId}/settlement/category-checks/{category}/confirm
  • 接口名: 按最近读取指纹确认单个核单分类
  • 认证: 管理后台 JWT;需要财务写权限;房务角色不可访问
  • 幂等性: 非纯幂等;相同指纹重复确认不会改变来源事实
  • 限流: 无接口级特殊限流

路径参数

字段 类型 必填 说明
orderId Long/String 订单 ID,必须大于 0
category String 分类枚举,大小写不敏感,见 §6.1

请求体字段

字段 类型 必填 说明 校验规则
expectedSourceFingerprint String 最近读取的分类来源事实 SHA-256 64 位小写十六进制
confirmEmpty Boolean 是否明确确认空分类 空分类传 true,非空分类传 false

响应字段: 同 §3.1 items[] 单项。

错误码

code 含义 触发场景
400 参数校验失败 指纹不是 64 位十六进制、缺少 confirmEmpty
584315 核单来源数据已变化,请刷新后重新生成 前端传入的指纹与当前分类来源不一致
584318 空分类必须显式确认,非空分类不得按空分类确认 confirmEmpty 与当前分类是否为空不匹配
584319 核单存在未知分类或历史迁移数据不完整 category 不是 8 分类枚举

典型成功示例

请求:

POST /v3/admin/order/1914050000000001/settlement/category-checks/HOTEL/confirm
Authorization: Bearer <token>
Content-Type: application/json

{
  "expectedSourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "confirmEmpty": false
}

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "category": "HOTEL",
    "categoryName": "住宿",
    "rowCount": 2,
    "empty": false,
    "sourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "confirmStatus": "CONFIRMED",
    "confirmedBy": "10001",
    "confirmedByName": "张三",
    "confirmedAt": "2026-07-25T15:24:00"
  }
}

边界示例

请求:

POST /v3/admin/order/1914050000000001/settlement/category-checks/MEAL/confirm
Authorization: Bearer <token>
Content-Type: application/json

{
  "expectedSourceFingerprint": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
  "confirmEmpty": true
}

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "category": "MEAL",
    "categoryName": "餐食",
    "rowCount": 0,
    "empty": true,
    "sourceFingerprint": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
    "confirmStatus": "CONFIRMED",
    "confirmedBy": "10001",
    "confirmedByName": "张三",
    "confirmedAt": "2026-07-25T15:25:00"
  }
}

异常示例

请求:

POST /v3/admin/order/1914050000000001/settlement/category-checks/UNKNOWN/confirm
Authorization: Bearer <token>
Content-Type: application/json

{
  "expectedSourceFingerprint": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "confirmEmpty": false
}

响应:

{
  "code": 584319,
  "msg": "核单存在未知分类或历史迁移数据不完整",
  "data": null
}

业务边界

  • 适用:确认当前分类数据没有变化。
  • 不适用:前端未先读取 sourceFingerprint 时不应直接确认。
  • 特殊边界:OTHER_INCOME 确认前会校验其他收入可提交状态。

3.3 主报账人报账表

  • 查询: GET /v3/admin/order/{orderId}/settlement/reports/reimbursement
  • 生成: POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/generate
  • 确认: POST /v3/admin/order/{orderId}/settlement/reports/reimbursement/confirm
  • 接口名: 查询主报账人报账表 / 八分类确认后生成主报账人报账表 / 完成转账、预支及签字门禁后确认主报账人报账表
  • 认证: 管理后台 JWT;房务角色不可访问
  • 幂等性: 查询幂等;生成/确认会更新报告状态和确认信息
  • 限流: 无接口级特殊限流

路径参数

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

确认请求体字段

字段 类型 必填 说明 校验规则
expectedSourceFingerprint String 最近读取的主报账表来源 SHA-256 64 位小写十六进制
transferStatus String 转账状态 后端按字符串保存
transferDate String/date 转账日期 YYYY-MM-DD
transferRef String 转账流水/备注 字符串
advanceSettledFlag Boolean 预支是否已结清 不能为空
signedVoucher Object 签字单回收信息 不能为空
signedVoucher.files Array 文件列表 元素见下
signedVoucher.files[].name String 文件名 字符串
signedVoucher.files[].url String OSS 文件地址 字符串
signedVoucher.note String 备注 字符串

响应字段

字段 类型 说明
id String/null 主报账记录 ID;未生成时可为 null
orderId String 订单 ID
reportStatus String 报告状态,见 §6.2
sourceFingerprint String 当前来源 SHA-256
primaryReporterId String/null 主报账人 ID
primaryReporterName String/null 主报账人姓名
primaryReporterRole String/null 主报账人角色
primaryReporterCollectedAmount Decimal 主报账人代收金额
publicPrepaidAmount Decimal 公共预支金额
primaryReporterDueAmount Decimal 主报账人应报账金额
advanceOutstandingAmount Decimal 未结清预支金额
reconNetAmount Decimal 报账净额
transferDirection String/null 转账方向
transferAmount Decimal 转账金额
incomeLines Array 收入明细行
expenseLines Array 支出明细行
advanceLines Array 预支明细行
transferStatus String/null 转账状态
transferDate String/date/null 转账日期
transferRef String/null 转账流水/备注
advanceSettledFlag Boolean/null 预支是否已结清
signedVoucher Object/null 签字单信息
generatedBy / generatedByName / generatedAt String/String/String 生成信息
confirmedBy / confirmedByName / confirmedAt String/String/String 确认信息

错误码

code 含义 触发场景
584310 八个核单分类尚未全部确认或数据已变化 生成主报账表前 8 分类未全部确认或指纹已失效
584311 主报账表尚未生成 查询/确认时还没有可用主报账表
584315 核单来源数据已变化,请刷新后重新生成 确认时传入的报告指纹已过期
584316 核单报告发生并发变化,请刷新后重试 并发确认冲突
584317 当前报告状态不允许执行该操作 当前状态不能生成或确认

典型成功示例

请求:

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

{
  "expectedSourceFingerprint": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
  "transferStatus": "TRANSFERRED",
  "transferDate": "2026-07-25",
  "transferRef": "BANK-20260725-001",
  "advanceSettledFlag": true,
  "signedVoucher": {
    "files": [
      {
        "name": "签字单.pdf",
        "url": "https://oss.example.com/voucher.pdf"
      }
    ],
    "note": "签字单已回收"
  }
}

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": "9200000000001",
    "orderId": "1914050000000001",
    "reportStatus": "CONFIRMED",
    "sourceFingerprint": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
    "primaryReporterId": "3001",
    "primaryReporterName": "王司机",
    "primaryReporterRole": "DRIVER",
    "primaryReporterCollectedAmount": 2000.00,
    "publicPrepaidAmount": 500.00,
    "primaryReporterDueAmount": 1500.00,
    "advanceOutstandingAmount": 0.00,
    "reconNetAmount": 1500.00,
    "transferDirection": "COMPANY_TO_REPORTER",
    "transferAmount": 1500.00,
    "incomeLines": [],
    "expenseLines": [],
    "advanceLines": [],
    "transferStatus": "TRANSFERRED",
    "transferDate": "2026-07-25",
    "transferRef": "BANK-20260725-001",
    "advanceSettledFlag": true,
    "signedVoucher": {
      "files": [
        {
          "name": "签字单.pdf",
          "url": "https://oss.example.com/voucher.pdf"
        }
      ],
      "note": "签字单已回收"
    },
    "generatedBy": "10001",
    "generatedByName": "张三",
    "generatedAt": "2026-07-25T15:30:00",
    "confirmedBy": "10001",
    "confirmedByName": "张三",
    "confirmedAt": "2026-07-25T15:35:00"
  }
}

边界示例

请求:

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

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": "9200000000001",
    "orderId": "1914050000000001",
    "reportStatus": "STALE",
    "sourceFingerprint": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
    "primaryReporterId": null,
    "primaryReporterName": null,
    "primaryReporterRole": null,
    "primaryReporterCollectedAmount": 0.00,
    "publicPrepaidAmount": 0.00,
    "primaryReporterDueAmount": 0.00,
    "advanceOutstandingAmount": 0.00,
    "reconNetAmount": 0.00,
    "transferDirection": null,
    "transferAmount": 0.00,
    "incomeLines": [],
    "expenseLines": [],
    "advanceLines": [],
    "transferStatus": null,
    "transferDate": null,
    "transferRef": null,
    "advanceSettledFlag": null,
    "signedVoucher": null,
    "generatedBy": "10001",
    "generatedByName": "张三",
    "generatedAt": "2026-07-25T15:30:00",
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  }
}

异常示例

请求:

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

响应:

{
  "code": 584310,
  "msg": "八个核单分类尚未全部确认或数据已变化",
  "data": null
}

业务边界

  • 适用8 分类全部确认后生成主报账表。
  • 不适用8 分类未确认完成时不能生成。
  • 特殊边界:查询返回 STALE 时表示来源已变化,应重新生成后再确认。

3.4 单团核算表

  • 查询: GET /v3/admin/order/{orderId}/settlement/reports/group
  • 生成: POST /v3/admin/order/{orderId}/settlement/reports/group/generate
  • 确认: POST /v3/admin/order/{orderId}/settlement/reports/group/confirm
  • 接口名: 查询单团核算表 / 主报账表确认后生成单团核算表 / 按最近读取指纹确认单团核算表
  • 认证: 管理后台 JWT;房务角色不可访问
  • 幂等性: 查询幂等;生成/确认会更新报告状态和确认信息
  • 限流: 无接口级特殊限流

路径参数

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

确认请求体字段

字段 类型 必填 说明 校验规则
expectedSourceFingerprint String 最近读取的单团核算表来源 SHA-256 64 位小写十六进制

响应字段

字段 类型 说明
id String/null 单团核算记录 ID
orderId String 订单 ID
reportStatus String 报告状态,见 §6.2
sourceFingerprint String 当前来源 SHA-256
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 收入明细行
costCategories Array 成本分类行
generatedBy / generatedByName / generatedAt String/String/String 生成信息
confirmedBy / confirmedByName / confirmedAt String/String/String 确认信息

错误码

code 含义 触发场景
584312 主报账表尚未确认或数据已变化 生成单团核算表前主报账表未确认或已过期
584313 单团核算表尚未生成 查询/确认时还没有可用单团核算表
584315 核单来源数据已变化,请刷新后重新生成 确认时传入的报告指纹已过期
584316 核单报告发生并发变化,请刷新后重试 并发确认冲突
584317 当前报告状态不允许执行该操作 当前状态不能生成或确认

典型成功示例

请求:

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

{
  "expectedSourceFingerprint": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
}

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": "9300000000001",
    "orderId": "1914050000000001",
    "reportStatus": "CONFIRMED",
    "sourceFingerprint": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
    "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": [],
    "costCategories": [],
    "generatedBy": "10001",
    "generatedByName": "张三",
    "generatedAt": "2026-07-25T15:40:00",
    "confirmedBy": "10001",
    "confirmedByName": "张三",
    "confirmedAt": "2026-07-25T15:45:00"
  }
}

边界示例

请求:

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

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": "9300000000001",
    "orderId": "1914050000000001",
    "reportStatus": "GENERATED",
    "sourceFingerprint": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
    "baseOrderAmount": 0.00,
    "otherIncomeAmount": 0.00,
    "discountAmount": 0.00,
    "adjustedReceivableAmount": 0.00,
    "paidAmount": 0.00,
    "actualRefundedAmount": 0.00,
    "netRevenueAmount": 0.00,
    "netReceivedAmount": 0.00,
    "outstandingAmount": 0.00,
    "hotelCost": 0.00,
    "ticketCost": 0.00,
    "mealCost": 0.00,
    "vehicleCost": 0.00,
    "guideCost": 0.00,
    "photographerCost": 0.00,
    "otherExpenseCost": 0.00,
    "insurancePremium": 0.00,
    "totalCost": 0.00,
    "paidCost": 0.00,
    "unpaidCost": 0.00,
    "grossProfit": 0.00,
    "grossProfitRate": 0.000000,
    "travelerCount": 0,
    "perCapitaRevenue": 0.00,
    "perCapitaCost": 0.00,
    "perCapitaProfit": 0.00,
    "incomeLines": [],
    "costCategories": [],
    "generatedBy": "10001",
    "generatedByName": "张三",
    "generatedAt": "2026-07-25T15:40:00",
    "confirmedBy": null,
    "confirmedByName": null,
    "confirmedAt": null
  }
}

异常示例

请求:

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

响应:

{
  "code": 584312,
  "msg": "主报账表尚未确认或数据已变化",
  "data": null
}

业务边界

  • 适用:主报账表已确认后生成单团核算表。
  • 不适用:主报账表未确认或为 STALE 时不能生成。
  • 特殊边界:金额为 0 时仍返回完整字段,数组字段为空数组。

3.5 完成核单

  • 方法 + 路径: POST /v3/admin/order/{orderId}/settlement/finalize
  • 接口名: 单团核算表确认后完成核单
  • 认证: 管理后台 JWT;房务角色不可访问
  • 幂等性: 非幂等;完成后订单进入核单提交后的状态
  • 限流: 无接口级特殊限流

路径参数

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

请求体: 无

响应字段

字段 类型 说明
summaryId String 新写入的 settlement summary 主键
orderId String 订单 ID
settledAt String 核单完成时间
totalAmount Decimal 订单总金额快照
paidAmount Decimal 已付金额快照
balanceAmount Decimal 尾款金额快照
roomCost Decimal 住宿实际成本
ticketCost Decimal 门票实际成本
staffCost Decimal 人员费用实际成本
subsidyCost Decimal 补助实际成本
mealCost Decimal 餐食实际成本
otherExpenseCost Decimal 其他支出实际成本,含车辆费用
insurancePremium Decimal 保险实际保费
totalActualCost Decimal 总实际成本
driverTransferAmount Decimal 给司机/主报账人转回金额
profitAmount Decimal 公司毛利
profitRate Decimal 毛利率
orderStatusAfter String 结算后订单状态
mqTriggered Boolean 结算事件是否成功触发
warnings Array 软预警列表

错误码

code 含义 触发场景
584314 单团核算表尚未确认或数据已变化 finalize 前单团核算表未确认或已过期
584317 当前报告状态不允许执行该操作 当前流程状态不能完成核单

典型成功示例

请求:

POST /v3/admin/order/1914050000000001/settlement/finalize
Authorization: Bearer <token>

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "summaryId": "9400000000001",
    "orderId": "1914050000000001",
    "settledAt": "2026-07-25T15:50: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,
    "otherExpenseCost": 1560.00,
    "insurancePremium": 180.00,
    "totalActualCost": 11960.00,
    "driverTransferAmount": 11780.00,
    "profitAmount": 13040.00,
    "profitRate": 0.5216,
    "orderStatusAfter": "待财务复核",
    "mqTriggered": true,
    "warnings": []
  }
}

边界示例

请求:

POST /v3/admin/order/1914050000000001/settlement/finalize
Authorization: Bearer <token>

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "summaryId": "9400000000002",
    "orderId": "1914050000000001",
    "settledAt": "2026-07-25T15:55: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,
    "otherExpenseCost": 0.00,
    "insurancePremium": 0.00,
    "totalActualCost": 0.00,
    "driverTransferAmount": 0.00,
    "profitAmount": 0.00,
    "profitRate": 0,
    "orderStatusAfter": "待财务复核",
    "mqTriggered": true,
    "warnings": ["住宿 D2 现付缺凭证"]
  }
}

异常示例

请求:

POST /v3/admin/order/1914050000000001/settlement/finalize
Authorization: Bearer <token>

响应:

{
  "code": 584314,
  "msg": "单团核算表尚未确认或数据已变化",
  "data": null
}

业务边界

  • 适用:单团核算表已确认后完成核单。
  • 不适用:单团核算表未确认、已过期或流程状态不允许。
  • 特殊边界:warnings 为软预警,不阻塞成功响应。

3.6 查询核单应收财务总览

  • 方法 + 路径: GET /v3/admin/order/{orderId}/settlement/financial-overview
  • 接口名: 查询核单应收财务总览
  • 变更点: 查询接口保留,但返回字段删除旧确认状态/指纹语义;确认动作迁移到 8 分类和报告流。

响应字段

字段 类型 说明
baseOrderAmount Decimal 订单基础金额
otherIncomeAmount Decimal 有效增费合计
discountAmount Decimal 有效优惠合计
adjustedReceivableAmount Decimal 调整后应收
onlinePaidAmount Decimal 成功线上支付合计
offlinePaidAmount Decimal 有效线下收款合计
primaryReporterCollectedAmount Decimal 当前主报账司机正式代收
paidAmount Decimal 已收合计
actualRefundedAmount Decimal 实际退款合计
netPaidAmount Decimal 净已收
outstandingAmount Decimal 待收
surchargeMirrorMatched Boolean 增费镜像是否匹配权威明细
discountMirrorMatched Boolean 优惠镜像是否匹配权威明细
paidMirrorMatched Boolean 已收镜像是否匹配权威明细
refundedMirrorMatched Boolean 退款镜像是否匹配权威明细
discounts Array 当前有效优惠
discounts[].discountId String 优惠 ID
discounts[].name String 优惠名称
discounts[].type String 优惠类型
discounts[].amount Decimal 优惠金额

示例

请求:

GET /v3/admin/order/1914050000000001/settlement/financial-overview
Authorization: Bearer <token>

响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "baseOrderAmount": 24800.00,
    "otherIncomeAmount": 500.00,
    "discountAmount": 300.00,
    "adjustedReceivableAmount": 25000.00,
    "onlinePaidAmount": 22000.00,
    "offlinePaidAmount": 3000.00,
    "primaryReporterCollectedAmount": 2000.00,
    "paidAmount": 25000.00,
    "actualRefundedAmount": 0.00,
    "netPaidAmount": 25000.00,
    "outstandingAmount": 0.00,
    "surchargeMirrorMatched": true,
    "discountMirrorMatched": true,
    "paidMirrorMatched": true,
    "refundedMirrorMatched": true,
    "discounts": [
      {
        "discountId": "9100000000001",
        "name": "老客优惠",
        "type": "CUSTOMER_DISCOUNT",
        "amount": 300.00
      }
    ]
  }
}

6. 枚举 / 数据字典

6.1 categorySettlementCategory

所属字段: 路径参数 category、响应 items[].category | 类型: String

中文 说明
HOTEL 住宿 住宿核单分类
TICKET 门票/游玩项目 门票及游玩项目核单分类
MEAL 餐食 餐食核单分类
VEHICLE 车辆 车辆费用核单分类
GUIDE 导游 导游费用核单分类
PHOTOGRAPHER 摄影 摄影费用核单分类
OTHER_INCOME 其他收入 其他收入核单分类
OTHER_EXPENSE 其他支出 其他支出核单分类

6.2 reportStatusSettlementReportStatus

所属字段: reportStatus | 类型: String

中文 说明
GENERATED 已生成 报告已生成,尚未确认
CONFIRMED 已确认 报告已确认
STALE 已过期 来源事实已变化,需要重新生成

6.3 confirmStatus

所属字段: items[].confirmStatus | 类型: String

中文 说明
UNCONFIRMED 未确认 分类尚未确认
CONFIRMED 已确认 分类已确认

7. 错误码汇总

code 含义 触发场景
584310 八个核单分类尚未全部确认或数据已变化 生成主报账表前门禁失败
584311 主报账表尚未生成 主报账表查询/确认前置缺失
584312 主报账表尚未确认或数据已变化 生成单团核算表前门禁失败
584313 单团核算表尚未生成 单团核算表查询/确认前置缺失
584314 单团核算表尚未确认或数据已变化 finalize 前门禁失败
584315 核单来源数据已变化,请刷新后重新生成 分类或报告指纹过期
584316 核单报告发生并发变化,请刷新后重试 并发确认冲突
584317 当前报告状态不允许执行该操作 当前状态不能执行生成/确认/finalize
584318 空分类必须显式确认,非空分类不得按空分类确认 confirmEmpty 与分类是否为空不匹配
584319 核单存在未知分类或历史迁移数据不完整 分类枚举非法或历史数据缺失

10. 修改前后对比

10.1 字段级对比

接口/字段 改前 改后
GET /settlement/financial-overview 返回应收总览及逐条优惠确认状态 只返回应收总览和优惠明细,不再承载确认流
POST /settlement/financial-overview/confirm 请求体 expectedOverviewFingerprint 接口删除,改用 POST /settlement/category-checks/{category}/confirmexpectedSourceFingerprint + confirmEmpty
POST /settlement/financial-overview/discounts/{discountId}/confirm 请求体 expectedSourceFingerprint 接口删除,优惠纳入 8 分类/报告流
主报账表 无独立响应结构 新增 SettlementReimbursementReportRespVO
单团核算表 无独立响应结构 新增 SettlementGroupReportRespVO
完成核单 旧入口为 POST /settlement/step6/submit 新增原型流入口 POST /settlement/finalize,返回 SettlementSubmitRespVO

10.2 行为级对比

行为 改前 改后
核单确认门禁 财务总览/优惠逐条确认 8 分类全部确认
报账表 无独立生成/确认步骤 先生成并确认主报账人报账表
单团核算 无独立生成/确认步骤 主报账表确认后生成并确认单团核算表
最终提交 直接 Step6 提交 单团核算表确认后调用 finalize
旧 POST 接口 可调用 下线,调用方需迁移

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容: 是。两个旧 POST 确认接口删除;财务总览查询响应语义收窄。
  • 前端是否必须同步上线: 是。核单页面需要按 8 分类确认、主报账表、单团核算表、finalize 的顺序对接。
  • 影响已有数据: 前端接口层不需要处理数据库迁移细节;历史订单在接口层按当前数据计算状态。

11.2 回滚方案

  • 回滚方式: 回滚 PR #5243 后恢复旧确认流。
  • 回滚后清理: 前端需恢复旧 financial-overview/confirmdiscounts/{discountId}/confirm 调用。
  • 回滚耗时: 取决于后端回滚与重新部署;前端接口调用需同步回退。

12. 注意事项

  • 前端不要继续调用已删除的两个旧 POST 确认接口。
  • 8 分类确认必须使用刚查询到的 sourceFingerprint,报告确认必须使用刚查询/生成返回的 sourceFingerprint
  • STALE 表示来源已变化,不能继续确认。
  • 空分类确认必须传 confirmEmpty=true;非空分类必须传 false

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人: @yst