diff --git a/changelogs-v2/2026-08/10_5809_完成核单去凭据-修改接口-管理后台.md b/changelogs-v2/2026-08/10_5809_完成核单去凭据-修改接口-管理后台.md new file mode 100644 index 0000000..e7fc244 --- /dev/null +++ b/changelogs-v2/2026-08/10_5809_完成核单去凭据-修改接口-管理后台.md @@ -0,0 +1,328 @@ +--- +schema: "hl-changelog/v2" +ticket: "5809" +title: "完成核单去转账/签字凭据采集:finalize 改无请求体,主报账对账与报账表删除凭据字段" +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" +--- + +# 【⚠️ 修改接口·管理后台】完成核单去转账/签字凭据采集:finalize 改无请求体,recon 入参删 4 字段,报账表出参删 4 字段(#5809) + +> **PR**: [#5813](https://git.1814.love:8443/wx/HL/pulls/5813) | **服务**: hl-order-service-v3 | **更新时间**: 2026-08-10 + +## 1. 接口背景 + +核单流程此前在「完成核单」和「主报账对账保存」两个环节采集转账/签字凭据:转账日期、转账流水号、预支是否已处理、签字凭证文件(图片 + 备注)。产品上决定凭据采集不再挂在核单链路(核单只负责核算确认,凭据留档走线下或其他系统),因此本次把凭据相关字段从 3 个接口整体摘除: + +- **完成核单 finalize**:整个请求体删除,改为仅 Path 传 orderId 的无 body 接口; +- **主报账对账保存 recon**:入参只保留 transferStatus,删 4 个凭据字段及其必填校验; +- **主报账人报账表 GET**:出参删同样 4 个凭据字段,报账弹窗改纯展示。 + +> ⚠️ 本次为**入参删字段 + 出参删字段的硬破坏契约**:相关 ReqVO 配置了 ignoreUnknown=false,前端若继续传已删字段会直接 400,**前后端必须同批上线**(详见 §11、§12)。 + +## 2. 变更清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 前端动作 | +|---|---|---|---|---|---| +| 1 | 完成核单 | POST | /v3/admin/order/{orderId}/settlement/finalize | 删除整个请求体(原 SettlementSubmitReqVO:remark + reimbursementConfirmation 凭据对象) | 请求不再带 body;清理凭据表单/校验逻辑 | +| 2 | 主报账对账保存 | PUT | /v3/admin/order/{orderId}/settlement/recon | 入参删 transferDate / transferRef / advanceSettledFlag / signedVoucher,仅保留 transferStatus | 请求体只传 transferStatus;清理凭据表单 | +| 3 | 主报账人报账表 | GET | /v3/admin/order/{orderId}/settlement/reports/reimbursement | 出参删 transferDate / transferRef / advanceSettledFlag / signedVoucher | 停读 4 字段;报账弹窗删凭据展示区 | + +## 3. 接口详情 + +- **使用场景**: + - finalize:管理后台核单页面对账完成后点击「完成核单」,把订单核算推进到终态(落 FINALIZED 快照)。 + - recon:主报账对账弹窗保存转账状态(待转账 / 已转账)。 + - reports/reimbursement:主报账人报账表弹窗,展示主报账人收付对账与转账结论。 +- **认证**:需要管理后台登录态(Bearer Token);房务角色(HOUSE)被 OrderViewGuard 拦截。 +- **幂等性**: + - finalize:改为纯终态校验,已有 FINALIZED 快照且终态一致时直接返回原结果,**天然幂等**,重复点击无副作用。 + - recon:同一 transferStatus 重复保存为覆盖写,幂等。 + - reports/reimbursement:只读查询,天然幂等。 +- **限流**:未声明接口专属限流。 + +## 4. 接口入参 + +### 4.1 路径参数 + +三个接口一致: + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| orderId | Long | 是 | 订单 ID,路径参数,必须大于 0 | + +### 4.2 请求体字段 + +#### POST /v3/admin/order/{orderId}/settlement/finalize(完成核单) + +**无请求体**。原 SettlementSubmitReqVO 整体删除,被删字段如下(前端不得再传): + +| 原字段 | 类型 | 原说明 | 现状 | +|---|---|---|---| +| remark | String | 核单整体备注 | 已删除;服务端不再写 settlement_summary.remark | +| reimbursementConfirmation | Object | 凭据对象 | 已删除 | +| reimbursementConfirmation.transferDate | String(yyyy-MM-dd) | 转账日期 | 已删除 | +| reimbursementConfirmation.transferRef | String | 转账流水号 | 已删除 | +| reimbursementConfirmation.advanceSettledFlag | Boolean | 预支是否已处理 | 已删除 | +| reimbursementConfirmation.signedVoucher | Object | 签字凭证,含 files[{name,url}] + note | 已删除 | + +> 原「reporterNetAmount 非 0 时强制 transferDate / transferRef 必填」的服务端校验同步移除;原 finalize 凭据校验失败错误码 584317 在此接口不再触发。 + +#### PUT /v3/admin/order/{orderId}/settlement/recon(主报账对账保存) + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| transferStatus | String | 是 | 转账状态,枚举:PENDING(待转账)/ COMPLETED(已转账) | + +被删字段(前端不得再传,传了会 400): + +| 原字段 | 类型 | 原说明 | 现状 | +|---|---|---|---| +| transferDate | String(yyyy-MM-dd) | 转账日期 | 已删除 | +| transferRef | String | 转账流水号 | 已删除 | +| advanceSettledFlag | Boolean | 预支是否已处理 | 已删除 | +| signedVoucher | Object | 签字凭证,含 files[{name,url}] + note | 已删除 | + +> 原「transferStatus=COMPLETED 时 transferRef 必填」校验同步移除。 + +#### GET /v3/admin/order/{orderId}/settlement/reports/reimbursement(主报账人报账表) + +无请求体、无 Query 参数,入参零变化。 + +## 5. 出参字段 + +### 5.1 POST finalize / PUT recon + +统一响应 Result 包装,data 为操作结果(成功 code=200)。出参结构无变化。 + +### 5.2 GET /v3/admin/order/{orderId}/settlement/reports/reimbursement(主报账人报账表) + +统一响应 Result 包装,data 字段如下(仅列关键字段 + 本次删除项): + +| 字段 | 类型 | 说明 | +|---|---|---| +| id | String(Long) | 报表记录 ID;未落库时可为 null | +| orderId | String(Long) | 订单 ID | +| reportStatus | String | 报表状态:GENERATED / CONFIRMED | +| primaryReporterId | String(Long) | 主报账人人员安排 ID | +| primaryReporterName | String | 主报账人姓名 | +| primaryReporterRole | String | 主报账人角色(如 DRIVER) | +| reportVersion | Integer | 报表版本号 | +| driverCollectedTailAmount | String(BigDecimal) | 司机代收尾款 | +| approvedAdvanceAmount | String(BigDecimal) | 已审批预支金额 | +| reportablePaidCostAmount | String(BigDecimal) | 可报账已付成本 | +| reporterNetAmount | String(BigDecimal) | 报账人净额 | +| primaryReporterCollectedAmount | String(BigDecimal) | 主报账人已收款 | +| publicPrepaidAmount | String(BigDecimal) | 对公预付金额 | +| primaryReporterDueAmount | String(BigDecimal) | 主报账人应结金额 | +| advanceOutstandingAmount | String(BigDecimal) | 预支未销余额 | +| reconNetAmount | String(BigDecimal) | 对账净额 | +| transferDirection | String | 转账方向 | +| transferAmount | String(BigDecimal) | 转账金额 | +| incomeLines | Array | 收款行;每项含 type / typeName / receiptId / amount / channel / channelName / payType / payTypeName / collectorStaffId / collectorName / collectorRole / collectorRoleName / receivedAt / remark | +| expenseLines | Array | 支出行;每项含 kind / category / categoryName / amount / paymentMethod / paymentMethodName / voucherUrls / remark + 类别扩展字段 | +| advanceLines | Array | 预支行 | +| vehicleLines | Array | 已确认车辆逐日费用明细;无数据固定返回空数组 | +| transferStatus | String | 转账状态(PENDING / COMPLETED),保留 | +| ~~transferDate~~ | - | **已删除**,前端不再收到此字段 | +| ~~transferRef~~ | - | **已删除** | +| ~~advanceSettledFlag~~ | - | **已删除** | +| ~~signedVoucher~~ | - | **已删除** | +| generatedBy / generatedByName / generatedAt | - | 生成人 ID / 姓名 / 时间 | +| confirmedBy / confirmedByName / confirmedAt | - | 确认人 ID / 姓名 / 时间 | + +> 除删除 4 个凭据字段外,其余字段名称、类型、语义均无变化。前端不要再读取这 4 个字段,读取结果恒为 undefined。 + +## 6. 枚举 / 数据字典 + +### transferStatus(recon 入参 + 报账表出参共用) + +| 值 | 含义 | 本次变化 | +|---|---|---| +| PENDING | 待转账 | 不变 | +| COMPLETED | 已转账 | 不变(原「COMPLETED 时 transferRef 必填」联动校验移除) | + +其余枚举/字典(reportStatus、incomeLines[].type、channel、payType、paymentMethod、transferDirection 等)取值与语义均无变化。 + +## 7. 错误码 + +| 错误码 | 含义 | 本次变化 | +|---|---|---| +| 400(参数校验) | 请求体含未知字段 | **新增触发路径**:ReqVO ignoreUnknown=false,前端继续传已删凭据字段(recon / finalize)会直接返回 400 | +| 584317 | 原 finalize 凭据校验失败(transferDate/transferRef 缺失等) | **此接口不再触发**(凭据校验整体移除) | + +其余既有错误码(订单不存在、双报告未生成保护 584311 / 584313、房务角色 403 等)行为不变。 + +## 8. 示例 + +### 8.1 典型成功(完成核单,无请求体) + +```http +POST /v3/admin/order/2084000000000002978/settlement/finalize +Authorization: Bearer +Content-Length: 0 +``` + +```json +{ + "code": 200, + "message": "success", + "data": null, + "success": true +} +``` + +> 注意:请求不带任何 body。幂等——已有 FINALIZED 快照且终态一致时重复调用直接返回原结果。 + +主报账对账保存(只传 transferStatus): + +```http +PUT /v3/admin/order/2084000000000002978/settlement/recon +Authorization: Bearer +Content-Type: application/json + +{"transferStatus": "COMPLETED"} +``` + +```json +{"code": 200, "message": "success", "data": null, "success": true} +``` + +### 8.2 边界(报账表出参已无凭据字段) + +```http +GET /v3/admin/order/2084000000000002978/settlement/reports/reimbursement +Authorization: Bearer +``` + +```json +{ + "code": 200, + "message": "success", + "data": { + "id": "8802", + "orderId": "2084000000000002978", + "reportStatus": "GENERATED", + "primaryReporterId": "7001", + "primaryReporterName": "司机甲", + "primaryReporterRole": "DRIVER", + "reportVersion": 1, + "driverCollectedTailAmount": "0.00", + "approvedAdvanceAmount": "0.00", + "reportablePaidCostAmount": "0.00", + "reporterNetAmount": "0.00", + "primaryReporterCollectedAmount": "0.00", + "publicPrepaidAmount": "0.00", + "primaryReporterDueAmount": "0.00", + "advanceOutstandingAmount": "0.00", + "reconNetAmount": "0.00", + "transferDirection": null, + "transferAmount": "0.00", + "incomeLines": [], + "expenseLines": [], + "advanceLines": [], + "vehicleLines": [], + "transferStatus": "PENDING", + "generatedBy": "1001", + "generatedByName": "张三", + "generatedAt": "2026-08-10 10:20:30", + "confirmedBy": null, + "confirmedByName": null, + "confirmedAt": null + }, + "success": true +} +``` + +> 响应中已无 transferDate / transferRef / advanceSettledFlag / signedVoucher 四个字段(不是返回 null,是字段不存在)。 + +### 8.3 业务失败(前端仍传已删字段 → 400) + +```http +PUT /v3/admin/order/2084000000000002978/settlement/recon +Authorization: Bearer +Content-Type: application/json + +{"transferStatus": "COMPLETED", "transferRef": "202608100001"} +``` + +```json +{"code": 400, "message": "请求参数格式错误(含未识别字段 transferRef)", "data": null, "success": false} +``` + +> ReqVO ignoreUnknown=false,任何已删字段(transferDate / transferRef / advanceSettledFlag / signedVoucher / remark / reimbursementConfirmation)传入都会 400。这是本次最需要前端规避的失败路径。 + +## 9. 业务边界 + +- ✅ 完成核单只需订单处于可核单终态 + 双报告已生成(584311 / 584313 保护不变),不再要求任何凭据。 +- ✅ recon 只需选择转账状态(PENDING / COMPLETED),COMPLETED 也不再要求转账流水号。 +- ✅ 报账表弹窗改为纯展示核算数据 + 转账状态,无凭据上传/回填交互。 +- ❌ 不要在前端保留凭据采集表单(转账日期/流水号/预支处理标记/签字凭证上传),继续提交会 400。 +- ❌ 不要把本地缓存/草稿里的凭据数据回传到 finalize 或 recon。 +- ❌ 订单历史凭据数据仍在库中(零 DDL,列未删),但接口不再返回;不要依赖报账表接口读取历史凭据。 + +## 10. 修改前后对比 + +### 10.1 字段级对比 + +| 接口 | 字段 | 原来 | 现在 | +|---|---|---|---| +| POST finalize | 请求体整体 | SettlementSubmitReqVO(remark + reimbursementConfirmation{transferDate, transferRef, advanceSettledFlag, signedVoucher{files[{name,url}], note}}) | **无请求体**,仅 Path 传 orderId | +| PUT recon | transferDate / transferRef / advanceSettledFlag / signedVoucher | 入参(transferStatus=COMPLETED 时 transferRef 必填) | **已删除**,入参仅保留 transferStatus | +| GET reports/reimbursement | transferDate / transferRef / advanceSettledFlag / signedVoucher | 出参 | **已删除**,其余出参不变 | + +### 10.2 行为级对比 + +| 场景 | 原来 | 现在 | +|---|---|---| +| 完成核单时 reporterNetAmount 非 0 | 强制要求 transferDate / transferRef,缺失报 584317 | 无任何凭据校验,直接走终态确认 | +| 完成核单提交备注 remark | 写入 settlement_summary.remark | 不再接收、不再写入 | +| recon 保存 transferStatus=COMPLETED | transferRef 必填 | 仅保存 transferStatus | +| 报账表弹窗 | 展示并可回填凭据区 | 纯展示,无凭据字段 | +| finalize 终态快照比对 | 含凭据字段比对 | 不再比对凭据 | +| finalize 重复调用 | 凭据差异可能导致非幂等 | 纯终态校验,终态一致直接返回原结果,天然幂等 | + +## 11. 影响评估 / 回滚 + +### 11.1 影响评估 + +- **是否破坏向后兼容**:**是,硬破坏**。finalize 请求体删除 + recon 入参删 4 字段 + 报账表出参删 4 字段;且 ReqVO ignoreUnknown=false,旧前端继续传凭据字段会直接 400(不是静默忽略)。 +- **前端是否必须同步上线**:**必须同批**。前端需先删掉凭据表单与字段读取,再与后端同批发布。 +- **上线顺序边界**:前后端同批发布;若必须分先后,**先上前端(停传/停读凭据字段),再上后端**。旧前端 + 新后端 = finalize / recon 直接 400,功能不可用。 +- **数据库侧**:**零 DDL**,数据库列未动,历史凭据数据保留在库中(接口不再读写),无数据迁移成本。 + +### 11.2 回滚方案 + +- 代码回滚即恢复原请求体/入参/出参与凭据校验;数据库无变更,历史数据完整,回滚无数据修复成本。 +- **回滚必须前后端同批回滚**:新前端(不传凭据)+ 旧后端(reporterNetAmount 非 0 强制凭据)会导致 finalize 报 584317 失败。 + +## 12. 注意事项 + +- **契约破坏红线**:相关 ReqVO 配置了 ignoreUnknown=false,前端**继续传任何已删字段都会 400**(不是忽略)。包括:finalize 的 remark / reimbursementConfirmation 整个对象,recon 的 transferDate / transferRef / advanceSettledFlag / signedVoucher。前后端必须同批上线。 +- 本次只动凭据采集相关字段;订单金额核算逻辑、reportStatus 枚举、双报告生成/确认保护(584311 / 584313)均未变化。 +- finalize 的 Swagger 描述中若残留凭据相关文案属文档残留,以本 changelog 为准。 +- 小程序端(/v3/mp/*)不涉及本次变更,无需任何改动。 + +## 13. 关联 / 联系人 + +### 13.1 链接 + +- **Issue**: [#5809](https://git.1814.love:8443/wx/HL/issues/5809) +- **PR**: [#5813](https://git.1814.love:8443/wx/HL/pulls/5813) +- **Commit**: [0e2ee34d6d](https://git.1814.love:8443/wx/HL/commit/0e2ee34d6d) +- **相关批次**: Issue [#5739](https://git.1814.love:8443/wx/HL/issues/5739) / PR [#5764](https://git.1814.love:8443/wx/HL/pulls/5764)(核单指纹下线,changelog 见 2026-08/09_5739) + +### 13.2 联系人 + +- **后端负责人**: @yaosutu (yst) 腰苏图