diff --git a/changelogs-v2/2026-06/04_3451_核单住宿行入参settleType-修改接口-管理后台.md b/changelogs-v2/2026-06/04_3451_核单住宿行入参settleType-修改接口-管理后台.md new file mode 100644 index 0000000..433ec84 --- /dev/null +++ b/changelogs-v2/2026-06/04_3451_核单住宿行入参settleType-修改接口-管理后台.md @@ -0,0 +1,346 @@ +# 二期 v3:核单 Step 1 住宿录入 —— 新增入参 settleType,派生行不再自动派生 paymentMethod + +> **服务**: hl-order-service-v3 | **端**: 管理后台 +> **接口**: `PUT /v3/admin/order/{orderId}/settlement/step1` +> **Issue**: [#3451](https://git.1814.love:8443/wx/HL/issues/3451) | **PR**: [#3452](https://git.1814.love:8443/wx/HL/pulls/3452) +> **日期**: 2026-06-04 +> **影响**: ⚠️ **破坏性** —— 派生行(hotelAssignmentId 非空)原先可不传 paymentMethod,后端自动派生;改后必须传 settleType 或 paymentMethod,否则报错。 + +--- + +## 一、接口背景 + +核单 Step 1「录住宿明细」接口用于保存一批住宿核单行(全量替换语义)。 +行分两类: +- **派生行**:`hotelAssignmentId` 非空,从房务配房记录派生基础字段 +- **临时行**:`hotelAssignmentId` 为 null,完全手填 + +原逻辑:派生行的 `paymentMethod`(付款方式)由后端查 house 配房记录的 `settleType` 自动填充,前端可不传。 +本次变更:**删除后端自动派生逻辑**,前端必须在每行明确传入 `settleType`(或直接传 `paymentMethod`),后端不再主动查库派生。 + +--- + +## 二、变更清单 + +| 变更类型 | 字段 / 行为 | 说明 | +|---|---|---| +| ✨ 新增入参字段 | `items[].settleType` | 结算类型简码(cash / sign / company),与 paymentMethod 二选一,新增优先入口 | +| 🔧 行为变更 | 派生行 paymentMethod 不再自动派生 | 后端不再查配房记录自动填充;前端必须显式传 settleType 或 paymentMethod | +| ⚠️ 删除错误码 | 584004 | 原「配房记录不存在」码删除,不再有此分支 | +| ⚠️ 删除错误码 | 584063 | 原「无法派生 paymentMethod」码删除 | +| ⚠️ 新增错误场景 | 584062 | 派生行/临时行既未传 settleType 又未传 paymentMethod 时触发 | +| ✨ 新增错误码校验 | 584064 | settleType 字典值非法(非 cash/sign/company)时触发 | + +--- + +## 三、接口详情 + +| 属性 | 值 | +|---|---| +| 方法 | `PUT` | +| 路径 | `/v3/admin/order/{orderId}/settlement/step1` | +| 接口名 | Step 1 录住宿核单明细 | +| 认证 | Bearer Token(管理后台 JWT) | +| 幂等性 | 全量替换语义,相同请求体重复提交安全(幂等) | +| 限流 | 无特殊限流 | +| Content-Type | `application/json` | + +--- + +## 四、接口入参 + +### 4.1 路径参数 + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `orderId` | Long | 是 | 订单 ID | + +### 4.2 请求体字段 + +**顶层** + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `items` | Array\ | 是 | 住宿明细行数组(全量替换) | + +**HotelItemVO 字段** + +| 字段 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---| +| `id` | Long | 否 | — | 已存在行 ID(更新);空表示新增 | +| `hotelAssignmentId` | Long | 否 | — | 派生行配房 assignment ID;临时行为 null | +| `stayDate` | String (date) | 是 | 格式 `yyyy-MM-dd` | 入住日期 | +| `hotelName` | String | 是 | 最长 200 字符 | 酒店名(派生行拷贝自配房,临时行手填) | +| `roomType` | String | 否 | 最长 64 字符 | 房型(多房型可填"混合"或留空) | +| `roomCount` | Integer | 是 | ≥ 1 | 总间数 | +| `plannedCost` | BigDecimal | 是 | ≥ 0,单位元 | 计划成本 | +| `actualCost` | BigDecimal | 是 | ≥ 0,单位元 | 实际成本 | +| `settleType` | String | 条件必填 | cash / sign / company | **新增字段**。结算类型简码,后端映射为 paymentMethod;当 paymentMethod 未传时必填 | +| `paymentMethod` | String | 条件必填 | CASH_PAID / SIGNED / COMPANY_PAID | 付款方式枚举值;若传则直接使用,优先级高于 settleType | +| `remark` | String | 否 | 最长 500 字符 | 备注 | + +**条件必填规则**(全类型行统一适用): + +| 情况 | 规则 | +|---|---| +| `paymentMethod` 非空 | 直接使用,settleType 忽略 | +| `paymentMethod` 为空,`settleType` 非空 | 后端按映射表转换为 paymentMethod | +| `paymentMethod` 和 `settleType` 都为空 | 报 584062 | + +--- + +## 五、出参字段 + +**顶层返回 `Result`** + +| 字段 | 类型 | 说明 | +|---|---|---| +| `addedIds` | Array\ | 本次新增行的 ID 列表 | +| `updatedIds` | Array\ | 本次更新行的 ID 列表 | +| `deletedIds` | Array\ | 本次软删行的 ID 列表(全量替换时缺失的行) | +| `totalActualCost` | BigDecimal | 保存后当前订单住宿核单 actual_cost 汇总值(元) | + +--- + +## 六、枚举 / 数据字典 + +### settleType(入参,本次新增字段) + +| 值 | 中文含义 | +|---|---| +| `cash` | 现付 | +| `sign` | 签单 | +| `company` | 公司支付 | + +### paymentMethod(入参,原有字段) + +| 值 | 中文含义 | 对应 settleType | +|---|---|---| +| `CASH_PAID` | 现付 | `cash` | +| `SIGNED` | 签单 | `sign` | +| `COMPANY_PAID` | 公司支付 | `company` | + +**settleType → paymentMethod 映射关系** + +| settleType | 映射为 paymentMethod | +|---|---| +| `cash` | `CASH_PAID` | +| `sign` | `SIGNED` | +| `company` | `COMPANY_PAID` | + +--- + +## 七、错误码 + +| 错误码 | 含义 | 触发场景 | +|---|---|---| +| 584062 | 必须指定 paymentMethod(无配房关联/未提供结算类型) | 任意行既未传 settleType 又未传 paymentMethod 时 | +| 584064 | settleType 字典值非法 | settleType 不在 cash/sign/company 范围内 | +| 400 | 参数校验失败 | paymentMethod 不在 SIGNED/COMPANY_PAID/CASH_PAID 范围内;roomCount/plannedCost/actualCost 为 null 等 Bean Validation 报错 | + +**删除的错误码**(本次移除,前端不必再处理): + +| 已删错误码 | 原含义 | +|---|---| +| 584004 | 配房记录不存在 | +| 584063 | 无法派生 paymentMethod | + +--- + +## 八、示例 + +### 8.1 典型成功 —— 派生行 + 临时行混合 + +**请求** + +``` +PUT /v3/admin/order/1900000000001/settlement/step1 +Authorization: Bearer +Content-Type: application/json +``` + +```json +{ + "items": [ + { + "id": 9100000000010, + "hotelAssignmentId": 8800000000001, + "stayDate": "2026-07-10", + "hotelName": "布达拉宫酒店", + "roomType": "标准间", + "roomCount": 2, + "plannedCost": 800.00, + "actualCost": 880.00, + "settleType": "sign", + "remark": "" + }, + { + "hotelAssignmentId": null, + "stayDate": "2026-07-11", + "hotelName": "临时酒店(自定义)", + "roomType": null, + "roomCount": 1, + "plannedCost": 300.00, + "actualCost": 300.00, + "paymentMethod": "CASH_PAID", + "remark": "临时加行" + } + ] +} +``` + +**响应** + +```json +{ + "code": 200, + "msg": "success", + "data": { + "addedIds": [9100000000088], + "updatedIds": [9100000000010], + "deletedIds": [], + "totalActualCost": 1180.00 + } +} +``` + +--- + +### 8.2 边界情况 —— paymentMethod 和 settleType 同时传(paymentMethod 优先) + +**请求(paymentMethod 优先,settleType 被忽略)** + +```json +{ + "items": [ + { + "hotelAssignmentId": 8800000000002, + "stayDate": "2026-07-10", + "hotelName": "测试酒店", + "roomCount": 1, + "plannedCost": 0.00, + "actualCost": 0.00, + "settleType": "cash", + "paymentMethod": "COMPANY_PAID" + } + ] +} +``` + +**响应**(paymentMethod 直接用 COMPANY_PAID,settleType 忽略) + +```json +{ + "code": 200, + "msg": "success", + "data": { + "addedIds": [9100000000099], + "updatedIds": [], + "deletedIds": [], + "totalActualCost": 0.00 + } +} +``` + +--- + +### 8.3 业务失败 —— 未传 settleType 也未传 paymentMethod + +**请求** + +```json +{ + "items": [ + { + "hotelAssignmentId": 8800000000003, + "stayDate": "2026-07-10", + "hotelName": "布达拉宫酒店", + "roomCount": 2, + "plannedCost": 600.00, + "actualCost": 600.00 + } + ] +} +``` + +**响应** + +```json +{ + "code": 584062, + "msg": "(无配房关联/未提供结算类型)必须指定 paymentMethod", + "data": null +} +``` + +--- + +## 九、业务边界 + +**适用场景** + +- 管理员在核单流程第 1 步保存住宿明细 +- 可多次调用(草稿模式,全量替换,最后一次调用数据生效) +- 支持派生行(关联配房记录)和临时行(完全手填)混合提交 + +**不适用场景** + +- 订单已完成核单提交(Step 6 执行后),此时行锁定,Step 1 接口不可再调用 +- 订单不在「待核单」状态下调用将被业务校验拦截 + +**特殊边界** + +- `items` 为空数组 `[]` 时,等同于清空全部住宿明细行(软删所有现存行) +- 全量替换:请求里没有的 `id` 对应现存行将被软删,`deletedIds` 返回被删的 ID 列表 +- 派生行的 `hotelName` / `stayDate` / `roomType` 由前端从配房列表取值后传入(后端不再从配房记录二次查库填充) + +--- + +## 十、修改前后对比 + +### 字段级 + +| 字段 | 改前 | 改后 | +|---|---|---| +| `items[].settleType` | **不存在** | ✨ 新增,String,枚举 cash/sign/company | +| `items[].paymentMethod`(派生行) | 可不传,后端自动从配房记录 settleType 派生 | 必须传(或通过 settleType 间接传),后端不再自动查库 | + +### 行为级 + +| 行为 | 改前 | 改后 | +|---|---|---| +| 派生行 paymentMethod 来源 | 后端查 house 配房记录 settleType 自动派生 | 前端从配房列表取 settleType 传入,后端映射 | +| 未传 paymentMethod 时 | 派生行:后端静默补充;临时行:报 584004 → 584063 | 无论派生行还是临时行:报 **584062** | + +--- + +## 十一、影响评估 / 回滚 + +**影响评估** + +- 前端**必须**在构造 Step 1 请求时,为每一行(含派生行)提供 `settleType`(推荐)或 `paymentMethod` +- `settleType` 的值来源:调用房务配房列表接口,取配房记录的 `settleType` 字段 +- 改动为破坏性变更,但当前处于开发阶段,无需向后兼容,直接硬切换 + +**是否破坏兼容**:是(派生行原有 `paymentMethod` 不传的调用会报 584062) + +**前端是否需同步上线**:是,前端必须补传 `settleType` 后才能正常调用 + +**回滚方案**:开发阶段,老订单可删,无需回滚保护;如需回滚,重新部署旧版 hl-order-service-v3 即可 + +--- + +## 十二、注意事项 + +1. `settleType` 是**字符串小写简码**(cash/sign/company),与现有 `paymentMethod` 枚举大写风格不同,注意区分 +2. 推荐前端统一使用 `settleType` 传入(更直观),让后端做映射;`paymentMethod` 字段保留兼容直传 +3. 房务配房列表接口返回的 `settleType` 字段即为此处入参的来源,两者枚举值一致 +4. 全量替换语义:每次调用请带上**全部**行(包括未改动行),否则缺失行会被软删 + +--- + +## 十三、关联 / 联系人 + +- **Issue**: [#3451 核单 saveHotel 入参新增 settleType 字段](https://git.1814.love:8443/wx/HL/issues/3451) +- **PR**: [#3452](https://git.1814.love:8443/wx/HL/pulls/3452) +- **后端负责人**: yst