docs(changelog): 团期核单重做8类tab明细+公摊/指定报名拆账前端契约(#8714 整批6PR + teamNo #8779)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
- 8 类费用 tab GET 换实现 + 新增 8 个 PUT 整 tab 暂存(全量替换 + expectedVersion CAS) - 新增面板族 7 端点:panel / sub-orders / lines 增删 / panel confirm / alloc-preview / invoice - 旧 /audit 6 端点下线 404,旧四表 DROP - sharedCostByType 键值 BatchCostType 4 值切 settlement_category 8 值 - 错误码新增 589750-589755 拆账段,589569/589570 废弃
这个提交包含在:
@@ -0,0 +1,657 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8714"
|
||||
title: "团期核单重做为8类tab明细结构+公摊/指定报名拆账(旧/audit端点下线)"
|
||||
consumer: "admin"
|
||||
author: "yst"
|
||||
change_type: "修改接口"
|
||||
backend_status: "merged"
|
||||
gateway_status: "not_required"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "整批 6 PR 累积的结构重做,8 tab 出参结构变化 + 15 个新接口 + 旧 /audit/* 端点下线 404 + teamNo 新增,前端需按本契约重对接;sharedCostByType 键值从 BatchCostType 4 值切到 settlement_category 8 值。已合 dev-v3 未部署测试服。"
|
||||
updated_at: "2026-10-04"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# order-v3 groupbatch:团期核单重做为 8 类 tab 明细结构 + 公摊/指定报名拆账(管理后台)
|
||||
|
||||
> ⚠️ **修改接口(整体重做,破坏性)**:团期核单从旧「四表模型(统一科目行 + 逐户用量 + 逐户分摊)」重做为对齐常规订单核单的「**8 类费用 tab 明细结构**」,新增**公摊 / 指定报名拆账**能力。旧 `/audit/*` 6 个端点**全部下线 404**(开发期无向后兼容),由 8 个分类 tab GET/PUT + 面板族 7 个新端点替代。费用类别从硬编码 AuditCategory 切换为数据字典 `settlement_category`(8 值)。前端原核单页需按本契约**整体重对接**。
|
||||
|
||||
## 1. 接口背景
|
||||
|
||||
团期核单(#7868 初版)采用「统一科目行 + 逐户用量 + 逐户分摊」四表模型,与单订单核单的 8 类费用 tab 结构不一致:运营要在两套交互之间切换,且旧模型只有「均分 / 指定比例」粗粒度分摊,无法表达「这笔车费全团公摊、那笔房费只摊给指定几户」的真实业务。
|
||||
|
||||
#8714 整批 6 个 PR 把团期核单推倒重做:
|
||||
|
||||
- **存储**:旧四表 `order_batch_audit` / `_item` / `_detail` / `_alloc` 已 **DROP**,新建 10 张表(1 主表 `order_group_settlement_main` + 8 张分类明细表 + 1 张拆账表 `order_group_settlement_alloc`)。
|
||||
- **结构**:对齐常规订单核单的 **8 类费用 tab 明细结构**——住宿 / 门票·游玩 / 餐食 / 车辆 / 导游 / 摄影师 / 其他收入 / 其他支出,每类一个 tab,每 tab 内是明细行数组。
|
||||
- **拆账**:每行支持两种分摊方式——**公摊 SHARED**(按全团人数均摊 / 按户均摊)与**指定报名 DESIGNATED**(勾选子订单子集 + 逐户比例 + 可手改金额),强校验 Σ拆账 = 明细行总额。
|
||||
- **状态机**:从旧多态简化为 **DRAFT(录入中)→ CONFIRMED(已确认)** 两态;确认后不可逆,不提供 un-confirm。
|
||||
- **费用类别**:废弃硬编码 AuditCategory,改走数据字典 `settlement_category`(8 值),类别中文名由字典下发。
|
||||
|
||||
本批已合并 dev-v3,**尚未部署测试服**(`backend_status: merged`),前端可先做接口层适配,联调待部署后进行。
|
||||
|
||||
## 2. 变更清单
|
||||
|
||||
| # | 接口 | 变更点 | 类型 |
|
||||
|---|------|--------|------|
|
||||
| 1 | `GET …/settlement/{hotels/activities/meals/vehicles/guide-fees/photographer-fees/other-incomes/other-expenses}` | 8 个分类 tab 读端点**路径不变、实现整体替换**:出参从旧科目行结构改为 GroupSettleTabRespVO(明细行 + 拆账 splits + 版本号) | ⚠️ 出参结构重做 |
|
||||
| 2 | `PUT …/settlement/{同上 8 个路径}` | **新增** 8 个整 tab 暂存写端点(全量替换语义 + expectedVersion CAS) | ✨ 新增接口 |
|
||||
| 3 | `GET …/settlement/panel` | **新增**核单面板:状态主行 + 8 类合计 + 在团户视图(已摊成本/收入/毛利) | ✨ 新增接口 |
|
||||
| 4 | `GET …/settlement/sub-orders` | **新增**在团子订单列表(指定报名勾选数据源) | ✨ 新增接口 |
|
||||
| 5 | `POST …/settlement/lines` | **新增**单条明细行新增 | ✨ 新增接口 |
|
||||
| 6 | `DELETE …/settlement/lines/{lineId}` | **新增**明细行删除(级联删拆账) | ✨ 新增接口 |
|
||||
| 7 | `POST …/settlement/panel/confirm` | **新增**确认核单(确认后不可逆;**注意路径是 panel/confirm 不是 /settlement/confirm**,后者被团期结算财务复核占用) | ✨ 新增接口 |
|
||||
| 8 | `POST …/settlement/alloc-preview` | **新增**拆账试算不落库(前端录入期预览,P2 可选) | ✨ 新增接口 |
|
||||
| 9 | `POST …/settlement/invoice` | **新增**按子订单开票(GB-ADM-054 自旧 `/audit/invoice` 迁移,门禁改为核单 CONFIRMED) | ✨ 新增接口 |
|
||||
| 10 | `GET/PUT …/audit`、`POST …/audit/allocate`、`POST …/audit/reallocate`、`GET …/audit/export`、`POST …/audit/invoice` | **全部下线,调旧路径 404**(开发期无向后兼容) | ⚠️ 删除接口 |
|
||||
| 11 | 出参 VO | `panel.households[]` / `sub-orders[]` / tab `lines[].splits[]` 新增 **teamNo** 团号字段(#8779) | ✨ 字段新增 |
|
||||
| 12 | `sharedCostByType`(GroupReturnDetailRespVO / GroupBatchSettlementSummaryRespVO) | `costType` 键值从 BatchCostType 4 值(BUS/LEADER/PHOTOGRAPHER/OTHER)**切到 settlement_category 8 值**;`costTypeDesc` 走数据字典 | ⚠️ 键值域变化 |
|
||||
| 13 | 错误码 | 新增 589750-589755 拆账段;旧 589569/589570 废弃(语义分别由 589753/589750 承接) | ⚠️ 错误码调整 |
|
||||
|
||||
路径前缀统一为 `/v3/admin/order/group-batch/{groupBatchId}/settlement`,下文用 `…` 代指。
|
||||
|
||||
## 3. 接口详情
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 服务 | hl-order-service-v3(端口 8086) |
|
||||
| 路径前缀 | `/v3/admin/order/group-batch/{groupBatchId}/settlement` |
|
||||
| 使用场景 | 管理后台 → 团期详情 → 核单 Tab:8 类费用明细录入、公摊/指定报名拆账、确认核单、按子订单开票 |
|
||||
| 认证 | 管理后台登录态(JWT);网关既有路由 `/v3/admin/**`,无新增网关配置 |
|
||||
| 权限码 | `group-batch:audit:view`(8 tab GET / panel / sub-orders / alloc-preview);`group-batch:audit:edit`(8 tab PUT / lines 新增删除);`group-batch:audit:allocate`(确认核单);`group-batch:audit:invoice`(开票)。**缺码一律 589507** |
|
||||
| 幂等性 | 写口不加 `@Idempotent`:并发与重复提交由 main 主行锁 + **expectedVersion CAS** 兜底(过期必吃 589573);开票防重由发票域自带 SETNX 承接 |
|
||||
| 限流 | 无特殊限流 |
|
||||
|
||||
## 4. 接口入参
|
||||
|
||||
### 4.1 路径 / Query 参数
|
||||
|
||||
| 参数 | 位置 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | 团期 ID,全部端点共有 |
|
||||
| lineId | Path | Long | ✅ | 明细行 ID,仅 `DELETE …/lines/{lineId}` |
|
||||
| category | Query | string | ✅ | 费用类别 8 值之一,仅 `DELETE …/lines/{lineId}`(决定从哪张分类表删) |
|
||||
| expectedVersion | Query | int | ✅ | 乐观锁版本(≥0),仅 `DELETE …/lines/{lineId}`;过期返 589573 |
|
||||
|
||||
### 4.2 `PUT …/settlement/{tab}` 整 tab 暂存请求体(GroupSettleTabSaveReqVO)
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| expectedVersion | int | ✅ | 乐观锁版本(GET tab/panel 返回的 `version` **原样回传**);与库值不符返 589573,本次请求零写入 |
|
||||
| lines | array | ✅ | 整 tab **全量**行数组(≤500 行)。**全量替换语义**:库里存在但未提交的行 = 删除;空数组 `[]` = 清空本 tab |
|
||||
|
||||
`lines[]` 元素(GroupSettleLineSaveReqVO)公共列:
|
||||
|
||||
| 字段 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| lineId | Long | 可空 | - | 已有行 ID;空 = 新增行 |
|
||||
| allocMode | string | ✅ | `SHARED` / `DESIGNATED` | 分摊方式:SHARED=公摊 / DESIGNATED=指定报名 |
|
||||
| allocRule | string | 条件必填 | `PER_HEAD_AVG` / `PER_ORDER_AVG` | 公摊口径;SHARED 缺省按类别默认(导游/摄影师/其他收入=按户均摊,其余=按人数均摊);**DESIGNATED 必须为 null** |
|
||||
| allocGroup | string | 可空 | ≤32 字 | 分摊分组键(如 BUS/SUV;同组内单独均摊) |
|
||||
| budgetAmount | number | 可空 | ≥0,2 位小数 | 预算额/带出值(只对比不参与拆账计算) |
|
||||
| actualAmount | number | ✅ | ≥0,2 位小数 | **实际总额(拆账基准)** |
|
||||
| changeReason | string | 条件必填 | ≤255 字 | 改价原因(实际总额与库值不同且偏离带出值时必填) |
|
||||
| paymentMethod | string | 可空 | `SIGNED` / `COMPANY_PAID` / `CASH_PAID` | 付款方式:签单 / 对公已付 / 现金已付(**固定 3 值枚举,不走数据字典**) |
|
||||
| voucherUrls | string[] | 可空 | ≤9 张 | 凭证图 URL 数组 |
|
||||
| remark | string | 可空 | ≤255 字 | 备注 |
|
||||
| splits | array | 条件必填 | - | 拆账明细:**仅 DESIGNATED 行必填且 ≥1**;SHARED 行服务端自动重算,提交内容被忽略 |
|
||||
|
||||
`splits[]` 元素(SplitSaveReqVO,仅指定报名行):
|
||||
|
||||
| 字段 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| orderId | Long | ✅ | 须属本团在团户 | 承担子订单 ID;不属本团返 589572;同户重复出现被拒 |
|
||||
| ratio | number | 可空 | ≥0,6 位小数 | 拆分权重(不强制合计为 1,服务端按权重归一化) |
|
||||
| amount | number | 可空 | ≥0,2 位小数 | **手改金额**(非空优先,不再参与权重分剩余);**全部手改时 Σamount 必须分毫不差 = 行 actualAmount**,否则 589750 |
|
||||
| note | string | 可空 | ≤255 字 | 备注(提前离团等) |
|
||||
|
||||
`lines[]` 各类特有列(只填本 tab 类别的列,其余留空;字段定义同 §5.2 各类特有列表):
|
||||
|
||||
- 住宿 HOTEL:hotelId / roomTypeId / dayNumber(≥1) / stayDate / hotelName / roomTypeName / roomCount(≥0) / unitPrice
|
||||
- 门票·游玩 TICKET:dayNumber / dayDate / scenicName / specName / ticketCount(≥0) / ticketUnitPrice
|
||||
- 餐食 MEAL:mealType / mealDate / mealName / restaurantId / restaurantName / quantity(≥0) / unitPrice
|
||||
- 车辆 VEHICLE:serviceStartDate / serviceEndDate / vehicleId / vehiclePlate / vehicleModelName / driverId / driverName / dailyPrice
|
||||
- 导游 GUIDE / 摄影师 PHOTOGRAPHER:staffId / staffName / workDays(≥0,1 位小数) / perDayFee
|
||||
- 其他收入 OTHER_INCOME:incomeDate / projectName / projectCategory / specification / quantity(2 位小数) / unitPrice
|
||||
- 其他支出 OTHER_EXPENSE:expenseType / expenseDate / projectName
|
||||
|
||||
### 4.3 `POST …/settlement/lines` 新增单条明细行(GroupSettleLineCreateReqVO)
|
||||
|
||||
继承 4.2 行字段(`lineId` 传了也被忽略),额外两个字段:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| category | string | ✅ | 费用类别 8 值之一(决定落哪张分类明细表;非法值 589753) |
|
||||
| expectedVersion | int | ✅ | 乐观锁版本(同 4.2) |
|
||||
|
||||
### 4.4 `POST …/settlement/panel/confirm` 确认核单(GroupSettleConfirmReqVO)
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| expectedVersion | int | ✅ | 乐观锁版本(GET panel/tab 返回的 `version` 原样回传) |
|
||||
|
||||
**确认后不可逆**:不提供 un-confirm,前端须二次确认弹窗提示「确认后不可修改」。确认后全部写口拒绝(589568)。
|
||||
|
||||
### 4.5 `POST …/settlement/alloc-preview` 拆账试算(GroupSettleAllocPreviewReqVO,不落库)
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| category | string | ✅ | 费用类别 8 值之一 |
|
||||
| lines | array | ✅ | 待试算明细行数组(≤500 行,结构同 4.2 `lines[]`);**无 expectedVersion**(纯试算不写库) |
|
||||
|
||||
### 4.6 `POST …/settlement/invoice` 按子订单开票(GroupBatchInvoiceReqVO)
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| orderId | Long | ✅ | 子订单 ID(须为本团在团户,否则 589572;该户已有有效发票 589571) |
|
||||
| titleType | string | ✅ | `PERSONAL` 个人 / `COMPANY` 单位 |
|
||||
| title | string | ✅ | 发票抬头(≤128 字,公司全称或个人姓名) |
|
||||
| taxNo | string | 条件必填 | 税号(≤32 字,**titleType=COMPANY 时必填**,跨字段约束由 Service 判定) |
|
||||
| email | string | ✅ | 收件邮箱(合法邮箱格式,≤128 字) |
|
||||
|
||||
发票类型不由前端选:服务端固定**增值税普通发票**。本请求**不带 expectedVersion**(开票不写核单主行,version 不变)。
|
||||
|
||||
## 5. 出参字段
|
||||
|
||||
通用约定:**金额一律字符串输出**(DECIMAL 防精度),**ID 一律字符串输出**(Long 防 JS 精度丢失),日期 `yyyy-MM-dd`,日期时间 `yyyy-MM-dd HH:mm:ss`。
|
||||
|
||||
### 5.1 `GET …/settlement/{tab}` 分类 tab 出参(GroupSettleTabRespVO)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| groupBatchId | string | 团期 ID |
|
||||
| category | string | 本 tab 类别值(**activities tab 恒 TICKET**) |
|
||||
| categoryName | string | 类别中文名(数据字典 `settlement_category`) |
|
||||
| status | string | 核单状态:`DRAFT` 录入中 / `CONFIRMED` 已确认 |
|
||||
| version | int | 乐观锁版本(PUT/DELETE/confirm 回传 expectedVersion 用) |
|
||||
| editable | boolean | 是否可编辑(= status == DRAFT;false 时前端禁用全部写交互) |
|
||||
| budgetTotal | string 或 null | 本类 Σ 带出值/预算额(全行为空则 null) |
|
||||
| actualTotal | string | 本类 Σ 实际总额 |
|
||||
| allocatedTotal | string | 本类已拆账金额(Σ splits.amount) |
|
||||
| lines | array | 明细行数组(无行时 `[]`;**首读未落库时返回「两层带出预览」行**:lineId=null、splits=[],不落库) |
|
||||
|
||||
**首读即建行**:任何团期状态(含未返团)首读都返回真实结构,不再是旧版 NOT_STARTED 空壳。
|
||||
|
||||
### 5.2 `lines[]` 明细行(LineVO)——公共列
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| lineId | string 或 null | 明细行 ID(带出预览行为 null) |
|
||||
| confirmStatus | string | 行确认态:`UNCONFIRMED` / `CONFIRMED`(核单确认时批量翻 CONFIRMED) |
|
||||
| allocMode | string | `SHARED` 公摊 / `DESIGNATED` 指定报名 |
|
||||
| allocRule | string 或 null | `PER_HEAD_AVG` 按全团人数均摊 / `PER_ORDER_AVG` 按户均摊;DESIGNATED 恒 null |
|
||||
| allocGroup | string 或 null | 分摊分组键(如 BUS/SUV) |
|
||||
| budgetAmount | string 或 null | 带出值/预算额(只对比不参与计算) |
|
||||
| actualAmount | string | 实际总额(拆账基准) |
|
||||
| changeReason | string 或 null | 改价原因 |
|
||||
| sourceType | string | `MANUAL` 手工 / `CARRY_OVER` 第 1 层带出 / `BATCH_COST` 共享成本带出 |
|
||||
| paymentMethod | string 或 null | `SIGNED` 签单 / `COMPANY_PAID` 对公已付 / `CASH_PAID` 现金已付 |
|
||||
| voucherUrls | string[] | 凭证图 URL 数组(无则 `[]`) |
|
||||
| remark | string 或 null | 备注 |
|
||||
| splits | array | 本行拆账结果(未拆账为 `[]`),结构见 5.3 |
|
||||
|
||||
**各类特有列**(出参为全类别并集,**非本 tab 的特有列恒为 null**,按 category 取本类列即可):
|
||||
|
||||
| 类别 | 特有列 |
|
||||
|------|--------|
|
||||
| HOTEL 住宿 | hotelId / roomTypeId / dayNumber / stayDate / hotelName / roomTypeName / roomCount / unitPrice(元/间夜) |
|
||||
| TICKET 门票·游玩 | dayNumber / dayDate / scenicName / specName / ticketCount / ticketUnitPrice |
|
||||
| MEAL 餐食 | mealType / mealDate / mealName / restaurantId / restaurantName / quantity(份数) / unitPrice(元/份) |
|
||||
| VEHICLE 车辆 | serviceStartDate / serviceEndDate / vehicleId / vehiclePlate / vehicleModelName / driverId / driverName / dailyPrice(日单价) |
|
||||
| GUIDE 导游 / PHOTOGRAPHER 摄影师 | staffId / staffName / workDays(1 位小数) / perDayFee(日费) |
|
||||
| OTHER_INCOME 其他收入 | incomeDate / projectName / projectCategory / specification / quantity(2 位小数) / unitPrice |
|
||||
| OTHER_EXPENSE 其他支出 | expenseType / expenseDate / projectName |
|
||||
|
||||
### 5.3 `lines[].splits[]` 拆账明细(SplitVO)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| orderId | string | 子订单 ID |
|
||||
| teamNo | string 或 null | **团号**(order_main.team_no,订金支付成功后生成;未付订金为 null)。⚠️ `alloc-preview` 试算回执的 splits.teamNo **本期恒 null 未填充** |
|
||||
| householdName | string | 户名(客户姓名快照) |
|
||||
| ratio | string | 拆账比例(6 位小数;公摊=计算快照,指定报名=用户比例/归一化权重快照) |
|
||||
| peopleCount | int 或 null | 该户参与人数快照 |
|
||||
| amount | string | 拆账金额 |
|
||||
| roundingBearer | boolean | 尾差承担户标记(公摊尾差整笔记 eligible 集合中 **order_id 最小**的户) |
|
||||
| note | string 或 null | 备注(提前离团等) |
|
||||
|
||||
### 5.4 `PUT …/settlement/{tab}` 暂存回执(GroupSettleTabWriteRespVO)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| version | int | 写入后的乐观锁版本(已 +1) |
|
||||
| status | string | 核单状态(恒 `DRAFT`;CONFIRMED 时写口已被 589568 拦截) |
|
||||
| lines | array | 写入后本 tab 全量明细行(结构同 5.2,含重算后的 splits),**前端直接整页替换** |
|
||||
|
||||
### 5.5 `GET …/settlement/panel` 面板出参(GroupSettlePanelRespVO)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| groupBatchId | string | 团期 ID |
|
||||
| status | string | `DRAFT` / `CONFIRMED`(确认后不可逆) |
|
||||
| version | int | 乐观锁版本 |
|
||||
| confirmedAt | string 或 null | 确认时间(DRAFT 为 null) |
|
||||
| confirmedByName | string 或 null | 确认人姓名(DRAFT 为 null) |
|
||||
| editable | boolean | 是否可编辑(= status == DRAFT) |
|
||||
| readyToAllocate | boolean | 各户第 1 层核单是否全部定稿 |
|
||||
| blockingOrderIds | string[] | 第 1 层核单未定稿的子订单 ID;空数组 = 全部定稿 |
|
||||
| categories | array | **8 类合计(恒 8 条,按类别序)**,元素见下表 |
|
||||
| households | array | 在团子订单列表(仅排除已取消),元素见下表 |
|
||||
|
||||
`categories[]`(CategorySummaryVO):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| category | string | 费用类别 8 值 |
|
||||
| categoryName | string | 类别中文名(字典 `settlement_category`) |
|
||||
| budgetAmount | string 或 null | 该类 Σ 带出值/预算额(全行为空则 null) |
|
||||
| actualAmount | string | 该类 Σ 实际总额 |
|
||||
| allocatedAmount | string | 该类已拆账金额(Σ splits.amount) |
|
||||
| unallocatedAmount | string | 该类未拆账金额(actualAmount − allocatedAmount) |
|
||||
|
||||
`households[]`(HouseholdVO):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| orderId | string | 子订单 ID |
|
||||
| orderNo | string | 订单号 |
|
||||
| teamNo | string 或 null | 团号(未付订金为 null) |
|
||||
| householdName | string | 户名 |
|
||||
| peopleCount | int | 人数 |
|
||||
| roomCount | int 或 null | 房间数 |
|
||||
| allocatedCost | string | 已摊成本(该户 7 个支出类 Σ splits.amount) |
|
||||
| allocatedIncome | string | 已摊收入(该户其他收入 Σ splits.amount) |
|
||||
| grossProfit | string | 毛利(应收口径 − 已摊成本 + 已摊收入) |
|
||||
|
||||
### 5.6 `GET …/settlement/sub-orders` 在团子订单出参(GroupSettleSubOrderRespVO[])
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| orderId | string | 子订单 ID |
|
||||
| orderNo | string | 订单号 |
|
||||
| teamNo | string 或 null | 团号(未付订金为 null) |
|
||||
| householdName | string | 户名 |
|
||||
| peopleCount | int | 人数(公摊按人摊的分子预览) |
|
||||
| roomCount | int 或 null | 房间数 |
|
||||
|
||||
在团口径 = **仅排除已取消**。用途:指定报名勾选弹窗的数据源。
|
||||
|
||||
### 5.7 写端点回执
|
||||
|
||||
`POST …/settlement/lines`(GroupSettleLineCreateRespVO):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| lineId | string | 新增明细行 ID |
|
||||
| version | int | 写入后的乐观锁版本(已 +1) |
|
||||
|
||||
`DELETE …/settlement/lines/{lineId}`(GroupSettleLineDeleteRespVO):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| version | int | 写入后的乐观锁版本(已 +1);该行拆账已同事务级联软删 |
|
||||
|
||||
`POST …/settlement/panel/confirm`(GroupSettleConfirmRespVO):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| status | string | 恒 `CONFIRMED` |
|
||||
| version | int | 确认后的乐观锁版本(已 +1) |
|
||||
| confirmedAt | string | 确认时间 |
|
||||
| confirmedByName | string | 确认人姓名 |
|
||||
|
||||
`POST …/settlement/alloc-preview`(GroupSettleAllocPreviewRespVO):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| lines | array | 试算后的明细行(结构同 5.2 LineVO;confirmStatus 恒 UNCONFIRMED、lineId 原样回显或 null、sourceType 恒 MANUAL;splits 为重算预览,**splits[].teamNo 本期恒 null**)。**无任何写库** |
|
||||
|
||||
`POST …/settlement/invoice`(GroupSettleInvoiceRespVO):
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| status | string | 核单状态(恒 `CONFIRMED`,开票门禁) |
|
||||
| version | int | 核单乐观锁版本(开票不改主行,原值) |
|
||||
| invoiceId | string | 新发票 ID |
|
||||
|
||||
## 6. 枚举 / 数据字典
|
||||
|
||||
### category(费用类别,数据字典 `settlement_category`,8 值)
|
||||
|
||||
| 值 | 中文 | 路径段 | 支出/收入 |
|
||||
|----|------|--------|-----------|
|
||||
| `HOTEL` | 住宿 | hotels | 支出 |
|
||||
| `TICKET` | 门票·游玩 | **activities**(旧名沿用,出参 category 恒 TICKET) | 支出 |
|
||||
| `MEAL` | 餐食 | meals | 支出 |
|
||||
| `VEHICLE` | 车辆 | vehicles | 支出 |
|
||||
| `GUIDE` | 导游 | guide-fees | 支出 |
|
||||
| `PHOTOGRAPHER` | 摄影师 | photographer-fees | 支出 |
|
||||
| `OTHER_INCOME` | 其他收入 | other-incomes | **收入** |
|
||||
| `OTHER_EXPENSE` | 其他支出 | other-expenses | 支出 |
|
||||
|
||||
中文名以后端下发的 `categoryName` 为准(字典驱动),前端不要硬编码。
|
||||
|
||||
### allocMode(分摊方式)
|
||||
|
||||
| 值 | 含义 | 配套约束 |
|
||||
|----|------|----------|
|
||||
| `SHARED` | 公摊(全团 eligible 户分摊) | allocRule 可省(按类别默认);splits 由服务端重算,提交被忽略 |
|
||||
| `DESIGNATED` | 指定报名(勾选子订单子集承担) | allocRule 必须 null;splits 必填 ≥1(未选返 589751);Σ拆账=行总额(不等返 589750) |
|
||||
|
||||
### allocRule(公摊口径,仅 SHARED 有效)
|
||||
|
||||
| 值 | 含义 | 类别默认 |
|
||||
|----|------|----------|
|
||||
| `PER_HEAD_AVG` | 按全团人数均摊(eligible 户按人数加权,人数 0 的户不参与) | 住宿/门票·游玩/餐食/车辆/其他支出默认 |
|
||||
| `PER_ORDER_AVG` | 按户均摊(eligible 户等权,不看人数) | **导游/摄影师/其他收入默认** |
|
||||
|
||||
公摊尾差规则:非尾差户按 ROUND_HALF_UP 到分,**尾差 = 总额 − Σ其余户份额,整笔记 eligible 集合中 order_id 最小的户**(splits 里 `roundingBearer=true`);尾差户金额为负时全组改 ROUND_DOWN 重算,尾差恒非负。
|
||||
|
||||
### status(核单状态)/ confirmStatus(行确认态)
|
||||
|
||||
| 字段 | 值 | 含义 |
|
||||
|------|----|------|
|
||||
| status | `DRAFT` | 录入中(可编辑) |
|
||||
| status | `CONFIRMED` | 已确认(不可逆,全部写口拒 589568) |
|
||||
| confirmStatus | `UNCONFIRMED` / `CONFIRMED` | 明细行确认态,随核单确认批量翻 CONFIRMED |
|
||||
|
||||
### sourceType(明细行来源)
|
||||
|
||||
| 值 | 含义 |
|
||||
|----|------|
|
||||
| `MANUAL` | 手工录入 |
|
||||
| `CARRY_OVER` | 第 1 层(子订单核单)带出 |
|
||||
| `BATCH_COST` | 共享成本带出 |
|
||||
|
||||
### paymentMethod(付款方式,固定 3 值枚举,**不走数据字典**)
|
||||
|
||||
| 值 | 含义 |
|
||||
|----|------|
|
||||
| `SIGNED` | 签单 |
|
||||
| `COMPANY_PAID` | 对公已付 |
|
||||
| `CASH_PAID` | 现金已付 |
|
||||
|
||||
### 其他字典(特有列内引用)
|
||||
|
||||
| 字段 | 字典 | 取值 |
|
||||
|------|------|------|
|
||||
| mealType(餐食) | `meal_type` | `BREAKFAST` / `LUNCH` / `DINNER` / `SELF` |
|
||||
| expenseType(其他支出) | `expense_type` | `FUEL` / `TOLL` / `PARKING` / `RENTAL` / `MAINTENANCE` / `OTHER` |
|
||||
|
||||
## 7. 错误码
|
||||
|
||||
| 错误码 | 文案({0} 为动态定位串) | 触发场景 |
|
||||
|--------|--------------------------|----------|
|
||||
| 589507 | 无操作权限(当前角色未授予团期权限,或该团期不在您名下) | 缺 `group-batch:audit:*` 对应权限码 |
|
||||
| 589567 | 该团期尚未进入整团核单:{0} | 尚未建核单主记录时直接调写口/确认(正常链路首读 GET 即建行,不会遇到) |
|
||||
| 589568 | 整团核单当前状态不允许该操作:{0} | ① CONFIRMED 后任何写操作;② 确认核单时在团子订单第 1 层核单未全部定稿({0} 带未定稿订单号清单,与 panel 的 blockingOrderIds 对应) |
|
||||
| 589571 | 已开票冲突:{0} | 该子订单已有有效发票仍重复开票 |
|
||||
| 589572 | 所选订单不属于本团期的整团核单范围 | 指定报名 splits / 开票 orderId 不属本团在团户 |
|
||||
| 589573 | 整团核单数据已被他人修改(当前版本 {0},提交版本 {1}),请刷新后重试 | expectedVersion 与库值不一致(CAS 并发冲突),本次请求零写入,**前端须重新 GET 读回全量再提交** |
|
||||
| 589750 | 拆账合计与明细行总额不一致({0}),请核对后再提交 | 指定报名行 Σ拆账 ≠ actualAmount;{0} 为四数文案「{行名}拆账合计 {实} / 明细总额 {应},差额 {差}」 |
|
||||
| 589751 | 指定报名须至少选择一个承担子订单 | DESIGNATED 行 splits 为空 |
|
||||
| 589752 | 全团人数为 0,无法按人数均摊;请改用按户均摊或先维护出行人 | SHARED + PER_HEAD_AVG 时全团人数为 0 |
|
||||
| 589753 | 核单拆账入参非法:{0} | 金额/单价/数量为负、未知费用类别等入参层非法 |
|
||||
| 589754 | 在团子订单已变化({0}),已拆账数据失效,请重新暂存各分类完成拆账后再确认 | 确认核单前置校验:子订单退团/转入后未重新暂存拆账 |
|
||||
| 589755 | 核单无明细行,不可确认,请先在各分类 Tab 录入明细后再确认 | 零明细行尝试确认 |
|
||||
|
||||
**废弃错误码**(保留占位不再抛出,前端可清理映射):589569(金额非法 → 由 589753 承接)、589570(四数对平 → 由 589750 承接)、589517(导出超限,导出端点已下线)。
|
||||
|
||||
## 8. 示例
|
||||
|
||||
### 8.1 典型:GET 住宿 tab(已录入两行,一行公摊一行指定报名)
|
||||
|
||||
请求:
|
||||
|
||||
GET /v3/admin/order/group-batch/1934567890123456789/settlement/hotels
|
||||
|
||||
响应 200:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"groupBatchId": "1934567890123456789",
|
||||
"category": "HOTEL",
|
||||
"categoryName": "住宿",
|
||||
"status": "DRAFT",
|
||||
"version": 3,
|
||||
"editable": true,
|
||||
"budgetTotal": "8600.00",
|
||||
"actualTotal": "8400.00",
|
||||
"allocatedTotal": "8400.00",
|
||||
"lines": [
|
||||
{
|
||||
"lineId": "1934567890123456790",
|
||||
"confirmStatus": "UNCONFIRMED",
|
||||
"allocMode": "SHARED",
|
||||
"allocRule": "PER_HEAD_AVG",
|
||||
"allocGroup": null,
|
||||
"budgetAmount": "4800.00",
|
||||
"actualAmount": "4600.00",
|
||||
"changeReason": "酒店涨价已与对方确认",
|
||||
"sourceType": "CARRY_OVER",
|
||||
"paymentMethod": "SIGNED",
|
||||
"voucherUrls": ["https://oss.example.com/voucher/1.jpg"],
|
||||
"remark": "含早餐",
|
||||
"hotelId": "1934567890123400001",
|
||||
"roomTypeId": "1934567890123400002",
|
||||
"dayNumber": 2,
|
||||
"stayDate": "2026-10-03",
|
||||
"hotelName": "图嘎营地",
|
||||
"roomTypeName": "蒙古包",
|
||||
"roomCount": 5,
|
||||
"unitPrice": "380.00",
|
||||
"splits": [
|
||||
{ "orderId": "1934567890123450001", "teamNo": "26-0001", "householdName": "张三",
|
||||
"ratio": "0.300000", "peopleCount": 3, "amount": "1380.00", "roundingBearer": true, "note": null },
|
||||
{ "orderId": "1934567890123450002", "teamNo": "26-0002", "householdName": "李四",
|
||||
"ratio": "0.700000", "peopleCount": 7, "amount": "3220.00", "roundingBearer": false, "note": null }
|
||||
]
|
||||
},
|
||||
{
|
||||
"lineId": "1934567890123456791",
|
||||
"confirmStatus": "UNCONFIRMED",
|
||||
"allocMode": "DESIGNATED",
|
||||
"allocRule": null,
|
||||
"allocGroup": null,
|
||||
"budgetAmount": "3800.00",
|
||||
"actualAmount": "3800.00",
|
||||
"changeReason": null,
|
||||
"sourceType": "MANUAL",
|
||||
"paymentMethod": "COMPANY_PAID",
|
||||
"voucherUrls": [],
|
||||
"remark": "升级房型差价",
|
||||
"hotelId": "1934567890123400001",
|
||||
"roomTypeId": "1934567890123400003",
|
||||
"dayNumber": 2,
|
||||
"stayDate": "2026-10-03",
|
||||
"hotelName": "图嘎营地",
|
||||
"roomTypeName": "豪华蒙古包",
|
||||
"roomCount": 1,
|
||||
"unitPrice": "3800.00",
|
||||
"splits": [
|
||||
{ "orderId": "1934567890123450002", "teamNo": "26-0002", "householdName": "李四",
|
||||
"ratio": "1.000000", "peopleCount": 7, "amount": "3800.00", "roundingBearer": false, "note": "李四家要求升级" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 边界:PUT 整 tab 暂存(指定报名混合「比例 + 手改金额」+ 未付订金 teamNo=null)
|
||||
|
||||
请求:
|
||||
|
||||
PUT /v3/admin/order/group-batch/1934567890123456789/settlement/vehicles
|
||||
Content-Type: application/json
|
||||
|
||||
```json
|
||||
{
|
||||
"expectedVersion": 3,
|
||||
"lines": [
|
||||
{
|
||||
"lineId": null,
|
||||
"allocMode": "DESIGNATED",
|
||||
"allocRule": null,
|
||||
"actualAmount": 3000.00,
|
||||
"paymentMethod": "CASH_PAID",
|
||||
"serviceStartDate": "2026-10-02",
|
||||
"serviceEndDate": "2026-10-04",
|
||||
"vehiclePlate": "蒙E·12345",
|
||||
"vehicleModelName": "考斯特",
|
||||
"driverName": "巴特尔",
|
||||
"dailyPrice": 1500.00,
|
||||
"splits": [
|
||||
{ "orderId": "1934567890123450001", "ratio": 1.000000, "amount": null, "note": null },
|
||||
{ "orderId": "1934567890123450002", "ratio": null, "amount": 2000.00, "note": "手改固定 2000" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
响应 200(李四家手改 2000 优先,张三家按权重吸收剩余 1000 并承担尾差;该两户未付订金故 teamNo=null):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"version": 4,
|
||||
"status": "DRAFT",
|
||||
"lines": [
|
||||
{
|
||||
"lineId": "1934567890123456800",
|
||||
"confirmStatus": "UNCONFIRMED",
|
||||
"allocMode": "DESIGNATED",
|
||||
"allocRule": null,
|
||||
"actualAmount": "3000.00",
|
||||
"sourceType": "MANUAL",
|
||||
"splits": [
|
||||
{ "orderId": "1934567890123450001", "teamNo": null, "householdName": "张三",
|
||||
"ratio": "0.333333", "peopleCount": 3, "amount": "1000.00", "roundingBearer": true, "note": null },
|
||||
{ "orderId": "1934567890123450002", "teamNo": null, "householdName": "李四",
|
||||
"ratio": null, "peopleCount": 7, "amount": "2000.00", "roundingBearer": false, "note": "手改固定 2000" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
读法:回执 `lines` 是写入后本 tab 全量回读(含重算后的 splits),前端直接整页替换;`version` 已 +1,下次写操作回传 4。
|
||||
|
||||
### 8.3 业务失败
|
||||
|
||||
**8.3a 指定报名拆账合计 ≠ 行总额(589750)**:
|
||||
|
||||
PUT /v3/admin/order/group-batch/1934567890123456789/settlement/hotels
|
||||
|
||||
```json
|
||||
{ "expectedVersion": 4, "lines": [ { "allocMode": "DESIGNATED", "actualAmount": 3800.00,
|
||||
"splits": [ { "orderId": "1934567890123450001", "amount": 3000.00 } ] } ] }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 589750,
|
||||
"message": "拆账合计与明细行总额不一致(图嘎营地蒙古包拆账合计 3000.00 / 明细总额 3800.00,差额 800.00),请核对后再提交" }
|
||||
```
|
||||
|
||||
**8.3b 调旧 /audit 路径(已下线,404)**:
|
||||
|
||||
GET /v3/admin/order/group-batch/1934567890123456789/audit
|
||||
|
||||
HTTP/1.1 404 Not Found
|
||||
|
||||
旧 `GET/PUT …/audit`、`POST …/audit/allocate`、`POST …/audit/reallocate`、`GET …/audit/export`、`POST …/audit/invoice` 六个端点**全部已删除**,网关/服务均不再路由,调用一律 404。前端若保留旧核单页代码必须整体替换。
|
||||
|
||||
## 9. 业务边界
|
||||
|
||||
**适用**:
|
||||
- 管理后台团期详情的整团核单:8 类费用明细录入 / 暂存 / 拆账 / 确认 / 按子订单开票。
|
||||
- 公摊(全团分摊)与指定报名(部分户承担)两种成本核算口径的录入与试算。
|
||||
|
||||
**不适用**:
|
||||
- **逐子订单独立应收应付**:拆账只影响成本/毛利**核算口径**,不生成逐户应收应付单;财务主链仍一团一张报账单(biz_no = 团号 batch_no),走既有 `POST …/settlement/finalize` → `POST …/settlement/confirm`(财务复核,**与本次新增的 panel/confirm 是两个不同端点**)。
|
||||
- 确认后修改:CONFIRMED 不可逆,不提供 un-confirm;录错只能走后端人工处理。
|
||||
- 旧四表模型的科目行/逐户用量交互:已随旧表 DROP 彻底移除。
|
||||
|
||||
**特殊边界**:
|
||||
- **首读即建行**:任何团期状态(含未返团)GET tab/panel 都会建核单主行并返回真实结构;库里无明细行时 tab 返回「两层带出预览」行(lineId=null、splits=[],不落库)——前端不要把预览行当已保存行渲染删除/编辑按钮(lineId 为 null 即预览行)。
|
||||
- **全量替换语义**:PUT 整 tab 是覆盖写——库里存在但未提交的行会被删除;前端编辑后必须提交**整 tab 全量行**,不能只传改动行。
|
||||
- **CAS 冲突处理**:任何写口返 589573 时,前端必须重新 GET 读回全量(含新 version)再让用户基于最新数据重改,不能本地 version+1 重试。
|
||||
- **确认前置**:确认核单要求 ① 有明细行(否则 589755);② 在团子订单第 1 层核单全部定稿(否则 589568,未定稿清单见 panel `blockingOrderIds` / `readyToAllocate`,前端可在确认按钮上据此置灰);③ 在团户集合与已落拆账一致(退团/转入后须重新暂存,否则 589754)。
|
||||
- **开票门禁**:仅 CONFIRMED 后可开票;一户一票(589571)。
|
||||
- **eligible 户**:公摊的 eligible 集合 = 在团户(仅排除已取消);PER_HEAD_AVG 时人数为 0 的户不参与分摊。
|
||||
|
||||
## 10. 修改前后对比
|
||||
|
||||
### 字段级对比
|
||||
|
||||
| 项 | 原来(旧 /audit 契约) | 现在(#8714 重做后) |
|
||||
|----|--------------------------|----------------------|
|
||||
| 核单数据载体 | 统一科目行 + 逐户用量 + 逐户分摊(四表) | 8 类分类明细行 + 行内 splits 拆账(10 表) |
|
||||
| 费用类别 | 硬编码 AuditCategory | 数据字典 `settlement_category` 8 值,`categoryName` 字典下发 |
|
||||
| 核单状态机 | DRAFT → ALLOCATED → CHECKED 等多态 | **DRAFT → CONFIRMED 两态**,确认后不可逆 |
|
||||
| 分摊方式 | 均分 / 指定比例(粗粒度) | SHARED 公摊(按人/按户两口径)/ DESIGNATED 指定报名(比例 + 手改金额混合) |
|
||||
| 尾差承担 | 旧决策(order_id 最小户) | **沿用**:eligible 集合 order_id 最小户,`roundingBearer` 标记 |
|
||||
| 写口并发控制 | expectedVersion(order_batch_audit.version) | expectedVersion(order_group_settlement_main.version),同 CAS 语义、同 589573 |
|
||||
| 出参 ID / 金额 | 数值型 | **全部字符串化**(Long 防精度丢失、DECIMAL 防精度) |
|
||||
| 团号 | 出参无 teamNo | panel.households[] / sub-orders[] / tab splits[] 新增 **teamNo**(#8779) |
|
||||
| sharedCostByType.costType | BatchCostType 4 值:`BUS` / `LEADER` / `PHOTOGRAPHER` / `OTHER` | **`settlement_category` 8 值**(HOTEL/TICKET/MEAL/VEHICLE/GUIDE/PHOTOGRAPHER/OTHER_INCOME/OTHER_EXPENSE),`costTypeDesc` 走数据字典 |
|
||||
|
||||
### 行为级对比
|
||||
|
||||
| 行为 | 原来 | 现在 |
|
||||
|------|------|------|
|
||||
| 打开核单页 | 返团后才可查,未返团 NOT_STARTED 空壳 | **任何团期状态首读即建行**,返回真实结构;无明细行给带出预览(不落库) |
|
||||
| 保存 | 整单保存(一次 PUT 全科目) | **按 tab 保存**(8 个 PUT 各自全量替换本类)+ 单行新增/删除端点 |
|
||||
| 分摊计算 | 提交核算时整团重算 | 每次暂存/新增/删除行即重算该行 splits 并落库;另有不落库试算 `alloc-preview` |
|
||||
| 确认/提交核算 | allocate → reallocate → 验团多步 | **一次 panel/confirm**(8 表全量复核后锁 CONFIRMED,不可逆) |
|
||||
| 开票 | `POST …/audit/invoice` | `POST …/settlement/invoice`(门禁从旧状态改为 CONFIRMED) |
|
||||
| 导出 | `GET …/audit/export` | **端点下线**,本期无导出 |
|
||||
| 旧 /audit 6 端点 | 正常服务 | **全部删除,调用 404** |
|
||||
| 下游 D2 汇总(return-detail / settlement summary) | 共享成本读旧四表 | 改读新 8 表明细(PR-5),`sharedCostByType` 键值域同步切换 |
|
||||
| 验团(结算)门禁 | 看旧核单主表状态 | 切看新核单主表 CONFIRMED(PR-5) |
|
||||
|
||||
## 11. 影响评估 / 回滚
|
||||
|
||||
- **破坏兼容**:**是,整体重做**。旧 `/audit/*` 端点已删(404),旧四表已 DROP,8 个 tab GET 出参结构完全变化。前端原团期核单页(科目行交互)**必须整体重写对接**,不存在渐进迁移路径。
|
||||
- **前端必须同步上线**:是。后端部署后旧前端核单页全部 404 / 解析失败。**建议前后端同批上线**;后端当前已合 dev-v3 **未部署测试服**,前端可先行开发,联调窗口在部署后。
|
||||
- **跨页面影响**:消费 `GroupReturnDetailRespVO` / `GroupBatchSettlementSummaryRespVO` 的 **`sharedCostByType[].costType`** 渲染页(核团详情、结算汇总)须同批适配——键值从 BatchCostType 4 值切到 settlement_category 8 值,展示名直接用后端下发的 `costTypeDesc`(字典驱动),不要再做 4 值硬编码映射。
|
||||
- **workaround 清理点**:旧核单页对 589569/589570 的错误码映射可删(已废弃);对旧多态状态机(DRAFT/ALLOCATED/CHECKED 等)的分支渲染可删;「未返团空壳」占位逻辑可删(现在任何状态都返回真实结构)。
|
||||
- **回滚方案**:后端回滚 = 需恢复旧四表 DDL + 旧代码(代价大,实际不可回滚——旧表已 DROP,数据不迁移)。本批按「开发期推倒重做、无向后兼容」交付,**前端务必在同批部署窗口前完成适配**。
|
||||
|
||||
## 12. 注意事项
|
||||
|
||||
1. **确认路径别调错**:确认核单是 `POST …/settlement/panel/confirm`;`POST …/settlement/confirm`(无 panel 段)是**团期结算财务复核**(旧财务主链,权限与语义都不同),两者不是一回事。
|
||||
2. **activities = TICKET**:门票·游玩 tab 的路径段是历史沿用的 `activities`,但出参/入参的 category 值恒为 `TICKET`。路由映射写死:`hotels→HOTEL`、`activities→TICKET`、`meals→MEAL`、`vehicles→VEHICLE`、`guide-fees→GUIDE`、`photographer-fees→PHOTOGRAPHER`、`other-incomes→OTHER_INCOME`、`other-expenses→OTHER_EXPENSE`。
|
||||
3. **特有列是并集**:LineVO 出参包含全部 8 类特有列的并集,非本 tab 类别的列恒为 null——按 `category` 只读本类列,不要对 null 列做渲染兜底之外的逻辑。
|
||||
4. **全量替换**:PUT 暂存必须提交整 tab 全量行;漏传 = 删除。
|
||||
5. **金额/ID 按字符串处理**:所有金额、ID 均为 JSON 字符串,禁转 number(精度丢失)。
|
||||
6. **teamNo 可空**:未付订金的子订单 teamNo 为 null,列表渲染需做空值兜底;`alloc-preview` 回执的 splits.teamNo 本期恒 null(试算不查团号),不要用它做展示。
|
||||
7. **预览行识别**:GET tab 首读的带出预览行 `lineId=null`,不是已保存数据,编辑/删除交互应只对 lineId 非空的行开放。
|
||||
8. **editable 驱动写交互**:`editable=false`(CONFIRMED)时禁用全部写按钮;硬调写口会吃 589568。
|
||||
9. **付款方式不走字典**:paymentMethod 是固定 3 值(SIGNED/COMPANY_PAID/CASH_PAID),前端硬编码映射即可;mealType / expenseType 走对应数据字典。
|
||||
10. **指定报名校验在服务端**:Σ拆账=行总额(589750)、至少一户(589751)、户属本团(589572)都由服务端强校验,前端可做预校验提升体验,但不能替代服务端回执处理。
|
||||
11. **删除行必带 category + expectedVersion**(Query 参数),不是请求体。
|
||||
|
||||
## 13. 关联 / 联系人
|
||||
|
||||
- Issue(主):https://git.1814.love/wx/HL/issues/8714
|
||||
- Issue(teamNo 跟进):https://git.1814.love/wx/HL/issues/8779
|
||||
- PR 序列(6 PR + 1 跟进,按合并序):
|
||||
- PR-1 建表迁移:https://git.1814.love/wx/HL/pulls/8716 | commit https://git.1814.love/wx/HL/commit/3bad2ad276
|
||||
- PR-2 DO/Mapper/枚举骨架:https://git.1814.love/wx/HL/pulls/8718 | commit https://git.1814.love/wx/HL/commit/ee90112a2d
|
||||
- PR-3 公摊/指定报名拆账计算器:https://git.1814.love/wx/HL/pulls/8722 | commit https://git.1814.love/wx/HL/commit/34d10981c0
|
||||
- PR-4 8 类 tab + 面板/暂存/确认/开票 Service 与接口:https://git.1814.love/wx/HL/pulls/8737 | commit https://git.1814.love/wx/HL/commit/788b9c1493
|
||||
- PR-5 下游改造(D2 汇总读新 8 表 + 验团门禁切新主表):https://git.1814.love/wx/HL/pulls/8764 | commit https://git.1814.love/wx/HL/commit/b9f22e3adc
|
||||
- PR-6 旧代码清理 + DROP 旧四表:https://git.1814.love/wx/HL/pulls/8778 | commit https://git.1814.love/wx/HL/commit/30f83ada81
|
||||
- teamNo 补字段(#8779):https://git.1814.love/wx/HL/pulls/8780 | commit https://git.1814.love/wx/HL/commit/d759fba111
|
||||
- 后端负责人:@yst
|
||||
在新工单中引用
屏蔽一个用户