支付宝退款提示ACQ.TRADE_HAS_CLOSE但未退款成功
结论
ACQ.TRADE_HAS_CLOSE 表示支付宝侧的原交易已经是 TRADE_CLOSED 状态,无法继续退款。这不代表本次退款已经成功。返回结果中的 refund_fee: "0.00" 和 send_back_fee: "0.00" 只说明本次请求没有产生退款金额,不能据此判断此前是否发生过退款。
通常有两种情况:
- 订单没有成功支付,因超时、撤销或关闭操作进入
TRADE_CLOSED。 - 订单曾经支付成功,但已全额退款,最终进入
TRADE_CLOSED。
如果商户系统中没有退款记录,应以支付宝的交易查询和退款查询结果为准,并检查订单号、运行环境、应用身份以及是否有其他退款请求。
为什么未退款也会提示交易关闭
订单没有支付成功
订单创建后,如果买家没有完成付款,交易可能因支付超时、调用交易关闭接口或支付过程被撤销而关闭。
这类订单没有可退款资金。即使商户系统仍将订单显示为 “待支付” 或 “处理中”,支付宝侧也会拒绝退款。
订单已通过其他请求全额退款
同一笔支付宝交易可以使用不同的退款请求号发起退款。如果商户系统只查询当前 out_request_no,可能漏掉以下情况:
- 使用其他退款请求号发起的退款;
- 人工操作或其他业务系统发起的退款;
- 商户系统超时后没有正确记录的退款;
- 重试时使用了不同的
out_request_no; - 分账、资金退回等关联处理。
原交易全额退款后,交易可能显示为 TRADE_CLOSED。此时再次申请退款,就会返回 ACQ.TRADE_HAS_CLOSE。
查询或退款时使用了错误的订单标识
需要确认请求中的 trade_no 或 out_trade_no 确实属于目标订单。常见问题包括:
out_trade_no被重复使用;- 退款请求传入了其他历史订单的订单号;
- 测试环境与生产环境混用;
- 支付和退款使用了不同的应用、支付宝商户账号或签约主体;
- 本地订单与支付宝交易号绑定错误。
trade_no 是支付宝交易号。核查具体交易时,通常比商户订单号 out_trade_no 更准确。
建议的核实步骤
1. 查询原交易状态
先调用 alipay.trade.query,优先使用退款请求对应的 trade_no 查询。如果只有商户订单号,再使用 out_trade_no。
需要检查这些字段:
trade_statustrade_noout_trade_nototal_amountbuyer_pay_amountreceipt_amountrefund_amountfund_bill_list
各状态可以这样判断:
trade_status | 含义及处理建议 |
|---|---|
WAIT_BUYER_PAY | 尚未支付,通常没有可退款资金 |
TRADE_SUCCESS | 已支付,可结合可退金额继续核查 |
TRADE_FINISHED | 交易已完成,能否退款还需结合产品规则和退款期限判断 |
TRADE_CLOSED | 未支付后关闭,或支付后已全额退款 |
如果查询结果是 TRADE_CLOSED,且 buyer_pay_amount、receipt_amount 都是 0.00,通常说明这笔交易没有完成支付。如果支付金额不为零,并且 refund_amount 已达到交易金额,则需要重点核查历史退款记录。
2. 查询已知退款请求
对所有曾使用过的 out_request_no 调用:
alipay.trade.fastpay.refund.query
查询时必须使用原退款请求对应的:
trade_no或out_trade_noout_request_no
示例请求参数:
{
"trade_no": "2026xxxxxxxxxxxxxxxx",
"out_request_no": "REFUND_20260909_001"
}
退款查询通常无法在缺少 out_request_no 的情况下直接列出该交易的所有退款申请。因此,商户系统应保存每次退款使用的请求号,并检查日志、数据库和其他业务系统是否生成过不同的退款请求号。
3. 核对账单和资金流水
如果交易查询显示已经退款,但商户系统没有记录成功结果,还需要核对:
- 支付宝商家中心的交易记录;
- 退款记录和资金明细;
- 支付宝账单;
- 商户收款账户及买家支付渠道的退回记录;
- 退款接口的原始请求和响应日志。
买家暂时没有看到退款到账,也不一定表示退款失败。款项可能退回支付宝余额、银行卡、花呗或其他原支付渠道,各渠道的到账时间和展示方式可能不同。具体结果应以支付宝资金记录和退款查询结果为准。
4. 检查接口调用身份和环境
确认支付、查询和退款使用了同一套身份信息:
- 同一个
app_id; - 同一个支付宝网关环境;
- 同一个商户签约主体;
- 正确的私钥和支付宝公钥;
- 正确的应用授权关系。
如果支付由服务商代商户调用,还要确认退款请求使用了正确的被授权商户身份。身份不一致时,商户系统查询到的订单和实际操作的支付宝交易可能不是同一笔。
Java 排查示例
下面的代码展示了基本查询思路。支付宝 Java SDK 的版本不同,类名和方法可能略有差异,请以项目实际使用的 SDK 为准。
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setTradeNo("2026xxxxxxxxxxxxxxxx");
// 如果没有 trade_no,可改为:
// model.setOutTradeNo("ORDER_20260909_001");
request.setBizModel(model);
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
System.out.println("trade_no: " + response.getTradeNo());
System.out.println("out_trade_no: " + response.getOutTradeNo());
System.out.println("trade_status: " + response.getTradeStatus());
System.out.println("total_amount: " + response.getTotalAmount());
System.out.println("buyer_pay_amount: " + response.getBuyerPayAmount());
System.out.println("receipt_amount: " + response.getReceiptAmount());
System.out.println("refund_amount: " + response.getRefundAmount());
} else {
System.out.println("code: " + response.getCode());
System.out.println("msg: " + response.getMsg());
System.out.println("sub_code: " + response.getSubCode());
System.out.println("sub_msg: " + response.getSubMsg());
}
查询某次退款:
AlipayTradeFastpayRefundQueryRequest request =
new AlipayTradeFastpayRefundQueryRequest();
AlipayTradeFastpayRefundQueryModel model =
new AlipayTradeFastpayRefundQueryModel();
model.setTradeNo("2026xxxxxxxxxxxxxxxx");
model.setOutRequestNo("REFUND_20260909_001");
request.setBizModel(model);
AlipayTradeFastpayRefundQueryResponse response =
alipayClient.execute(request);
if (response.isSuccess()) {
System.out.println("trade_no: " + response.getTradeNo());
System.out.println("out_trade_no: " + response.getOutTradeNo());
System.out.println("out_request_no: " + response.getOutRequestNo());
System.out.println("refund_amount: " + response.getRefundAmount());
} else {
System.out.println("code: " + response.getCode());
System.out.println("msg: " + response.getMsg());
System.out.println("sub_code: " + response.getSubCode());
System.out.println("sub_msg: " + response.getSubMsg());
}
生产环境中不要只把信息打印到控制台。应保存请求时间、app_id、trade_no、out_trade_no、out_request_no、网关响应原文以及支付宝返回的请求标识,便于后续对账和定位问题。
注意事项
退款请求中的 out_request_no 是控制退款幂等的重要依据。同一笔退款重试时,应保持该值不变。如果每次重试都生成新的请求号,支付宝可能将其视为多次独立退款申请,后续排查也会更困难。
不能只根据商户数据库中的订单状态判断支付宝交易状态。网络超时、回调遗漏或数据库事务回滚,都可能造成商户系统与支付宝的状态不一致。
失败响应中的:
{
"refund_fee": "0.00",
"send_back_fee": "0.00"
}
只表示当前接口调用没有完成退款,不能证明这笔交易以前从未退款。最终需要结合 alipay.trade.query、已知退款请求的查询结果以及支付宝账单进行核对。
如果查询确认交易已支付、没有任何退款金额,但接口仍返回 TRADE_CLOSED,应整理完整请求参数、响应原文、trade_no、out_trade_no、out_request_no、app_id 和调用时间,提交给支付宝官方技术支持进一步核查。提交材料前,应对用户身份、密钥等敏感信息进行脱敏。
备注:内容仅供参考。
