PAYATHON 2026

支付报错ACQ.TRADE_HAS_SUCCESS,请问如何处理?

支付阿杰

结论

ACQ.TRADE_HAS_SUCCESS 表示这笔交易已经支付成功,支付宝因此拒绝了重复支付请求。此时不要再次发起支付。应先查询支付宝端的交易状态,再把本地订单更新为已支付。

如果用户已经扣款,但业务系统仍显示未支付,常见原因是异步通知尚未到达、通知处理失败,或者本地订单状态未正确更新。

常见原因

该报错一般由以下情况引起:

  • 用户已经完成支付,但页面再次提交了支付请求。
  • 用户刷新页面、重复点击,或者网络重试,导致系统使用同一个 out_trade_no 再次发起支付。
  • 支付宝异步通知处理失败,本地订单仍处于”待支付”状态。
  • 业务系统没有检查订单状态,直接对已支付订单重新调用支付接口。
  • 创建新订单时,误用了已经支付成功的 out_trade_no。

out_trade_no 是商户订单号。在同一商户账号下,它应唯一对应一笔交易,不能随意复用。

处理步骤

1. 停止重复支付

收到 ACQ.TRADE_HAS_SUCCESS 后,不要更换支付方式、重复请求或自动重试,以免造成业务状态混乱。

前端可以提示用户:

该订单已经支付,请勿重复支付。正在确认订单状态。

2. 主动查询交易状态

调用 alipay.trade.query 查询实际交易结果。查询时通常传入商户订单号 out_trade_no。如果系统已经保存了支付宝交易号,也可以使用 trade_no。

需要重点检查返回结果中的 trade_status:

  • TRADE_SUCCESS:交易支付成功。
  • TRADE_FINISHED:交易已完成,按支付成功处理。
  • WAIT_BUYER_PAY:交易等待付款。
  • TRADE_CLOSED:交易已经关闭。

如果查询结果是 TRADE_SUCCESS 或 TRADE_FINISHED,应核对商户订单号、金额和收款账号等信息,确认无误后再更新本地订单。

3. 修正本地订单状态

更新订单前,至少要校验以下信息:

  • out_trade_no 是否与本地订单一致。
  • 支付金额是否与订单应付金额一致。
  • 收款方身份是否属于当前商户。
  • 当前订单是否已经处理过。

订单状态更新和后续业务操作必须支持幂等。即使异步通知和主动查询同时确认支付,发货、充值或开通服务等操作也只能执行一次。

4. 检查异步通知

如果支付宝端已经支付成功,但本地仍显示未支付,需要检查:

  • notify_url 能否从公网正常访问。
  • 系统是否正确验签。
  • 通知处理是否因超时或程序异常而失败。
  • 处理成功后,是否按接口要求返回了成功响应。
  • 系统是否错误地依赖同步跳转结果更新订单。

支付结果应以支付宝异步通知或服务端主动查询的结果为准,不能只依赖浏览器跳转页面。

Java 处理示例

以下示例演示收到重复支付提示后,如何通过 alipay.trade.query 查询交易状态。具体类名和调用方式应以项目使用的支付宝 Java SDK 版本为准。

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent(
    "{\"out_trade_no\":\"" + outTradeNo + "\"}"
);

AlipayTradeQueryResponse response = alipayClient.execute(request);

if (response.isSuccess()) {
    String tradeStatus = response.getTradeStatus();

    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {

        // 必须先校验订单号、金额、收款方等信息
        verifyTrade(response);

        // 使用条件更新或事务保证幂等
        boolean updated = orderService.markPaidIfUnpaid(
            outTradeNo,
            response.getTradeNo(),
            response.getTotalAmount()
        );

        if (updated) {
            // 仅首次更新成功时执行发货、充值或开通服务
            orderService.processPaidOrder(outTradeNo);
        }
    } else {
        // 根据 WAIT_BUYER_PAY、TRADE_CLOSED 等状态分别处理
        orderService.handleTradeStatus(outTradeNo, tradeStatus);
    }
} else {
    // 查询接口调用失败不等于交易失败,应记录信息并稍后重查
    log.warn(
        "支付宝交易查询失败,outTradeNo={}, code={}, subCode={}, subMsg={}",
        outTradeNo,
        response.getCode(),
        response.getSubCode(),
        response.getSubMsg()
    );
}

幂等更新可以使用类似下面的条件:

UPDATE payment_order
SET status = 'PAID',
    trade_no = ?,
    paid_at = CURRENT_TIMESTAMP
WHERE out_trade_no = ?
  AND status = 'UNPAID';

只有受影响行数为 1 时,才继续执行一次性的支付成功业务。如果受影响行数为 0,通常表示订单已经处理过,不能再次发货或充值。

注意事项

  • 不要直接生成新的 out_trade_no 让用户再次付款,否则同一业务订单可能被支付两次。
  • 不要因为接口调用失败就直接认定交易失败。遇到网络超时或响应丢失时,交易仍可能已经成功,必须主动查询。
  • ACQ.TRADE_HAS_SUCCESS 本身通常不需要退款。只有确认存在重复扣款,或业务确实需要撤销时,才进入退款流程。
  • 同步返回、异步通知和主动查询可能先后到达,这三条处理链路都必须支持幂等。
  • 如果查询到的金额、订单号或收款方信息不一致,不要自动更新订单。应记录异常并转交人工核查。
  • 如果本地订单并未支付,但同一个商户订单号持续返回该错误,应检查 out_trade_no 是否被历史订单复用。

备注:内容仅供参考。