hl-api-changelog/changelogs/2026-05/23_2930_admin代用户发起退款接口-新增接口-管理后台.md
yaosutu 905e64ee42 chore: 修正路径 changelogs-v2/ -> changelogs/ (admin代用户发起退款接口)
PR #2932 / Issue #2930 的 changelog 原推到了 changelogs-v2/, 但按
最新约定一期老前端走 changelogs/ 默认目录, changelogs-v2/ 仅给 v3 项目仓。
本次为 admin 改动应在 changelogs/, 故 git mv 修正路径。

原 commit: e3ca303 (保留, 不 force push)
2026-05-23 10:55:09 +08:00

13 KiB

[新增接口·管理后台] admin H5 客服代用户发起退款 (#2930)

PR: #2932 | 服务: hl-order-service-v2 | 更新时间: 2026-05-23 10:30

1. 接口背景

管理后台 H5 客服操作台需要支持定制师/客服代用户发起退款申请。现有小程序端退款接口由用户自助发起,不适用客服代操作场景。

本接口允许客服在 H5 操作台手动填写退款金额并代用户提交,后端校验金额不超过订单订金金额,申请人留痕为 ADMIN 类型,创建后仍走主管审批流程。

2. 变更清单

# 接口 方法 路径 变更类型 说明
1 代用户发起退款申请 POST /admin/order/refund/apply 新增 客服 H5 代用户提交退款,金额客服手填,不超订金

3. 接口详情

3.1 代用户发起退款申请

  • 使用场景:客服在 H5 操作台查看订单后,代用户发起退款申请
  • 认证:需要管理后台 JWTBearer Token,adminId 由后端从 Token 中提取
  • 幂等性是,Header 携带 Idempotent-KeyUUID,5 秒内重复提交视为同一请求
  • 限流:无

调用前置步骤:先调 GET /admin/order/refund/reason/list 获取退款原因字典,拿到 reasonValue字典 key和 reasonText字典显示文本后再调本接口。

4. 接口入参

4.1 路径参数 / Query 参数

无。

4.2 请求体字段

字段 类型 必填 说明 校验规则
orderId Long 订单 ID 不能为空
amount BigDecimal 退款金额 最小 0.01,且不能超过订单订金金额
reasonValue String 退款原因字典值 从 /admin/order/refund/reason/list 获取;最长 100 字符
reasonText String 退款原因文本 字典对应的显示文本;最长 500 字符
reasonDetail String 补充说明 最长 2000 字符

注意refundType 无需前端传入,后端固定设置为 DEPOSIT订金退款

5. 出参(响应)

5.1 响应结构

Result<RefundApplicationVO>

5.2 响应字段

字段 类型 说明
applicationId Long 退款申请 ID
orderId Long 订单 ID
orderNo String 订单号
productName String 产品名称
refundType String 退款类型,本接口固定返回 DEPOSIT
refundTypeLabel String 退款类型标签,固定返回 订金退款
reasonText String 退款原因文本
reasonDetail String 补充说明(可为 null
paidAmount BigDecimal 订单已付金额
calculatedAmount BigDecimal 本次退款金额(即客服填写的 amount
actualAmount BigDecimal 实际退款金额(审批后确认,初始为 null
status String 退款申请状态,创建后固定返回 PENDING
statusLabel String 退款状态标签,创建后固定返回 待审核
applicantType String 申请人类型,固定返回 ADMIN
applicantId Long 申请人管理员 ID
applicantName String 申请人姓名
createTime String (ISO 8601) 申请创建时间
updateTime String (ISO 8601) 最后更新时间
reviewAdminId Long 审批人 ID创建时为 null,审批后填充
reviewAdminName String 审批人姓名(创建时为 null
reviewRemark String 审批备注(创建时为 null
reviewedAt String (ISO 8601) 审批时间(创建时为 null
approvalNo String 审批单号(创建时为 null
departureDate String (yyyy-MM-dd) 出发日期
daysBeforeDept Integer 距出发天数
refundRatio Integer 退款比例(百分比,本接口为 null,不调退款政策
policyId Long 退款政策 ID本接口为 null
policyName String 退款政策名称(本接口为 null
appealStatus Integer 申诉状态(创建时为 null
appealStatusLabel String 申诉状态标签(创建时为 null
appealReason String 申诉原因(创建时为 null
appealAmount BigDecimal 申诉退款金额(创建时为 null
appealedAt String (ISO 8601) 申诉时间(创建时为 null
refundedAt String (ISO 8601) 退款完成时间(创建时为 null

本接口创建的申请policyId / policyName / refundRatio 均为 null客服手填金额,不走退款政策计算

6. 枚举 / 数据字典

6.1 refundType退款类型,出参字段

所属字段refundType | 类型String | 本接口固定为 DEPOSIT

中文 说明
FULL 全额退款 全额退还已付金额
PARTIAL 部分退款 部分退款
DEPOSIT 订金退款 仅退还订金部分,本接口固定此类型
BALANCE 尾款退款 仅退还尾款部分

6.2 status退款申请状态,出参字段

所属字段status | 类型String | 创建后固定为 PENDING

中文 说明
PENDING 待审核 申请已提交,等待主管审批
APPROVED 已通过 主管审批通过,进入退款流程
REJECTED 已拒绝 主管审批拒绝
APPEALING 申诉中 用户对拒绝结果申诉
APPEAL_APPROVED 申诉通过 申诉被通过
APPEAL_REJECTED 申诉拒绝 申诉被拒绝
REFUNDING 退款中 正在处理退款
REFUNDED 已退款 退款已完成
CANCELLED 已取消 申请已撤回取消

活跃状态同订单已有此类状态时拒绝重复提交PENDING / APPROVED / REFUNDING / APPEALING / APPEAL_APPROVED

6.3 applicantType申请人类型,出参字段

所属字段applicantType | 类型String | 本接口固定为 ADMIN

中文 说明
USER 用户 小程序用户自助发起mp 接口)
ADMIN 管理员 客服/定制师代发起(本接口)

6.4 reasonValue退款原因字典值,入参字段

所属字段reasonValue | 类型String | 必填:是

字典值通过 GET /admin/order/refund/reason/list 接口获取,下面为示例(以实际字典接口返回为准):

值(示例) 中文
schedule_conflict 行程冲突/时间变动
personal_reason 个人原因
product_issue 产品问题
service_complaint 服务投诉

实际可用值以 GET /admin/order/refund/reason/list 返回为准。

7. 错误码

code 含义 触发场景
200 成功 退款申请创建成功
401 未授权 未携带或 Token 无效/过期
404 订单不存在 orderId 对应的订单不存在
530007 退款金额超过订金金额 amount 大于订单 depositAmount,message 含具体金额:退款金额不能超过订金金额: amount={x}, deposit={y}
530004 重复退款申请 同一订单已存在 ACTIVE 状态的退款申请

8. 示例

8.1 典型成功

场景说明:客服代用户发起订金退款,退 500 元,选择行程冲突原因。

请求:

POST /admin/order/refund/apply
Authorization: Bearer <admin-jwt>
Idempotent-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Content-Type: application/json
{
  "orderId": 1234567890123,
  "amount": 500.00,
  "reasonValue": "schedule_conflict",
  "reasonText": "行程冲突/时间变动",
  "reasonDetail": "客户因工作变动无法出行,需要退款"
}

响应:

{
  "code": 200,
  "data": {
    "applicationId": 9876543210001,
    "orderId": 1234567890123,
    "orderNo": "HL2026052300001",
    "productName": "云南大理双廊古镇 5 日深度游",
    "refundType": "DEPOSIT",
    "refundTypeLabel": "订金退款",
    "reasonText": "行程冲突/时间变动",
    "reasonDetail": "客户因工作变动无法出行,需要退款",
    "paidAmount": 2000.00,
    "calculatedAmount": 500.00,
    "actualAmount": null,
    "policyId": null,
    "policyName": null,
    "refundRatio": null,
    "status": "PENDING",
    "statusLabel": "待审核",
    "applicantType": "ADMIN",
    "applicantId": 10086,
    "applicantName": "李小明",
    "departureDate": "2026-06-15",
    "daysBeforeDept": 23,
    "reviewAdminId": null,
    "reviewAdminName": null,
    "reviewRemark": null,
    "reviewedAt": null,
    "approvalNo": null,
    "appealStatus": null,
    "appealStatusLabel": null,
    "appealReason": null,
    "appealAmount": null,
    "appealedAt": null,
    "refundedAt": null,
    "createTime": "2026-05-23T10:30:00",
    "updateTime": "2026-05-23T10:30:00"
  },
  "message": "ok",
  "success": true
}

8.2 边界情况

场景说明退款金额等于订单订金金额上限全额退订金,不填补充说明reasonDetail 为 null

请求:

POST /admin/order/refund/apply
Authorization: Bearer <admin-jwt>
Idempotent-Key: b2c3d4e5-f6a7-8901-bcde-f12345678901
Content-Type: application/json
{
  "orderId": 1234567890124,
  "amount": 2000.00,
  "reasonValue": "personal_reason",
  "reasonText": "个人原因",
  "reasonDetail": null
}

响应:

{
  "code": 200,
  "data": {
    "applicationId": 9876543210002,
    "orderId": 1234567890124,
    "orderNo": "HL2026052300002",
    "productName": "西藏拉萨布达拉宫 7 日游",
    "refundType": "DEPOSIT",
    "refundTypeLabel": "订金退款",
    "reasonText": "个人原因",
    "reasonDetail": null,
    "paidAmount": 5000.00,
    "calculatedAmount": 2000.00,
    "actualAmount": null,
    "policyId": null,
    "policyName": null,
    "refundRatio": null,
    "status": "PENDING",
    "statusLabel": "待审核",
    "applicantType": "ADMIN",
    "applicantId": 10086,
    "applicantName": "李小明",
    "departureDate": "2026-06-10",
    "daysBeforeDept": 18,
    "reviewAdminId": null,
    "reviewAdminName": null,
    "reviewRemark": null,
    "reviewedAt": null,
    "approvalNo": null,
    "createTime": "2026-05-23T10:35:00",
    "updateTime": "2026-05-23T10:35:00"
  },
  "message": "ok",
  "success": true
}

8.3 业务失败(异常)

场景说明:退款金额超过订金金额,触发 530007 错误。

请求:

POST /admin/order/refund/apply
Authorization: Bearer <admin-jwt>
Idempotent-Key: c3d4e5f6-a7b8-9012-cdef-123456789012
Content-Type: application/json
{
  "orderId": 1234567890123,
  "amount": 9999.00,
  "reasonValue": "personal_reason",
  "reasonText": "个人原因"
}

响应:

{
  "code": 530007,
  "message": "退款金额不能超过订金金额: amount=9999.00, deposit=2000.00",
  "success": false
}

9. 业务边界

  • 适用场景:订单已支付(存在成功支付记录)时可发起退款申请
  • 不适用场景:
    • 订单不存在 -> 返回 404
    • 订单未支付 -> 后端校验失败,返回业务错误
    • 同订单已有 ACTIVE 状态退款申请PENDING/APPROVED/REFUNDING/APPEALING/APPEAL_APPROVED-> 返回 530004 拒绝重复提交
    • amount 超过订单订金金额 -> 返回 530007
    • amount <= 0 -> 返回 400 参数校验失败
  • 特殊边界:
    • 本接口不调退款政策计算,policyId/policyName/refundRatio 均为 null
    • 退款类型固定为 DEPOSIT,不允许客服指定其他类型
    • 申请创建后状态固定为 PENDING,需走 PUT /admin/order/refund/{applicationId}/review 主管审批流程
    • 5 秒内携带相同 Idempotent-Key 重复提交视为同一请求,返回第一次的结果(不重复创建)

10. 修改前后对比

全新接口,无修改前后对比。管理后台之前没有代用户发起退款的入口,本次为纯新增。

11. 影响评估 / 回滚

  • 是否破坏向后兼容:否(全新接口,旧代码无感知)
  • 前端是否必须同步上线:否(后端先上,前端可独立部署)

12. 注意事项

  • Header 必须携带 Idempotent-KeyUUID 格式),防止客服误操作重复提交。前端在进入发起退款页时生成一个 UUID,整个提交流程复用同一个 key
  • 退款原因字典值需提前获取:调本接口前先调 GET /admin/order/refund/reason/list 拿到可用的 reasonValue 列表,不可自行填写字典 key
  • 金额校验上限为订单订金金额,超过返回 530007,message 含具体金额数值
  • 提交成功后申请状态为 PENDING,可通过 applicationId 跳转至退款进度页,或按订单维度查询退款列表

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人: @yaosutu