如何通过 Global Payments API 查询历史付款
明确结论
可以查询,但接入的 Global Payments HPP 产品和账户必须支持 HPP Status Query(状态查询)。
查询通常使用创建付款请求时的 order ID,不能依赖浏览器重定向。重定向只用于改善用户体验,不能单独证明付款成功。用户可能关闭页面,网络可能中断,商户服务也可能暂时不可用。
推荐处理方式
生成 HPP JSON 之前,应为每次付款创建一个全局唯一、可追踪的订单号,并先将其保存到本地数据库。不要等到 JSON 序列化完成后再临时提取订单号。
示意代码如下:
String orderId = UUID.randomUUID().toString();
// 先保存订单,初始状态设置为 PENDING
paymentRepository.create(
orderId,
paymentDTO.getAmount(),
paymentDTO.getCurrency(),
"PENDING"
);
hppJson = service
.charge(new BigDecimal(paymentDTO.getAmount()))
.withCurrency(paymentDTO.getCurrency())
.withOrderId(orderId)
.withHostedPaymentData(hostedPaymentData)
.withAddress(billingAddress, AddressType.Billing)
.withAddress(shippingAddress, AddressType.Shipping)
.serialize();
orderId 应由商户系统生成,并保证唯一。具体的长度、字符集和重复规则,应以当前 Global Payments 账户和 SDK 版本的要求为准。
查询历史付款状态
部分版本的 Global Payments Java SDK 通过 HostedService 提供状态查询,典型调用形式如下:
Transaction transaction = service.getTransactionStatus(orderId);
取得结果后,应检查网关返回的交易状态和响应码,再更新本地订单:
Transaction transaction = service.getTransactionStatus(orderId);
String responseCode = transaction.getResponseCode();
String responseMessage = transaction.getResponseMessage();
if ("00".equals(responseCode)) {
paymentRepository.markPaid(
orderId,
transaction.getTransactionId()
);
} else {
paymentRepository.recordGatewayStatus(
orderId,
responseCode,
responseMessage
);
}
这段代码只用于说明处理流程。Global Payments 的产品线、地区、账户配置和 Java SDK 版本不同,getTransactionStatus、返回字段以及成功状态的判断方式也可能不同。未核对对应的 HPP 集成文档前,不能假定所有环境都用 "00" 表示最终付款成功。
如果当前 SDK 没有提供该方法,需要确认所用网关是否有独立的 HPP Status Query 接口,或者是否需要通过 Global Payments 的交易查询或报表 API 查询。Global Payments 不同平台的 API 并不完全通用。
服务恢复后的补偿流程
可以通过定时任务核对本地状态仍为 PENDING 的订单:
List<Payment> pendingPayments =
paymentRepository.findPendingPaymentsOlderThan(Duration.ofMinutes(5));
for (Payment payment : pendingPayments) {
try {
Transaction transaction =
service.getTransactionStatus(payment.getOrderId());
reconcile(payment, transaction);
} catch (Exception ex) {
// 保持 PENDING,记录错误并在稍后重试
log.warn(
"Unable to reconcile payment, orderId={}",
payment.getOrderId(),
ex
);
}
}
完整流程如下:
- 跳转到 HPP 前,保存
orderId、金额、币种和PENDING状态。 - 正常收到 HPP 返回结果后,验证响应签名并更新订单。
- 未收到返回结果时,主动查询付款状态。
- 查询超时或网关暂时不可用时,保留
PENDING状态并稍后重试。 - 只有经过签名验证的返回结果或服务端状态查询结果,才能将订单状态改为
PAID。
注意事项
不要把发生重定向直接视为付款成功。返回 URL 中的参数未经签名校验,也不能作为支付凭证。
查询状态时还需要注意:
- 保存请求付款时实际提交的
orderId。 - 不要为同一个业务订单无控制地创建多个付款请求,以免造成重复扣款。
- 为查询任务设置退避重试和最大查询期限。
- 保存网关返回的 transaction ID、response code 和原始状态,方便后续退款、撤销和对账。
- 不要只核对本地金额。查询结果中的订单号、金额和币种都应与本地记录一致。
- 如果账户启用了 webhook 或服务器通知,应将其作为主要的异步通知渠道,状态查询用于补偿。
- 长时间无法确认的订单应转入人工对账流程,不能自动判定为失败后立即重新扣款。
备注:内容仅供参考。
