hl-api-changelog/changelogs-v2/2026-08/06_5598_终止行程重复提交改一律581049-修改接口-管理后台.md
yaosutu be67501c86
所有检测均成功
changelog-filename-gate / validate (push) Successful in 1s
docs(changelog): 终止行程重复提交改一律581049(#5598 / PR #5604)
- COMPLETED 订单再次提交 terminate 由同正文 200 重放改为一律 581049「订单已终止,禁止重复提交」,零副作用
- 581049 文案由「终止行程重试与首次终止边界或请求不一致」改为「订单已终止,禁止重复提交」
- 首次终止(TRAVELLING→COMPLETED)行为不变;入参/出参字段结构不变
- 取代 04_5460 同正文重放契约,前端收到 581049 应视为订单已终止并改走查询接口取退款结果
2026-08-06 17:33:55 +08:00

14 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 5598 终止行程重复提交改一律 581049COMPLETED 订单再次提交不再重放首次结果 admin 修改接口 yst(GIT) deployed verified pending PR #5604 已合并 dev-v3 并部署 TEST,网关实测COMPLETED 订单再次提交 terminate 一律返回 581049「订单已终止,禁止重复提交」同正文也不再 200 重放)。前端如依赖 #5460 的同正文重放取回结果逻辑需适配。 2026-08-06 dev-v3

🔧【修改接口·管理后台】终止行程重复提交改一律 581049 (#5598)

PR#5604 服务hl-order-service-v3 更新时间2026-08-06 消费端:管理后台

1. 接口背景

终止行程(出行中提前结束订单)是有副作用的写操作:首次提交会把订单从 TRAVELLING 推进到 COMPLETED、生成终止退款单、写核单退款关联。此前#5460对"首次成功但响应丢失"的场景提供了幂等重放:同正文重放返回 200 和既有退款结果。实测中发现该重放语义让"重复提交"与"首次提交"边界模糊,且重放判定依赖请求指纹快照,对升级前的历史订单还要做语义等价兜底,复杂度高、收益低。

本次收紧为状态机幂等:订单一旦 COMPLETED已终止/已完成),再次提交终止一律拒绝,返回 581049「订单已终止,禁止重复提交」,零副作用(不重写退款、不重发事件、不做指纹比对)。

首次正常终止TRAVELLING → COMPLETED行为完全不变,仍返回 200 和退款结果。

变更接口清单

# 接口名 方法 路径 变更类型 说明
1 终止行程(出行中) POST /v3/admin/order/:id/terminate 修改 COMPLETED 订单重复提交:同正文重放由 200 返回既有结果改为一律 581049;581049 文案由「终止行程重试与首次终止边界或请求不一致」改为「订单已终止,禁止重复提交」

入参字段结构、出参字段结构均无变化

3. 接口详情

3.1 终止行程(出行中)

  • 接口说明:出行中因特殊原因提前终止订单,订单进入 COMPLETED 状态,由核单/结算流程继续处理;后端按权威数据重算退款金额。
  • 使用场景:管理后台订单详情页,出行中订单执行"终止行程"操作。
  • 认证:需要管理后台登录态和订单操作权限;房务角色不可操作。
  • 幂等性不再提供重放幂等。首次提交成功即生效;订单 COMPLETED 后任何再次提交(无论正文是否与首次一致)一律返回 581049,零副作用。
  • 限流:未声明接口级独立限流规则。

4. 接口入参

4.1 路径参数 / Query 参数

字段 位置 类型 必填 说明与校验
id Path Long 订单 ID路径写作 :id

无 Query 参数。

4.2 请求体字段

请求体类型:OrderTerminateTripReqVO本次无变化)。

字段 类型 必填 说明与校验
cancelReason String 终止原因 + 调整说明(合并,不单列 adjustReason
endDayNumber Integer 停在第几天截断点,1-based,最小 1
lineUsages[] Array 统一资源行已用判定列表;优先级高于旧分组数组,lineKey 来自 refund-preview 的 refundLines[].lineKey
lineUsages[].lineKey String 是(数组内) 退款资源行 key,示例 ITINERARY_NODE:97010:2
lineUsages[].used Boolean 是(数组内) 是否已使用
rooms[] Array 住宿已用判定列表;兼容旧入参,新逻辑优先使用 lineUsages
tickets[] Array 门票/活动已用判定列表;兼容旧入参,refId = 行程节点 nodeId
services[] Array 服务已用判定列表;兼容旧入参,refId = 行程节点 nodeId
supplies[] Array 备品已用判定列表;兼容旧入参,refId 与预览返回一致
rooms[]/tickets[]/services[]/supplies[] 元素 Object 结构为 refId Long 必填 + used Boolean 必填
vehicles[] Array 用车每天已用判定列表;仅兼容接收,used 不参与计算,后端按车辆 serviceDate 与终止日权威重算
vehicles[].refId Long 是(数组内) 配车记录 ID同段车跨天 refId 相同,靠 dayNumber 区分)
vehicles[].dayNumber Integer 是(数组内) 第几天1-based
vehicles[].used Boolean 是(数组内) 兼容字段:必填,但车辆退款金额不采用该值
adjustAmount Decimal 人工调整额(允许负,默认 0;说明并入 cancelReason

5. 出参字段

响应类型:Result<OrderTerminateTripRespVO>本次无变化)。

5.1 统一响应外层

字段 类型 可空 说明
code Integer 成功为 200;失败见第 7 节
message String 结果说明
data Object/null 失败时为空 成功时为终止结果
traceId String 链路追踪 ID
success Boolean code=200 时为 true

5.2 成功响应 data

字段 类型 可空 说明
terminateRefundId String(Long) 终止退款主表 ID,按字符串返回
baselineRefund String(Decimal) 系统建议基线 = max(0, 已付金额 - 已用金额),按字符串返回
adjustAmount String(Decimal) 人工调整额(入参回显,默认 0,按字符串返回
finalRefund String(Decimal) 最终返还额 = max(0, baselineRefund + adjustAmount),按字符串返回
settlementRefundId String(Long) 关联的核单退款结算 ID核单模块写入后回填,按字符串返回
newStatus String 终止后订单粗状态,固定 COMPLETED
newFlowStatus String 终止后流程细状态,固定 PENDING_REVIEW

6. 枚举 / 数据字典

6.1 data.newStatus(订单粗状态,本接口相关取值)

中文 说明
TRAVELLING 出行中 终止前状态;只有该状态可首次提交终止
COMPLETED 已完成 终止后状态;该状态下再次提交一律 581049

6.2 data.newFlowStatus(流程细状态)

中文 说明
PENDING_REVIEW 待核单 终止成功后进入核单流程

本次无数值新增/删除/改义。

7. 错误码

code 含义 触发场景
200 终止成功 订单为 TRAVELLING 且校验通过;订单推进 COMPLETED 并生成终止退款
400 请求参数错误 cancelReason/endDayNumber、数组内必填字段缺失等
581007 订单不存在 id 对应订单不存在
581018 出行中取消仅适用于出行中订单 订单非 TRAVELLING 且非 COMPLETED待出行/已取消等)时提交终止
581044 终止行程:结束日之前的资源必须标记为已使用 结束日前资源 used=false
581047 终止行程:结束日不在订单行程范围内 endDayNumber 越界
581048 终止行程:本地车辆费用服务日与订单行程不一致 车辆费用服务日与订单行程对不上
581049 订单已终止,禁止重复提交(原「终止行程重试与首次终止边界或请求不一致」) 订单已 COMPLETED 时再次提交终止,无论正文是否与首次一致
584100 车务车辆总车费暂时不可用,请稍后重试 Fleet 车辆费用事实不可用,fail closed

8. 示例

8.1 典型成功:出行中订单首次终止(行为不变)

请求

POST /v3/admin/order/2084280231786430466/terminate
Authorization: Bearer <管理后台访问令牌>
Content-Type: application/json
{
  "cancelReason": "客户高反送医终止",
  "endDayNumber": 2,
  "adjustAmount": 0,
  "lineUsages": [
    {
      "lineKey": "HOTEL_ASSIGNMENT:96011:1",
      "used": true
    },
    {
      "lineKey": "ITINERARY_NODE:97010:1",
      "used": true
    }
  ],
  "vehicles": [
    {
      "refId": 9000004500000001,
      "dayNumber": 1,
      "used": true
    }
  ]
}

响应

{
  "code": 200,
  "message": "成功",
  "data": {
    "terminateRefundId": "2084497785524011009",
    "baselineRefund": "6500.00",
    "adjustAmount": "0.00",
    "finalRefund": "6500.00",
    "settlementRefundId": "2084497785561759746",
    "newStatus": "COMPLETED",
    "newFlowStatus": "PENDING_REVIEW"
  },
  "traceId": null,
  "success": true
}

8.2 边界情况COMPLETED 订单重复提交(本次变化点)

场景说明:首次终止已成功(无论响应是否丢失),对同一订单再次提交终止——与首次正文完全相同或不同,结果一样。改前同正文重放会返回 200 和首次结果;改后一律 581049,零副作用。

请求:同 8.1(正文可与首次一致,也可不一致)。

响应TEST 网关实测):

{
  "code": 581049,
  "message": "订单已终止,禁止重复提交",
  "data": null,
  "traceId": null,
  "success": false
}

8.3 业务失败:结束日越界

请求

POST /v3/admin/order/2084280231786430466/terminate
Authorization: Bearer <管理后台访问令牌>
Content-Type: application/json
{
  "cancelReason": "客户临时改行程",
  "endDayNumber": 99
}

响应

{
  "code": 581047,
  "message": "终止行程:结束日不在订单行程范围内",
  "data": null,
  "traceId": null,
  "success": false
}

9. 业务边界

  • 适用场景:订单为 TRAVELLING出行中时首次提交终止,走正常终止流程,返回 200 和退款结果。
  • 不适用场景
    • 订单已 COMPLETED已终止/已完成):任何再次提交一律 581049,不产生任何副作用。
    • 订单为其他状态(待出行/已取消等):581018
  • 特殊边界:终止是有副作用操作,581049 不等于"重试成功";前端拿到 581049 后如需终止结果terminateRefundId / finalRefund,应改走订单详情 / 退款相关查询接口取数,不要再重放 terminate。
  • 金额口径不变:车辆已用仍以车辆 serviceDate 与终止日权威判定,vehicles[].used 仅为兼容字段。

10. 修改前后对比

10.1 字段级对比

原来 现在
入参字段结构 OrderTerminateTripReqVO 全字段 不变
出参字段结构 OrderTerminateTripRespVO 全字段 不变
581049 错误文案 终止行程重试与首次终止边界或请求不一致 订单已终止,禁止重复提交

10.2 行为级对比

场景 原来(#5460 现在
TRAVELLING 订单首次终止 200 返回退款结果,订单推进 COMPLETED 不变
COMPLETED 订单同正文重放 200,返回既有 terminateRefundId / baselineRefund / adjustAmount / finalRefund / settlementRefundId 581049 订单已终止,禁止重复提交,零副作用
COMPLETED 订单不同正文重试 581049(旧文案) 581049(新文案),行为不变
升级前已终止的历史订单重放 按快照语义等价校验,等价返 200 / 不等价 581049 一律 581049

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容是,行为级破坏。依赖"同正文重放返回 200 取回首次结果"的前端重试/补偿逻辑会失效——现在重放拿到的是 581049。
  • 前端是否必须同步上线建议同步。适配方式:
    1. 终止提交后若因超时/网络原因未收到响应,重试时收到 581049 应视为"订单已终止"(首次实际已成功),按成功路径收尾(刷新订单详情),不要当普通错误提示"提交失败"。
    2. 如需展示首次终止的退款结果,收到 581049 后拉订单详情/退款查询接口取数,不再从重放响应获取。
    3. 清理 #5460 时期按"同正文重放取回结果"编写的 workaround。
  • 首次终止路径零变化,不重试的正常操作流程无感。

11.2 回滚方案

  • 后端回滚即恢复 #5460 重放语义(同正文 200 / 不同正文 581049 旧文案)。前端兼容策略"581049 = 已终止,拉详情取数"在回滚后仍然成立(只是同正文重放会重新拿到 200,无需反向适配。

12. 注意事项

  • 581049 新文案是"订单已终止,禁止重复提交",不要再按旧文案"边界或请求不一致"做文案匹配;按 code 判断。
  • 收到 581049 时订单已是 COMPLETED,不要引导用户"修改正文后重试"——任何正文都会被拒。
  • 终止结果字段terminateRefundId / finalRefund 等)只有首次终止的 200 响应返回;之后只能从查询类接口获取。
  • 581018581049 分工:非 TRAVELLING 且未终止过 → 581018;已 COMPLETED → 581049。

验证证据

  • mvn -pl hl-order-service-v3 -am verify 全绿(含重复终止一律 581049 的回归测试)。
  • TEST 网关实测2026-08-06COMPLETED 订单再次提交 terminate 返回 code=581049message=订单已终止,禁止重复提交success=false,零副作用;TRAVELLING 订单首次终止仍 200 返回退款结果。
  • 已部署 TESTPR #5604 合并 dev-v3 后滚动发布)。

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人@yst / yaosutu腰苏图
  • 前端消费方:管理后台订单详情 - 终止行程操作