调整Rooming List付款方式选项
This commit is contained in:
@@ -34,7 +34,7 @@
|
||||
- 现有历史文档暂不按 AI-NSES 目录大搬迁,先通过索引和采用说明建立映射关系。
|
||||
- `docs/import/` 下按日期导入的资料是输入材料,不等同于当前权威开发契约;当前开发应优先看 `docs/project/README.md` 标记为当前有效或权威契约的文档。
|
||||
- 后续每完成一个 Feature 或 Checkpoint,需要更新本文件,避免项目状态继续沉淀在聊天记录里。
|
||||
- M010 Rooming List Excel 生成后端 CP1 和前端 V1 已实现:前端 `/reservation/rooming-lists/new` 上传来源名单并下载后端同步生成的 `.xlsx`,第一版不落库、不上传 OSS。CP2 已实现:来源 Excel `旅游日期` 派生 Arrival / Departure,Adults 由系统按分房结果计算,目标默认值区域只保留 Payment Type / Nationality,Payment Type 默认 / 当前唯一允许值为 `CA`,Nationality 只允许 `KR` / `CHN`。
|
||||
- M010 Rooming List Excel 生成后端 CP1 和前端 V1 已实现:前端 `/reservation/rooming-lists/new` 上传来源名单并下载后端同步生成的 `.xlsx`,第一版不落库、不上传 OSS。CP2 已实现:来源 Excel `旅游日期` 派生 Arrival / Departure,Adults 由系统按分房结果计算,目标默认值区域只保留 Payment Type / Nationality,Payment Type 默认 `BTQR` 且当前允许 `BTQR` / `CA`,Nationality 只允许 `KR` / `CHN`。
|
||||
- M011 Booking Excel 附件预处理 CP1/CP2/CP3 已实现:后端可排除人员名单类 Excel,按最近 6 个月候选窗口选择实际存在的最新 3 个业务月,抽取 Booking Update / 附加费表高亮行业务 JSON;Debug EML 和 AgentBus dispatch 在各自 include 开关与总开关同时启用时,会在调用 SuperAgent 前追加 `attachment_extractions[]`。测试机 AgentBus 增强已开启;生产链路仍默认关闭,生产开启需单独确认。
|
||||
- M002 V4 CP1 当前已完成入站解析和现有任务链路过渡适配;M002 V4 CP2 已完成订单任务与多卡领域模型设计;M002 V4 CP3 已完成 V4 订单任务、多卡和 S10/S99 来源通知表结构与 Repository 基线;M002 V4 CP4 已完成入站写入新模型;M002 V4 CP5 已完成前端查询接口并补齐订单详情 `v4_order_tasks[]` 时间线;M002 V4 CP6 已完成普通卡片确认和 S10/S99 来源通知 ack;M002 V4 CP7 已完成 `REVIEW_REQUIRED` 卡复核解阻和复核场景订单归属确认;M002 V4 CP8 已完成目录校验、V4 卡片 `fields[]` 字段白名单、确认写入白名单收口和嵌套业务字段目录校验;M002 V4 CP11 已完成数据库目录、初始化种子、启动补种子、Account / Room Type / Rate Code lookup API,并把 V4 入站、确认、复核目录校验切换到当前酒店数据库目录;M002 V4 CP12 已完成前端 lookup 接入第一版和 V4 订单任务时间线消费;M002 V4 CP13 目录管理后台 CP1 已完成前后端列表、新增、启用 / 停用闭环;M002 V4 CP14 已完成订单列表 V4 继续处理入口字段和前端入口消费,`GET /api/reservation/orders` 返回 V4 下一步订单任务、卡片、动作类型、动作状态、V4 open 数和统一展示计数 `open_work_item_count`,前端按 V4 优先跳转,并按 `open_work_item_count` 展示待处理数量;V4 业务审计查询已补齐订单任务审计和来源通知 ack 审计两个只读接口;订单详情已补齐并完成前端接入 V4 `order_overview`、`next_v4_action`、`related_source_messages[]` 和 `v4_order_tasks[].cards[]`;V4 普通业务入站已停止双写旧 `workflow_reservation_task`;Room Information 后端展示模型和前端业务化展示第一版已完成;Rooming List 确认触发 Group Booking Status 自动置 `DEF` 已完成,前端轻量事项确认卡也已完成;Payment 附件安全摘要后端和前端预览接入均已完成。OWNER RATE Room Type / Rate Code 目录口径已落文档;真实 PMS 同步和 SuperAgent 目录机器接口仍未完成。
|
||||
- M002 V4 CP2 已确认:V4 工作台统一列表草案为 `/api/reservation/workbench-items`,业务订单任务接口新开 `/api/reservation/order-tasks/**`,S10/S99 来源通知详情草案为 `/api/reservation/source-notifications/{notificationId}`;S10/S99 使用来源通知模型,不再挂隐藏技术订单;`FIT + BOOKING_CODE` 不建 ACTIVE 唯一约束,匹配多条进人工复核;Basic Information 必须先确认;Rooming List 卡第一版只做事项确认;Account 通过数据库目录选择,Market / Source 可默认来自目录并允许前端人工覆盖提交;旧 V2/V3 任务详情和草稿确认接口后续可逐步废弃。
|
||||
|
||||
@@ -416,6 +416,7 @@ export default {
|
||||
adults: 'Adults',
|
||||
children: 'Children',
|
||||
paymentType: 'Payment Type',
|
||||
paymentTypeBtqr: 'BTQR',
|
||||
paymentTypeCa: 'CA',
|
||||
vip: 'VIP',
|
||||
nationality: 'Nationality',
|
||||
@@ -442,7 +443,7 @@ export default {
|
||||
departureAfterArrival: 'Departure must be later than arrival.',
|
||||
roomTypeRequired: 'Enter room type.',
|
||||
paymentTypeRequired: 'Select payment type.',
|
||||
paymentTypeAllowed: 'Only CA is currently allowed.',
|
||||
paymentTypeAllowed: 'Only BTQR or CA are currently allowed.',
|
||||
nationalityRequired: 'Select nationality.',
|
||||
nationalityAllowed: 'Only KR or CHN are currently allowed.',
|
||||
invalidEmail: 'Invalid email.',
|
||||
|
||||
@@ -416,6 +416,7 @@ export default {
|
||||
adults: 'Adults',
|
||||
children: 'Children',
|
||||
paymentType: 'Payment Type',
|
||||
paymentTypeBtqr: 'BTQR',
|
||||
paymentTypeCa: 'CA',
|
||||
vip: 'VIP',
|
||||
nationality: 'Nationality',
|
||||
@@ -442,7 +443,7 @@ export default {
|
||||
departureAfterArrival: 'Departure ต้องอยู่หลัง Arrival',
|
||||
roomTypeRequired: 'กรุณากรอก Room Type',
|
||||
paymentTypeRequired: 'กรุณาเลือก Payment Type',
|
||||
paymentTypeAllowed: 'รองรับเฉพาะ CA ในตอนนี้',
|
||||
paymentTypeAllowed: 'รองรับเฉพาะ BTQR หรือ CA ในตอนนี้',
|
||||
nationalityRequired: 'กรุณาเลือก Nationality',
|
||||
nationalityAllowed: 'รองรับเฉพาะ KR หรือ CHN ในตอนนี้',
|
||||
invalidEmail: 'รูปแบบ Email ไม่ถูกต้อง',
|
||||
|
||||
@@ -415,6 +415,7 @@ export default {
|
||||
adults: '成人数(Adults)',
|
||||
children: '儿童数(Children)',
|
||||
paymentType: '付款方式(Payment Type)',
|
||||
paymentTypeBtqr: 'BTQR',
|
||||
paymentTypeCa: 'CA',
|
||||
vip: 'VIP',
|
||||
nationality: '国籍(Nationality)',
|
||||
@@ -441,7 +442,7 @@ export default {
|
||||
departureAfterArrival: '离店日期必须晚于入住日期。',
|
||||
roomTypeRequired: '请填写房型。',
|
||||
paymentTypeRequired: '请选择付款方式。',
|
||||
paymentTypeAllowed: '付款方式当前只允许 CA。',
|
||||
paymentTypeAllowed: '付款方式当前只允许 BTQR 或 CA。',
|
||||
nationalityRequired: '请选择国籍。',
|
||||
nationalityAllowed: '国籍当前只允许 KR 或 CHN。',
|
||||
invalidEmail: 'Email 格式不正确。',
|
||||
|
||||
@@ -168,7 +168,7 @@ describe('ReservationRoomingListGenerationView', () => {
|
||||
hotelId: 'HOTEL-TEST',
|
||||
peoplePerRoom: 2,
|
||||
roomType: 'DLX',
|
||||
paymentType: 'CA',
|
||||
paymentType: 'BTQR',
|
||||
nationality: 'CHN',
|
||||
})
|
||||
expect(URL.createObjectURL).toHaveBeenCalledWith(expect.any(Blob))
|
||||
@@ -176,6 +176,27 @@ describe('ReservationRoomingListGenerationView', () => {
|
||||
expect(wrapper.text()).toContain('rooming-list-HOTEL-TEST.xlsx')
|
||||
})
|
||||
|
||||
it('allows submitting CA payment type when selected', async () => {
|
||||
vi.mocked(generateReservationRoomingListExcel).mockResolvedValue({
|
||||
blob: new Blob(['xlsx-binary'], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
}),
|
||||
fileName: 'rooming-list-HOTEL-TEST.xlsx',
|
||||
})
|
||||
const wrapper = mountView()
|
||||
await fillRequiredFields(wrapper)
|
||||
await wrapper.find('[data-testid="rooming-list-payment-type"]').setValue('CA')
|
||||
|
||||
await wrapper.find('[data-testid="rooming-list-submit"]').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(generateReservationRoomingListExcel).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
paymentType: 'CA',
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('does not submit the same source file again while generation is pending', async () => {
|
||||
let resolveGeneration!: (value: { blob: Blob; fileName: string }) => void
|
||||
vi.mocked(generateReservationRoomingListExcel).mockImplementation(
|
||||
|
||||
@@ -141,6 +141,9 @@
|
||||
:class="validationClass('paymentType')"
|
||||
v-bind="validationAria('paymentType')"
|
||||
>
|
||||
<option value="BTQR">
|
||||
{{ t('roomingList.paymentTypeBtqr') }}
|
||||
</option>
|
||||
<option value="CA">
|
||||
{{ t('roomingList.paymentTypeCa') }}
|
||||
</option>
|
||||
@@ -265,7 +268,7 @@ type RoomingListFieldKey =
|
||||
| 'paymentType'
|
||||
| 'nationality'
|
||||
|
||||
const allowedPaymentTypes = new Set(['CA'])
|
||||
const allowedPaymentTypes = new Set(['BTQR', 'CA'])
|
||||
const allowedNationalities = new Set(['KR', 'CHN'])
|
||||
|
||||
const { t, te } = useI18n()
|
||||
@@ -275,7 +278,7 @@ const form = reactive({
|
||||
file: null as File | null,
|
||||
peoplePerRoom: '',
|
||||
roomType: '',
|
||||
paymentType: 'CA',
|
||||
paymentType: 'BTQR',
|
||||
nationality: '',
|
||||
})
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@ RESERVATION_ROOMING_LIST_GENERATE
|
||||
- 每组第一位旅客写入 `Name` / `First Name`,同组剩余旅客写入 `Accompanying Guests`,多人用英文逗号分隔。
|
||||
- CP2 起前端不再展示或提交 `Arrival` / `Departure`,后端从来源 Excel 的 `旅游日期` 派生。样例 `2026年5月9日-5月14日` 应生成 `Arrival=2026-05-09`、`Departure=2026-05-14`。
|
||||
- CP2 起前端不再展示或提交 `Adults`,后端按每个分房行的实际人数派生;尾房不足满房人数时按尾房实际人数写入。`Children` 第一版固定为 `0`。
|
||||
- CP2 起目标默认值区域只保留 `Payment Type` 和 `Nationality`:`Payment Type` 默认且当前唯一允许值为 `CA`;`Nationality` 只允许 `KR`、`CHN`。
|
||||
- CP2 起目标默认值区域只保留 `Payment Type` 和 `Nationality`:`Payment Type` 默认 `BTQR`,当前允许 `BTQR`、`CA`;`Nationality` 只允许 `KR`、`CHN`。
|
||||
- CP2 页面不再展示或提交 `Title`、`Rate Code`、`VIP`、`Email`、`ID Type`、`ID Number`,这些目标列第一版固定为空。
|
||||
- 第一版接口成功后直接返回 Excel 文件流,前端应按 Blob 下载处理,不要期待 JSON 里的 URL。
|
||||
- 失败时返回统一 JSON 错误,例如 `ROOMING_LIST_VALIDATION_FAILED`、`ROOMING_LIST_SOURCE_FILE_INVALID`、`HOTEL_ACCESS_DENIED` 或 `FRONTEND_PERMISSION_DENIED`。
|
||||
|
||||
@@ -1201,7 +1201,7 @@ CP2 前端提交字段:
|
||||
| `hotel_id` | 否 | 当前选择酒店;不传时由后端按登录用户酒店上下文解析。 |
|
||||
| `people_per_room` | 是 | 每间房人数,正整数。 |
|
||||
| `room_type` | 是 | 目标 Excel 的 Room Type。 |
|
||||
| `payment_type` | 否 | 目标 Excel 的 Payment Type;默认和当前唯一允许值为 `CA`。 |
|
||||
| `payment_type` | 否 | 目标 Excel 的 Payment Type;默认 `BTQR`,当前允许 `BTQR`、`CA`。 |
|
||||
| `nationality` | 是 | 目标 Excel 的 Nationality;只允许 `KR`、`CHN`。 |
|
||||
|
||||
CP2 前端不再提交:
|
||||
@@ -1231,7 +1231,7 @@ id_number
|
||||
|
||||
- 页面第一部分保留上传来源 Excel、每房人数、Room Type。
|
||||
- 目标默认值区域只保留 Payment Type 和 Nationality 两个下拉。
|
||||
- Payment Type 默认选中 `CA`,当前不开放其他选项。
|
||||
- Payment Type 默认选中 `BTQR`,当前提供 `BTQR`、`CA` 两个选项。
|
||||
- Nationality 只提供 `KR` 和 `CHN`。
|
||||
- 前端不读取完整 Excel 作为权威解析结果;旅游日期和成人数以后端生成结果为准。
|
||||
- 页面不要把上传文件内容、客人名单、生成文件内容写入浏览器日志、埋点、错误上报、URL 或 localStorage。
|
||||
|
||||
@@ -33,7 +33,7 @@ CP2 目标调整:
|
||||
- 后端从来源 Excel 的 `旅游日期` 列解析入住日期和离店日期,不再要求前端手填 `arrival` / `departure`。
|
||||
- 后端按分房结果计算目标 `Adults`,不再要求前端手填 `adults`。
|
||||
- 目标默认值区域只保留 `Payment Type` 和 `Nationality` 两个字段。
|
||||
- `Payment Type` 前端默认为 `CA`,后端也按 `CA` 作为当前唯一允许值校验。
|
||||
- `Payment Type` 前端默认为 `BTQR`,当前可选择 `BTQR` 或 `CA`,后端按同一枚举校验。
|
||||
- `Nationality` 前端只允许选择 `KR` 或 `CHN`,后端按同一枚举校验。
|
||||
|
||||
第一阶段不做:
|
||||
@@ -169,7 +169,7 @@ people_per_room = 3
|
||||
| `Number of Rooms` | 第一版每行固定为 `1`,后续如目标模板变化再调整 |
|
||||
| `Adults` | CP2 由后端按当前房间实际人数派生 |
|
||||
| `Children` | CP2 固定为 `0` |
|
||||
| `Payment Type` | 前端选择;当前默认和唯一允许值为 `CA` |
|
||||
| `Payment Type` | 前端选择;当前默认值为 `BTQR`,允许 `BTQR`、`CA` |
|
||||
| `VIP` | CP2 固定为空,后续如有稳定默认值再单独确认 |
|
||||
| `Accompanying Guests` | 同房其他旅客姓名,英文逗号分隔 |
|
||||
| `Nationality` | 前端选择;当前只允许 `KR`、`CHN` |
|
||||
@@ -202,7 +202,7 @@ Content-Type: multipart/form-data
|
||||
| `hotel_id` | string | 否 | 酒店 ID;不传时按当前登录用户默认酒店或单酒店上下文解析 |
|
||||
| `people_per_room` | integer | 是 | 每间房人数,必须大于 0 |
|
||||
| `room_type` | string | 是 | 目标 Excel 的 `Room Type` |
|
||||
| `payment_type` | string | 否 | CP2 目标 Excel 的 `Payment Type`;为空时后端按 `CA` 处理;当前只允许 `CA` |
|
||||
| `payment_type` | string | 否 | CP2 目标 Excel 的 `Payment Type`;为空时后端按 `BTQR` 处理;当前只允许 `BTQR`、`CA` |
|
||||
| `nationality` | string | 是 | CP2 目标 Excel 的 `Nationality`;当前只允许 `KR`、`CHN` |
|
||||
|
||||
CP2 不再接收以下前端业务字段作为生成依据:
|
||||
@@ -244,7 +244,7 @@ Content-Disposition: attachment; filename="rooming-list-<timestamp>.xlsx"
|
||||
|
||||
- multipart 必填字段缺失,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- `people_per_room` 数字格式错误,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- `payment_type` 非 `CA`,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- `payment_type` 非 `BTQR` / `CA`,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- `nationality` 非 `KR` / `CHN`,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- 来源文件缺失、非 `.xls` / `.xlsx`、无法读取、缺少 `护照全名` 表头或缺少 / 无法解析 `旅游日期` 表头,返回 `ROOMING_LIST_SOURCE_FILE_INVALID`。
|
||||
- 同一来源文件出现多个不同旅游日期区间,CP2 返回受控错误,不生成 Excel。
|
||||
@@ -309,7 +309,7 @@ RESERVATION_ROOMING_LIST_GENERATE
|
||||
- 填写每间房人数。
|
||||
- 填写目标 `Room Type`。
|
||||
- 目标默认值区域只保留 `Payment Type` 和 `Nationality`。
|
||||
- `Payment Type` 使用下拉或固定选择,默认 `CA`,当前不开放其他值。
|
||||
- `Payment Type` 使用下拉选择,默认 `BTQR`,当前可选择 `BTQR` 或 `CA`。
|
||||
- `Nationality` 使用下拉,只允许 `KR`、`CHN`。
|
||||
- 展示解析预览:总人数、预计房间数、前几行分房结果。
|
||||
- 点击生成后下载 `.xlsx`。
|
||||
@@ -336,7 +336,7 @@ RESERVATION_ROOMING_LIST_GENERATE
|
||||
- 尾房人数不足时仍生成一行。
|
||||
- `Adults` 按每个房间实际人数派生,尾房人数不足时不使用满房人数。
|
||||
- `Children` 默认为 `0`。
|
||||
- `payment_type` 为空时按 `CA` 处理,非 `CA` 返回受控错误。
|
||||
- `payment_type` 为空时按 `BTQR` 处理,非 `BTQR` / `CA` 返回受控错误。
|
||||
- `nationality=KR` / `CHN` 成功,其他值返回受控错误。
|
||||
- 来源文件中多个不同旅游日期区间返回受控错误。
|
||||
- 缺少 `旅游日期` 表头或旅游日期格式无法解析时返回受控错误。
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | `FRONTEND_USER` | 当前为 OPERA 模拟 | 登录 + `RESERVATION_OPERA_SIM_EXECUTE` + 酒店访问权 | 必须写业务审计和 attempt |
|
||||
| `GET /api/reservation/tasks/{taskId}/audits` | `FRONTEND_USER` | 已强制 Bearer 登录 + `RESERVATION_AUDIT_READ`;按任务实际所属酒店校验访问权 | 保持登录 + `RESERVATION_AUDIT_READ` + 酒店访问权 | 查询审计不再写审计 |
|
||||
| `POST /api/reservation/invoices/manual-generations` | `FRONTEND_USER` | 已实现 M009 CP2;强制 Bearer 登录 + `RESERVATION_INVOICE_GENERATE` + 酒店访问权;`task_id` / `order_id` 可为空,传入时反查对象所属酒店 | 保持登录 + `RESERVATION_INVOICE_GENERATE` + 酒店访问权;后续如增加历史列表或预填接口需单独登记权限 | 写业务审计,记录来源类型、模板版本、生成结果摘要;生成失败写入生成记录安全错误摘要 |
|
||||
| `POST /api/reservation/rooming-lists/generations` | `FRONTEND_USER` | 已实现 M010 CP1 / CP2;multipart 上传来源名单并直接下载 `.xlsx`;已在 multipart 参数绑定前前置校验登录和生成权限 | 登录 + `RESERVATION_ROOMING_LIST_GENERATE` + 酒店访问权;后端从来源 Excel `旅游日期` 派生 Arrival / Departure,Adults 按分房结果计算,目标默认值区域只保留 Payment Type / Nationality;第一版仍不落库、不上传 OSS | CP1 / CP2 不落生成记录表;错误响应不得记录完整名单、证件信息、源文件内容或生成文件内容;后续若增加历史记录再补业务审计 |
|
||||
| `POST /api/reservation/rooming-lists/generations` | `FRONTEND_USER` | 已实现 M010 CP1 / CP2;multipart 上传来源名单并直接下载 `.xlsx`;已在 multipart 参数绑定前前置校验登录和生成权限 | 登录 + `RESERVATION_ROOMING_LIST_GENERATE` + 酒店访问权;后端从来源 Excel `旅游日期` 派生 Arrival / Departure,Adults 按分房结果计算,目标默认值区域只保留 Payment Type / Nationality;Payment Type 默认 `BTQR` 且仅允许 `BTQR` / `CA`;第一版仍不落库、不上传 OSS | CP1 / CP2 不落生成记录表;错误响应不得记录完整名单、证件信息、源文件内容或生成文件内容;后续若增加历史记录再补业务审计 |
|
||||
|
||||
### 3.2.1 V4 工作台、订单详情和任务详情页展示层技术信息边界
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ package cn.nianxx.thhotel.workflows.reservation.common.request;
|
||||
* @param hotelId 酒店 ID;为空时按当前登录用户默认酒店解析
|
||||
* @param peoplePerRoom 每间房人数
|
||||
* @param roomType 目标 Excel 的 Room Type
|
||||
* @param paymentType 目标 Excel 的 Payment Type;当前默认和唯一允许值为 CA
|
||||
* @param paymentType 目标 Excel 的 Payment Type;默认 BTQR,当前允许 BTQR 或 CA
|
||||
* @param nationality 目标 Excel 的 Nationality;当前只允许 KR 或 CHN
|
||||
*/
|
||||
public record ReservationRoomingListGenerationRequest(
|
||||
|
||||
@@ -27,7 +27,9 @@ public class ReservationRoomingListGenerationServiceImpl implements ReservationR
|
||||
private static final long MAX_SOURCE_FILE_BYTES = 20L * 1024L * 1024L;
|
||||
private static final DateTimeFormatter FILE_TIMESTAMP_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
||||
private static final String DEFAULT_PAYMENT_TYPE = "CA";
|
||||
private static final String PAYMENT_TYPE_BTQR = "BTQR";
|
||||
private static final String PAYMENT_TYPE_CA = "CA";
|
||||
private static final String DEFAULT_PAYMENT_TYPE = PAYMENT_TYPE_BTQR;
|
||||
private static final String NATIONALITY_KR = "KR";
|
||||
private static final String NATIONALITY_CHN = "CHN";
|
||||
|
||||
@@ -132,8 +134,8 @@ public class ReservationRoomingListGenerationServiceImpl implements ReservationR
|
||||
return DEFAULT_PAYMENT_TYPE;
|
||||
}
|
||||
String code = normalized.toUpperCase(java.util.Locale.ROOT);
|
||||
if (!DEFAULT_PAYMENT_TYPE.equals(code)) {
|
||||
errors.add("payment_type: 当前只允许 CA。");
|
||||
if (!PAYMENT_TYPE_BTQR.equals(code) && !PAYMENT_TYPE_CA.equals(code)) {
|
||||
errors.add("payment_type: 当前只允许 BTQR 或 CA。");
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class ReservationRoomingListGenerationControllerTest {
|
||||
.param("hotel_id", "HOTEL-TEST")
|
||||
.param("people_per_room", "2")
|
||||
.param("room_type", "UG1")
|
||||
.param("payment_type", "CA")
|
||||
.param("payment_type", "BTQR")
|
||||
.param("nationality", "CHN"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(
|
||||
@@ -109,7 +109,7 @@ class ReservationRoomingListGenerationControllerTest {
|
||||
.andExpect(result -> assertThat(workbookCell(result.getResponse().getContentAsByteArray(), 1, 10))
|
||||
.isEqualTo("0"))
|
||||
.andExpect(result -> assertThat(workbookCell(result.getResponse().getContentAsByteArray(), 1, 11))
|
||||
.isEqualTo("CA"))
|
||||
.isEqualTo("BTQR"))
|
||||
.andExpect(result -> assertThat(workbookCell(result.getResponse().getContentAsByteArray(), 1, 14))
|
||||
.isEqualTo("CHN"))
|
||||
.andExpect(content().string(not(containsString("P123456"))));
|
||||
|
||||
@@ -67,7 +67,7 @@ class ReservationRoomingListGenerationServiceImplTest {
|
||||
assertThat(cellText(firstRoom.getCell(8))).isEqualTo("1");
|
||||
assertThat(cellText(firstRoom.getCell(9))).isEqualTo("3");
|
||||
assertThat(cellText(firstRoom.getCell(10))).isEqualTo("0");
|
||||
assertThat(cellText(firstRoom.getCell(11))).isEqualTo("CA");
|
||||
assertThat(cellText(firstRoom.getCell(11))).isEqualTo("BTQR");
|
||||
assertThat(cellText(firstRoom.getCell(13))).isEqualTo("ZHANG GAILI, LI HONG");
|
||||
assertThat(cellText(firstRoom.getCell(14))).isEqualTo("CHN");
|
||||
assertThat(cellText(firstRoom.getCell(15))).isEmpty();
|
||||
@@ -88,6 +88,26 @@ class ReservationRoomingListGenerationServiceImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAcceptCaPaymentTypeForRoomingListWorkbook() throws Exception {
|
||||
when(hotelContextService.requireAccessibleHotel("HOTEL-TEST")).thenReturn("HOTEL-TEST");
|
||||
|
||||
ReservationRoomingListGeneratedFile generatedFile = service.generate(
|
||||
sourceFileWithTravelDate("2026-05-09 - 05-14", List.of("LI/CHUNHONG")),
|
||||
new ReservationRoomingListGenerationRequest(
|
||||
"HOTEL-TEST",
|
||||
1,
|
||||
"UG1",
|
||||
"ca",
|
||||
"CHN"),
|
||||
actor());
|
||||
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(generatedFile.content()))) {
|
||||
Row firstRoom = workbook.getSheetAt(0).getRow(1);
|
||||
assertThat(cellText(firstRoom.getCell(11))).isEqualTo("CA");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseTravelDateWithNumericHyphenRange() throws Exception {
|
||||
when(hotelContextService.requireAccessibleHotel("HOTEL-TEST")).thenReturn("HOTEL-TEST");
|
||||
@@ -156,7 +176,7 @@ class ReservationRoomingListGenerationServiceImplTest {
|
||||
|
||||
assertThat(exception.getErrorCode()).isEqualTo("ROOMING_LIST_VALIDATION_FAILED");
|
||||
assertThat(exception.getDetails())
|
||||
.contains("payment_type: 当前只允许 CA。", "nationality: 当前只允许 KR 或 CHN。");
|
||||
.contains("payment_type: 当前只允许 BTQR 或 CA。", "nationality: 当前只允许 KR 或 CHN。");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user