# 【管理后台+小程序】小蒙马团期库存模型重构(删库存上限·订单数/线下占位·已报名聚合·班期状态)

> **类型**: 后端模型重构(feat,含字段增删)
> **服务**: hl-product-service-v2 + hl-order-service-v2
> **日期**: 2026-05-29
> **影响范围**: 管理后台班期编辑/列表 + 小程序班期列表(下方逐接口列出)
> **归属**: 后端已改(PR #3267 + #3269 → dev,已同步 dev-v3)
> **状态**: 已部署测试服并验证通过
> **关联工单**: #3266

---

## 一、模型总览(前端先理解这套口径)

- **容量只看「最大房间数」`maxRooms`**(0/null=不限)。「最大人数」不再作为限制,人数仅展示。
- **删除「库存上限」**(原 `productStockLimit`)。
- **「订单数(消耗)」= 实时线上订单数 + 线下占位数(相加)**;1 单 = 1 房。
- **库存/可报名 = `maxRooms − 订单数`**,后端实时算、**不落库**。
- **已报名人数 = 聚合活跃订单总人数**,后端实时算、不落库。
- 库存=0 不能开启「报名中」;下单占库存、取消/退款释放(后端自动,前端无需处理)。

## 二、管理后台·班期编辑(`POST` / `PUT /admin/product/item/{id}/schedule`,ScheduleSaveReqVO)

**字段调整:**
- ❌ 移除 `productStockLimit`(库存上限)输入。
- ➕ 新增 `manualOrderCount`(**线下占位房数**,可空,默认 0,不能为负):用于运营把线下/电话占的房手动占进库存,恒加在实时线上订单之上。
- `maxRooms`(最大房间数=容量)保留。

**保存校验(后端会拒绝):**
- `manualOrderCount` 为负 → `code 410203 线下占位数不能为负数`。
- 若该班期库存已 ≤ 0 却要置/保持「报名中」→ `code 410204 库存不足,无法开启报名中`。

## 三、管理后台·班期列表/回显(`GET /admin/product/item/{id}/schedule/list`,ScheduleRespVO)

- ❌ 移除 `enrolledCount`(旧人数计数器)、`bookedRooms`、`productStockLimit`。
- ➕ 新增(均后端实时计算,只读):
  - `manualOrderCount` — 回显线下占位数
  - `orderCount` — 有效订单数(= 实时线上订单数 + 线下占位)
  - `enrolledPeople` — 已报名人数(聚合)
  - `remainStock` — 库存/可报名(= maxRooms − orderCount;**null = 不限**)

## 四、小程序·班期列表(`GET /mp/product/{id}/schedules`,MpScheduleRespVO)

- **返回该产品全部团期(含已出发,仅排除已删除)**,前端按状态展示。
- 每条 `batchStatus`(前端**只对 `ENROLLING` 放开报名按钮**,其余禁止报名):
  - `ENROLLING` 报名中(可报名)
  - `FINISHED` 报名结束(已出发 / 报名截止日已过 / 出发前 1 天)
  - `FULL` 已满额(售罄)
  - `CANCELLING` / `CANCELLED` 取消中 / 已取消
- 字段语义:
  - `enrolledCount` → 现为**已报名人数(聚合)**
  - `remainFamilies` → **可报名/库存**(= remainStock;null=不限)。**前端「还可报 X 组」取此字段**。
  - `remainParticipants` → 恒 `null`(人数不再限制)

## 五、测试服实测

- 加法库存:maxRooms=5、线下占位=2、线上 0 单 → `orderCount=2`、`remainStock=3`、`enrolledPeople=0`。
- 库存=0 开报名中被拒(410204);线下占位负数被拒(410203)。
- mp `/schedules` 返回含已出发团期并标 `FINISHED`;售罄标 `FULL`。
