hl-api-changelog/changelogs-v2/2026-06/18_3965_订单v3接口契约审计修复W1-金额String+被保人脱敏+退款筛选+幂等-修改接口-管理后台.md

6.2 KiB

订单服务v3 接口契约审计修复W1 钱/状态热区:金额=String + 被保人脱敏 + 退款筛选 + 投保幂等)— 修改接口 — 管理后台

变更类型:⚠️ 序列化口径变更(金额字段改 String+ 安全收紧PII 脱敏)+ 行为收紧(投保幂等)+ 数据补全(退款筛选/派生字段),无破坏性删除 端类型:管理后台(保险 / 订单 / 支付 / 退款 / 结算 / 调价 / 折扣 / 班期) 日期2026-06-18 服务hl-order-service-v3 PRwx/HL#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/terminateGET /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 等)仍为数字,不受影响。

示例(支付列表):

{ "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(返回详情)
{ "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+ sortOrderASC/DESC,默认 createTime DESC
  • 派生字段填充reviewerNameLast(最后审核人)、refundRecordCount(退款执行记录数)此前恒 null,现批量回填
  • 移除字段appealRoundCountrefund_appeal 表已于 V20260527_001 DROP,该字段永不可填,删除避免误导

4. 投保幂等防护(行为收紧)

POST /v3/admin/insurance/purchase(手动投保)/ selective-purchase(选择性投保)此前无幂等/锁,重复提交会重复出单扣保费。本次加 @Idempotent + @Lock4j(按 orderId 串行 + 业务键去重),短时间内完全相同的重复请求会被拦截,前端无须额外处理但可知悉。


5. 其它(前端基本无感 / 字典对齐)

  • 支付交易状态字典FAILEDREFUNDED(对齐枚举/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,重型