diff --git a/changelogs-v2/2026-10/02_8246_流团审批放开团期管理员与批后退款二审-修改接口-管理后台.md b/changelogs-v2/2026-10/02_8246_流团审批放开团期管理员与批后退款二审-修改接口-管理后台.md new file mode 100644 index 00000000..65241828 --- /dev/null +++ b/changelogs-v2/2026-10/02_8246_流团审批放开团期管理员与批后退款二审-修改接口-管理后台.md @@ -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