--- schema: "hl-changelog/v2" ticket: "7178" title: "团期调整满团名额同步产品域库存" consumer: "admin" author: "jw(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "verified" frontend_owner: "mmg" frontend_ref: "84c0cd5b" target_release: "" verified_at: "2026-09-06" status_note: "修复「调了不生效」:调名额此前只写订单域,而库存权威在产品域。后端已部署 TEST 并实测:加减名额驱动产品域满团即停/放开继续招募、低于已报名拒绝且零写入、物料准备起阶段门。请求体形状已变更(净增量),前端待接。" updated_at: "2026-09-06" base: "dev-v3" --- # 团期调整满团名额:同步产品域库存 + 阶段门 + 净增量入参 > **影响范围**:管理后台「团期详情 → 整团总览 → 调整满团名额」弹窗。 > 当前状态:后端已部署 TEST 并实测;前端待接入(**请求体形状已变更**)。 ## ⚠️ 关键变化 1. **修复「调了不生效」**。此前调名额只写订单域,而下单侧的剩余名额由**产品域**算出, 于是加名额放不出空位、减名额停不了售,但看板数字会变。现在调整会真正驱动售卖状态。 2. **请求体不兼容变更**:由 `{maxParticipants, maxRooms}` 两个绝对值, 改为 `{capacityDelta, reason}` —— **净增量、只调户数**。 3. **新增阶段门**:仅「招募中」与「资源准备中」可调,物料准备中及之后返回 589538。 4. **新增权限校验** `group-batch:manage`(此前该接口无任何权限校验)。 5. **响应由空改为返回结果对象**,直接给出弹窗三格所需数据。 ## 一、背景 调整满团名额是给运营临时增减本期可报名户数用的。此前的实现只更新了团期侧的展示值, 没有同步到真正决定「还能不能报名」的那一侧,导致这个功能实际上不起作用—— **页面上数字变了,但客户仍按老上限被卡住**。本次修复把调整落到库存权威侧, 并按新库存重算班期是否已满额。 ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | | --- | --- | --- | --- | --- | --- | | 1 | 调整团期满团名额 | PUT | `/v3/admin/order/group-batch/{groupBatchId}/capacity` | 修改接口 | 入参改为净增量并只调户数;新增阶段门与权限校验;同步产品域库存;响应改为结果对象 | ## 三、接口详情 ### 1. 调整团期满团名额 `PUT /v3/admin/order/group-batch/{groupBatchId}/capacity` **VO**: `AdjustCapacityReqVO` #### 使用场景 管理员在「团期详情 → 整团总览」底部操作条点「调整满团名额」, 弹窗用 −/+ 步进器改满团户数,点「保存名额」时把**净变化量**提交给本接口。 典型用法:某期已满员但还有客户想报,加 2 个名额把空位放出来继续招募; 或临近出团减名额提前收口。**已成团的团期加名额后仍保持成团,不会退回招募中。** #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | | --- | --- | --- | --- | --- | --- | | groupBatchId | path | Long | 是 | 正整数 | 团期 ID | | capacityDelta | body | Integer | 是 | 不能为 0 | 满团名额净增量(户),可正可负。新满团户数 = 当前满团户数 + 该值 | | reason | body | String | 否 | 最长 256 字 | 调整原因,填了写进团期操作记录。**不强制必填** | #### 出参 | 字段 | 类型 | 说明 | | --- | --- | --- | | batchId | String | 团期 ID | | beforeMaxRooms | Integer | 调整前满团户数 | | maxRooms | Integer | 调整后满团户数,0 表示不限 | | capacityDelta | Integer | 本次净增量 | | enrolledRooms | Integer | 已报名户数(户 = 订单 = 房) | | remainRooms | Integer | 调整后余量 = max(0, maxRooms − enrolledRooms);满团户数为 0(不限)时为 null | #### 请求示例 ```json { "capacityDelta": 3, "reason": "客户加订,放三个空位继续招募" } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "batchId": "2096510069465088002", "beforeMaxRooms": 2, "maxRooms": 5, "capacityDelta": 3, "enrolledRooms": 1, "remainRooms": 4 }, "traceId": null, "success": true } ``` #### 空数据 / 降级响应 调整后满团户数为 0 时表示**不限名额**,此时 `remainRooms` 返回 null, 前端不显示余量。这是正常语义而非异常。 本接口没有空列表形态;任何失败都以错误码返回,且**失败一律零写入**—— 产品侧与团期侧都不会留下半改状态。 #### 错误响应 ```json { "code": 589538, "message": "物料准备开始后不可再调整满团名额(仅招募中、资源准备中可调)", "data": null, "traceId": null, "success": false } ``` #### 业务边界 - **仅「招募中」与「资源准备中」可调**;物料准备中及之后返回 589538。 - **调整后不得低于已报名户数**,否则返回 589509;新值也不得为负。 - **新值为 0 表示不限名额**,此时不受已报名数约束。 - `capacityDelta` 为 0 返回 589539(等于没调)。 - 需要 `group-batch:manage` 权限,无权限返回 589507。 - **调整不改团期状态**:已成团的仍保持成团,不会退回招募中。 - 产品侧同步失败时整笔失败并返回 589540,团期侧零写入。 ## 四、契约约束与正确调用方式 - **提交净增量,不要提交总数**。前端步进器算出的总数只用于展示, 提交时给差值即可。这样两人同时调也不会互相覆盖成对方的总数。 - **不再接收人数容量**。此前的 `maxParticipants` 字段已移除,人数容量由产品侧维护。 - **调整前先看能不能调**:团期进入物料准备后按钮应置灰,避免用户点了才报错。 - **弹窗三格数据**:调整前可从团期详情取「当前名额 / 已报名」; 调整成功后直接用本接口返回的 `maxRooms` / `enrolledRooms` / `remainRooms` 刷新, 不必再拉一次详情。 - **重试是安全的**。若前端超时后重试同一请求,服务端以团期侧当前值为基数重算, 不会把同一个增量叠加两次。 ## 五、数据库行为 - 调整会**同时更新产品侧与团期侧的满团户数**,并按新库存重算班期是否已满额: 售罄时停止继续接单,库存恢复时重新开放报名。 - **先写产品侧,成功后才写团期侧**;产品侧写失败即整笔失败、团期侧不留任何痕迹。 - 每次成功调整写一条团期操作记录,内容形如 「满团名额:9→10(+1) · 理由:客户加订一间」,含操作人与时间;未填理由时省略后半段。 - 拒绝的三种情况(阶段不允许 / 低于已报名 / 增量为 0)**均不产生任何写入**。 - 历史上两侧数值已经不一致的团期,本次不做批量订正;下一次调整会自动把两侧拉齐。 ## 六、边界行为 - 已成团的团期加名额后**仍保持成团**,只是把空位放出来继续招募,满团即停。 - 减名额减到正好等于已报名户数是允许的(余量为 0),再减一户即被拒绝。 - 满团户数为 0 表示不限,此时无论已报名多少都不触发下限校验。 - 团期未绑定产品班期时返回 589540(无处可写,不静默放过)。 ## 六.6、修改前后对比 | 项 | 修改前 | 修改后 | | --- | --- | --- | | 是否真正影响售卖 | ❌ 只改团期侧展示值,**加名额放不出空位、减名额停不了售** | ✅ 同步到库存权威侧,满团即停 / 放开继续招募都生效 | | 请求体 | `{maxParticipants, maxRooms}` 两个绝对值,均必填 | `{capacityDelta, reason}`,净增量、只调户数 | | 响应 | 空(调完要再拉一次详情) | 返回调整前后值、已报名与余量 | | 阶段限制 | **无**,任何状态都能调 | 仅招募中与资源准备中,其余 589538 | | 权限 | **无任何校验** | `group-batch:manage` | | 调整原因 | 无此入参 | `reason` 选填,写进操作记录 | | 操作记录 | 只有「最大人数:20→24,最大房间:8→9」 | 「满团名额:9→10(+1) · 理由:…」 | ## 六.7、影响评估 - **请求体不兼容**:字段整体更换。上线前已核对管理后台前端仓库, **没有任何页面在调用本接口**(原型侧本就是提交净增量,只是此前只在前端本地累加), 因此未设兼容期。若有未知调用方,需同步改造。 - **阶段门是行为变更**:此前任何状态都能调,现在物料准备后会被拒。 这是有意收紧——那之后房车已按户数配好,改名额会让资源计划失真。 - **权限是行为变更**:`group-batch:manage` 已随上一单建好并授予管理员与超级管理员, 本次直接复用,无需额外配置。 - **资源准备中调整的已知风险**:该阶段房务/车务可能已按当前户数派单订房订车, 此时加减名额**不会回头改动已派资源**,需人工复核资源计划。 - 新增字段与新响应均为增量,不改动任何既有字段的类型与含义。 ## 七、不影响范围 - 下单与库存扣减的判定口径不变,仍按满团户数与人数上限;本次只是让调整真正作用到它。 - 人数容量不受影响,仍由产品侧维护。 - 团期状态机不变:调整不推进也不回退任何状态。 - 成团、取消成团、流团三个动作本次未改动。 - 小程序端不受影响,改动全部在管理后台侧。 ## 八、测试环境已验证 TEST 环境已部署产品服务与订单服务并实测通过: - 加名额 +1:产品侧满团户数随之变化,团期侧同步,返回三格数据。 - 减名额 −2:两侧同步。 - 减到正好等于已报名户数:班期转为**已满额、停止接单**。 - 再加 1 户:班期**恢复报名中**,空位重新放出。 - 减到低于已报名户数:拒绝且**零写入**(产品侧数值未变)。 - 增量为 0:拒绝。 - 物料准备中及之后调整:拒绝且零写入。 - **已成团(资源准备中)加名额:成功,班期继续招募,团期仍保持成团不回退**。 ## 十、相关文档 - 工单:HL#7178 - 合并:HL PR#7181(已合入 dev-v3) - 关联工单:HL#7158(团期手动成团),本单复用其建立的 `group-batch:manage` 权限码; 弹窗顶部「满 6 户成团 · 满 9 户满团」的成团标准数据亦由该单交付 ## 关联 / 联系人 - 后端:jw - 前端待接:弹窗步进器改为提交净增量、接收新的响应结构刷新三格; 团期进入物料准备后按钮置灰;未达标提示与「不得低于已报名数」的前端拦截保持不变