文件
hl-api-changelog/changelogs-v2/2026-09/20_7972_接送机用车的免车闸与结算闸改为非对称判据-修改接口-管理后台.md
T

17 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 7972 接送机用车的免车闸与结算闸改为非对称判据 admin wx(GIT) 修改接口 deployed not_required not_required 本次改动为后端行为调整(错误码判定条件变化),网关无需变更。gateway_status not_required 意味着网关侧无需部署(网关只转发,错误码处理由后端定义)。 前端实证维持 not_required(mmg 2026-09-20):809114/584131 全仓零命中,两码均走拦截器透后端 message 不建字典(同 8091xx 惯例);TRANSFER 前端不可达(开关未开,#7443 维持挂起),判据变化无可消费面;开放后须知(809114 只看 TRAVEL、584131 finalize 硬阻、免车不豁免 TRANSFER)已入前端 memory。 2026-09-20 dev-v3

order-v3: 接送机用车的免车闸与结算闸改为非对称判据

存放目录: changelogs-v2/2026-09/

服务: hl-order-service-v3 PR: #7976 Issue: #7972 日期: 2026-09-20 影响范围: 管理后台团期用车需求编辑、整团确认、订单结算门禁


⚠️ 关键变化

免车判据从「两种需求(TRAVEL+TRANSFER)任一已进行就拒」改为「只看 TRAVEL,TRANSFER 独立判」。

  • 前端以为:只有 TRANSFER(接送机)、没有 TRAVEL(团车)的户被 809114 拒绝免车
  • 实际现在:809114 放行这类户;584131 只针对 TRANSFER 本身判(不存在/DONE 放行,其余拒)

结算闸新增硬阻:有 TRANSFER 且未完工的户在 finalize 时被 584131 拒绝,且存量 PENDING 的 TRANSFER 会在本次上线后对应户 finalize 变 584131(非回归,是改动预期行为)。


一、背景

只订接送机、不订团车 是合法的在团户(存在真实订单),但被原判据的两支 OR 条件挡住。 免车意在「本团无需用车」,而只有 TRANSFER 的户仍有接送机需求,整团免车不能替接送机放行。 改为非对称判据后:整团免车只豁免 TRAVEL,接送机必须逐户推进到 DONE。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 保存团期用车需求 PUT /admin/group-batch/{groupBatchId}/vehicle-requirement 行为变化 809114 放宽(不挡仅 TRANSFER 户)
2 整团确认 POST /admin/group-batch/{groupBatchId}/vehicle-requirement/confirm 行为变化 同上
3 订单结算 POST /admin/order/{orderId}/submit 行为变化 新增 584131 拒绝条件
4 读团期用车需求 GET /admin/group-batch/{groupBatchId}/vehicle-requirement 行为变化 只读,无副作用

三、接口详情

1. 保存团期用车需求 PUT /admin/group-batch/{groupBatchId}/vehicle-requirement

VO: GroupVehicleRequirementSaveReqVO → GroupVehicleRequirementRespVO

使用场景

管理员在团期用车需求编辑页保存草稿或点「整团免车」。 本次改动只影响点「整团免车」按钮时的 809114 门禁判定:只有 TRANSFER(接送机)、没有 TRAVEL(团车)的户现在能通过。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键
reason Body String ✅ 不含空格、不超 200 字 免车原因(写入备注留痕)
operatorId 上下文 String ✅ 取决于登录用户 操作人 ID(管理员工号)

出参 Result<GroupVehicleRequirementRespVO>

字段 类型 说明
requirementId Long 正式需求聚合主键
status String 状态(DRAFT/CONFIRMED/DISPATCHED/DONE)
groups Array 乘车分组列表,免车声明时为空数组
version Integer 乐观锁版本号
confirmedBy String 确认人 ID(免车时为当前操作人)
confirmedAt LocalDateTime 确认时刻

请求示例

{
  "reason": "只订接送机,不需要团车"
}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "requirementId": 7200000000000001,
    "groupBatchId": 7100000000000001,
    "status": "CONFIRMED",
    "groups": [],
    "version": 2,
    "confirmedBy": "admin001",
    "confirmedAt": "2026-09-20 10:30:00",
    "remark": "[2026-09-19 15:22:00 撤回] 改房型; [2026-09-20 10:30:00 免车] 只订接送机,不需要团车"
  },
  "success": true
}

空数据 / 降级响应

无(必返回需求对象)。

错误响应

{
  "code": 809114,
  "message": "车务已开工(子订单 5100000000000001:PROCESSING),不能再声明整团免车",
  "success": false,
  "data": null
}

业务边界

  • 809114 新判据(仅 TRAVEL 分支):检查全部在团户的 active TRAVEL(非 TRANSFER)需求,若任一已进入 PENDING/PROCESSING/DONE,整团免车被拒
  • TRANSFER 不挡免车:即使某户有 active TRANSFER 处于上述状态,809114 不再拦住,转由结算闸(584131)独立硬阻
  • 幂等:整团已经是免车态(零分组已确认版本)时重复点免车返回 200,不抛错、不推版本
  • 无副作用:本端点不调 fleet,不修改户级需求状态,只操作团期层面的正式需求聚合根

2. 整团确认 POST /admin/group-batch/{groupBatchId}/vehicle-requirement/confirm

VO: 无请求体 → GroupVehicleRequirementRespVO

使用场景

整团确认页面完成预检后点确认按钮。整团确认作为保存需求的上游,同样需要过 809114 门禁(只看 TRAVEL)。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键

出参 Result<GroupVehicleRequirementRespVO>

字段 类型 说明
requirementId Long 正式需求聚合主键
status String 状态(DRAFT/CONFIRMED/DISPATCHED/DONE)
groups Array 乘车分组列表
version Integer 乐观锁版本号
confirmedBy String 确认人 ID
confirmedAt LocalDateTime 确认时刻

请求示例

{}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "requirementId": 7200000000000001,
    "status": "CONFIRMED",
    "groups": [
      {
        "groupCode": "BUS",
        "memberCount": 4,
        "days": [
          { "tripDate": "2026-10-01", "headcount": 4 }
        ]
      }
    ],
    "version": 1,
    "confirmedBy": "admin002",
    "confirmedAt": "2026-09-20 11:00:00"
  },
  "success": true
}

空数据 / 降级响应

无。

错误响应

{
  "code": 809114,
  "message": "车务已开工(子订单 5100000000000002:DONE),不能再声明整团免车",
  "success": false
}

业务边界

  • 与保存草稿共用同一把团级锁:concurrency 写入时后到者抛 809102
  • 状态转移:确认后正式需求进入 CONFIRMED,版本 +1

3. 订单结算 POST /admin/order/{orderId}/submit

VO: 无独立请求体 → SettlementSubmitRespVO

使用场景

管理员在订单结算页面点「提交核单」。本次改动新增 584131 硬阻:有 TRANSFER(接送机)且未完工的户无法 finalize。

入参

字段 位置 类型 必填 约束 说明
orderId Path Long ✅ - 子订单 ID

出参 Result<SettlementSubmitRespVO>

字段 类型 说明
orderId Long 子订单 ID
status String finalize 后的订单状态

请求示例

{}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "orderId": 5100000000000001,
    "status": "SETTLED"
  },
  "success": true
}

空数据 / 降级响应

无。

错误响应(新增 584131)

{
  "code": 584131,
  "message": "接送机:PENDING(团期已声明整团免车,跳过用车户级 TRAVEL 闸;但接送机未安排完成)",
  "success": false
}

业务边界

新增判据(584131,非对称):

  • TRAVEL 分支:若整团已声明免车(zero-group CONFIRMED 版本),TRAVEL 判定被短路,跳过需求检查
  • TRANSFER 分支(独立):
    • 不存在 active TRANSFER(未订接送机)→ 放行
    • TRANSFER 状态 = DONE → 放行
    • TRANSFER 状态 = PENDING/PROCESSING/其他 → 硬阻 584131,不受整团免车影响

存量数据行为:production 中停在 PENDING 的 TRANSFER 需求行(9 条已于 2026-09-19 走真实端点 reject 清掉),所属户的 finalize 在本次上线后会从 200 变 584131——这是本次改动的预期行为,不是回归。


4. 读团期用车需求 GET /admin/group-batch/{groupBatchId}/vehicle-requirement

VO: 无请求体 → GroupVehicleRequirementRespVO

使用场景

编辑页首次打开或重新加载时回填当前需求。本接口是配车刷新状态在 admin 侧唯一的无副作用观测口(#7988),不取锁、不进事务、无任何写操作。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ - 团期聚合主键

出参 Result<GroupVehicleRequirementRespVO>

字段 类型 说明
requirementId Long 正式需求聚合主键
status String 状态(DRAFT/CONFIRMED/DISPATCHED/DONE)
groups Array 乘车分组列表
version Integer 乐观锁版本号
confirmedBy String 确认人 ID
confirmedAt LocalDateTime 确认时刻

请求示例

{}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "requirementId": 7200000000000001,
    "status": "CONFIRMED",
    "groups": [],
    "version": 2,
    "confirmedBy": "admin001",
    "confirmedAt": "2026-09-20 10:30:00",
    "planRefreshStatus": "FAILED",
    "planRefreshFailReason": "fleet timeout"
  },
  "success": true
}

空数据 / 降级响应

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

错误响应

{
  "code": 589500,
  "message": "团期不存在",
  "success": false,
  "data": null
}

业务边界

  • 零写入:不锁、不改库、不进事务、不调 fleet、不推版本
  • 存在性:返回 null 表示「尚未形成正式需求」(正常),不区分「本该有但丢了」

四、契约约束与正确调用方式

✅ 正确 / ❌ 错误 payload 对照

场景 端点 payload 结果
✅ 仅 TRANSFER,免车通过 PUT /admin/group-batch/{id}/vehicle-requirement {"reason":"只订接送机"} 200,状态 CONFIRMED,groups=[]
✅ 仅 TRAVEL,整团确认通过 POST /admin/group-batch/{id}/vehicle-requirement/confirm (无体) 200,状态 CONFIRMED,groups=[{BUS}]
❌ 仅 TRANSFER,TRAVEL 已 PROCESSING,免车拒绝 PUT /admin/group-batch/{id}/vehicle-requirement {"reason":"..."} 409114「车务已开工」
✅ 有 TRANSFER 已 DONE,finalize 通过 POST /admin/order/{id}/submit (无体) 200
❌ 有 TRANSFER 未完工,finalize 拒绝 POST /admin/order/{id}/submit (无体) 584131「接送机未完成」

前后端协议

  • 809114 的「拒绝户」变了:从「TRAVEL 或 TRANSFER 任一进行」改为「仅看 TRAVEL 进行」。前端如有针对 809114 的兜底提示,需复查文案准确性
  • 584131 是新条件:不是对 809114 的替代,而是针对 TRANSFER 独立的硬阻(结算端)
  • 两道分离:免车判定(团期层,809114)与结算判定(订单层,584131)是两套独立的门禁,分别对 TRAVEL 与 TRANSFER 行为

五、数据库行为

免车声明

前置条件 结果
用户A: TRAVEL=PENDING, TRANSFER=null 809114 拒绝(TRAVEL 已进行)
用户B: TRAVEL=null, TRANSFER=PENDING 809114 放行(TRANSFER 不挡) → 免车声明成功
用户C: TRAVEL=DONE, TRANSFER=DONE 809114 拒绝(TRAVEL 已进行)

finalize 闸门

前置条件 结果
TRANSFER=null 584131 放行
TRANSFER=DONE 584131 放行
TRANSFER=PENDING 584131 拒绝(新判据)

版本化

  • 整团免车时若目标版本是「带分组已确认」,会先失活旧版本(CAS),再插入一条「零分组已确认」的新版本
  • version 字段自动 +1,乐观锁冲突返 809102

六、边界行为

  • 未登录 → 401(网关拦截)
  • 团期不存在 → 589500
  • 正式需求不存在 → 809100
  • 下游 fleet 超时 → 返 200,不阻断 finalize(结算与车配解耦)
  • 团期被锁(并发写) → 等待后重试

六.5、枚举

VehicleRequirementStatus(用车需求状态)

所属字段: GroupVehicleRequirementRespVO.status | 类型: String

值 中文 说明
DRAFT 草稿 编辑中
CONFIRMED 已确认 整团确认/免车声明后
DISPATCHED 已派发 fleet 配车完成
DONE 已完成 订单 finalize 后
PENDING_RECONFIRM 待重确认 被打回重新编辑后的中间态

VehicleRequirementKind(需求类型)

所属字段: 内部枚举,不直接暴露给前端 | 类型: String

值 中文 说明
TRAVEL 团车 整团用车需求
TRANSFER 接送机 机场接送

六.6、修改前后对比

行为级对比

行为 改前 改后
809114 判定 检查 TRAVEL 和 TRANSFER,任一进行则拒 只检查 TRAVEL,TRANSFER 不挡
接送机只户的免车 被 809114 拒绝 809114 放行(若 TRANSFER 未完工则被 584131 拒)
finalize 对 TRANSFER 无专项检查 新增 584131:不存在/DONE 放行,其余拒
整团免车对 TRANSFER 整户豁免 不豁免,TRANSFER 仍需逐户到 DONE
flow 推进(行程清单) 只看 TRAVEL 追加 TRANSFER 检查:即使整团免车也要看 TRANSFER

六.7、影响评估

  • 是否破坏向后兼容:是(行为变化)
  • 前端是否必须同步上线:否(后端改动前兼容,后端改动后错误码体验改善但不影响流程)
  • 前端 workaround 清理点:
    • 若有针对 809114「TRANSFER 已进行」的兜底提示,改成只提「TRAVEL 已进行」
    • 若有假设「整团免车豁免一切需求」的逻辑,补充 TRANSFER 的检查(与结算闸 584131 同口径)

七、不影响范围

  • 仅影响:管理后台团期车需求编辑、整团确认、订单结算三处门禁
  • 零影响:
    • 小程序(MP 端点)
    • 户级用车需求的创建/更新(只改 validation 判定,不改流程)
    • 价格、保险、酒店等其他模块
    • 一期业务(dev 分支无此改动)

八、测试环境已验证

部署版本: 8cdb9ad97(包含提交 572dc4037)

✓ PUT /admin/group-batch/7100000000000001/vehicle-requirement 
  {"reason":"只订接送机"} 
  → 200 + status=CONFIRMED + groups=[]
  
✓ POST /admin/group-batch/7100000000000001/vehicle-requirement/confirm 
  → 200 + CONFIRMED
  
✓ POST /admin/order/5100000000000001/submit 
  (TRANSFER=DONE) 
  → 200
  
✓ POST /admin/order/5100000000000002/submit 
  (TRANSFER=PENDING) 
  → 584131 (新判据)
  
✓ GET /admin/group-batch/7100000000000001/vehicle-requirement 
  → 200 + 当前需求

九、相关历史 PR

PR Issue 说明 是否仍有效
#7763 #7441 PR-3 首次引入 584131 硬拦「缺团车需求」 ✅ 有效(本次改动收紧范围,只看 TRANSFER)
#8033 #7988 补只读观测口(本端点) ✅ 有效
本 PR #7976 #7972 收口 809114/584131 的 kind 口径,非对称判定 ✅ 最新

十、相关文档


关联 / 联系人

链接

联系人

  • 后端负责人: @wx