文件
hl-api-changelog/changelogs-v2/2026-09/08_7283_流团后班期置为不可售与下单硬闸-修改接口-管理后台.md
T

15 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 7283 流团批准后自动把对应班期置为不可售,并给已流团团期的下单补 589551 硬闸 multiple jw(GIT) 修改接口 deployed verified not_required mmg 2026-09-08 后端已部署测试服并逐条实测(AC-1~AC-18 全过)。前端待办两项:①错误码字典补录 589551「该团期已流团,不可下单」;②知悉流团批准后该班期在小程序日历/班期列表会变为不可选、状态文案显示「取消中/已取消」。接口出入参结构零变化,前端不改也不会报错。 2026-09-08 dev-v3

团期: 流团后班期自动不可售 + 下单侧 589551 硬闸

服务: hl-order-service-v3、hl-product-service-v2(必须一起部署) PR: #7303 Issue: #7283 日期: 2026-09-08 影响范围: 团期流团审批、GROUP 产品下单(管理后台代客下单 + 小程序下单)、小程序班期日历


⚠️ 关键变化

出入参结构一个字段都没改。 前端不改不报错,但有两件事必须知道:

  1. 流团批准后,该班期会自动变为不可售——小程序日历上该出发日 isSelectable=false, 班期状态文案显示「取消中」或「已取消」。这是现有枚举字典的限制,不是产品下架, 同产品的其它班期不受任何影响。
  2. 已流团团期再下单会被拒,新增错误码 589551「该团期已流团,不可下单」, 前端错误码字典需补录。

改前:流团批准后班期仍停在「报名中」,客户能成功下单到一个已经解散的团,钱收得进来、退不回去。


一、背景

流团在 #7196 之后已是一条完整审批链:发起申请 → 管理员审批 → 通过后系统自动置团期取消、 批量退各户定金、释放配车占用。这条链唯一漏掉的一步是「把对应班期置为不可售」。

后果实测(AC-5 改前对照,在部署本次改动之前于测试服复现):批准流团后, group_tour_batch.batch_status 仍是 ENROLLING,对同一 productBatchId 再下单返回 code=200 且订单创建成功(订单号 HL20260907222635897)。新单挂到一个终态团期上, 团期看板、配房、配车、合同保险等所有按团聚合的链路都会拿到错的事实,需要人工善后并再退一次款。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 同意流团申请 POST /v3/admin/order/group-batch/disband/:approvalId/approve 行为变化 批准后额外把对应班期置为不可售;出入参与错误码集合不变
2 管理后台代客下单 POST /v3/admin/order 新增错误码 已流团团期下单被拒,返 589551 或 581028;入参出参不变

三、接口详情

1. 同意流团申请 POST /v3/admin/order/group-batch/disband/:approvalId/approve

VO: DisbandApprovalRespVO

使用场景

管理后台团期「流团审批」中同意一条待审流团申请。调用方 hl-ui 团期审批页。 权限:仅管理员角色(不满足抛 589547)。

入参

字段 位置 类型 必填 约束 说明
approvalId Path Long ✅ — 流团审批单 ID;入参一个都没变
remark Body String ❌ — 批复备注;请求体整体可不传

出参 Result<DisbandApprovalRespVO>

字段 类型 说明
approvalId Long 审批单 ID;响应结构完全不变
approvalStatus String PENDING / APPROVED / REJECTED
affectedOrderCount Integer 影响子订单户数
actualRefundAmount BigDecimal 执行后回填的实际退款合计
其余全部字段 — 完全不变

请求示例

POST /v3/admin/order/group-batch/disband/2096968377787392001/approve HTTP/1.1
Authorization: Bearer <admin-token>
Content-Type: application/json

{"remark":"确认无法成团"}

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "approvalId": "2096971122355458049",
    "groupBatchId": "2096971120853897217",
    "approvalStatus": "APPROVED",
    "affectedOrderCount": 1,
    "actualRefundAmount": 0.0,
    "approvedByName": "admin",
    "approvedAt": "2026-09-07 22:37:30"
  }
}

空数据 / 降级响应

置班期不可售失败不影响本接口返回值,仍返回 200 且 approvalStatus=APPROVED。 失败只记 ERROR 日志并往团期状态流水写一条 changeType=DATA 的记录, 内容为「班期置不可售失败,请到产品后台手动取消该班期(班期 ID:…)」, 由运营到产品后台对该班期手动执行取消收尾。

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": { "approvalId": "2097162345619902466", "approvalStatus": "APPROVED" }
}

错误响应

{
  "code": 589546,
  "message": "该流团申请已处理",
  "success": false,
  "data": null
}

错误码集合无新增。既有:589545 申请不存在、589546 已处理、589547 非管理员、 589500 团期不存在、589501 团期已处于终态。

业务边界

  • 只写该班期一行:作用域严格限定为该 batchId 的班期状态列,不触产品表、不影响同产品的其它班期。
  • 目标值两种:该班期仍有活跃订单时置「取消中」,无活跃订单时置「已取消」,两者都不可售。 实测中流团路径几乎恒落「取消中」——判定读的是订单域持久计数,而扣减计数与本动作同为提交后回调、 先后不保证,通常本动作先跑。两者对售卖的效果一致,前端不必区分。
  • 不回滚:跨服务同步在流团事务提交后执行,失败无从回滚,故只告警不回滚,由下单侧硬闸兜底。
  • 上线期间的预期毛刺:流团审批执行期间(含逐户退款,秒级)该班期的下单会短暂阻塞, 热门班期可能出现下单毛刺甚至锁等待超时。这是预期行为不是故障,客服口径需同步。

2. 管理后台代客下单 POST /v3/admin/order

VO: OrderCreateRespVO

使用场景

管理后台定制师代客下单。GROUP 产品必须带 productBatchId。 同一行为变化也适用于小程序下单链路(经 mp BFF 的 /v3/internal/mp/order/create), 错误码与文案一致。

入参

字段 位置 类型 必填 约束 说明
productId Body Long ✅ — 入参一个都没变
productBatchId Body Long GROUP 必填 — 产品侧班期 ID;本次新增的两道拒单都按它判定
departureDate Body String(date) ✅ yyyy-MM-dd 不变
adultCount / childCount / youngChildCount / babyCount Body Integer 成人必填 — 不变
customerName / customerPhone Body String ✅ — 不变
其余字段 — — — — 不变

出参 Result<OrderCreateRespVO>

字段 类型 说明
id Long 订单 ID;成功响应结构完全不变
orderNo String 订单号
orderStatus String PENDING_PAY 等
其余全部字段 — 完全不变

请求示例

{
  "productId": "2056947670512971778",
  "tierSeq": 1,
  "departureDate": "2026-12-18",
  "adultCount": 2,
  "childCount": 0,
  "customerName": "张三",
  "customerPhone": "13900000000",
  "productBatchId": "2096971118245015554",
  "roomCount": 1
}

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "id": "2096971120677736450",
    "orderNo": "HL20260907223729183",
    "orderStatus": "PENDING_PAY",
    "totalAmount": "6000.00"
  }
}

空数据 / 降级响应

无空数据形态。产品域同步失败导致班期仍显示可选时,下单仍会被本地硬闸拒掉(返 589551), 不会漏出一笔挂在已解散团期上的订单。

错误响应

班期已成功置为不可售时(正常路径):

{
  "code": 581028,
  "message": "团期状态不允许报名",
  "success": false,
  "data": null
}

班期置不可售失败、产品域仍显示报名中时(兜底路径):

{
  "code": 589551,
  "message": "该团期已流团,不可下单",
  "success": false,
  "data": null
}

新增错误码 589551,前端错误码字典需补录。既有 581028 语义不变。

业务边界

  • 两道闸,命中哪一道取决于产品域是否同步成功:同步成功走 581028(产品域状态不允许报名), 同步失败走 589551(订单域本地判定)。前端两者都要能展示。
  • 拒单零副作用:整单回滚,不留脏订单、不误扣产品域名额(实测 order_main 无新增、名额未变动)。
  • 成团后加单不受影响:判定只认「已流团」这一个终态,团期成团后(资源准备中及之后)的正常加单照常放行。
  • 转期入口不变:转入已流团团期早已由 589510 拦下,本次不改。

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

场景 做法
✅ 错误码字典 补录 589551 = 该团期已流团,不可下单,与既有 581028 = 团期状态不允许报名 并列
✅ 下单失败提示 581028 与 589551 都提示「该班期已不可报名,请换一期」即可,不必向客户区分两者
✅ 班期状态展示 该班期会显示「取消中」或「已取消」,两者都表示不可售,不要只把「已取消」当不可售
✅ 流团审批结果 仍以接口返回的 200 为准;置班期不可售是尽力而为的后续动作,不改变审批成败
❌ 把「取消中」当成「还能报名」 「取消中」表示仍有活跃订单待处理,售卖上与「已取消」等价,一律不可选
❌ 把班期不可售理解成产品下架 只是这一条班期,同产品其它班期与产品本身状态一字未动
❌ 依赖流团后班期一定变成「已取消」 实际几乎恒为「取消中」,见接口 1 的业务边界

五、数据库行为

  • 写:目标班期的状态列(既有列、既有取值,「取消中」或「已取消」),单行; 团期状态流水表新增一条记录(正常路径为流团记录,同步失败时额外一条 DATA 类留痕记录)。
  • 读:团期主订单状态、该班期下的子订单集合。
  • 不写:产品表、同产品的其它班期、班期的名额与价格等任何其它列。
  • 无表结构变更、无数据迁移。

六、边界行为

  • 小程序链路同步生效:经 mp BFF 的下单同样返 589551 / 581028,文案一致。
  • 已付款子订单在流团时仍不会被自动取消——这是既有缺陷(已另立工单 #7294 跟进), 与本次改动无关,本次也未修改流团取消哪些户。
  • 团期主订单未绑定产品班期时(历史脏数据):置不可售无处可写,按同步失败处理,记 ERROR 与流水留痕。
  • 重复批准:审批入口本就有幂等双保险,重复触发不会重复置状态;置不可售动作本身也幂等, 班期已是不可售状态时直接返回当前值、不重复写。

六.6、修改前后对比

维度 改前 改后
流团批准后产品域班期状态 停在「报名中」 自动置「取消中」/「已取消」
小程序日历该出发日 可选 isSelectable=false
已流团团期再下单 成功建单(实测 code=200,订单号 HL20260907222635897) 被拒:581028(正常)或 589551(同步失败兜底)
运营收尾动作 必须另外去产品后台手动取消该班期 系统自动完成;仅同步失败时才需人工兜底
审批接口出入参 — 完全不变
下单接口出入参 — 完全不变,仅多一个错误码

六.7、影响评估

  • 前端:无接口结构变化,不改也不报错;两项待办是「补录 589551 文案」与「知悉班期会显示取消中/已取消」。
  • 后端:hl-order-service-v3 与 hl-product-service-v2 必须一起部署, 且上线顺序为 product-v2 先、order-v3 后(回滚反序)——order-v3 的新调用依赖 product-v2 本次新增的内部端点。
  • 运营:流团审批期间该班期下单会短暂阻塞(秒级),属预期行为; 团期流水出现「班期置不可售失败」时,需到产品后台对该班期手动执行取消。
  • 数据:存量已流团但班期仍显示报名中的团期不会被自动修复,需要时由运营手动取消该班期。

七、不影响范围

  • 产品状态、产品上下架、同产品其它班期:一字未动。
  • 流团审批的响应结构、错误码集合、权限规则:全部不变。
  • 下单接口的入参与成功响应结构:全部不变。
  • 流团取消哪些子订单、退款金额口径:不变(已付款户仍不被自动取消,见 #7294)。
  • 定制师提需求、团期成团、调名额、转期等其它团期动作:不变。
  • 取消成团(资源准备中回退到招募中):不联动置班期不可售——班期本就应继续可售。

八、测试环境已验证

测试服 https://api.test.1814.love:9443,order-v3 与 product-v2 已一起部署。工单 AC-1~AC-18 全部逐条取证:

项 结果
改前对照(部署本次改动前) 流团批准后班期仍 ENROLLING,再下单 code=200 成功建单 HL20260907222635897
流团后班期状态 产品域「取消中」、订单域「已取消」
作用域未越界 同产品 17 条班期只有目标那条变化,产品状态仍为已上架
展示层不可选 班期日历状态「已取消」;小程序价格日历该出发日 isSelectable=false
改后下单 code=581028
硬闸兜底 手工把班期改回报名中后下单 → code=589551,无新增订单、名额未变动
幂等 连续两次置不可售均 200 且结果相同,第二次未产生任何写入
班期不存在 返 code=200 + data=null,由调用方按同步失败告警
同步失败留痕 审批仍 200、订单域仍「已取消」、ERROR 日志含两个 ID、状态流水出现 DATA 类「班期置不可售失败…」记录
并发正确性 真实 MySQL 并发集成测试:流团先提交 → 创单被拒且整单回滚;创单后提交 → 被流团一并取消;相反加锁顺序产生的真实死锁下,创单侧整单回滚、无脏订单
隔离级别 测试库实测 REPEATABLE-READ
全量回归 order-v3 全量单测 9008 例 0 失败 0 错误;product-v2 1592 例 0 失败 0 错误

十、相关文档

  • Issue: #7283
  • PR: #7303
  • 后续工单: #7294(流团不取消已付款子订单)、#7293(库存聚合降级改写满员班期)、#7284(下单校验改判实时库存)、#7304(团期状态流水只读端点)
  • 设计文档: docs/order-v3/notes/14-group-tour-order-design.md 流团章节

关联 / 联系人

  • 后端: jw
  • 前端: mmg(hl-ui / 小程序)
  • 业务口径: wx