docs(changelog): #8246 流团审批放开团期管理员,批后各户退款进退款审批中心二审(修改接口·管理后台)
changelog-filename-gate / validate (push) Failing after 2s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
这个提交包含在:
jw
2026-10-02 19:26:46 +08:00
共同撰写人 Claude Opus 5.5
父节点 5442f80523
当前提交 358be6ddb2
@@ -0,0 +1,510 @@
---
schema: "hl-changelog/v2"
ticket: "8246"
title: "流团审批放开团期管理员,批准后各户退款进退款审批中心二审——GB-ADM-062 审批人集合与批后退款行为、GB-ADM-061 canApprove 取值同步变化"
consumer: "admin"
author: "jw(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "jw 2026-10-02 定案,照 #8436 退单审批的做法:一是流团审批(GB-ADM-062 同意 / 拒绝)在管理员之外放行团期管理员 GROUP_BATCH_MANAGER,不新增权限码;二是同意流团后各户退款单停在 PENDING 进退款审批中心二审,不再以流团审批人身份自动放行。审批中心列表与流团详情的 canApprove 与端点同一道判定,团期管理员在待审批流团上由 false 变 true。两项都受 nacos 开关控制(默认开):group-batch.disband.refund-second-review 关掉即回到改前自动放行,并同时收回团期管理员的流团审批权;group-batch.acl.allow.disband-approver-group-batch-manager 关掉只收回团期管理员审批权。路径、入参、出参字段名与类型零变化,错误码不变(589547 文案「仅管理员可处理流团审批」未改,与 #8436 对 589530 的处理一致);变的是审批人集合、canApprove 取值与批后退款单状态,属行为 / 语义变化,按 jw 2026-09-18 口径推送。已合并 dev-v3(PR #8734,merge commit c4a410a94)并部署测试服。hl-ui v2.1 审批中心页已对团期管理员开放(canAccess = isAdmin || isGroupBatchManager),同意 / 拒绝按钮按 canApprove 显隐,前端零改动,frontend_status 记 not_required。"
updated_at: "2026-10-02"
base: "dev-v3"
---
# 流团审批放开团期管理员与批后退款二审(管理后台)
> **服务**: hl-order-service-v3(端口 8086/8186)
## 一、接口背景
团期管理员能发起流团,却批不了流团:流团审批的角色门只放管理员。退单审批已在 #8436 放开团期管理员,并把批后退款改成进退款审批中心二审;流团这次照同一做法处理。
本次两处行为变化:
- 流团审批(同意 / 拒绝)在管理员之外放行团期管理员;审批中心列表与流团详情的 `canApprove` 随之变化。
- 同意流团后,各户的退款单停在 `PENDING`,进退款审批中心由有退款审核权的人二审;改前是以流团审批人身份自动审核通过。这一条对所有审批人生效,不只团期管理员。
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | GB-ADM-062 同意流团 | POST | `/v3/admin/order/group-batch/disband/{approvalId}/approve` | 修改接口 | 审批人集合加团期管理员;批后各户退款单停在 PENDING 进二审。入参、出参、错误码零变化 |
| 2 | GB-ADM-062 拒绝流团 | POST | `/v3/admin/order/group-batch/disband/{approvalId}/reject` | 修改接口 | 审批人集合加团期管理员。入参、出参、错误码零变化 |
| 3 | GB-ADM-061 团期审批中心列表 | GET | `/v3/admin/order/group-batch/approvals/page` | 修改接口 | 流团行 `canApprove` 对团期管理员由 false 变 true(待审批行);字段零变化 |
| 4 | GB-ADM-061 流团申请详情 | GET | `/v3/admin/order/group-batch/disband/{approvalId}` | 修改接口 | `canApprove` 同上;字段零变化 |
## 三、接口详情
### 1. GB-ADM-062 同意流团 `POST /v3/admin/order/group-batch/disband/{approvalId}/approve`
**VO**: `DisbandApprovalRespVO`
#### 使用场景
团期审批中心「流团」行或流团详情页点「同意」。同意后才真正执行流团:团期置 CANCELLED,全团子订单取消,已付户按已付全额建退款单,释放配车占用。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| approvalId | path | Long | 是 | 正整数,流团申请单 ID | 不存在返 589545 |
| remark | body | String | 否 | ≤ 512 字 | 批复备注;整个 body 可省略 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| approvalStatus | String | 同意后为 `APPROVED` |
| approvedById / approvedByName | Long / String | 本次审批人;**团期管理员现在也会出现在这里** |
| estimatedRefundAmount | BigDecimal | 提交时的预估退款合计(既有字段,未改) |
| actualRefundAmount | BigDecimal | 实际进退款的合计,由对账定稿(既有字段,未改)。**现在是「已建退款单、待二审」的金额,不是已退出的钱** |
| canApprove | Boolean | 已处理后恒为 false |
| 其余字段 | — | 与流团详情相同,未改 |
#### 请求示例
```http
POST /v3/admin/order/group-batch/disband/2105977953445969921/approve HTTP/1.1
Host: api.test.1814.love
Authorization: Bearer <团期管理员 token>
Content-Type: application/json
{"remark": "确认无法成团"}
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"approvalId": "2105977953445969921",
"groupBatchId": "2105974855696547842",
"batchNo": "T26-7048",
"batchName": "11月26日海拉尔-额尔古纳4日团",
"approvalStatus": "APPROVED",
"approvalStatusName": "已通过",
"reason": "临近出团报名不足 6 户,无法成团",
"affectedOrderCount": 2,
"participantCount": 4,
"estimatedRefundAmount": 3360.0,
"actualRefundAmount": 3360.0,
"applicantId": "2102259564525301761",
"applicantName": "gbm8154test",
"approvedById": "2102259564525301761",
"approvedByName": "gbm8154test",
"approveRemark": "确认无法成团",
"canApprove": false
}
}
```
#### 空数据 / 降级响应
团里没有已付户时不建任何退款单,`actualRefundAmount` 为 `0.00`。退款单建单失败的户不计入 `actualRefundAmount`,由对账 Job 兜底补建;接口本身仍返回成功(流团已提交,不回滚)。
```json
{
"code": 200,
"message": "成功",
"data": {
"approvalStatus": "APPROVED",
"affectedOrderCount": 1,
"estimatedRefundAmount": 0.0,
"actualRefundAmount": 0.0,
"canApprove": false
}
}
```
#### 错误响应
```json
{
"code": 589547,
"message": "仅管理员可处理流团审批",
"data": null
}
```
| 错误码 | 触发条件 |
|---|---|
| 589547 | 当前角色不是管理员 / 超级管理员 / 团期管理员(如定制师、财务);或有请求但网关未透传角色;或团期管理员放行开关已关 |
| 589545 | 流团申请不存在 |
| 589546 | 申请已被处理(并发时后到者) |
| 589544 | 团期已确认或更靠后,不可批复流团 |
#### 业务边界
- 团期管理员按「任一团期管理员」放行,系统里还没有「本团团期管理员」关系,与 #8436 退单一致。
- 不禁止自审:团期管理员可以批自己提交的申请;`applicant*` 与 `approvedBy*` 分开落库。
- 批后各户退款单为 `PENDING`,`calculatedAmount` = 该户已付全额(流团按已付全额退,不扣违约金),审核人在退款审批中心不填金额直接同意即按此额退。
- 退款审核端点 `POST /v3/admin/refund/review` 仍禁止团期管理员(581008),所以团期管理员批了流团也退不出钱,钱的出口由退款审核人把关。
### 2. GB-ADM-062 拒绝流团 `POST /v3/admin/order/group-batch/disband/{approvalId}/reject`
**VO**: `DisbandApprovalRespVO`
#### 使用场景
团期审批中心「流团」行或流团详情页点「拒绝」。只改申请单状态,团期继续正常招募,订单与钱一律不动。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| approvalId | path | Long | 是 | 正整数,流团申请单 ID | 不存在返 589545 |
| remark | body | String | 是 | 非空白,≤ 512 字 | 拒绝原因,写进团期时间线 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| approvalStatus | String | 拒绝后为 `REJECTED` |
| approvedById / approvedByName | Long / String | 本次审批人;团期管理员现在也会出现在这里 |
| approveRemark | String | 拒绝原因 |
| canApprove | Boolean | 已处理后恒为 false |
#### 请求示例
```http
POST /v3/admin/order/group-batch/disband/2105980238163030017/reject HTTP/1.1
Host: api.test.1814.love
Authorization: Bearer <团期管理员 token>
Content-Type: application/json
{"remark": "本周还有两户在咨询,继续招募到下周一再定"}
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"approvalId": "2105980238163030017",
"groupBatchId": "2105980235310923777",
"batchNo": "T26-9826",
"approvalStatus": "REJECTED",
"approvalStatusName": "已拒绝",
"approvedByName": "gbm8154test",
"approveRemark": "本周还有两户在咨询,继续招募到下周一再定",
"canApprove": false
}
}
```
#### 空数据 / 降级响应
无降级分支:拒绝只写申请单一行和一条时间线,失败即整体回滚并返回错误码。
```json
{
"code": 589546,
"message": "该流团申请已处理,不可重复操作",
"data": null
}
```
#### 错误响应
```json
{
"code": 589547,
"message": "仅管理员可处理流团审批",
"data": null
}
```
| 错误码 | 触发条件 |
|---|---|
| 589547 | 同「同意流团」 |
| 589545 | 流团申请不存在 |
| 589546 | 申请已被处理 |
| 400 | `remark` 为空或超长 |
#### 业务边界
- 拒绝后同一团期可以再次提交流团。提交接口有防重窗口,拒绝后立刻重提会返回 100502「请勿重复提交」,隔几秒再提即可(既有行为,本次未改)。
- 审批人范围与「同意流团」完全一致,共用同一道角色门。
### 3. GB-ADM-061 团期审批中心列表 `GET /v3/admin/order/group-batch/approvals/page`
**VO**: `GroupBatchApprovalItemRespVO`
#### 使用场景
团期审批中心页的统一列表(流团 + 退单两类)。前端按行的 `canApprove` 决定是否显示「同意 / 拒绝」。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| bizType | query | String | 否 | `DISBAND` / `WITHDRAW` | 业务类型 |
| approvalStatus | query | String | 否 | `PENDING` / `APPROVED` / `REJECTED` / `CANCELLED` | 审批状态 |
| groupBatchId | query | Long | 否 | 正整数 | 按团期筛 |
| batchName | query | String | 否 | — | 团期名称关键字 |
| pageNum | query | Integer | 否 | ≥ 1,默认 1 | 页码 |
| pageSize | query | Integer | 否 | 默认 20 | 每页条数 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| records[].canApprove | Boolean | **本次取值变化**:流团行 = 待审批 + 团期仍可流团 + 当前人过 GB-ADM-062 的角色门。团期管理员在待审批流团行上由 false 变 true;退单行口径不变 |
| records[].approvedByName | String | 审批人,团期管理员现在也会出现 |
| 其余字段 | — | 未改 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/approvals/page?pageNum=1&pageSize=20&bizType=DISBAND&approvalStatus=PENDING HTTP/1.1
Host: api.test.1814.love
Authorization: Bearer <团期管理员 token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"approvalId": "2105977252741349378",
"bizType": "DISBAND",
"bizTypeName": "流团",
"groupBatchId": "2105974855696547842",
"batchNo": "T26-7048",
"batchName": "11月26日海拉尔-额尔古纳4日团",
"approvalStatus": "PENDING",
"approvalStatusName": "待审批",
"affectedOrderCount": 2,
"participantCount": 4,
"estimatedRefundAmount": 3360.0,
"reason": "临近出团报名不足 6 户,无法成团",
"applicantName": "gbm8154test",
"canApprove": true
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
}
```
#### 空数据 / 降级响应
没有匹配的申请时返回空页。
```json
{
"code": 200,
"message": "成功",
"data": {
"records": [],
"total": 0,
"page": 1,
"pageSize": 20
}
}
```
#### 错误响应
```json
{
"code": 589507,
"message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)",
"data": null
}
```
| 错误码 | 触发条件 |
|---|---|
| 589507 | 无 `group-batch:view` 权限码(读端点判权码,与审批角色门无关,本次未改) |
#### 业务边界
- `canApprove` 整页只算一次,与行数无关。
- 定制师、财务等角色在流团行上仍为 false;管理员 / 超级管理员仍为 true。
- 团期管理员放行开关关掉时,团期管理员在流团行上回到 false。
### 4. GB-ADM-061 流团申请详情 `GET /v3/admin/order/group-batch/disband/{approvalId}`
**VO**: `DisbandApprovalRespVO`
#### 使用场景
审批中心点进流团详情;详情页的「同意 / 拒绝」按钮按 `canApprove` 显隐。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| approvalId | path | Long | 是 | 正整数,流团申请单 ID | 不存在返 589545 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| canApprove | Boolean | **本次取值变化**,口径同列表:待审批 + 团期仍可流团 + 过角色门。团期管理员由 false 变 true |
| 其余字段 | — | 未改 |
#### 请求示例
```http
GET /v3/admin/order/group-batch/disband/2105980238163030017 HTTP/1.1
Host: api.test.1814.love
Authorization: Bearer <团期管理员 token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"approvalId": "2105980238163030017",
"groupBatchId": "2105980235310923777",
"batchNo": "T26-9826",
"batchName": "12月10日海拉尔-额尔古纳4日团",
"approvalStatus": "PENDING",
"approvalStatusName": "待审批",
"reason": "临近出团报名不足 6 户,无法成团",
"affectedOrderCount": 2,
"participantCount": 4,
"estimatedRefundAmount": 3360.0,
"applicantName": "gbm8154test",
"canApprove": true
}
}
```
#### 空数据 / 降级响应
申请已处理(通过 / 拒绝 / 撤销)或团期已不可流团时,`canApprove` 为 false,其余字段照常返回。
```json
{
"code": 200,
"message": "成功",
"data": {
"approvalId": "2105980238163030017",
"approvalStatus": "REJECTED",
"approvalStatusName": "已拒绝",
"canApprove": false
}
}
```
#### 错误响应
```json
{
"code": 589545,
"message": "流团申请不存在",
"data": null
}
```
| 错误码 | 触发条件 |
|---|---|
| 589545 | 申请不存在 |
| 589507 | 无 `group-batch:view` 权限码 |
#### 业务边界
- `canApprove` 与 GB-ADM-062 走同一个判定方法,不会出现「显示了按钮、点下去 589547」。
- 缺角色时会打一条 `GB_APPROVAL_ROLE_CLAIM_MISSING` WARN,`canApprove` 返回 false。
## 四、契约约束与正确调用方式
- 前端按 `canApprove` 显隐「同意 / 拒绝」,**不要按角色自己判**:团期管理员能否审批受 nacos 开关控制,角色相同、结果可能不同。
- 同意流团的响应里 `actualRefundAmount` 现在表示「已建退款单、待二审」的合计,不代表钱已退出。要看每户退款进度,查退款审批中心(`GET /v3/admin/refund/application/page`)或订单退款列表。
- 退款审批中心会多出流团产生的 `PENDING` 退款单,申请人类型为 `SYSTEM`,原因文案是流团原因。审核人可直接同意(按 `calculatedAmount` 即已付全额退),也可改额或拒绝。
- 团期管理员不能审核退款(581008),流团退款的二审要由财务 / 管理员等有退款审核权的人处理。
## 五、数据库行为
- **零 schema 变更**,无 Flyway 迁移。
- 同意流团的写入集合不变:申请单、团期、子订单、时间线、配车释放 outbox 照旧;退款单照旧由取消事件建出。
- 唯一变化是退款单的落库状态:改前建单后同一流程里自动写一条 `refund_review`(审核人 = 流团审批人)并把 `refund_application.status` 推到 `APPROVED`;改后只建 `PENDING` 单,`refund_review` 零行、`reviewed_at` 为空,等退款审批中心处理。
- 流团退款对账建单时写入的 `calculated_amount` 由「按退款政策算」改为「该户已付全额」,与通用建单路径写同一个数。
- 拒绝流团的写入不变:只改申请单一行 + 一条时间线。
## 六、边界行为
- 两个 nacos 开关,默认都开:
- `group-batch.disband.refund-second-review`:关掉时,退款回到改前自动放行,每次同意都打 `GB_DISBAND_REFUND_SECOND_REVIEW_OFF` WARN;**同时收回团期管理员的流团审批权**(否则团期管理员一个人就能把整团的钱自动退出去)。
- `group-batch.acl.allow.disband-approver-group-batch-manager`:关掉时只收回团期管理员的流团审批权,二审保留;团期管理员被拒时打 `GB_DISBAND_APPROVER_GBM_DISABLED` WARN。
- 流团这对开关与退单(#8436)那对开关互不牵动,两类审批分别回滚。
- 开关取不到(容器未绑定)时按更严处理:不放团期管理员。
- 未付户随流团取消,不建退款单(既有行为)。
## 六.6、修改前后对比
| 场景 | 改前 | 改后 |
|---|---|---|
| 团期管理员同意 / 拒绝流团 | 589547 | 成功,审批人记为团期管理员 |
| 定制师 / 财务同意 / 拒绝流团 | 589547 | 589547(不变) |
| 管理员同意 / 拒绝流团 | 成功 | 成功(不变) |
| 同意流团后已付户的退款单 | `APPROVED`,带 1 条审核记录(审核人 = 流团审批人) | `PENDING`,0 条审核记录,`calculated_amount` = 已付全额 |
| 审批中心 / 流团详情 `canApprove`(团期管理员,待审批流团) | false | true |
| 审批中心 / 流团详情 `canApprove`(定制师) | false | false(不变) |
## 六.7、影响评估
- **前端**:零改动。审批中心页已对团期管理员开放,按钮按 `canApprove` 显隐,后端放开后按钮自动出现。
- **财务 / 退款审核人**:退款审批中心多出流团退款单,需要人工审核后才会退款,流团退款到账时间会因此延后。这是本次的目的。
- **回滚**:改 nacos 开关即可,不需要发版。
## 七、不影响范围
- 发起流团 GB-ADM-060:判权(`group-batch:manage` 权限码)与行为不变。
- 退单审批 GB-ADM-072 ~ 075:判定、开关、二审都不变,#8436 的那对开关不受本次影响。
- 退款审核端点 `POST /v3/admin/refund/review`:仍禁止团期管理员。
- 单笔取消订单、C 端申请退款等其他建退款单的路径:不变。
## 八、测试环境已验证
部署:dev-v3 @ `c4a410a94`,2026-10-02 19:01 部署 hl-order-service-v3。运行字节探针在 8086 / 8186 两个实例上都命中本次新增的 `GB_DISBAND_APPROVER_GBM_DISABLED` 与 `GB_DISBAND_REFUND_SECOND_REVIEW_OFF`;进程 jar 与磁盘 jar 为同一 inode。
判权一律用低权限角色声明取证:团期管理员用 TEST 上当前角色即团期管理员的 `gbm8154test`;不用超级管理员。
| 场景 | 改前(`1f8b1dacd`,团期 `T26-0659`) | 改后(`c4a410a94`,团期 `T26-7048` / `T26-3437` / `T26-9826`) |
|---|---|---|
| 团期管理员同意 / 拒绝真实待审批流团 | 589547 / 589547 | 拒绝成功(`T26-7048` 申请 `2105977252741349378`);同意成功(申请 `2105977953445969921`) |
| 定制师同意 / 拒绝 | 589547 / 589547 | 589547 / 589547,申请单仍 PENDING |
| 管理员同意 | 成功 | 成功(申请 `2105977508052828161`) |
| 已付户退款单(全款 3360.00) | `APPROVED`,`refund_review` 1 行 | 团期管理员批、管理员批两例都是 `PENDING`,`calculated_amount=3360.00`,`refund_review` 0 行,`reviewed_at` 为空 |
| 退款审批中心 PENDING 列表 | — | 两张流团退款单都在列 |
| 审批中心 `canApprove`(团期管理员 / 定制师) | false / — | true / false |
| 流团详情 `canApprove`(团期管理员 / 定制师 / 管理员) | — | true / false / true;拒绝后 false |
| 团期管理员调退款审核端点 | — | 581008,钱的出口仍挡住团期管理员 |
全部调用 HTTP 200;审批单 `actual_refund_amount` 两例都定稿为 3360.00。
## 十、相关文档
- 工单:wx/HL#8246
- PR:wx/HL#8734(merge commit `c4a410a94`)
- 参照:#8436 退单审批放开团期管理员 + 退款二审
- 代码:`WithdrawApprovalGuard#assertDisbandApproverRole`、`GroupBatchDisbandApprovalService#approveInTx`、`GroupBatchAclToggle`
## 关联 / 联系人
- 后端:jw
- 前端:无需改动(hl-ui v2.1 已按 `canApprove` 显隐)
- 关联工单:#8436、#8253、#7294、#7609