docs(changelog): order-v3 接口契约审计修复 W1(金额String+被保人脱敏+退款筛选+投保幂等) PR #3965

这个提交包含在:
API Changelog Bot 2026-06-18 12:34:29 +08:00
父节点 05fa996c27
当前提交 bc50894a09

查看文件

@ -0,0 +1,97 @@
# 订单服务v3 接口契约审计修复W1 钱/状态热区:金额=String + 被保人脱敏 + 退款筛选 + 投保幂等)— 修改接口 — 管理后台
> 变更类型:⚠️ 序列化口径变更(金额字段改 String+ 安全收紧PII 脱敏)+ 行为收紧(投保幂等)+ 数据补全(退款筛选/派生字段),无破坏性删除
> 端类型:管理后台(保险 / 订单 / 支付 / 退款 / 结算 / 调价 / 折扣 / 班期)
> 日期2026-06-18
> 服务hl-order-service-v3
> PRhttps://git.1814.love:8443/wx/HL/pulls/3965
---
## ⚠️ 关键说明
`api-contract-audit` workflow 对 order-v3 钱/状态关键热区 14 个 Controller 做语义审计(实现 声明契约 设计文档 7 维度业务规则)+ 对抗式复核,97 发现 → 50 确认P0=0/P1=17/P2=19/P3=14,本批修复其中 32 条清晰契约 bug。已合并 dev-v3、部署测试服双实例totalCodes=626、本地全量 3566 单测零净增回归、测试服 9443 + 真 admin token 行为实测通过。
**前端最需关注:第 1 条金额字段序列化口径变更(解析方式要改)。**
---
## 1. 🔴 金额字段统一改为 String解析口径变更,前端必看
平台铁律「JSON 金额必为 String」此前在 order-v3 多处 RespVO 漏标 `@JsonSerialize(ToStringSerializer)`,金额被序列化成 JSON number。本次全部补齐,**这些字段从「数字」变为「带引号字符串」**
| 端点 | VO / 字段 |
|---|---|
| `GET /v3/admin/order/{id}/finance` | FinanceVO 全部金额 + 内部 payments/discounts/surcharges.amount |
| `GET /v3/admin/order` 列表 / `GET /v3/admin/order/list` | 列表项 totalAmount/paidAmount/balanceAmount/depositAmount/singleRoomSurcharge |
| `GET /v3/admin/order/{id}/refund`(退款 Tab | totalRefundAmount/refundAmount/amount |
| `POST /v3/admin/order/{id}/cancel/pre-trip``/terminate``GET /cancel-preview` | refundAmount/baselineRefund/adjustAmount/finalRefund/paidAmount/deductAmount |
| `GET /v3/admin/payment/list``/{transactionId}``/order/{orderId}` | PaymentTransactionVO.totalAmount / PaymentListItemRespVO.amount |
| `GET /v3/admin/order/{orderId}/payment/list` | amount |
| `GET /v3/admin/refund/{refundId}` 等退款记录 | RefundRecordVO.refundAmount/totalAmount |
| 折扣 5 端点 / 结算各保存与汇总 / 调价 / 保险方案 preview-apply / 保险方案保费 | 各金额字段 |
比率字段profitRate 等)仍为数字,不受影响。
示例(支付列表):
```json
{ "code": 200, "data": { "records": [ { "totalAmount": "1500.00" } ] } } // 此前是 1500.00(数字)
```
前端请用字符串解析金额(`new Decimal(str)` / `parseFloat(str)`),勿假设为 number。
---
## 2. 被保人证件号 / 手机号脱敏(安全收紧)
此前以下端点返回的 `insuredPersons[].idNo / idCardNo / phone` 为**明文**VO 声明「脱敏」但实现直塞解密值)。本次在装配处统一脱敏(前 3 后 4,与司机险链口径一致
| 端点 |
|---|
| `GET /v3/admin/insurance/orders/{id}`(详情) |
| `GET /v3/admin/insurance/coverage/{orderId}` |
| `GET /v3/internal/insurance/coverage/{orderId}` |
| `POST /v3/admin/insurance/purchase` / `selective-purchase` / `orders/{id}/sync-status`(返回详情) |
```json
{ "insuredPersons": [ { "idNo": "152***********5216", "phone": "138****8000" } ] }
```
如管理端确需明文,需另开专用解密端点(产品决策,见 PR
---
## 3. 退款申请分页:筛选维度补齐 + 派生字段填充
`GET /v3/admin/refund/application/page` 此前声称支持多维筛选但实现全部忽略(仅分页 + createTime 倒序)。本次补齐:
- **筛选**(均可选):`orderId` / `orderNo`(模糊)/ `applicantName`(模糊)/ `applicantId` / `status`(多选)/ `auditStatus` / `createTimeFrom`-`createTimeTo` / `refundedAtFrom`-`refundedAtTo`
- **排序**`sortField`(白名单 createTime/refundedAt/actualAmount+ `sortOrder`ASC/DESC,默认 createTime DESC
- **派生字段填充**`reviewerNameLast`(最后审核人)、`refundRecordCount`(退款执行记录数)此前恒 null,现批量回填
- **移除字段**`appealRoundCount`refund_appeal 表已于 V20260527_001 DROP,该字段永不可填,删除避免误导
---
## 4. 投保幂等防护(行为收紧)
`POST /v3/admin/insurance/purchase`(手动投保)/ `selective-purchase`(选择性投保)此前无幂等/锁,重复提交会重复出单扣保费。本次加 `@Idempotent + @Lock4j`(按 orderId 串行 + 业务键去重),**短时间内完全相同的重复请求会被拦截**,前端无须额外处理但可知悉。
---
## 5. 其它(前端基本无感 / 字典对齐)
- **支付交易状态字典**`FAILED``REFUNDED`(对齐枚举/DB;此前 notes/VO/DTO 写的 FAILED 实际无法存储)。状态取值:`PENDING/SUCCESS/CLOSED/REFUNDED`
- **新增错误码 `589516`**:团期共享成本录入的成本类型非法(此前抛裸异常)。
- **保单下载 notes 修正**`GET /v3/internal/insurance/policy/{id}/download` 返回的是 **OSS 下载 URL 字符串**(非 Base64,未生成返 540310 / 手工单返 540226。
- **保险方案删除**:删除前引用校验只统计在途/生效保单INSURED/INSURING,历史退保/失败单不再永久拦死删除。
- **保险方案 toggle-status**:改为原子操作(消除并发读改写竞态)。
- **被保人 gender**新投保单详情正确返回性别1=男/2=女/0=未知);修复前的历史单仍可能为 null不回填历史
- 删除若干孤儿字段(保险方案 autoInsure/segmentType/destinationCode 等声明但从未赋值)。
---
## 备注
- P3 + 低置信发现暂未处理;以下**产品/行为决策项**未改行为,待确认:删退款政策语义(禁删 vs 软删降级)、结算 step6 金额公式与状态语义、后台建单幂等键定义、班期结算 D1/D2 返回结构、preview-apply 覆盖参数、PARTIAL 部分退款语义、transition 的 Map payload。
- **结算 step6 逻辑补全**confirmCheckHash 校验 / OrderSettledEvent MQ / Step 前置校验 / Step3 响应字段 / insurance_premium 实值建议独立工单P1,重型