hl-api-changelog/changelogs-v2/2026-08/08_5704_核单域下线数据指纹-修改接口-管理后台.md
yaosutu 3928b35212
一些检查失败了
changelog-filename-gate / validate (push) Failing after 1s
docs(changelog): 撤回含错误指纹说法的 #5674 白名单,只读字段清单并入 #5704
2026-08-08 22:44:38 +08:00

16 KiB

schema, ticket, title, consumer, change_type, author, 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 author backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 5704 核单域下线数据指纹乐观锁6 个端点删除指纹/版本号入参与出参字段 admin 修改接口 yaosutu(GIT) deployed verified pending PR #5709 已合并 dev-v3;核单域 6 个端点删除 expectedSourceFingerprint/version 入参与 sourceFingerprint/version 出参,错误码 584108/584110/584325 同步下线。字段删除属硬破坏契约,前端必须先停传这些字段再与后端同批发布。 2026-08-08 dev-v3

⚠️ 修改接口·管理后台】核单域下线数据指纹乐观锁,6 个端点删除指纹/版本号字段(#5704

PR: #5709 | 服务: hl-order-service-v3 | 更新时间: 2026-08-08

1. 接口背景

核单为单人负责场景,不存在多人并发同时修改同一订单核单数据的情况。此前引入的数据指纹sha256/版本号乐观锁机制(前端 GET 拿到指纹,保存/确认/提交时回传,数据被他人改动则拒存)对单人操作无实际保护价值,且强制前端每次保存前 GET 并回传 64 位十六进制指纹,增加对接负担。本次将核单域内该机制整体下线:删除 6 个端点的指纹/版本号入参字段与对应出参字段,3 个相关错误码不再触发

⚠️ 本次为字段删除类硬破坏契约:其中 5 个端点的请求体带未知字段白名单校验,前端若继续传已删除的字段会被拒绝(详见 §11前端必须先删除这些字段的传参,再与后端同批发布。

2. 变更清单

# 接口 方法 路径 变更类型 前端动作
1 保存导游费用 PUT /v3/admin/order/{orderId}/settlement/guide-fees 删除入参 expectedSourceFingerprint、删除出参 sourceFingerprint 停止传参/读字段
2 确认导游费用 POST /v3/admin/order/{orderId}/settlement/guide-fees/confirm 删除入参 expectedSourceFingerprint 停止传参
3 保存摄影费用 PUT /v3/admin/order/{orderId}/settlement/photographer-fees 删除入参 expectedSourceFingerprint、删除出参 sourceFingerprint 停止传参/读字段
4 确认摄影费用 POST /v3/admin/order/{orderId}/settlement/photographer-fees/confirm 删除入参 expectedSourceFingerprint 停止传参
5 保存车辆核单草稿 PUT /v3/admin/order/{orderId}/settlement/step3/vehicles 删除入参 version、删除出参 version 停止传参/读字段
6 完成核单 POST /v3/admin/order/{orderId}/settlement/finalize 删除入参 reimbursementExpectedSourceFingerprintgroupExpectedSourceFingerprint 停止传参

同时下线的错误码:584108584110584325(详见 §7

3. 接口详情

  • 使用场景:核单人员在订单核单页维护导游费用、摄影费用、车辆核单草稿,并在全部分类就绪后完成核单提交。
  • 认证需要管理后台登录态Bearer Token
  • 幂等性:保存类接口按订单维度覆盖式保存,重复提交相同载荷结果一致;确认/提交接口重放安全(不再有指纹前置校验)。
  • 限流:未声明接口专属限流。
  • 方法/路径:见 §2 变更清单(共 6 个端点;对应的 GET 查询端点出参同步删除指纹/版本号字段,见 §5

4. 接口入参

4.1 路径参数

参数 类型 必填 说明
orderId Long 订单 ID,路径参数,6 个端点一致

4.2 请求体字段(变更后现状)

PUT /settlement/guide-fees保存导游费用

字段 类型 必填 说明
items Array 导游费用明细全量集合,最多 200 条;每项含 id/candidateKey/staffAssignmentId/serviceDate/name/serviceType/paymentMethod/amount/remark/voucherUrls/sourceResolution/candidateStatus
excludedCandidateKeys Array of String 明确排除的候选 key;空数组表示本次不新增排除项
expectedSourceFingerprint - - 已删除,禁止再传(传了会被 584128 白名单拒绝)

POST /settlement/guide-fees/confirm确认导游费用

字段 类型 必填 说明
itemIds Array of Long 待确认 INCLUDED 费用明细 ID 列表JSON 中每项为字符串,1~200 条
expectedSourceFingerprint - - 已删除,禁止再传

PUT /settlement/photographer-fees、POST /settlement/photographer-fees/confirm:字段结构同导游两个端点,仅业务对象为摄影费用,删除字段同为 expectedSourceFingerprint

PUT /settlement/step3/vehicles保存车辆核单草稿

字段 类型 必填 说明
items Array 车辆核单全量明细
version - - 已删除,禁止再传(传了会被白名单拒绝,返回 400

POST /settlement/finalize完成核单

字段 类型 必填 说明
remark String 提交备注
reimbursementConfirmation Object 条件必填 主报账确认凭据;含 transferDate(转账日期)、transferRef(转账流水号,主报账净额非 0 时必填,trim 后最长 128 字符)、advanceSettledFlag(预支是否已处理,必填布尔)、signedVoucher(签字凭证,至少 1 个 URL 非空文件:files[{name,url}] + note
reimbursementExpectedSourceFingerprint - - 已删除,禁止再传
groupExpectedSourceFingerprint - - 已删除,禁止再传

finalize 请求体未启用未知字段白名单,误传旧指纹字段会被静默忽略(不报 400,但前端仍应停止传参,避免依赖「传了也没事」的行为。

5. 出参字段

成功路径出参结构不变,仅删除指纹/版本号字段:

端点 删除的出参字段 原作用
GET/PUT /settlement/guide-fees、POST /settlement/guide-fees/confirm 响应 sourceFingerprint 导游费用来源数据 sha256 指纹
GET/PUT /settlement/photographer-fees、POST /settlement/photographer-fees/confirm 响应 sourceFingerprint 摄影费用来源数据指纹
GET/PUT /settlement/step3/vehicles 响应 version 车辆核单草稿版本号

其余出参字段(如导游/摄影的 category/totalAmount/cashPaidAmount/unconfirmedCount/pendingCandidateCount/settlementReady/blockReasonCode/items/editable/readOnlyReasonCode,车辆的 orderId/totalAmount/allConfirmed/settlementReady/blockReasonCode/items/frozen 等)均无变化。前端不要再读取 sourceFingerprint / version,读取结果恒为 undefined。

6. 枚举 / 数据字典

本次不涉及枚举或字典的新增、删除、改值、改语义。serviceTypeFULL_COURSE_GUIDE/LOCAL_GUIDE/COMMENTARY_SERVICE/TEMPORARY_SUPPLEMENTpaymentMethodCOMPANY_PAID/CASH_PAID/SIGNEDblockReasonCode 等既有取值不变。

7. 错误码

code 含义 本次变化
584108 车辆核单明细已变化,请刷新 已删除,不再触发
584110 导游或摄影费用数据已变化,请刷新 已删除,不再触发
584325 核单提交指纹缺失FINALIZE_FINGERPRINT_REQUIRED 已删除,不再触发
584315 核单来源数据已变化,请刷新后重新确认 仍在用:车辆保存的来源数据漂移门禁改抛此码(承接原 584108 场景)
584128 导游或摄影费用请求字段不合法:{具体原因} 不变;前端误传已删除字段时由该码拒绝(见 §8.3

前端如曾对 584108/584110/584325 写过特判(专属提示/自动刷新分支),这些分支不会再命中,应移除;车辆来源漂移场景改判 584315

8. 示例

8.1 典型成功(保存导游费用,不再回传指纹)

PUT /v3/admin/order/2084000000000002978/settlement/guide-fees
Authorization: Bearer <token>
Content-Type: application/json
{
  "items": [
    {
      "id": "9001",
      "candidateKey": null,
      "staffAssignmentId": "11",
      "serviceDate": "2026-08-08",
      "name": "导游甲",
      "serviceType": "FULL_COURSE_GUIDE",
      "paymentMethod": "COMPANY_PAID",
      "amount": "500.00",
      "remark": null,
      "voucherUrls": [],
      "sourceResolution": null,
      "candidateStatus": "COMPLETE"
    }
  ],
  "excludedCandidateKeys": []
}
{
  "code": 200,
  "message": "success",
  "data": {
    "category": "GUIDE",
    "totalAmount": "500.00",
    "cashPaidAmount": "0.00",
    "unconfirmedCount": 1,
    "pendingCandidateCount": 0,
    "settlementReady": false,
    "blockReasonCode": "UNCONFIRMED_ITEMS",
    "items": [],
    "editable": true,
    "readOnlyReasonCode": null
  },
  "success": true
}

注意:响应中已无 sourceFingerprint 字段。

8.2 边界(完成核单,不再传双指纹)

POST /v3/admin/order/2084000000000002978/settlement/finalize
Authorization: Bearer <token>
Content-Type: application/json
{
  "remark": "核单完成",
  "reimbursementConfirmation": {
    "transferDate": "2026-08-08",
    "transferRef": "TX20260808001",
    "advanceSettledFlag": true,
    "signedVoucher": {
      "files": [{"name": "voucher.jpg", "url": "https://oss.example.com/voucher/1.jpg"}],
      "note": null
    }
  }
}
{"code": 200, "message": "success", "data": {"submitted": true}, "success": true}

8.3 业务失败(旧前端仍传已删除字段,被白名单拒绝)

场景 A保存导游费用仍传 expectedSourceFingerprint

PUT /v3/admin/order/2084000000000002978/settlement/guide-fees
Authorization: Bearer <token>
Content-Type: application/json
{
  "expectedSourceFingerprint": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "items": []
}
{"code": 584128, "message": "导游或摄影费用请求字段不合法:导游费用请求不支持字段: expectedSourceFingerprint", "data": null, "success": false}

场景 B保存车辆核单草稿仍传 version

PUT /v3/admin/order/2084000000000002978/settlement/step3/vehicles
Authorization: Bearer <token>
Content-Type: application/json
{
  "version": 3,
  "items": []
}
{"code": 400, "message": "请求数据格式错误:车辆核单请求不支持字段: version", "data": null, "success": false}

9. 业务边界

  • 保存/确认/提交不再要求前端先 GET 取指纹,可直接操作;单人负责场景下后写覆盖先写,与既有使用方式一致。
  • 车辆保存仍保留「来源数据漂移」业务门禁:草稿加载后若派单/用车来源数据已变化,保存时返回 584315,提示刷新后重新确认——这不是乐观锁,是业务一致性校验。
  • 导游/摄影 4 个端点与车辆保存端点对请求体做字段白名单校验,任何未知字段都会被拒(含本次删除的指纹/版本号字段),不要把查询响应整个 echo 回请求体。
  • 已终态(冻结)的核单数据仍不可编辑,该约束与本次变更无关,保持不变。

9.1 保存时必须剥掉的只读派生字段(导游/摄影)

导游/摄影保存接口PUT guide-fees / photographer-fees的 GET 响应 items[] 里含有后端计算的只读派生字段,保存回传时必须剥掉,否则触发白名单 400错误码 584128「不支持字段: xxx」

必须剥掉的字段:

字段 含义
sourceType / sourceTypeName 来源类型及中文名
sourceActive 来源是否仍有效
serviceTypeName 导游服务类型中文名
feeTypeName 摄影费用类型中文名
paymentMethodName 付款方式中文名
settlementConfirmStatus / settlementConfirmStatusName 核算确认状态及中文名
candidateResolution 候选处理结果

通则:所有 *Name 中文字段 + sourceType/sourceActive + 确认状态 + 候选处理结果,都是后端算的,保存一律不回传。 推荐前端保存前按允许字段重建 payload维护 toSaveItem 映射),不要把 GET 响应对象整个 echo 回去。

10. 修改前后对比

10.1 字段级对比

端点 字段 原来 现在
PUT guide-fees / photographer-fees expectedSourceFingerprint 入参,回传 GET 拿到的指纹 已删除
POST guide-fees/confirm、photographer-fees/confirm expectedSourceFingerprint 入参 已删除
GET/PUT guide-fees、photographer-fees 响应 sourceFingerprint 出参,64 位十六进制 已删除
PUT step3/vehicles version 入参,草稿版本号 已删除
GET/PUT step3/vehicles 响应 version 出参,整数版本号 已删除
POST finalize reimbursementExpectedSourceFingerprintgroupExpectedSourceFingerprint 入参,双指纹 已删除

10.2 行为级对比

场景 原来 现在
保存导游/摄影费用 必须先 GET 取 sourceFingerprint 回传,指纹不匹配返回 584110 直接保存,无指纹校验
保存车辆核单草稿 必须回传 version,不匹配返回 584108 直接保存;来源数据漂移改返回 584315
完成核单提交 必须传主报账+单团核算双指纹,缺失返回 584325 直接提交,无指纹校验
请求体含已删除字段 正常受理 导游/摄影返回 584128、车辆返回 400;finalize 静默忽略

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容是,硬破坏。导游/摄影 4 个端点 + 车辆保存端点带请求体字段白名单,旧前端继续传 expectedSourceFingerprint / version 会被拒绝584128 / 400,核单保存、确认链路直接不可用。
  • 前端是否必须同步上线必须同批。前端需先删除上述字段的传参与读取,再与后端同批发布;旧前端 + 新后端 = 核单保存/确认全部报错。
  • 上线顺序边界:前后端同批发布;若必须分先后,先上前端(停传字段),再上后端
  • 前端特判清理:移除对 584108/584110/584325 的特判;车辆来源漂移提示改挂 584315

11.2 回滚方案

  • 后端回滚即恢复原指纹契约;但已改造的新前端(不传指纹)在旧后端上会触发指纹校验失败——回滚必须前后端同批回滚
  • 数据侧无迁移:指纹/版本号不持久化在业务表,回滚无数据修复成本。

12. 注意事项

  • 本次只下线核单域内上述 6 个端点的指纹机制;应收总览/逐条优惠确认的指纹错误码 584300/584302OVERVIEW_FINGERPRINT_EXPIRED / DISCOUNT_FINGERPRINT_EXPIRED不在本次范围,仍在用,相关确认接口的指纹传参保持不变。
  • 保存类接口幂等语义不变:按订单维度覆盖式全量保存,重复提交相同载荷结果一致。
  • 排查用户报错时,584128 / 400 的 message 已含具体不支持的字段名,可直接据此定位前端是否还在传旧字段。
  • 小程序端(/v3/mp/*)不涉及本次变更,无需任何改动。

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人: @yaosutu (yst)