From 71a05449147be03203d93cc12c75ddd0de304398 Mon Sep 17 00:00:00 2001 From: yaosutu <770858045@qq.com> Date: Mon, 10 Aug 2026 22:42:28 +0800 Subject: [PATCH] =?UTF-8?q?docs(changelog):=20=E5=8D=95=E5=9B=A2=E6=A0=B8?= =?UTF-8?q?=E7=AE=97=E8=A1=A8=E6=89=A9=E5=85=85=E9=80=90=E9=A1=B9=E6=98=8E?= =?UTF-8?q?=E7=BB=86=E5=87=BA=E5=8F=82=EF=BC=88#5781=20/=20PR=20#5786?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit incomeLines[i] 新增 details 收入逐项、costCategories[i] 新增 lines 成本逐项(按 category 窄化); 配套新增 insurance_biz_type / settlement_refund_source 两个字典。纯出参增量,向后兼容。 --- ...团核算表扩充逐项明细-修改接口-管理后台.md | 680 ++++++++++++++++++ 1 file changed, 680 insertions(+) create mode 100644 changelogs-v2/2026-08/10_5781_单团核算表扩充逐项明细-修改接口-管理后台.md diff --git a/changelogs-v2/2026-08/10_5781_单团核算表扩充逐项明细-修改接口-管理后台.md b/changelogs-v2/2026-08/10_5781_单团核算表扩充逐项明细-修改接口-管理后台.md new file mode 100644 index 0000000..19fefe8 --- /dev/null +++ b/changelogs-v2/2026-08/10_5781_单团核算表扩充逐项明细-修改接口-管理后台.md @@ -0,0 +1,680 @@ +--- +schema: "hl-changelog/v2" +ticket: "5781" +title: "单团核算表扩充逐项明细出参(incomeLines.details / costCategories.lines)" +consumer: "admin" +change_type: "修改接口" +author: "yaosutu(GIT)" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "" +updated_at: "2026-08-10" +base: "dev-v3" +--- + +# 【✨ 修改接口·管理后台】单团核算表扩充逐项明细出参(#5781) + +> **PR**: #5786 | **服务**: hl-order-service-v3 | **更新时间**: 2026-08-10 + +## 1. 接口背景 + +单团核算表(GET /v3/admin/order/{orderId}/settlement/reports/group)此前只返回「4 行收入合计 + 8 行成本合计」,财务/运营在核对某一行合计时看不到它是由哪些逐项明细加总出来的,只能跳回各分类明细页签逐条对账。 + +本次变更为**纯出参增量**:在每条收入行下挂 details(收入逐项明细)、在每个成本分类下挂 lines(成本逐项明细,分类专属结构),让前端在核算表内直接展开逐项,无需再跳页签拼装。 + +**不变的部分**:顶部汇总字段(baseOrderAmount / totalCost / grossProfit 等全部金额字段)、incomeLines 仍固定 4 行、costCategories 仍固定 8 行、各行 amount 合计口径,全部与变更前一致。 + +## 2. 变更清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 查询单团核算表 | GET | /v3/admin/order/{orderId}/settlement/reports/group | 修改(出参纯增量) | incomeLines[i] 新增 details 数组;costCategories[i] 新增 lines 数组(元素结构随 category 不同而不同,按 category 窄化) | + +配套数据字典(前端可调 GET /admin/dict/data/{dictType} 动态渲染中文名): + +| 字典 type | 用途 | 本次状态 | +|-----------|------|----------| +| settlement_category | 成本分类中文名 | 已存在(不变) | +| settlement_payment_method | 付款方式中文名 | 已存在(不变) | +| settlement_report_line_type | 收入行类型中文名 | 已存在(不变) | +| insurance_biz_type | 保险业务类型中文名 | **本次新增** | +| settlement_refund_source | 人工返还来源中文名 | **本次新增** | + +## 3. 接口详情 + +### 3.1 查询单团核算表 + +- **使用场景**:核单工作台「单团核算」页签,财务/运营查看单团收入成本毛利全貌及逐项明细 +- **认证**:管理后台 JWT;房务角色(ROOM_MANAGER / HOUSE_KEEPER_LEAD)无权调用(返 581045) +- **幂等性**:是(GET 只读) +- **限流**:无 + +## 4. 接口入参 + +### 4.1 路径参数 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `orderId` | Long | ✅ | 订单 ID,必须 > 0,否则返参数校验错误 | + +### 4.2 请求体字段 + +无请求体。 + +## 5. 出参(响应) + +响应类型:`Result`(`code=200` 表示成功,`data` 为下表结构)。 + +### 5.1 顶层字段(SettlementGroupReportRespVO) + +> ⚠️ 本表全部字段与变更前一致,**本次无增删改**,列出仅为自包含。 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | String | 报表 ID(Long 序列化为字符串,无落库记录时可能缺省) | +| `orderId` | String | 订单 ID(Long 序列化为字符串) | +| `reportStatus` | String | 报表状态:`GENERATED`=已生成(实时组装)/ `CONFIRMED`=已确认(终态快照回放) | +| `baseOrderAmount` | Number | 订单应收金额,两位小数 | +| `otherIncomeAmount` | Number | 其他收入合计 | +| `discountAmount` | Number | 优惠合计(负数) | +| `adjustedReceivableAmount` | Number | 调整后应收 | +| `paidAmount` | Number | 已收金额 | +| `actualRefundedAmount` | Number | 实际退款合计(负数) | +| `netRevenueAmount` | Number | 净收入 | +| `netReceivedAmount` | Number | 实收净额 | +| `outstandingAmount` | Number | 未收尾款 | +| `hotelCost` / `ticketCost` / `mealCost` / `vehicleCost` / `guideCost` / `photographerCost` / `otherExpenseCost` / `insurancePremium` | Number | 8 个成本分类合计(住宿/门票/餐食/车辆/导游/摄影/其他支出/保险) | +| `totalCost` | Number | 成本总计 | +| `paidCost` | Number | 已付成本合计 | +| `unpaidCost` | Number | 未付成本合计 | +| `grossProfit` | Number | 毛利 | +| `grossProfitRate` | Number | 毛利率 | +| `travelerCount` | Number | 出行人数 | +| `perCapitaRevenue` / `perCapitaCost` / `perCapitaProfit` | Number | 人均收入 / 人均成本 / 人均毛利 | +| `incomeLines` | Array | 收入行,**固定 4 行**,结构见 5.2 | +| `costCategories` | Array | 成本分类行,**固定 8 行**,结构见 5.3 | +| `generatedBy` / `generatedByName` / `generatedAt` | String / String / String | 生成人 ID / 姓名 / 生成时间 | +| `confirmedBy` / `confirmedByName` / `confirmedAt` | String / String / String | 确认人 ID / 姓名 / 确认时间(未确认时缺省) | + +### 5.2 收入行(SettlementGroupIncomeLineVO) + +| 字段 | 类型 | 说明 | +|------|------|------| +| `type` | String | 行类型:`BASE_ORDER`=订单应收 / `OTHER_INCOME`=其他收入 / `DISCOUNT`=优惠 / `ACTUAL_REFUND`=实际退款 | +| `typeName` | String | 行类型中文名(字典 `settlement_report_line_type` 回填) | +| `amount` | Number | 行合计金额,两位小数;`DISCOUNT` / `ACTUAL_REFUND` 为负数 | +| `details` | Array | ✨ **本次新增**:收入逐项明细(`SettlementGroupIncomeDetailVO`),无逐项时为空数组 `[]` | + +### 5.3 收入逐项明细(SettlementGroupIncomeDetailVO)✨ 本次新增 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `itemName` | String | 项目名(订单应收 / 增费项目名 / 优惠名称 / 退款来源中文名) | +| `content` | String | 内容说明(如规格、退款原因) | +| `source` | String | 人工返还来源 code,**仅** `ACTUAL_REFUND` 下的人工返还行透出:`DRIVER_ONSITE` / `COMPANY_COMPENSATION` | +| `sourceName` | String | 人工返还来源中文名(字典 `settlement_refund_source`) | +| `unitPrice` | Number | 单价,两位小数;无单价概念时缺省 | +| `headCount` | Number | 人数;无人数概念时缺省 | +| `quantity` | Number | 数量;无数量概念时缺省 | +| `amount` | Number | 金额,两位小数;`DISCOUNT` / `ACTUAL_REFUND` 明细为负数 | +| `paymentMethod` | String | 付款方式:`CASH_PAID` / `COMPANY_PAID` / `SIGNED`;无付款方式时缺省 | +| `paymentMethodName` | String | 付款方式中文名(字典 `settlement_payment_method`) | +| `sourceType` | String | 来源类型(9 值,见 §6.6);无来源时缺省 | +| `sourceTypeName` | String | 来源中文名 | +| `remark` | String | 备注 | +| `voucherUrls` | Array<String> | 凭证 URL 数组 | + +**各 type 下 details 的内容口径**: + +| type | details 内容 | +|------|-------------| +| `BASE_ORDER` | 订单应收一行汇总(订单侧无逐项时单行) | +| `OTHER_INCOME` | 其他收入逐项 | +| `DISCOUNT` | 优惠逐项(金额取负) | +| `ACTUAL_REFUND` | 实际退款逐项:线上退款 + 人工返还(`source` = DRIVER_ONSITE / COMPANY_COMPENSATION),金额取负 | + +### 5.4 成本分类行(SettlementGroupCostCategoryVO) + +| 字段 | 类型 | 说明 | +|------|------|------| +| `category` | String | 费用类别:`HOTEL` / `TICKET` / `MEAL` / `VEHICLE` / `GUIDE` / `PHOTOGRAPHER` / `OTHER_EXPENSE` / `INSURANCE` | +| `categoryName` | String | 费用类别中文名(字典 `settlement_category`) | +| `amount` | Number | 分类合计金额,两位小数 | +| `lines` | Array | ✨ **本次新增**:成本逐项明细,**元素结构随 `category` 不同而不同**(分类专属行 VO),无逐项时为空数组 `[]`;前端按 `category` 判别窄化到 5.5~5.11 的对应结构 | + +### 5.5 成本逐项行 · HOTEL 住宿(SettlementGroupHotelLineVO)✨ + +| 字段 | 类型 | 说明 | +|------|------|------| +| `stayDate` | String | 入住日期,`yyyy-MM-dd` | +| `hotelName` | String | 酒店名称 | +| `roomTypeName` | String | 房型名称 | +| `roomCount` | Number | 房间数 | +| `unitPrice` | Number | 单价,两位小数 | +| `plannedCost` | Number | 计划成本,两位小数 | +| `amount` | Number | 核算金额(实际成本),两位小数 | +| `paymentMethod` / `paymentMethodName` | String | 付款方式 code / 中文名 | +| `sourceType` / `sourceTypeName` | String | 来源类型 code / 中文名 | +| `remark` | String | 备注 | +| `voucherUrls` | Array<String> | 凭证 URL 数组 | + +### 5.6 成本逐项行 · TICKET 门票(SettlementGroupTicketLineVO)✨ + +| 字段 | 类型 | 说明 | +|------|------|------| +| `dayDate` | String | 游玩日期,`yyyy-MM-dd` | +| `scenicName` | String | 景区/项目名称 | +| `specName` | String | 规格名称(如 成人票) | +| `ticketCount` | Number | 票数 | +| `ticketUnitPrice` | Number | 门票单价,两位小数 | +| `sellPrice` | Number | 销售价,两位小数 | +| `plannedCost` | Number | 计划成本,两位小数 | +| `amount` | Number | 核算金额(实际成本),两位小数 | +| `paymentMethod` / `paymentMethodName` | String | 付款方式 code / 中文名 | +| `sourceType` / `sourceTypeName` | String | 来源类型 code / 中文名 | +| `remark` | String | 备注 | +| `voucherUrls` | Array<String> | 凭证 URL 数组 | + +### 5.7 成本逐项行 · MEAL 餐食(SettlementGroupMealLineVO)✨ + +| 字段 | 类型 | 说明 | +|------|------|------| +| `mealDate` | String | 用餐日期,`yyyy-MM-dd` | +| `mealName` | String | 餐食名称 | +| `mealType` | String | 餐食类型:`BREAKFAST` / `LUNCH` / `DINNER` / `SELF` | +| `mealTypeName` | String | 餐食类型中文名(字典 `meal_type`) | +| `quantity` | Number | 份数 | +| `unitPrice` | Number | 单价,两位小数 | +| `amount` | Number | 核算金额(实际金额),两位小数 | +| `paymentMethod` / `paymentMethodName` | String | 付款方式 code / 中文名 | +| `sourceType` / `sourceTypeName` | String | 来源类型 code / 中文名;餐食明细无来源时缺省 | +| `remark` | String | 备注 | +| `voucherUrls` | Array<String> | 凭证 URL 数组 | + +### 5.8 成本逐项行 · VEHICLE 用车(SettlementGroupVehicleLineVO)✨ + +> 车务逐日行(VEHICLE_FEE 族)与车辆费用行(EXPENSE 族:油费/过路费等)的**稀疏并集**:每行仅本族字段非空,另一族字段整体缺省。无单价/数量概念,`dailyPrice` 即核算单价列。 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `serviceDate` | String | [VEHICLE_FEE] 服务日期,`yyyy-MM-dd` | +| `startDate` | String | [VEHICLE_FEE] 服务开始日期,`yyyy-MM-dd` | +| `endDate` | String | [VEHICLE_FEE] 服务结束日期,`yyyy-MM-dd` | +| `vehiclePlate` | String | [VEHICLE_FEE] 车牌号 | +| `vehicleModelName` | String | [VEHICLE_FEE] 车型名称 | +| `driverName` | String | [VEHICLE_FEE] 司机姓名 | +| `dailyPrice` | Number | [VEHICLE_FEE] 日单价(即核算单价列),两位小数 | +| `paymentTypeName` | String | [VEHICLE_FEE] 车务付款类型名称 | +| `amount` | Number | 核算金额,两位小数 | +| `paymentMethod` / `paymentMethodName` | String | 付款方式 code / 中文名 | +| `sourceType` / `sourceTypeName` | String | 来源类型 code / 中文名 | +| `expenseType` | String | [EXPENSE] 车辆费用类型:`FUEL` / `TOLL` / `PARKING` / `RENTAL` / `MAINTENANCE` | +| `expenseTypeName` | String | [EXPENSE] 车辆费用类型中文名(字典 `expense_type`) | +| `projectName` | String | [EXPENSE] 项目名称 | +| `expenseDate` | String | [EXPENSE] 费用发生日期,`yyyy-MM-dd` | +| `remark` | String | 备注 | +| `voucherUrls` | Array<String> | 凭证 URL 数组 | + +### 5.9 成本逐项行 · GUIDE 导游 / PHOTOGRAPHER 摄影(SettlementGroupStaffLineVO,两分类共用)✨ + +| 字段 | 类型 | 说明 | +|------|------|------| +| `serviceDate` | String | 服务日期,`yyyy-MM-dd`;无服务日时缺省 | +| `name` | String | 人员姓名 | +| `serviceType` | String | 服务类型:`GUIDE` / `PHOTOGRAPHER` | +| `serviceTypeName` | String | 服务类型中文名(字典 `staff_role`) | +| `amount` | Number | 核算金额,两位小数 | +| `paymentMethod` / `paymentMethodName` | String | 付款方式 code / 中文名 | +| `sourceType` / `sourceTypeName` | String | 来源类型 code / 中文名;无来源时缺省 | +| `remark` | String | 备注 | +| `voucherUrls` | Array<String> | 凭证 URL 数组 | + +### 5.10 成本逐项行 · OTHER_EXPENSE 其他支出(SettlementGroupOtherExpenseLineVO)✨ + +> 其他费用行(EXPENSE 族)与补贴行(SUBSIDY 族)的**稀疏并集**:每行仅本族字段非空。无单价/数量概念。 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `expenseDate` | String | 费用发生日期,`yyyy-MM-dd` | +| `projectName` | String | 项目名称 | +| `expenseType` | String | [EXPENSE] 其他费用类型:固定 `OTHER` | +| `expenseTypeName` | String | [EXPENSE] 其他费用类型中文名(字典 `expense_type`) | +| `subsidyType` | String | [SUBSIDY] 补贴类型:`PHONE` / `OVERTIME` | +| `subsidyTypeName` | String | [SUBSIDY] 补贴类型中文名(字典 `subsidy_type`) | +| `amount` | Number | 核算金额(实际金额),两位小数 | +| `paymentMethod` / `paymentMethodName` | String | 付款方式 code / 中文名 | +| `sourceType` / `sourceTypeName` | String | 来源类型 code / 中文名;无来源时缺省 | +| `remark` | String | 备注 | +| `voucherUrls` | Array<String> | 凭证 URL 数组 | + +### 5.11 成本逐项行 · INSURANCE 保险(SettlementGroupInsuranceLineVO)✨ + +| 字段 | 类型 | 说明 | +|------|------|------| +| `productName` | String | 保险产品名称 | +| `bizType` | String | 业务类型:`ORDER` / `DRIVER` | +| `bizTypeName` | String | 业务类型中文名(字典 `insurance_biz_type`,本次新增) | +| `totalPremium` | Number | 保费(即核算金额列),两位小数 | +| `extPolicyNo` | String | 外部保单号 | +| `voucherUrls` | Array<String> | 凭证 URL 数组(电子保单 PDF) | + +> 保险行无 `plannedCost` / `sourceType` 字段,不输出。 + +## 6. 枚举 / 数据字典 + +### 6.1 `incomeLines[].type`(字典 `settlement_report_line_type`) + +| 值 | 中文 | 说明 | +|----|------|------| +| `BASE_ORDER` | 订单应收 | 订单应收行 | +| `OTHER_INCOME` | 其他收入 | 其他收入行 | +| `DISCOUNT` | 优惠 | 优惠行(金额为负) | +| `ACTUAL_REFUND` | 实际退款 | 实际退款行(金额为负) | + +### 6.2 `costCategories[].category`(字典 `settlement_category`) + +| 值 | 中文 | 对应 lines 行结构 | +|----|------|-------------------| +| `HOTEL` | 住宿 | §5.5 | +| `TICKET` | 门票/游玩项目 | §5.6 | +| `MEAL` | 餐食 | §5.7 | +| `VEHICLE` | 车辆 | §5.8 | +| `GUIDE` | 导游 | §5.9 | +| `PHOTOGRAPHER` | 摄影 | §5.9(与 GUIDE 共用) | +| `OTHER_EXPENSE` | 其他支出 | §5.10 | +| `INSURANCE` | 保险 | §5.11 | + +### 6.3 `paymentMethod`(字典 `settlement_payment_method`) + +出现于:收入逐项明细、HOTEL / TICKET / MEAL / VEHICLE / 人员 / 其他支出各成本逐项行。 + +| 值 | 中文 | +|----|------| +| `CASH_PAID` | 现金已付 | +| `COMPANY_PAID` | 公司支付 | +| `SIGNED` | 签单 | + +### 6.4 `details[].source`(字典 `settlement_refund_source`,✨ 本次新增字典) + +仅 `ACTUAL_REFUND` 下人工返还行透出。 + +| 值 | 中文 | +|----|------| +| `DRIVER_ONSITE` | 司机现场返还 | +| `COMPANY_COMPENSATION` | 公司赔付 | + +### 6.5 `lines[].bizType`(字典 `insurance_biz_type`,✨ 本次新增字典) + +仅 INSURANCE 保险行。 + +| 值 | 中文 | +|----|------| +| `ORDER` | 订单险 | +| `DRIVER` | 司机险 | + +### 6.6 `sourceType`(后端枚举 SettlementDetailSourceType) + +出现于:收入逐项明细、HOTEL / TICKET / MEAL / VEHICLE / 人员 / 其他支出各成本逐项行。 + +| 值 | 中文 | +|----|------| +| `MANUAL` | 手工 | +| `HOUSE_ASSIGNMENT` | 配房结果 | +| `SCENIC_ASSIGNMENT` | 景区 | +| `ACTIVITY_ASSIGNMENT` | 游玩项目 | +| `MEAL_ASSIGNMENT` | 餐饮安排 | +| `FLEET` | 车务 | +| `STAFF_ASSIGNMENT` | 人员安排 | +| `ORDER_SURCHARGE` | 订单增费 | +| `SYSTEM` | 系统 | + +### 6.7 `lines[].mealType`(字典 `meal_type`) + +仅 MEAL 餐食行。 + +| 值 | 中文 | +|----|------| +| `BREAKFAST` | 早餐 | +| `LUNCH` | 午餐 | +| `DINNER` | 晚餐 | +| `SELF` | 自理 | + +### 6.8 `lines[].serviceType`(字典 `staff_role`) + +仅 GUIDE / PHOTOGRAPHER 人员行。本接口只会出现 `GUIDE` / `PHOTOGRAPHER` 两个值(字典另有 助理导游/领队/司机/其他,不在本接口出现)。 + +| 值 | 中文 | +|----|------| +| `GUIDE` | 导游 | +| `PHOTOGRAPHER` | 摄影师 | + +### 6.9 `lines[].expenseType`(字典 `expense_type`) + +VEHICLE 行(EXPENSE 族):`FUEL`=油费 / `TOLL`=过路费 / `PARKING`=停车费 / `RENTAL`=租车费 / `MAINTENANCE`=维修保养。 +OTHER_EXPENSE 行(EXPENSE 族):固定 `OTHER`=其他。 + +### 6.10 `lines[].subsidyType`(字典 `subsidy_type`) + +仅 OTHER_EXPENSE 行(SUBSIDY 族)。 + +| 值 | 中文 | +|----|------| +| `PHONE` | 话补 | +| `OVERTIME` | 加班补贴 | + +### 6.11 `reportStatus` + +| 值 | 中文 | 说明 | +|----|------|------| +| `GENERATED` | 已生成 | 未核单订单,实时组装 | +| `CONFIRMED` | 已确认 | 已核单(SETTLED)订单,终态快照回放 | + +## 7. 错误码 + +| code | 含义 | 触发场景 | +|------|------|----------| +| 400 | 参数校验失败 | `orderId` 缺失或 < 1 | +| 581007 | 订单不存在 | `orderId` 对应订单不存在或已删除 | +| 581045 | 房务角色无权查看订单详情,房务仅可配房 | 房务管理员 / 房务组长角色调用 | + +## 8. 示例(3 组:典型 / 边界 / 异常) + +### 8.1 典型成功(已核单订单,逐项明细完整填充) + +**请求**: + + GET /v3/admin/order/1956112233445566778/settlement/reports/group + Authorization: Bearer + (无请求体) + +**响应**(节选,仅展示本次新增结构所在的 incomeLines / costCategories,顶层汇总字段与变更前一致故省略): + +```json +{ + "code": 200, + "data": { + "id": "1957000000000000001", + "orderId": "1956112233445566778", + "reportStatus": "CONFIRMED", + "incomeLines": [ + { + "type": "BASE_ORDER", + "typeName": "订单应收", + "amount": 12800.00, + "details": [ + { + "itemName": "订单应收", + "content": "小红书(孙雷) 王彧琪", + "unitPrice": 1280.00, + "headCount": 10, + "amount": 12800.00 + } + ] + }, + { + "type": "OTHER_INCOME", + "typeName": "其他收入", + "amount": 200.00, + "details": [ + { + "itemName": "现场加收骑马费", + "unitPrice": 100.00, + "quantity": 2, + "amount": 200.00, + "paymentMethod": "CASH_PAID", + "paymentMethodName": "现金已付", + "sourceType": "ORDER_SURCHARGE", + "sourceTypeName": "订单增费", + "remark": "现场加收" + } + ] + }, + { + "type": "DISCOUNT", + "typeName": "优惠", + "amount": -500.00, + "details": [ + { + "itemName": "早鸟优惠", + "amount": -500.00 + } + ] + }, + { + "type": "ACTUAL_REFUND", + "typeName": "实际退款", + "amount": -300.00, + "details": [ + { + "itemName": "司机现场返还", + "content": "少住一晚退房差", + "source": "DRIVER_ONSITE", + "sourceName": "司机现场返还", + "amount": -300.00, + "paymentMethod": "CASH_PAID", + "paymentMethodName": "现金已付", + "remark": "现场返还现金" + } + ] + } + ], + "costCategories": [ + { + "category": "HOTEL", + "categoryName": "住宿", + "amount": 3600.00, + "lines": [ + { + "stayDate": "2026-07-30", + "hotelName": "草原明珠大酒店", + "roomTypeName": "标间", + "roomCount": 3, + "unitPrice": 400.00, + "plannedCost": 1200.00, + "amount": 1200.00, + "paymentMethod": "CASH_PAID", + "paymentMethodName": "现金已付", + "sourceType": "HOUSE_ASSIGNMENT", + "sourceTypeName": "配房结果", + "remark": "含早", + "voucherUrls": ["https://oss/v1.jpg"] + } + ] + }, + { + "category": "VEHICLE", + "categoryName": "车辆", + "amount": 1760.00, + "lines": [ + { + "serviceDate": "2026-07-30", + "startDate": "2026-07-30", + "endDate": "2026-07-31", + "vehiclePlate": "蒙A-5376", + "vehicleModelName": "坦克500", + "driverName": "司机甲", + "dailyPrice": 880.00, + "amount": 880.00, + "paymentMethod": "CASH_PAID", + "paymentMethodName": "现金已付", + "sourceType": "FLEET", + "sourceTypeName": "车务" + }, + { + "expenseType": "FUEL", + "expenseTypeName": "油费", + "projectName": "全程油费", + "expenseDate": "2026-07-31", + "amount": 880.00, + "paymentMethod": "COMPANY_PAID", + "paymentMethodName": "公司支付", + "sourceType": "FLEET", + "sourceTypeName": "车务" + } + ] + }, + { + "category": "GUIDE", + "categoryName": "导游", + "amount": 1600.00, + "lines": [ + { + "serviceDate": "2026-07-30", + "name": "导游乙", + "serviceType": "GUIDE", + "serviceTypeName": "导游", + "amount": 1600.00, + "paymentMethod": "SIGNED", + "paymentMethodName": "签单", + "sourceType": "STAFF_ASSIGNMENT", + "sourceTypeName": "人员安排" + } + ] + }, + { + "category": "INSURANCE", + "categoryName": "保险", + "amount": 150.00, + "lines": [ + { + "productName": "保游畅享境内游保险", + "bizType": "ORDER", + "bizTypeName": "订单险", + "totalPremium": 150.00, + "extPolicyNo": "PY20260730001", + "voucherUrls": ["https://oss/policy1.pdf"] + } + ] + } + ] + }, + "msg": "" +} +``` + +### 8.2 边界情况(无任何逐项明细 / 金额为 0) + +**场景说明**:订单无任何其他收入、优惠、退款,且各成本分类未录入任何逐项 —— `details` / `lines` 返回**空数组** `[]`(不是 null),对应分类 `amount` 可为 `0.00`。所有 null 的可选字段(unitPrice / headCount / paymentMethod / remark / voucherUrls 等)**整体缺省不出现在 JSON 中**。 + +**请求**: + + GET /v3/admin/order/1956112233445566889/settlement/reports/group + Authorization: Bearer + (无请求体) + +**响应**(节选): + +```json +{ + "code": 200, + "data": { + "orderId": "1956112233445566889", + "reportStatus": "GENERATED", + "incomeLines": [ + { "type": "BASE_ORDER", "typeName": "订单应收", "amount": 12800.00, "details": [ + { "itemName": "订单应收", "unitPrice": 1280.00, "headCount": 10, "amount": 12800.00 } + ] }, + { "type": "OTHER_INCOME", "typeName": "其他收入", "amount": 0.00, "details": [] }, + { "type": "DISCOUNT", "typeName": "优惠", "amount": 0.00, "details": [] }, + { "type": "ACTUAL_REFUND", "typeName": "实际退款", "amount": 0.00, "details": [] } + ], + "costCategories": [ + { "category": "HOTEL", "categoryName": "住宿", "amount": 0.00, "lines": [] }, + { "category": "TICKET", "categoryName": "门票/游玩项目", "amount": 0.00, "lines": [] }, + { "category": "MEAL", "categoryName": "餐食", "amount": 0.00, "lines": [] }, + { "category": "VEHICLE", "categoryName": "车辆", "amount": 0.00, "lines": [] }, + { "category": "GUIDE", "categoryName": "导游", "amount": 0.00, "lines": [] }, + { "category": "PHOTOGRAPHER", "categoryName": "摄影", "amount": 0.00, "lines": [] }, + { "category": "OTHER_EXPENSE", "categoryName": "其他支出", "amount": 0.00, "lines": [] }, + { "category": "INSURANCE", "categoryName": "保险", "amount": 0.00, "lines": [] } + ] + }, + "msg": "" +} +``` + +### 8.3 业务失败(订单不存在 / 房务角色越权) + +**场景说明 A**:`orderId` 不存在 → 581007。 + +**请求**: + + GET /v3/admin/order/999999999/settlement/reports/group + Authorization: Bearer + (无请求体) + +**响应**: + +```json +{ "code": 581007, "msg": "订单不存在", "data": null } +``` + +**场景说明 B**:房务管理员角色调用 → 581045。 + +```json +{ "code": 581045, "msg": "房务角色无权查看订单详情,房务仅可配房", "data": null } +``` + +## 9. 业务边界 + +- ✅ **适用场景**:订单存在即可调;未核单订单(`reportStatus=GENERATED`)走实时组装,已核单订单(`reportStatus=CONFIRMED`)走终态快照回放,**两条路径出参结构完全一致**,前端无需区分 +- ❌ **不适用场景**:房务角色(ROOM_MANAGER / HOUSE_KEEPER_LEAD)调用 → 581045 +- ⚠️ **特殊边界**: + - 逐项明细**不出已付/未付逐行列**,逐行只有单价/数量/核算金额(`paidCost` / `unpaidCost` 仍是顶层分类维度的合计口径,不在逐项层) + - VEHICLE / OTHER_EXPENSE 两分类的行是同数组内两族结构稀疏并集(见 §5.8 / §5.10),前端渲染列时按「本族字段是否出现」判别 + - `DISCOUNT` / `ACTUAL_REFUND` 行及其明细金额均为**负数**,前端不要自行取绝对值 + +## 10. 修改前后对比 + +### 10.1 字段级对比 + +| 字段 | 改前 | 改后 | +|------|------|------| +| `incomeLines[].details` | 无此字段 | ✨ 新增 `Array`,无逐项时为 `[]` | +| `costCategories[].lines` | 无此字段 | ✨ 新增 `Array`(分类专属行结构,按 `category` 窄化),无逐项时为 `[]` | +| 顶层汇总字段 / 4 行收入合计 / 8 行成本合计 | 现状 | **不变** | + +### 10.2 行为级对比 + +| 行为 | 改前 | 改后 | +|------|------|------| +| 核算表核对逐项明细 | 只能看到行合计,需跳各分类明细页签逐条对账 | 行内直接展开 `details` / `lines` 逐项 | +| 数据字典 | 无 `insurance_biz_type` / `settlement_refund_source` | ✨ 新增两个字典(保险业务类型 / 人工返还来源) | + +## 11. 影响评估 / 回滚 + +### 11.1 影响评估 + +- **是否破坏向后兼容**:否。纯出参增量,原有字段名 / 类型 / 结构 / 合计口径零变化;老前端不读 `details` / `lines` 不受影响 +- **前端是否必须同步上线**:否。前端按自身排期接入逐项展开即可 + +### 11.2 回滚方案 + +- **回滚方式**:revert PR #5786 +- **回滚后清理**:无(无 DDL、无缓存、无脏数据;两个字典 `insurance_biz_type` / `settlement_refund_source` 保留无害) + +## 12. 注意事项 + +- **null 字段整体缺省**:所有行 VO 标注了 null 不序列化,可选字段(unitPrice / headCount / quantity / paymentMethod / sourceType / remark / voucherUrls 等)为 null 时**该 key 不出现在 JSON 中**,前端按可选字段处理,不要断言 key 必存在 +- `details` / `lines` 无逐项时是**空数组 `[]`** 而不是字段缺省,可直接 `.length` 判空 +- **行结构窄化**:`costCategories[].lines` 元素是多态结构,前端必须先按 `category` 判别再取分类专属字段(GUIDE / PHOTOGRAPHER 共用人员行结构) +- **金额符号**:`DISCOUNT` / `ACTUAL_REFUND` 的行金额与明细金额均为负数;成本各行为正数 +- **中文名渲染**:`*Name` 字段后端已回填中文名(字典缺值时回退硬编码),可直接展示;如需动态字典渲染,调 `GET /admin/dict/data/{dictType}`,dictType 见 §6 各子节 +- 无历史 workaround 需要清理(本能力此前不存在) + +## 13. 关联 / 联系人 + +### 13.1 链接 + +- **Issue**: [#5781](https://git.1814.love:8443/wx/HL/issues/5781) +- **PR**: [#5786](https://git.1814.love:8443/wx/HL/pulls/5786) +- **Merge commit**: [fdc429bf](https://git.1814.love:8443/wx/HL/commit/fdc429bf8546ce2cbb8c69f4166b153cccb4839c) + +### 13.2 联系人 + +- **后端负责人**: @yaosutu