文件
hl-api-changelog/changelogs-v2/2026-09/23_8225_订单调整提交远程调用移出锁与事务并新增并发改动码587043-修改接口-管理后台.md
T
jw和Claude Opus 5.5 226deac4a2
changelog-filename-gate / validate (push) Failing after 2s
changelog: #8225 订单调整统一提交远程调用移出锁与事务,新增失败码 587043
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 16:12:15 +08:00

11 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, 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 author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 8225 订单调整统一提交:远程调用移出锁与事务,新增失败码 587043「提交期间订单已被其他操作修改,请刷新后重试」 admin jw(GIT) 修改接口 deployed verified not_required PR #8255 已合并 dev-v3(c2b261cd2),2026-09-23 15:40 滚动部署 TEST 双实例;其后另一会话部署的 f6d21648b 包含本单。真实网关实测:非法座位数提交返回 582024 且零写入,日志确认拒绝发生在拿锁之前;改出行人姓名正向往返 200 并落调整记录,已改回原值;无 token / 伪造 token 均 401。入参、出参结构不变,唯一的契约变化是新增失败码 587043;前端按通用失败提示展示后端 message 即可,无需改动。 2026-09-23 dev-v3

订单调整: 统一提交的远程调用移出锁与事务 + 新增失败码 587043

存放目录: 二期(v3) → changelogs-v2/2026-09/

服务: hl-order-service-v3 PR: #8255 Issue: #8225 日期: 2026-09-23 影响范围: 管理后台订单详情「调整订单」弹窗的统一提交


⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)

  • 本次变化:统一提交接口多了一个失败码 587043「提交期间订单已被其他操作修改,请刷新后重试」。
  • 前端以前以为的:同一订单两次调整并发提交时,后提交的那次会排队等前一次完成,然后照常成功。
  • 实际新行为:算价、协议价、车型校验这些远程调用现在在拿锁之前完成。如果在这段时间里另一笔调整改了本单的出发日、人数或产品,本次提交会被拒绝并返回 587043,整笔不写库;用户刷新后重新提交即可。请求和响应的结构都没有变。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 调整订单统一提交 POST /v3/admin/order/:id/adjustment/submit 新增失败码 新增 587043;入参、出参不变

三、接口详情

1. 调整订单统一提交 POST /v3/admin/order/:id/adjustment/submit

VO: AdjustmentSubmitReqVO → AdjustmentSubmitRespVO

使用场景

管理后台订单详情页「调整订单」弹窗,前端在内存里收集出行人、改期、行程、用房需求、行程用车、接送机用车等改动后一次性提交。

入参

字段 位置 类型 必填 约束 说明
Authorization Header String ✅ - 管理端登录令牌
id Path Long ✅ 订单须存在(581007) 订单 ID
updates Body Object ✅ 至少一个子领域有实际改动(587033) 各子领域修改内容,未改的子领域传 null
updates.people Body Object ❌ - 订单级紧急联系人 + 出行人增删改
updates.travelers Body Object ❌ - 出行人 add / update / remove
updates.schedule Body Object ❌ departDate 为 yyyy-MM-dd 改期
updates.itinerary Body Object ❌ - 行程天与节点的完整新版本
updates.hotelRequirement Body Object ❌ - 用房需求完整新版本
updates.vehicleRequirement Body Object ❌ fleet 车型须为车型大类、座位数须在车型库选项内 行程用车需求完整新版本
updates.transferRequirement Body Object ❌ 同上 接送机用车需求完整新版本

出参 Result<AdjustmentSubmitRespVO>

字段 类型 说明
success Boolean 提交成功恒为 true

请求示例

{
  "updates": {
    "travelers": {
      "update": [{ "id": "2098374040010772481", "name": "杨知川" }]
    }
  }
}

响应示例

{ "code": 200, "message": "成功", "data": { "success": true }, "traceId": null, "success": true }

空数据 / 降级响应

写接口没有空数据场景。所有提交都没有实际改动时返回 587033,零写入:

{ "code": 587033, "message": "未检测到有效变更,无需提交", "data": null, "traceId": null, "success": false }

错误响应

本次新增:

{ "code": 587043, "message": "提交期间订单已被其他操作修改,请刷新后重试", "data": null, "traceId": null, "success": false }

既有错误码照旧,例如车型座位数不合法:

{ "code": 582024, "message": "座位数不在该车型大类可选座位数中,请检查车型库", "data": null, "traceId": null, "success": false }

业务边界

  • 鉴权:未登录 → 业务码 401(「缺少有效的 Authorization 头」),token 签名不对 → 401(「Token 无效」)。
  • 587043 只在「本次提交读到的订单」与「拿锁后的订单」在出发日、人数、产品上不一致时出现,也就是有另一笔调整恰好在同一时刻提交;单人操作不会遇到。
  • 587043 与其它失败码一样整笔零写入,重新提交会按最新的订单状态重新计算差价。

四、契约约束与正确调用方式(接口类必写)

本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。

✅ 正确 / ❌ 错误 payload 对照

场景 payload 结果
✅ 只改出行人姓名 updates.travelers.update=[{id,name}] 200
❌ 没有任何实际改动 updates: {} 587033
❌ 行程用车座位数不在车型库选项内 fleet=[{vehicleType:"大巴", seats:999, count:1}] 582024,零写入
❌ 提交期间另一笔调整改了出发日 / 人数 / 产品 任意 587043,零写入(本次新增)
  • 请求与响应结构没有任何变化;587043 的 message 已写明处理方式,前端按通用失败提示展示后端文案即可。

五、数据库行为(涉及写操作时必写)

  • 无 Flyway migration、无 DDL、无表结构变更。
  • 写库集合与改前一致(出行人、行程、用房/用车需求版本、优惠加费、调整记录、状态日志),仍在同一个事务内原子完成。
  • 变化在事务边界:算价、协议价、车型校验等远程调用改为在拿锁、开事务之前完成,订单行与用车确认 fence 行的锁持有时间不再包含这些远程往返。
  • 任何失败(含新增的 587043)都在写库之前抛出,整笔零写入。TEST 实测:非法座位数提交后,订单主单、fence 行、用车需求、调整记录前后逐字段一致。

六、边界行为

  • 未登录 → 业务码 401。
  • 越权规则不变:非管理员只能调整自己负责的订单。
  • 拒绝原因的先后顺序不变:终态、已过天锁定、出行人/改期窗口、改期日期格式等守卫,仍然先于算价与车型校验。
  • 团期子订单改期仍只能改回所属团期出发日(587039),不走个人价格日历报价。

六.6、修改前后对比(修改/删除类接口必写,新增跳过)

字段级对比

字段 改前 改后
请求体 AdjustmentSubmitReqVO 不变
响应体 { success } 不变
失败码 无 587043 新增 587043

行为级对比

行为 改前 改后
远程调用(算价、协议价、车型字典/座位、字典标签)发生时机 拿锁、开事务之后 拿锁、开事务之前
两笔调整并发提交,前一笔改了出发日/人数 后一笔等锁后按新状态照常执行 后一笔返回 587043,刷新重提
车队 / 产品 / 资源服务响应慢 订单行被锁住直到远程返回 不影响锁持有时间

六.7、影响评估(修改/删除类必写)

  • 是否破坏向后兼容:请求、响应结构不变;只新增一个失败码,只在并发调整同一订单时出现。
  • 前端是否必须同步上线:否。前端的通用失败提示会展示后端 message(「提交期间订单已被其他操作修改,请刷新后重试」),无需改动。
  • 前端 workaround 清理点:无。

七、不影响范围(显式声明, 帮前端/QA 缩小排查面)

  • 仅影响:POST /v3/admin/order/:id/adjustment/submit 的内部执行顺序,以及新增失败码 587043。
  • 零影响:
    • GET /v3/admin/order/:id/adjustment/snapshot(调整弹窗初始化数据)与 GET /v3/admin/order/:id/adjustment-record(调整记录)。
    • 行程查询 getItinerary 返回的服务标准字段、大交通批次列表的旅客类型中文名(管理端读接口行为不变)。
    • 既有失败码与文案。

八、测试环境已验证

部署:PR #8255 合并 dev-v3(c2b261cd2),2026-09-23 15:40 滚动部署 TEST 双实例;其后另一会话部署的 f6d21648b 以本单为祖先,且其间没有提交改动本单涉及的文件。

真实网关(https://api.test.1814.love,管理端 token,订单 2098372757820428289):

POST /v3/admin/order/:id/adjustment/submit  无 token                    → 401 缺少有效的 Authorization 头 ✓
POST /v3/admin/order/:id/adjustment/submit  伪造 token                  → 401 Token 无效 ✓
POST ...  updates={}                                                    → 587033 未检测到有效变更 ✓
POST ...  vehicleRequirement.fleet=[大巴 × 999 座]                      → 582024,订单/fence/用车需求/调整记录前后一致 ✓
         同时刻 primary 实例日志:先是不加锁的 order_main 查询,全程 0 条 fence SQL、0 条 FOR UPDATE ✓
POST ...  travelers.update 改姓名                                       → 200,姓名已改、调整记录 0→1 ✓
POST ...  travelers.update 改回原名                                     → 200,姓名还原 ✓

587043 需要两笔调整真实竞态才能触发,TEST 上未造出;由单元测试覆盖(两段之间出发日变化 → 587043 且零写入;出发日未变 → 放行的对照)。

单元测试:rebase 后定向 239 类 / 3290 例 0 失败,含 AdjustmentServiceSubmitTest 86、TransactionalRemoteCallArchTest 2、SettlementLockContractTest 5。


十、相关文档

关联 / 联系人

链接

联系人

  • 后端负责人: @jw
  • 前端负责人: @mmg