PAYATHON 2026

支付宝退款提示ACQ.TRADE_HAS_CLOSE但未退款成功

支付阿杰

结论

ACQ.TRADE_HAS_CLOSE 表示支付宝侧的原交易已经是 TRADE_CLOSED 状态,无法继续退款。这不代表本次退款已经成功。返回结果中的 refund_fee: "0.00" 和 send_back_fee: "0.00" 只说明本次请求没有产生退款金额,不能据此判断此前是否发生过退款。

通常有两种情况:

  1. 订单没有成功支付,因超时、撤销或关闭操作进入 TRADE_CLOSED。
  2. 订单曾经支付成功,但已全额退款,最终进入 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_status
  • trade_no
  • out_trade_no
  • total_amount
  • buyer_pay_amount
  • receipt_amount
  • refund_amount
  • fund_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_no
  • out_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 和调用时间,提交给支付宝官方技术支持进一步核查。提交材料前,应对用户身份、密钥等敏感信息进行脱敏。

备注:内容仅供参考。