docs(changelog): #8753 团期管理员可为团期产品新增子订单,建单入参新增归属定制师 consultantId(修改接口·管理后台)
changelog-filename-gate / validate (push) Failing after 1s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
这个提交包含在:
jw
2026-10-03 20:05:59 +08:00
共同撰写人 Claude Opus 5.5
父节点 5e25e03897
当前提交 93027c27eb
@@ -0,0 +1,276 @@
---
schema: "hl-changelog/v2"
ticket: "8753"
title: "团期管理员可为团期产品新增子订单:建单入参新增归属定制师 consultantId,非团期产品仍 581008"
consumer: "admin"
author: "jw(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "已合并 dev-v3(ea502ba02)并部署 TEST(order-v3 @ ea502ba02),自签 token 经网关实测:团期管理员为团期产品建单带合法 consultantId → 200、定制师落所选账号;不传 581066、非定制师 / 未绑企微 / 不存在 581067、名单不可用 581068(nacos 注入 1ms 超时实测)、非团期产品 581008,均零落库;ADMIN / CUSTOMIZER 传了 consultantId 也被忽略。前端待做:团期看板 PeriodRow 对团期管理员放开「新增子订单」、建单向导加归属定制师下拉(GET /admin/user/designers)。注意:建单向导的报价接口 POST /admin/product/item/:id/quote 在 TEST 上对非超管均 403(product-v2 存量问题,见 #8753 评论),不解决则团期管理员仍提交不了。"
updated_at: "2026-10-03"
base: "dev-v3"
---
# order-v3: 团期管理员可为团期产品新增子订单(建单入参新增归属定制师)
**服务**: hl-order-service-v3
**PR**: `#8769`(已合入 `dev-v3`,合并提交 `ea502ba02`)
**Issue**: #8753
---
## ⚠️ 关键变化
🟢 **`POST /v3/admin/order` 入参纯新增 `consultantId`(归属定制师 adminId)**,出参不变。只有团期管理员会读它,其他角色传了也忽略。
🔴 **团期管理员(`GROUP_BATCH_MANAGER`)从「建单一律 581008」改为「可为团期产品建单,必须选归属定制师」**:订单的定制师是所选账号,不是团期管理员本人;建完之后这一单的其余写操作对团期管理员仍是 581008(#8154 不变)。
🟢 **三个新错误码**:`581066` 未选归属定制师、`581067` 所选账号不在定制师名单、`581068` 定制师名单暂不可用(稍后重试)。
---
## 一、背景
原型里团期看板每期都有「新增子订单」,是团期管理员视角。#8154 把订单写端点整体对团期管理员关掉,建单也在其中,前端随之对他隐藏了按钮。jw 10-03 定:团期管理员可以新增子订单,归属定制师选持定制师角色的人。只放开建单还不够——后台建单的定制师默认取当前登录人,团期管理员建出来的单会挂在他自己名下,而他按 #8154 又改不了,所以本次同时要求团期管理员指定归属定制师。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 创建订单 | POST | `/v3/admin/order` | 修改 | 入参新增 `consultantId`;团期管理员可为团期产品建单;新增错误码 581066 / 581067 / 581068 |
---
## 三、接口详情
### 1. 创建订单 `POST /v3/admin/order`
**VO**: `OrderCreateReqVO` → `Result<OrderCreateRespVO>`
#### 使用场景
团期看板某一期点「新增子订单」进入建单向导(深链带 `productId` / `productBatchId` / `departureDate`)。团期管理员在向导里多选一项「归属定制师」,提交后订单挂在该定制师名下,由他跟进补资料、收款;团期管理员只看不改。定制师、管理员等其他角色的建单流程不变。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| consultantId | Body | Long | 团期管理员必填,其他角色不读 | 须为持定制师角色、在职且已绑企微的后台账号 | 🆕 归属定制师 adminId;下拉数据源 `GET /admin/user/designers`(返回的 `id` 即 adminId) |
| productId | Body | Long | ✅ | 团期管理员只能选团期产品(GROUP) | **不变**;团期管理员选非团期产品返回 581008 |
| productBatchId | Body | Long | GROUP 产品必填 | 团期管理员必须带 | **不变**;团期管理员不带返回 581008 |
| tierSeq / departureDate / adultCount / childCount / youngChildCount / babyCount / customerName / customerPhone / customerRemark / createSource / roomCount / tags / sharerOpenid / customizerId | Body | — | — | — | **不变** |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| consultantId | String | **取值口径变化**:团期管理员建单时为所选归属定制师,其余角色仍为当前登录人 |
| consultantSource | String | 团期管理员建单时为 `MANUAL`(与后台代下单相同) |
| 其余字段 | — | **不变** |
#### 请求示例
```json
{
"productId": "2044306857534636034",
"tierSeq": 1,
"departureDate": "2026-11-05",
"adultCount": 2,
"customerName": "王建国",
"customerPhone": "13947012345",
"productBatchId": "2106318108807593985",
"roomCount": 1,
"consultantId": "1002"
}
```
#### 响应示例
团期管理员账号经网关建单,TEST 实际返回(省略了未变字段):
```json
{
"code": 200,
"message": "成功",
"data": {
"id": "2106348497395765250",
"orderNo": "HL20261003193950403",
"orderStatus": "PENDING_PAY",
"consultantId": "1002",
"consultantSource": "MANUAL",
"productName": "冻干粉发短信给",
"departureDate": "2026-11-05",
"returnDate": "2026-11-07",
"totalAmount": "3360.00",
"groupBatchId": "2106348497525788673",
"productBatchId": "2106318108807593985",
"groupOrder": true
},
"success": true
}
```
#### 空数据 / 降级响应
user-service 的定制师名单拿不到(超时、熔断降级返回空列表、非 200)时,团期管理员建单一律拒绝并返回 `581068`,不会放行,也不会误报成 `581067`;其他角色不查名单,不受影响。
#### 错误响应
团期管理员建单的拒绝顺序:范围(581008)→ 未选定制师(581066)→ 名单不可用(581068)→ 不在名单(581067)。
| code | message | 何时出现 |
|---|---|---|
| 581008 | 无权查看此订单 | 团期管理员选了非团期产品,或团期产品没带 `productBatchId` |
| 581066 | 请选择归属定制师 | 团期管理员没传 `consultantId` |
| 581067 | 所选归属定制师无效,请重新选择持定制师角色的在职账号 | 账号不存在、非定制师、不在职或未绑企微 |
| 581068 | 定制师名单暂不可用,请稍后重试 | user-service 名单接口不可用 |
```json
{
"code": 581066,
"message": "请选择归属定制师",
"data": null,
"success": false
}
```
```json
{
"code": 581067,
"message": "所选归属定制师无效,请重新选择持定制师角色的在职账号",
"data": null,
"success": false
}
```
#### 业务边界
- 只有团期管理员读 `consultantId`;定制师、管理员等传了也忽略,定制师仍是当前登录人。
- 名单口径 = 持定制师角色 + 在职 + 已绑企微,与 `GET /admin/user/designers` 是同一集合;**未绑企微的定制师选不了**。
- `consultantName` 取所选账号的企微姓名,没有则取用户名(与该定制师登录后自己建单时一致)。
- 建单后的改单、改出行人、取消、终止等写操作对团期管理员仍是 581008,改派定制师不在本次范围。
---
## 四、契约约束与正确调用方式
- 团期管理员建单必须带 `productBatchId` 与 `consultantId`;前端判断当前角色是团期管理员时,向导里显示「归属定制师」下拉并设为必填。
- 下拉调 `GET /admin/user/designers`,用返回的 `id`(字符串形式的 adminId)作为 `consultantId`,`name` 作为展示名。不要用 `GET /admin/user/customizers`:那个接口含禁用、锁定和未绑企微的账号,选了会被 581067 拒。
- 581068 是暂时性错误,提示「稍后重试」即可;581067 要让用户换人。
- 建单成功后跳转订单详情:团期管理员只读,详情可看,编辑按钮按 #8154 的 581008 处理。
---
## 五、数据库行为
- 零 DDL、零数据迁移。
- 团期管理员建单写入路径与其他角色相同(`order_main` 等),区别只在 `consultant_id` / `consultant_name` 取所选定制师、`consultant_source=MANUAL`。
- 建单准备阶段(事务外)多一次 user-service 内部调用 `GET /internal/user/admin/by-role-key?roleKey=CUSTOMIZER`,只在团期管理员建单时发生。
- 所有拒绝都发生在落库前,零写入。
---
## 六、边界行为
- 团期管理员 + 团期产品 + 带班期 + 合法 `consultantId` → 建单成功,团期报名户数、人数照常自增,订单 `groupBatchId` 非空。
- 团期管理员给非团期产品硬带 `productBatchId` → 581008(不是普通角色看到的 581056)。
- 零角色账号(网关未透传角色)不算团期管理员,走普通建单分支,与改前一致。
## 六.6、修改前后对比
| 场景 | 改前 | 改后 |
|---|---|---|
| 团期管理员为团期产品建单 | 581008 | 带合法 `consultantId` → 200,定制师 = 所选账号 |
| 团期管理员不传 `consultantId` | 581008 | 581066 |
| 团期管理员建非团期产品单 | 581008 | 581008(不变) |
| 团期管理员改这一单 | — | 581008(#8154 不变) |
| 定制师 / 管理员建单 | 定制师 = 当前登录人 | 不变,传了 `consultantId` 也忽略 |
## 六.7、影响评估
- **是否破坏向后兼容**:否。入参纯新增可选字段,出参不变;只有团期管理员的行为变化(从一律 581008 变为可建团期子订单)。
- **前端是否必须同步上线**:否。前端不改时团期管理员看不到按钮,行为与改前一致。要让团期管理员用起来需前端放开按钮、加定制师下拉,并且**建单向导的报价接口要能通**(见第八节 8.4)。
- **性能**:只有团期管理员建单多一次 user-service 内部调用。
- **回滚**:revert PR #8769 后重新部署 order-v3,无 DDL、无配置。
---
## 七、不影响范围
- 订单详情、列表等读接口:不变。
- 其余订单写接口对团期管理员的 581008:不变(#8154)。
- 小程序端下单(`/v3/mp/...`):不经此入口,不变。
- `GET /admin/user/designers`、`GET /internal/user/admin/by-role-key`:接口本身不变。
---
## 八、测试环境已验证
**环境**:TEST(`https://api.test.1814.love`) **验证时间**:2026-10-03 19:31~19:50
**构建身份**:order-v3 部署 `dev-v3 @ ea502ba02`(本单合并提交),两实例滚动完成。探针:团期管理员不传 `consultantId` 建单,部署前 `581008`,部署后 8/8 为 `581066`。
**身份**:自签 token 直打网关;团期管理员 `gbm8154test`(单角色),归属定制师测试号 `test_admin`(1002)。
### 8.1 正向与归属
| 项 | 结果 |
|---|---|
| 团期管理员建团期子订单(`consultantId=1002`) | 200;`order_main.consultant_id=1002`、`consultant_name=test_admin`、`consultant_source=MANUAL`、`group_batch_id` 非空 |
| 所选定制师 1002 | 订单列表(`orderKind=GROUP`)能查到这一户,详情 200,改客户备注 200 并落库;另一位定制师查不到 |
| 团期管理员 | 读详情 200;改备注、改出行人均 581008,库内未被改动 |
| 入团 | 建单前 0 户 0 人 → 团期管理员再建一户后 4 户 9 人,产品侧报名人数同步 |
### 8.2 反向与范围
| 操作 | 结果 |
|---|---|
| 不传 `consultantId` | 581066,零落库 |
| 传团期管理员本人 / 持定制师角色但未绑企微 / 不存在的 id | 均 581067,零落库 |
| 非团期产品(不带班期、硬带班期)/ 团期产品不带班期 | 均 581008,零落库 |
| ADMIN、CUSTOMIZER 传 `consultantId` | 200,定制师仍为本人 |
### 8.3 降级
nacos 只给 order-v3 的 `userFeignClient` 注入 1ms 超时并重启后,团期管理员带合法 `consultantId` 建单 7 次均 581068,零落库;验完配置原样还原(SHA-256 逐字节一致)并再次重启。
### 8.4 建单向导依赖的读接口(团期管理员)
| 接口 | 结果 |
|---|---|
| `GET /admin/product/line/order-picker`、`GET /admin/product/item/order-picker`、`GET /admin/product/item/:id`、`GET /admin/product/item/:id/pricing-calendar`、`GET /v3/admin/tag-library` | 均 200 |
| `GET /admin/user/designers` | 200,20 人,与「定制师 + 在职 + 已绑企微」的 SQL 名单逐个相同 |
| `POST /admin/product/item/:id/quote` | 🔴 403「无操作权限」——product-v2 存量问题,CUSTOMIZER / ADMIN 同样 403,只有 SUPER_ADMIN 能过;前端提交前必须报价成功,不解决则团期管理员仍提交不了。已在 #8753 列明,待另行处理 |
### 本地证据
| 项 | 读数 |
|---|---|
| 定向 13 组 | order-v3 607 例 0 失败(新增 Service 10 例、Controller 2 例、ArchTest 2 条规则) |
| 变异 | 删掉 Controller 的身份透传、删掉 Service 的策略调用 → 两条新规则同时变红;已还原 |
| order-v3 全量(有 Docker,两半) | A 10956 / 2 失败,B 4935 / 2 失败 / 7 跳过;1140 个可执行测试类全部有报告;3 条在基底逐条复现,1 条为并发负载下的锁等待抖动(单跑 2×14/14),本单零新增 |
---
## 十、相关文档
- Issue `#8753`;PR `#8769`
- 前置:#8154(团期管理员只读守卫)、#8440(同样定点放开 #8154 的先例:退单提交)、#7143(看板「新增子订单」深链)
## 关联 / 联系人
### 链接
- **Issue**: [#8753](https://git.1814.love/wx/HL/issues/8753)
- **PR**: [#8769](https://git.1814.love/wx/HL/pulls/8769)
- **Merge commit**: [ea502ba02](https://git.1814.love/wx/HL/commit/ea502ba02)
### 联系人
- **后端负责人**: @jw