# 核单子表扩列 - **变更日期**: 2026-07-07 - **端类型**: 管理后台 - **变更类型**: 修改接口 - **Issue**: https://git.1814.love:8443/wx/HL/issues/4764 - **PR**: https://git.1814.love:8443/wx/HL/pulls/4767 --- ## 1. 接口背景 核单 epic PR2。核单三个子表(车席、馨票、人员费用)分别扩充字段,具体: - 车席 Step 1: `HotelItemVO` 新增 `voucherUrls`(住宿凭证图片) - 馨票 Step 2: `TicketItemVO` 新增 `paymentMethod` / `voucherUrls`;`scenicAssignmentId` 由可空改必填(❗ 破坏兆容) - 人员费用 Step 3: `StaffFeeItemVO` 新增 `reimburse`;`SettlementStaffFeesSaveRespVO` 新增 `isPrimaryReporter` / `reimburse` --- ## 2. 变更清单 | 序号 | 方法 | 路径 | 说明 | |------|------|------|------| | 1 | GET | `/v3/admin/order/{orderId}/settlement/step1` | Step 1 查询,`HotelItemVO` +`voucherUrls` | | 2 | PUT | `/v3/admin/order/{orderId}/settlement/step1` | Step 1 保存,入参`HotelItemVO` +`voucherUrls` | | 3 | GET | `/v3/admin/order/{orderId}/settlement/step2` | Step 2 查询,`TicketItemVO` +`paymentMethod`/`voucherUrls`; `scenicAssignmentId` 由可空改必填 | | 4 | PUT | `/v3/admin/order/{orderId}/settlement/step2` | Step 2 保存,同上 | | 5 | GET | `/v3/admin/order/{orderId}/settlement/step3` | Step 3 查询,响应 +`isPrimaryReporter`/`reimburse` | | 6 | PUT | `/v3/admin/order/{orderId}/settlement/step3` | Step 3 保存,入参 +`reimburse` | --- ## 3. 接口详情 | 项 | 说明 | |-----|------| | 认证 | JWT Bearer(管理端) | | 幂等性 | PUT 非幂等(每次全量覆写子表) | | 核单状态 | 仅允许在 settlement_status=IN_PROGRESS 时调用 | --- ## 4. 接口入参 ### 4.1 路径参数(六个接口通用) | orderId | Long | 是 | 订单 ID | ### 4.2 Step 1 PUT 请求体(`List`) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | id | Long | 否 | 空表新建行 | | hotelAssignmentId | Long | 否 | 酒店配置 ID | | stayDate | LocalDate | 是 | 入住日期 | | roomType | String | 否 | 房间类型 | | roomCount | Integer | 是 | 房间数量 | | plannedCost | BigDecimal | 否 | 计划成本 | | actualCost | BigDecimal | 否 | 实际成本 | | paymentMethod | String | 否 | SIGNED/COMPANY_PAID/CASH_PAID | | settleType | String | 否 | 派生行类型:cash/sign/company | | remark | String | 否 | 备注 | | **voucherUrls** | List | 否 | **✨ 新增): 住宿凭证图片 URL | ### 4.3 Step 2 PUT 请求体(`List`) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | sourceType | String | 是 | SCENIC_ASSIGNMENT/ACTIVITY_ASSIGNMENT | | **scenicAssignmentId** | Long | **是** | **❗ 破坏兆容:旧可空,新必填** | | dayDate | LocalDate | 是 | 游玩日期 | | ticketCount | Integer | 是 | 馨票人数 | | ticketUnitPrice | BigDecimal | 否 | 单价 | | actualCost | BigDecimal | 否 | 实际成本 | | **paymentMethod** | String | 否 | **✨ 新增**: SIGNED/COMPANY_PAID/CASH_PAID | | **voucherUrls** | List | 否 | **✨ 新增**: 馨票凭证图片 URL | | remark | String | 否 | 备注 | ### 4.4 Step 3 PUT 请求体(`List`) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | id | Long | 否 | 实体主键 | | staffRole | String | 是 | LEADER/DRIVER/GUIDE/PHOTOGRAPHER/OTHER | | staffId | Long | 否 | 人员 ID | | detail | Object | 否 | 按角色不同, 见 §6 | | **reimburse** | BigDecimal | 否 | **✨ 新增**: 小算补助金额,⊰ 0 | | remark | String | 否 | 备注 | --- ## 5. 出参字段 ### Step 1 GET 响应(`List`) > 新增 **`voucherUrls`** (List) ### Step 2 GET 响应(`List`) > 新增 **`paymentMethod`** (String) / **`voucherUrls`** (List) ### Step 3 GET 响应(`SettlementStaffFeesSaveRespVO`) `StaffFeeRespItemVO` 内嵌子字段: | 字段 | 类型 | 说明 | |------|------|------| | **isPrimaryReporter** | Boolean | **✨ 新增**: 是否主报账人,由 AssignmentService 实时派生 | | **reimburse** | BigDecimal | **✨ 新增**: 小算补助金额,入参回显 | --- ## 6. 枚举/数据字典 **paymentMethod / settleType** | 値 | 含义 | |------|------| | SIGNED | 签单结算(酒店收取相应金额) | | COMPANY_PAID | 公司已付(公库打款) | | CASH_PAID | 现付(司机墙付) | **staffRole** | 値 | 含义 | |------|------| | LEADER | 地接 | | DRIVER | 司机 | | GUIDE | 导游 | | PHOTOGRAPHER | 摄影师 | | OTHER | 其他 | **detail 结构(按角色)** - DRIVER: `{is_used, daily_fee, extra_cost, days[{date,is_used}]}` - GUIDE/PHOTOGRAPHER: `{persons[{staffId,days[{date,is_used}]}], per_day}` - LEADER: `{days, per_day}` - OTHER: `[{name, amount}]` --- ## 7. 错误码 | 错误码 | 含义 | 触发场景 | |--------|------|---------| | 584028 | ❗ 破坏兆容 -- 馨票行必须关联资源配置 | Step 2 PUT 中 scenicAssignmentId 为空(曾可空,现必填) | | 584001-584009 | Step 1 酒店校验错 | - | | 584010-584018 | Step 2 馨票校验错 | - | | 584020-584027 | Step 3 人员费用校验错 | - | --- ## 8. 示例 ### 8.1 典型成功 -- Step 2 PUT (`scenicAssignmentId`必填) ```http PUT /v3/admin/order/1234567890123456/settlement/step2 Content-Type: application/json [{ "sourceType": "SCENIC_ASSIGNMENT", "scenicAssignmentId": 98001, "dayDate": "2026-07-10", "ticketCount": 4, "actualCost": 1200.00, "paymentMethod": "CASH_PAID", "voucherUrls": ["https://oss.example.com/ticket.jpg"] }] ``` 响应: 200 OK ### 8.2 边界 -- Step 3 GET (`isPrimaryReporter` = true) ```json { "code": 200, "data": { "items": [{ "staffRole": "DRIVER", "isPrimaryReporter": true, "reimburse": 500.00 }] } } ``` ### 8.3 业务失败 -- scenicAssignmentId 为空触发 584028 ```json [{ "sourceType": "SCENIC_ASSIGNMENT", "scenicAssignmentId": null, "dayDate": "2026-07-10" }] ``` ```json { "code": 584028, "msg": "馨票行必须关联资源配置(现必填,曾可空)" } ``` --- ## 9. 业务边界 适用: 核单流程中内 (settlement_status=IN_PROGRESS) 不适用: 已提交或已结算 特殊边界: - Step 1 `voucherUrls`: 不传默空列表,传空删除已传的凭证 - Step 2 scenicAssignmentId: 必填,不再允许自由录入 (破坏兆容!) - Step 3 isPrimaryReporter: 实时派生,前端只读 --- ## 10. 修改前后对比 ### Step 2 `TicketItemVO` 字段变化 | 字段 | 修改前 | 修改后 | |------|------|------| | scenicAssignmentId | 可空 | 必填 (❗破坏兆容) | | paymentMethod | 无 | 新增 String | | voucherUrls | 无 | 新增 List | ### Step 3 `StaffFeeRespItemVO` 字段变化 | 字段 | 修改前 | 修改后 | |------|------|------| | isPrimaryReporter | 无 | 新增 Boolean | | reimburse | 无 | 新增 BigDecimal | --- ## 11. 影响评估/回滚 破坏兆容: scenicAssignmentId 旧可空, 新必填。前端补充 scenicAssignmentId字段后提交。 回滚: 无需回滚,此为小版本内造数据制约。 --- ## 12. 注意事项 - scenicAssignmentId 必填是 **破坏兆容变更** - isPrimaryReporter 实时计算,前端只读 --- ## 13. 关联/联系人 - Issue: https://git.1814.love:8443/wx/HL/issues/4764 - PR: https://git.1814.love:8443/wx/HL/pulls/4767 - Commit: https://git.1814.love:8443/wx/HL/commit/3fdb51f5aac7ee6bee58f8e9ab125d82859eaffd - 后端负责人: 腰苏图