12 KiB
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 | 7527 | 团期发起核单端点(TRIP_FINISHED → REVIEWING) | admin | jw(GIT) | 新增接口 | deployed | verified | verified | mmg | a80b9670 | 2026-09-13 | 团期详情/看板需加「发起核单」按钮。重复点击返 200 且 alreadyStarted=true,前端应据此提示「该团期已在核单中」而非再弹一次成功。录成本自动推进的老行为不变,两条入口并存。 前端 2026-09-13 已交付(hl-admin a80b9670):groupBatchFinance.js 新增 startGroupBatchReview;详情页「更多操作」按 batchStatus===TRIP_FINISHED 白名单加「发起核单」,新建 ReviewStartModal 确认弹层;成功按 alreadyStarted 分支(true 幂等命中仅提示「已在核单中」不重复弹成功,false 弹成功并 fetchDetailSafe 刷新);589564/589565/589566/589507 走拦截器透后端 message;看板不加按钮;录成本自动推进老行为零改动。checkpoint 13 项全绿(全量 Vitest+生产构建)。 | 2026-09-13 | dev-v3 |
order-v3: 团期发起核单端点(TRIP_FINISHED → REVIEWING)
服务: hl-order-service-v3 PR: #7568 Issue: #7527
⚠️ 关键变化
🔴 补的是一个「团期卡死」的入口缺失,不是新功能。 TRIP_FINISHED → REVIEWING 这一跳此前
唯一入口是录共享成本的副作用。于是不用大巴、没请导摄的团根本没有共享成本可录,
就没有触发点,团期永久停在「出行完毕」——既进不了核单,也归不了档,
八桶看板的「核团中」桶对这类团恒为空。
🔴 两条入口并存,老行为一行未改。 「先点发起核单再录成本」与「直接录第一笔成本自动推进」 都继续可用。前端不需要为本端点调整任何现有调用。
🔴 重复点击返 200,不是报错。 用 data.alreadyStarted 区分:false = 本次真的推进了;
true = 调用前团期已在核单中,本次是幂等命中、零写入零时间线。
前端若只看 HTTP 码,重复点会连弹两次「已发起核单」。
一、背景
团期生命周期第 6 跳(出行完毕 → 核单中)没有人工入口。运营在八桶看板上点不动「核团中」桶, 只能等财务去改库,或者随便录一笔 0 元成本把状态机「骗」过去。 这是把一个流程动作绑死在一个数据录入动作上的后果。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 发起核单 | POST | /v3/admin/order/group-batch/{groupBatchId}/review/start |
新增 | TRIP_FINISHED → REVIEWING 的显式人工入口;重复点幂等返 200 |
三、接口详情
1. 发起核单 POST /v3/admin/order/group-batch/{groupBatchId}/review/start
VO: GroupBatchReviewStartRespVO
使用场景
hl-ui 管理后台「团期详情 / 团期看板」的「发起核单」按钮。团期返团后(状态「出行完毕」)由 运营或财务点一下,把团期推进到「核单中」,之后才能走验团归档。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | 雪花 ID,不存在返 589500 | 团期主订单 ID |
无请求体。
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | String | 团期主订单 ID(Long 经 ToStringSerializer 序列化,防精度丢失) |
| batchStatus | String | 推进后的团期状态,恒为 REVIEWING |
| batchStatusDesc | String | 状态中文名,恒为「核单中」 |
| alreadyStarted | Boolean | false=本次调用完成了推进;true=调用前团期已在核单中,本次为幂等命中、未产生任何写入与时间线 |
请求示例
POST /v3/admin/order/group-batch/2089679374176464898/review/start
Authorization: Bearer <admin token>
响应示例
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2089679374176464898",
"batchStatus": "REVIEWING",
"batchStatusDesc": "核单中",
"alreadyStarted": false
},
"success": true
}
空数据 / 降级响应
重复点击(团期已在核单中)返 200,alreadyStarted=true,零写入、零时间线:
{
"code": 200,
"message": "成功",
"data": {
"groupBatchId": "2089679374176464898",
"batchStatus": "REVIEWING",
"batchStatusDesc": "核单中",
"alreadyStarted": true
},
"success": true
}
时间线写入失败时不回滚状态推进,接口仍返成功(时间线不是主链路)。
错误响应
| 码 | 符号 | 触发 | 建议前端提示 |
|---|---|---|---|
| 589500 | GROUP_BATCH_NOT_FOUND |
groupBatchId 查不到团期 | 团期不存在 |
| 589507 | GROUP_BATCH_PERMISSION_DENIED |
角色未持 group-batch:finance:advance |
无操作权限 |
| 589564 | GROUP_BATCH_REVIEW_START_STATUS_INVALID |
状态早于「出行完毕」(招募中/资源准备中/物料准备中/待出发/出行中),或库中为脏值 | 「团队还没返团,返团后才能发起核单」 |
| 589565 | GROUP_BATCH_REVIEW_START_AFTER_SETTLED |
团期已验团归档 | 「该团已验团归档,如需重新核单请先做验团反确认」,并给一个跳转到反确认的入口 |
| 589566 | GROUP_BATCH_REVIEW_START_DISBANDED |
团期已流团 / 取消 | 「该团已流团,不能发起核单」,按钮应置灰 |
{
"code": 589564,
"message": "当前团期状态不可发起核单(须为「出行完毕」)",
"data": null,
"traceId": null,
"success": false
}
{
"code": 589565,
"message": "团期已验团归档,如需重新核单请先做验团反确认",
"data": null,
"traceId": null,
"success": false
}
{
"code": 589566,
"message": "团期已流团,不可发起核单",
"data": null,
"traceId": null,
"success": false
}
业务边界
- 幂等:由 CAS 的
from = TRIP_FINISHED条件天然保证。重复调用与并发双击的败者都落到alreadyStarted=true的成功分支,不会写出第二条时间线。前端无需做防抖去重(做了更好)。 - 三个错误码刻意分开,不共用通用的 589501「团期状态不允许当前操作」:这三种拒绝对运营的 下一步动作完全不同(等团回来 / 去做验团反确认 / 这团已经流了),共用一个码前端只能给出 一句无法行动的提示。
- 成功后团期进入「核单中」,共享成本录入端点
POST .../settlement/cost与验团归档端点POST .../settle随之可用。 - 权限码与录成本端点同一个(
group-batch:finance:advance):今天能录成本的人就能发起核单, 没有人凭空多出权限,前端的按钮可见性判据可直接复用录成本那一套。
四、契约约束与正确调用方式
- 不要把 200 当成「推进成功」:必须看
data.alreadyStarted。true时提示「该团期已在核单中」, 不要再弹一次「发起成功」。 - 不要用它做状态查询:本端点是写动作,读团期状态请用团期详情接口。
- 不要为它做重试:幂等安全,但重试没有意义——失败的三个码都是业务拒绝,重试结果相同。
- 589565 要给出口:提示里带上「验团反确认」的跳转,对应端点
POST /v3/admin/order/group-batch/{groupBatchId}/settle/reopen。 - 老入口不变:
POST /v3/admin/order/group-batch/{groupBatchId}/settlement/cost在TRIP_FINISHED上录第一笔成本仍会自动推进到REVIEWING,行为一行未改。
五、数据库行为
无表变更、无 Flyway、无新增列。 本端点只写两处既有的地方:
order_group_batch.batch_status:由TRIP_FINISHEDCAS 更新为REVIEWING(幂等命中时不写);group_batch_status_log:追加一条event_type=BATCH_TRIP_END/from_status=TRIP_FINISHED/to_status=REVIEWING/content=发起核单(管理员手动)的时间线(幂等命中时不写)。
时间线写入失败仅记 WARN 降级,不回滚状态推进——流水不是主链路,不能因为它写失败把 状态推进撤销掉。
六、边界行为
| 场景 | 行为 |
|---|---|
| 团期在「出行完毕」 | 200,alreadyStarted=false,状态变「核单中」,时间线 +1 |
| 团期已在「核单中」 | 200,alreadyStarted=true,零写入、零时间线 |
| 并发双击 / 与录成本并发 | 只有一个请求 CAS 成功;败者重读状态后也返 200 alreadyStarted=true |
| 团期早于「出行完毕」 | 589564 |
| 团期已「已结算」 | 589565 |
| 团期已「已取消」(流团) | 589566 |
| 团期不存在 | 589500 |
| 无权限 | 589507,零落库 |
库中 batch_status 为枚举外脏值 |
589564(业务码,不是 500) |
| 时间线写入失败 | 状态已推进,接口仍返 200 |
七、不影响范围
POST /v3/admin/order/group-batch/{groupBatchId}/settlement/cost一行未改——其内嵌的TRIP_FINISHED → REVIEWING副作用保持原样,两条入口并存。- 验团归档
POST .../settle与验团反确认POST .../settle/reopen未改动。 - 无 Mapper 改动(复用既有
casAdvanceToReviewing)、无 Entity 改动、无网关路由改动 (命中已有/v3/admin/**通配)、无 hl-user-service 权限种子改动(复用既有权限码)。 - 核团业务内容(核团四表、主次报账人记账、成本分摊)不在本单,仍归 GB-ADM-050~052。
八、测试环境已验证
部署:hl-order-service-v3 @ feat/7527-group-batch-review-start / 9f3ee37d9,双实例滚动重启完成。
全部实测经真实网关 api.test.1814.love:9443 + Bearer 鉴权,载体是 TEST 上一个 0 子订单的空闲团期
2089679374176464898。
| 场景 | 请求 | 响应 |
|---|---|---|
| 出行完毕 → 发起 | POST .../2089679374176464898/review/start |
200,alreadyStarted=false,batchStatus=REVIEWING;库 batch_status 变 REVIEWING;group_batch_status_log 新增 BATCH_TRIP_END / TRIP_FINISHED → REVIEWING / 发起核单(管理员手动) |
| 再点一次 | 同上 | 200,alreadyStarted=true;状态不变,时间线条数不变 |
| 出行中 | 同上 | 589564「当前团期状态不可发起核单(须为「出行完毕」)」 |
| 已结算 | 同上 | 589565「团期已验团归档,如需重新核单请先做验团反确认」 |
| 已取消 | 同上 | 589566「团期已流团,不可发起核单」 |
| 团期不存在 | POST .../999999999/review/start |
589500「团期不存在」 |
| 无权限角色 | 同上(roleKey=GUIDE / CUSTOMER_SERVICE) | 589507 |
| 老行为零回归 | 在「出行完毕」上 POST .../settlement/cost |
200,库 batch_status 仍自动变 REVIEWING |
前置条件达成方式:
TRIP_FINISHED/TRAVELLING/SETTLED/CANCELLED四态在 TEST 上一个都不存在 (它们由GroupBatchLifecycleJobService按班期日期定时推进),故用 SQL 直更batch_status逐个构造前置态, 取证后已还原为原始的RESOURCE_PREPARING。该路径没有验到状态机上游的推进逻辑,只验本端点自身的判据。
本地全量:mvn -o -pl hl-order-service-v3 -am test → 9935 例 / Failures 0;
RedLineArchTest / LayerEnforcementTest / MapperBoundaryArchTest 均通过(非 Skipped)。
本单新增 10 例单测。
十、相关文档
- Issue:https://git.1814.love:8443/wx/HL/issues/7527
- PR:https://git.1814.love:8443/wx/HL/pulls/7568
- 兄弟端点(验团归档 / 反确认):
POST /v3/admin/order/group-batch/{groupBatchId}/settle、.../settle/reopen
关联 / 联系人
- 后端:jw
- 前端(hl-ui 管理后台):mmg
- 需求定案:wx