当面付付款码支付取消密码输入后能否关单?
支付老李
结论
用户取消输入密码后,付款码订单通常不会立即变成失败状态,交易仍可能处于 WAIT_BUYER_PAY。因此,不能仅凭客户端的取消操作认定订单失败。
商户可以主动终止订单,但付款码支付可能出现支付结果尚未返回,或支付与关单同时发生的情况。建议先调用 alipay.trade.query 查询交易状态。对于支付结果不确定的付款码交易,应优先使用 alipay.trade.cancel 撤销交易。确认订单尚未支付后,才适合调用 alipay.trade.close 关单。
原因
用户取消密码输入,只表示当前付款确认流程已经终止,并不代表支付宝交易失败。此时可能出现以下状态:
WAIT_BUYER_PAY:交易已创建,正在等待用户付款。TRADE_SUCCESS:支付已经成功。TRADE_CLOSED:交易已经关闭。- 查询结果暂不明确:可能是网络超时、系统延迟,或支付结果仍在处理中。
如果商户在交易状态尚未明确时直接修改本地订单,可能导致支付宝侧已经扣款,本地订单却被标记为关闭。
alipay.trade.cancel 适合处理付款码支付结果不确定的情况。交易尚未支付时,接口会执行撤销;如果交易刚刚支付成功,资金能否退回以及接口会返回什么结果,应以实际响应和支付宝当前的接口规则为准。
建议处理步骤
- 调用
alipay.trade.pay后,如果接口明确返回支付成功,正常完成订单。 - 如果接口返回
10003、超时或其他等待支付的结果,进入查询流程。 - 用户取消密码输入后,调用
alipay.trade.query查询支付宝侧的交易状态。 - 按查询结果处理:
TRADE_SUCCESS:按支付成功处理,不再关单。TRADE_CLOSED:同步关闭本地订单。WAIT_BUYER_PAY:调用alipay.trade.cancel撤销交易。如果业务只处理未支付订单,也可以在确认交易尚未支付后调用alipay.trade.close。- 状态不明确:继续进行有限次数的查询。如果仍无法确认,应执行撤销,不要直接认定支付失败。
- 支付宝侧确认撤销或关单成功后,才能将本地订单更新为关闭状态。
- 如果撤销失败或返回结果不明确,应再次查询交易的最终状态。
代码示例
以下是 Java 风格的处理流程,具体类名和方法以当前使用的支付宝 SDK 版本为准:
AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
queryRequest.setBizContent(
"{\"out_trade_no\":\"" + outTradeNo + "\"}"
);
AlipayTradeQueryResponse queryResponse = alipayClient.execute(queryRequest);
if (queryResponse.isSuccess()) {
String tradeStatus = queryResponse.getTradeStatus();
switch (tradeStatus) {
case "TRADE_SUCCESS":
case "TRADE_FINISHED":
markOrderPaid(outTradeNo, queryResponse.getTradeNo());
break;
case "TRADE_CLOSED":
markOrderClosed(outTradeNo);
break;
case "WAIT_BUYER_PAY":
cancelTrade(alipayClient, outTradeNo);
break;
default:
scheduleTradeQuery(outTradeNo);
break;
}
} else {
// 查询失败不代表支付失败,应重试查询或进入撤销流程
scheduleTradeQuery(outTradeNo);
}
撤销付款码交易:
private void cancelTrade(
AlipayClient alipayClient,
String outTradeNo) throws AlipayApiException {
AlipayTradeCancelRequest cancelRequest = new AlipayTradeCancelRequest();
cancelRequest.setBizContent(
"{\"out_trade_no\":\"" + outTradeNo + "\"}"
);
AlipayTradeCancelResponse cancelResponse =
alipayClient.execute(cancelRequest);
if (cancelResponse.isSuccess()) {
// 建议再查询一次,确认支付宝侧最终状态
scheduleTradeQuery(outTradeNo);
} else {
// 撤销失败不能直接关闭本地订单
scheduleTradeQuery(outTradeNo);
}
}
如果已经确认交易尚未支付,也可以调用关单接口:
AlipayTradeCloseRequest closeRequest = new AlipayTradeCloseRequest();
closeRequest.setBizContent(
"{\"out_trade_no\":\"" + outTradeNo + "\"}"
);
AlipayTradeCloseResponse closeResponse =
alipayClient.execute(closeRequest);
if (closeResponse.isSuccess()) {
markOrderClosed(outTradeNo);
} else {
// 关单失败后重新查询,防止支付与关单并发
scheduleTradeQuery(outTradeNo);
}
注意事项
- 不要将“用户关闭密码框”直接视为支付失败。
- 不要只依赖前端页面显示的状态,应以服务端查询结果为准。
- 支付、查询、撤销和关单必须使用同一个
out_trade_no。 - 更新本地订单时必须保证幂等,避免重复通知或重复查询造成订单状态回退。
- 订单一旦标记为支付成功,不能再更新为待支付或普通关闭状态。
- 撤销或关单接口调用超时,不代表操作失败。应通过
alipay.trade.query查询并确认最终状态。 alipay.trade.close和alipay.trade.cancel的适用状态及具体行为,可能因产品接入方式或接口规则而不同,应以当前使用的支付宝开放平台接口文档和实际响应码为准。付款码支付结果不确定时,使用撤销通常比直接关单更稳妥。
备注:内容仅供参考。
