298 lines
12 KiB
Markdown
298 lines
12 KiB
Markdown
# M010 Rooming List Excel 生成 V1
|
||
|
||
| 项目 | 内容 |
|
||
| --- | --- |
|
||
| 文档状态 | 后端 CP1 已实现,第一版直接下载 `.xlsx`,不落库、不上传 OSS |
|
||
| 适用范围 | 从旅行团名单 Excel 解析护照姓名,并生成酒店 / PMS 可导入的 Rooming List Excel |
|
||
| 当前目标 | 第一阶段已支持前端上传来源 Excel、填写分房和目标列默认值,后端同步生成目标格式 `.xlsx` 供浏览器下载 |
|
||
| 依赖能力 | 登录权限、酒店上下文、Apache POI 或等价 Excel 读写能力 |
|
||
|
||
## 1. 背景
|
||
|
||
当前系统已经支持 Manual Invoice 生成,但运营中还存在另一类独立工具诉求:旅行社或渠道提供一份名单 Excel,里面包含旅客护照姓名,酒店侧需要整理成 PMS / 导入模板要求的 Rooming List Excel。
|
||
|
||
本功能第一版只解决“来源名单到目标 Rooming List”的结构转换和分房填表问题,不依赖订单、任务、SuperAgent、AgentBus 或 OPERA。
|
||
|
||
M002 V4 `ROOMING_LIST` 任务卡与本工具是两个独立能力:V4 卡第一版只做 Rooming List 事项确认,不调用本工具、不解析名单、不生成 Excel、不导入 PMS。
|
||
|
||
## 2. 第一阶段定位
|
||
|
||
第一阶段应做到:
|
||
|
||
- 前端上传 `.xls` / `.xlsx` 来源名单。
|
||
- 后端解析来源名单中的护照姓名字段。
|
||
- 前端输入每间房人数。
|
||
- 前端填写或选择目标 Excel 中除姓名外的字段。
|
||
- 后端按来源名单顺序分组,生成目标格式 Excel。
|
||
- 浏览器直接下载生成后的 `.xlsx` 文件。
|
||
|
||
第一阶段不做:
|
||
|
||
- 不落业务订单。
|
||
- 不创建任务。
|
||
- 不上传 OSS。
|
||
- 不新增生成记录表。
|
||
- 不做历史查询和重下载。
|
||
- 不接真实 OPERA / OHIP。
|
||
- 不做复杂房型混住、拖拽换房或手工调整入住人顺序。
|
||
- 不从任务详情或订单详情自动预填字段。
|
||
|
||
## 3. 与现有模块关系
|
||
|
||
本功能属于 Reservation 运营工具,不属于 M008 通用文件转换,也不属于 M009 Manual Invoice。
|
||
|
||
边界说明:
|
||
|
||
- M008 负责 Excel 转 PDF,面向平台文件转换和调试能力。
|
||
- M009 负责 Proforma Invoice 生成,输出 PDF 并上传 OSS。
|
||
- M010 负责 Rooming List Excel 生成,第一版只输出 `.xlsx` 文件流。
|
||
|
||
因此第一版建议在 Reservation 模块内新增独立接口、权限码和服务,不复用发票生成权限,也不让前端调用 M008 调试接口。
|
||
|
||
## 4. 来源 Excel 解析规则
|
||
|
||
基于当前样例来源文件,第一版默认识别以下表头:
|
||
|
||
| 来源字段 | 中文说明 | 第一版用途 |
|
||
| --- | --- | --- |
|
||
| `护照全名` | 护照姓名,可能包含 `/` 或空格 | 解析为目标 Excel 的 `Name` 和 `First Name` |
|
||
|
||
第一版只使用 `护照全名` 生成目标姓名字段。来源文件中的证件号、生日、性别、年龄等字段暂不自动写入目标 Excel,除非后续单独确认。
|
||
|
||
### 4.1 姓名拆分
|
||
|
||
支持的输入格式:
|
||
|
||
```text
|
||
LI/CHUNHONG
|
||
LI CHUNHONG
|
||
LIU/JIAYI
|
||
```
|
||
|
||
规则:
|
||
|
||
- 先 trim 首尾空格。
|
||
- 优先按 `/` 拆分。
|
||
- 如果没有 `/`,按连续空白拆分。
|
||
- 第一段写入目标 `Name`。
|
||
- 剩余部分合并后写入目标 `First Name`。
|
||
- 如果无法拆出两段,返回明确校验错误,由前端提示用户修正来源 Excel 或后续增加字段映射。
|
||
|
||
中文说明:
|
||
|
||
- 当前目标模板中 `Name` 更接近姓氏字段,`First Name` 更接近名字段。
|
||
- 第一版不尝试判断中文、韩文、英文姓名顺序,也不做大小写改写。
|
||
|
||
## 5. 分房生成规则
|
||
|
||
前端需要传入 `people_per_room`,表示每间房人数。
|
||
|
||
规则:
|
||
|
||
- 按来源 Excel 中旅客出现顺序分组。
|
||
- `room_count = ceil(total_people / people_per_room)`。
|
||
- 每组第一位旅客写入目标 Excel 的 `Name` 和 `First Name`。
|
||
- 同组剩余旅客写入目标 Excel 的 `Accompanying Guests`。
|
||
- 多个陪同人使用英文逗号 `,` 分隔。
|
||
- 最后一组人数不足 `people_per_room` 时,仍按一间房生成一行。
|
||
|
||
示例:
|
||
|
||
```text
|
||
people_per_room = 3
|
||
|
||
第 1 组:
|
||
Name = LI
|
||
First Name = CHUNHONG
|
||
Accompanying Guests = ZHANG GAILI, LI HONG
|
||
|
||
第 2 组:
|
||
Name = LIU
|
||
First Name = JIAYI
|
||
Accompanying Guests = ZHU XINGTONG, CHEN YUCHAI
|
||
```
|
||
|
||
## 6. 目标 Excel 字段
|
||
|
||
目标 Excel 第一版按当前样例模板生成以下列:
|
||
|
||
| 目标列 | 第一版来源 |
|
||
| --- | --- |
|
||
| `Line` | 后端按生成行号从 1 递增 |
|
||
| `Name` | 每间房第一位旅客的姓氏 / 第一段姓名 |
|
||
| `First Name` | 每间房第一位旅客的名字 / 剩余姓名 |
|
||
| `Title` | 前端传入,第一版可为空 |
|
||
| `Arrival` | 前端传入 |
|
||
| `Departure` | 前端传入 |
|
||
| `Room Type` | 前端传入 |
|
||
| `Rate Code` | 前端传入 |
|
||
| `Number of Rooms` | 第一版每行固定为 `1`,后续如目标模板变化再调整 |
|
||
| `Adults` | 前端传入;为空时可由后端按当前分组人数派生 |
|
||
| `Children` | 前端传入;第一版默认可为 `0` |
|
||
| `Payment Type` | 前端传入 |
|
||
| `VIP` | 前端传入,第一版可为空 |
|
||
| `Accompanying Guests` | 同房其他旅客姓名,英文逗号分隔 |
|
||
| `Nationality` | 前端传入 |
|
||
| `Email` | 前端传入,第一版可为空 |
|
||
| `ID Type` | 前端传入,第一版可为空 |
|
||
| `ID Number` | 前端传入,第一版可为空 |
|
||
|
||
中文说明:
|
||
|
||
- 除 `Line`、`Name`、`First Name`、`Number of Rooms`、`Accompanying Guests` 外,第一版都由前端输入或选择。
|
||
- 如果前端希望 `Adults` 自动等于当前房间人数,后端可以提供默认规则;但请求体仍建议显式保留覆盖字段,方便后续处理儿童、领队或特殊房间。
|
||
|
||
## 7. 接口契约
|
||
|
||
第一版已新增业务接口,不复用 M008 文件转换接口:
|
||
|
||
```text
|
||
POST /api/reservation/rooming-lists/generations
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: multipart/form-data
|
||
```
|
||
|
||
表单字段:
|
||
|
||
| 字段 | 类型 | 必填 | 中文说明 |
|
||
| --- | --- | --- | --- |
|
||
| `file` | file | 是 | 来源 Excel 文件,仅支持 `.xls` / `.xlsx` |
|
||
| `hotel_id` | string | 否 | 酒店 ID;不传时按当前登录用户默认酒店或单酒店上下文解析 |
|
||
| `people_per_room` | integer | 是 | 每间房人数,必须大于 0 |
|
||
| `arrival` | string | 是 | 入住日期,酒店本地业务日期,格式 `yyyy-MM-dd` |
|
||
| `departure` | string | 是 | 离店日期,酒店本地业务日期,格式 `yyyy-MM-dd` |
|
||
| `room_type` | string | 是 | 目标 Excel 的 `Room Type` |
|
||
| `title` | string | 否 | 目标 Excel 的 `Title` |
|
||
| `rate_code` | string | 否 | 目标 Excel 的 `Rate Code` |
|
||
| `adults` | integer | 否 | 目标 Excel 的 `Adults`;为空时可由后端按分组人数派生 |
|
||
| `children` | integer | 否 | 目标 Excel 的 `Children`;为空时默认 `0` |
|
||
| `payment_type` | string | 否 | 目标 Excel 的 `Payment Type` |
|
||
| `vip` | string | 否 | 目标 Excel 的 `VIP` |
|
||
| `nationality` | string | 否 | 目标 Excel 的 `Nationality` |
|
||
| `email` | string | 否 | 目标 Excel 的 `Email` |
|
||
| `id_type` | string | 否 | 目标 Excel 的 `ID Type` |
|
||
| `id_number` | string | 否 | 目标 Excel 的 `ID Number` |
|
||
|
||
成功响应:
|
||
|
||
```text
|
||
HTTP 200
|
||
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||
Content-Disposition: attachment; filename="rooming-list-<timestamp>.xlsx"
|
||
```
|
||
|
||
错误响应沿用后端统一错误模型,例如:
|
||
|
||
```json
|
||
{
|
||
"error_code": "ROOMING_LIST_SOURCE_FILE_INVALID",
|
||
"message": "来源名单文件不合法。",
|
||
"details": [
|
||
"未找到表头:护照全名"
|
||
]
|
||
}
|
||
```
|
||
|
||
已收口的第一版错误场景:
|
||
|
||
- multipart 必填字段缺失,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||
- `arrival` / `departure` 日期格式错误,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||
- `people_per_room`、`adults`、`children` 数字格式错误,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||
- 来源文件缺失、非 `.xls` / `.xlsx`、无法读取或缺少 `护照全名` 表头,返回 `ROOMING_LIST_SOURCE_FILE_INVALID`。
|
||
- 错误详情只返回字段名或行号,不回显完整名单、证件号或源文件内容。
|
||
|
||
## 8. 权限、安全和审计
|
||
|
||
接口分类:`FRONTEND_USER`。
|
||
|
||
已新增权限码:
|
||
|
||
```text
|
||
RESERVATION_ROOMING_LIST_GENERATE
|
||
```
|
||
|
||
管控要求:
|
||
|
||
- 必须登录。
|
||
- 必须拥有 `RESERVATION_ROOMING_LIST_GENERATE` 权限。
|
||
- 上传接口在 multipart 参数绑定前执行登录和权限前置校验,未登录或无权限请求不会进入来源文件解析。
|
||
- 必须校验用户对 `hotel_id` 的访问权。
|
||
- 第一版直接下载、不落库,因此不写生成记录表。
|
||
- 当前 CP1 不新增持久化审计表;后续如增加生成记录或历史下载,再补业务审计落库。
|
||
- 日志和错误响应不得输出完整名单、证件号、源文件内容或生成文件内容。
|
||
|
||
## 9. 后端实现拆分
|
||
|
||
已实现类职责:
|
||
|
||
| 类 / 能力 | 中文职责 |
|
||
| --- | --- |
|
||
| `ReservationRoomingListGenerationController` | 接收前端上传请求,做登录、权限和酒店上下文校验 |
|
||
| `ReservationRoomingListGenerationService` | 编排来源解析、分房、目标 Excel 渲染和文件响应 |
|
||
| `ReservationRoomingListGenerationServiceImpl` | 具体业务实现 |
|
||
| `RoomingListSourceExcelParser` | 解析来源 Excel,提取护照姓名 |
|
||
| `RoomingListNameParser` | 拆分 `/` 或空格格式的护照姓名 |
|
||
| `RoomingListGroupingService` | 按每房人数分组并生成目标行模型 |
|
||
| `RoomingListExcelRenderer` | 生成目标格式 `.xlsx` |
|
||
| `ReservationRoomingListGenerationRequest` | multipart 外的业务参数请求模型 |
|
||
| `ReservationRoomingListGeneratedFile` | 生成后的下载文件字节和文件名 |
|
||
| `ReservationRoomingListGuestDto` | 解析后的旅客姓名结构 |
|
||
| `ReservationRoomingListRoomDto` | 分房后的目标行结构 |
|
||
|
||
中文说明:
|
||
|
||
- 第一版不需要新增 Entity、Mapper 和 Repository。
|
||
- 如果后续要生成记录、OSS 上传、历史查询或重下载,再新增 `workflow_reservation_rooming_list_generation` 表。
|
||
- 解析和渲染能力应和 Controller 解耦,便于单元测试。
|
||
- 目标 Excel 固定列宽,不调用 POI `autoSizeColumn`,避免后端运行环境依赖本机字体或图形环境。
|
||
|
||
## 10. 前端实现建议
|
||
|
||
第一版页面可以放在 Reservation 工具入口,例如:
|
||
|
||
```text
|
||
/reservation/rooming-lists/new
|
||
```
|
||
|
||
页面能力:
|
||
|
||
- 上传来源 Excel。
|
||
- 填写每间房人数。
|
||
- 填写或选择 Arrival、Departure、Room Type、Rate Code、Payment Type、Nationality 等字段。
|
||
- 展示解析预览:总人数、预计房间数、前几行分房结果。
|
||
- 点击生成后下载 `.xlsx`。
|
||
|
||
前端注意:
|
||
|
||
- 不要在前端解析完整 Excel 作为权威结果;前端预览可以后置为后端 preview 接口。
|
||
- 第一版如果没有 preview 接口,可以只展示用户输入和文件名,生成成功后直接下载。
|
||
- 不要把上传文件内容、客人名单或生成文件内容写进浏览器日志、错误上报、URL 或 localStorage。
|
||
|
||
## 11. 测试范围
|
||
|
||
后端测试建议覆盖:
|
||
|
||
- 能识别 `护照全名` 表头。
|
||
- `LI/CHUNHONG` 能拆成 `Name=LI`、`First Name=CHUNHONG`。
|
||
- `LI CHUNHONG` 能拆成 `Name=LI`、`First Name=CHUNHONG`。
|
||
- 姓名首尾空格会 trim。
|
||
- `people_per_room=3` 时 32 人生成 11 行。
|
||
- 尾房人数不足时仍生成一行。
|
||
- `Accompanying Guests` 使用英文逗号拼接。
|
||
- 未找到表头时返回明确错误。
|
||
- 非 Excel 文件、空文件、超大文件返回明确错误。
|
||
- 无 token、无权限、无酒店访问权被拦截。
|
||
|
||
## 12. 后续版本候选
|
||
|
||
后续可以继续扩展:
|
||
|
||
- 生成记录表和历史下载。
|
||
- 生成文件上传 OSS。
|
||
- 后端预览接口。
|
||
- 支持前端手工调整分房顺序。
|
||
- 支持不同房间不同人数。
|
||
- 支持字段映射配置,允许用户选择来源 Excel 中的姓名列。
|
||
- 支持从订单、任务或 SourceMessage 附件自动带入名单。
|
||
- 支持从任务详情或订单详情预填 Arrival、Departure、Room Type、Rate Code 等字段。
|