Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,297 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8497"
|
||||
title: "团期团号改为 T+出发年份后两位-4位混淆号,新增存量换号的两个内部端点(产品回填 / order-v3 同步)"
|
||||
consumer: "internal"
|
||||
author: "jw(GIT)"
|
||||
change_type: "新增接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "not_required"
|
||||
frontend_status: "not_required"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "两个新增接口都是 internal(网关不暴露、X-Internal-Token 校验),只给运维一次性执行存量换号用,前端无需对接。TEST 已于 2026-09-29 执行完毕:297 个在册班期换号、13 个团期与 61 行应付快照同步,重跑零变更。附带说明:团期团号 batchNo 的取值格式由 28 位旧号改为形如 T26-8867 的新号,所有返回 batchNo 的接口字段名与类型不变,仅取值变短,前端列宽可收窄。"
|
||||
updated_at: "2026-09-29"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 团期:团号改为 T26-8867 形态,新增存量换号的两个内部端点
|
||||
|
||||
> **服务**: hl-product-service-v2(端口 8083)、hl-order-service-v3(端口 8086,含 finance 模块)
|
||||
> **PR**: #8514(新规则)、#8532(存量换号)
|
||||
> **Issue**: #8497
|
||||
> **日期**: 2026-09-29
|
||||
> **影响范围**: 团期团号 batchNo 的取值格式;两个一次性内部端点
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
- 团期团号(产品侧 `group_tour_batch.batch_no`,建团时原样抄进订单侧团期)由 28 位旧号 `Q + yyyyMMdd + 19 位雪花 ID`(如 `Q202611102104491287904428034`)改为 **`T` + 出发年份后两位 + `-` + 4 位混淆号**(如 `T26-8867`;一年超过 9999 个后为 5 位)。
|
||||
- 所有返回 `batchNo` 的既有接口(团期列表 / 详情、房务看板、车务派单、财务应收台账团行的 `orderNo` / `teamNo` 等)**字段名、类型、位置都不变**,只是取值变成新格式;存量在册班期已统一换成新号。
|
||||
- 团期子订单自己的订单号(`HL` + 年月日时分秒 + 3 位毫秒)与团号(`yy-NNNN`,如 `26-3821`)**不变**。
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
jw 2026-09-29 定:团号要能念、能记,参照订单团号 `26-8867` 的思路改为 `T26-8867`(T=团),年份取出发日期。新建班期由 PR-1 起按新规则取号;存量在册班期的旧号由本次新增的两个内部端点一次性换掉,旧号存进产品库 `legacy_batch_no` 列备查(不进任何接口、不做按旧号搜索的兼容)。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 团期存量团号回填 | POST | `/internal/product/group-tour-batch/batch-no/backfill` | 新增 | 产品服务:在册班期旧号换成新号,dryRun 默认 true |
|
||||
| 2 | 团期团号同步 | POST | `/v3/internal/order/group-batch/batch-no/sync` | 新增 | order-v3:订单侧团期与财务应付快照跟上产品侧新号,dryRun 默认 true |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 团期存量团号回填 `POST /internal/product/group-tour-batch/batch-no/backfill`
|
||||
|
||||
**VO**: `GroupTourBatchNoBackfillRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
运维在部署后一次性执行:把产品库在册班期里不是新格式的团号逐行换成新号(与新建班期共用同一个取号器、同一张按年序号表),旧号写进 `legacy_batch_no`;班期名等于旧号的一并换成新号;班期名长得像旧号(复制产品抄来的)的改回自身团号。先 dryRun 看数,再 `dryRun=false` 正式执行,紧接着调用接口 2。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| X-Internal-Token | header | string | 是 | 服务间内部令牌 | 缺失或错误返回 403 |
|
||||
| dryRun | query | boolean | 否 | 默认 true | true 只统计不修改;false 正式换号 |
|
||||
| limit | query | integer | 否 | 大于等于 0;不传为不限 | 本轮最多换号行数,只限制换号,不限制改名 |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| dryRun | boolean | 是否只统计 |
|
||||
| limit | integer | 本轮换号上限,null 为不限 |
|
||||
| scanned | integer | 扫描的在册班期数 |
|
||||
| legacyCandidates | integer | 在册班期中不是新格式的行数 |
|
||||
| converted | integer | 换号成功行数(dryRun 时为将会换号的行数) |
|
||||
| renamed | integer | 名字改回自身团号的行数 |
|
||||
| skipped | integer | 跳过行数(读后被并发改动 / 已删除,本行已回滚) |
|
||||
| mappingTotal | integer | 换号映射总数 |
|
||||
| mappings | array | 换号映射(最多返回前 N 条):batchId(string)、oldBatchNo、newBatchNo(dryRun 时为 null) |
|
||||
| skippedItems | array | 跳过明细:batchId、phase(CONVERT / RENAME)、reason |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
POST /internal/product/group-tour-batch/batch-no/backfill?dryRun=false HTTP/1.1
|
||||
Host: 192.168.100.236:8083
|
||||
X-Internal-Token: <内部令牌>
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"dryRun": false,
|
||||
"limit": null,
|
||||
"scanned": 301,
|
||||
"legacyCandidates": 297,
|
||||
"converted": 297,
|
||||
"renamed": 5,
|
||||
"skipped": 0,
|
||||
"mappingTotal": 297,
|
||||
"mappings": [
|
||||
{ "batchId": "2046126055898431490", "oldBatchNo": "Q202602262046126055885848578", "newBatchNo": "T26-0906" }
|
||||
],
|
||||
"skippedItems": []
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
没有需要换号的班期时(例如重跑)返回 `converted=0`、`renamed=0`、`mappings=[]`,HTTP 200:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": { "dryRun": false, "limit": null, "scanned": 306, "legacyCandidates": 0, "converted": 0, "renamed": 0, "skipped": 0, "mappingTotal": 0, "mappings": [], "skippedItems": [] },
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
缺少或错误的内部令牌:
|
||||
|
||||
```json
|
||||
{ "code": 403, "msg": "内部接口禁止外部访问" }
|
||||
```
|
||||
|
||||
`limit` 为负数:
|
||||
|
||||
```json
|
||||
{ "code": 400, "message": "数值超出允许范围,请修改后重试", "data": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 只处理在册班期,已删除的班期保留原号。
|
||||
- 每行一个独立事务;读后被并发改动的行回滚并计入 skipped,不影响后续行,序号不留空洞。
|
||||
- 回填过程中同时新建班期不会撞号(共用同一张按年序号表)。
|
||||
- 可重跑,已是新号的行不再处理。
|
||||
|
||||
### 2. 团期团号同步 `POST /v3/internal/order/group-batch/batch-no/sync`
|
||||
|
||||
**VO**: `GroupBatchNoSyncRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
紧接接口 1 执行:逐个团期拉产品侧当前团号(在事务外调用产品服务),与订单侧团期不一致时,在同一事务里回写订单侧团期团号(名字等于旧号时一并改),并把财务应付明细与应付团头里等于旧号的团号换成新号。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| X-Internal-Token | header | string | 是 | 服务间内部令牌 | 缺失或错误返回 403 |
|
||||
| dryRun | query | boolean | 否 | 默认 true | true 只统计不修改;false 正式同步 |
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| dryRun | boolean | 是否只统计 |
|
||||
| scanned | integer | 扫描的未删除团期数 |
|
||||
| synced | integer | 已同步团期数(dryRun 时为将会同步的数量) |
|
||||
| skipped | integer | 与产品侧已一致而跳过的团期数 |
|
||||
| failedCount | integer | 失败团期数(拉产品侧失败 / 产品侧团号为空 / 事务失败,均已回滚且不中断) |
|
||||
| payableLineRows | integer | 应付明细改号影响行数合计(只作留痕) |
|
||||
| payableTeamRows | integer | 应付团头改号影响行数合计(只作留痕) |
|
||||
| syncedItems | array | 同步明细:groupBatchId(string)、oldBatchNo、newBatchNo、batchNameChanged |
|
||||
| failed | array | 失败明细:groupBatchId、reason |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
POST /v3/internal/order/group-batch/batch-no/sync?dryRun=false HTTP/1.1
|
||||
Host: 192.168.100.236:8086
|
||||
X-Internal-Token: <内部令牌>
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"dryRun": false,
|
||||
"scanned": 17,
|
||||
"synced": 13,
|
||||
"skipped": 4,
|
||||
"failedCount": 0,
|
||||
"payableLineRows": 60,
|
||||
"payableTeamRows": 1,
|
||||
"syncedItems": [
|
||||
{ "groupBatchId": "2101506167098511362", "oldBatchNo": "Q202609272101502082564407298", "newBatchNo": "T26-9802", "batchNameChanged": false }
|
||||
],
|
||||
"failed": []
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
全部团期已与产品侧一致时返回 `synced=0`、`syncedItems=[]`;单个团期拉取产品侧失败时计入 `failedCount` 与 `failed`,其余团期照常处理:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": { "dryRun": false, "scanned": 17, "synced": 0, "skipped": 17, "failedCount": 0, "payableLineRows": 0, "payableTeamRows": 0, "syncedItems": [], "failed": [] },
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 错误响应
|
||||
|
||||
缺少或错误的内部令牌:
|
||||
|
||||
```json
|
||||
{ "code": 403, "msg": "内部接口禁止外部访问" }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 不改团期子订单的订单号与团号。
|
||||
- 同一团期的团期表与应付快照在同一事务内一起改或一起回滚。
|
||||
- 新号若与已有应付团头冲突,该团期回滚并计入 failed,需人工处理。
|
||||
- 可重跑,已一致的团期跳过。
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
- 两个接口只供运维一次性执行,不经网关(网关对 `/internal/**`、`/v3/internal/**` 返回 403),需直连服务端口并带 `X-Internal-Token`。
|
||||
- 执行顺序固定:接口 1 dryRun → 接口 1 正式 → **紧接着**接口 2 dryRun → 接口 2 正式。两者之间有新订单进来不影响结果(下单时不改团号)。
|
||||
- 不传 `dryRun` 等同 dryRun=true,不会误改数据。
|
||||
- 既有接口里的 `batchNo` 字段名、类型不变,取值格式变为新号;调用方不要按 28 位长度或 `Q` 前缀解析团号。
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库行为
|
||||
|
||||
- 接口 1:产品库班期的团号换成新号,旧号写入备查列;占用按出发年份计数的团号序号;不改已删除班期。
|
||||
- 接口 2:订单侧团期的团号(及等于旧号的班期名)与财务应付明细、应付团头上的团号改为新号;金额不变;不改订单主表。
|
||||
- 两个接口 dryRun 时只读不写。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 同一序号在不同年份后四位相同(如 `T26-0906`、`T27-0906`),靠年份段区分,属公式特性。
|
||||
- 号一经生成,出发日期改到别的年份也不改号。
|
||||
- 快照还原遇到旧格式的号会重新取号,避免换号后旧号回流。
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- 团期子订单的订单号(`HL…`)与团号(`yy-NNNN`)。
|
||||
- 所有既有接口的路径、入参、出参字段与类型。
|
||||
- 前端:无需对接这两个内部接口;`batchNo` 列宽可按新格式收窄(可选)。
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
2026-09-29 在 TEST 直连服务端口执行(换号前后各存全量快照逐行比对):
|
||||
|
||||
- 接口 1 dryRun:在册 301、旧格式 297、名字像旧号 5,序号表不变;正式:297 换号、5 改名、0 跳过,3.6 秒;执行期间并发新建 5 个班期全部成功且不撞号。
|
||||
- 接口 2 dryRun → 正式:扫描 17、同步 13、跳过 4、失败 0,应付明细改 60 行、应付团头改 1 行。
|
||||
- 重跑两接口零变更;无令牌 403;`limit=-1` 返回 400。
|
||||
- 换号后:在册班期无旧号、`legacy_batch_no` 与原号逐行一致;订单侧团期与产品侧逐行一致;全库团号列普查旧号 0;团期子订单订单号与团号 46 行逐行一致;应付台账按新号 `T26-9802` 查得应付 3120.00,与换号前一致。
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- 工单 #8497(含两轮 TEST 验收证据评论)
|
||||
- PR #8514(新规则)、PR #8532(存量换号)
|
||||
- 团期文档 `docs/group/数据模型.html`「新增事实三」已按新规则收口
|
||||
|
||||
---
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
- 后端:jw
|
||||
- 工单:https://git.1814.love/wx/HL/issues/8497
|
||||
在新工单中引用
屏蔽一个用户