diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java index 9362466a6..15ce53e95 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java @@ -27,7 +27,7 @@ public interface PayClient { * 调用支付渠道,统一下单 * * @param reqDTO 下单信息 - * @return 各支付渠道的返回结果 + * @return 支付订单信息 */ PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO); @@ -40,6 +40,14 @@ public interface PayClient { */ PayOrderRespDTO parseOrderNotify(Map params, String body); + /** + * 获得支付订单信息 + * + * @param outTradeNo 外部订单号 + * @return 支付订单信息 + */ + PayOrderRespDTO getOrder(String outTradeNo); + // ============ 退款相关 ========== /** diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java index 163ffce65..82050a6fc 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java @@ -94,38 +94,40 @@ public class PayOrderRespDTO { /** * 创建【SUCCESS】状态的订单返回 */ - public PayOrderRespDTO(String channelOrderNo, String channelUserId, LocalDateTime successTime, - String outTradeNo, Object rawData) { - this.status = PayOrderStatusRespEnum.SUCCESS.getStatus(); - this.channelOrderNo = channelOrderNo; - this.channelUserId = channelUserId; - this.successTime = successTime; + public static PayOrderRespDTO successOf(String channelOrderNo, String channelUserId, LocalDateTime successTime, + String outTradeNo, Object rawData) { + PayOrderRespDTO respDTO = new PayOrderRespDTO(); + respDTO.status = PayOrderStatusRespEnum.SUCCESS.getStatus(); + respDTO.channelOrderNo = channelOrderNo; + respDTO.channelUserId = channelUserId; + respDTO.successTime = successTime; // 相对通用的字段 - this.outTradeNo = outTradeNo; - this.rawData = rawData; + respDTO.outTradeNo = outTradeNo; + respDTO.rawData = rawData; + return respDTO; } /** - * 创建【SUCCESS】或【CLOSED】状态的订单返回,适合支付渠道回调时 + * 创建指定状态的订单返回,适合支付渠道回调时 */ - public PayOrderRespDTO(Integer status, String channelOrderNo, String channelUserId, LocalDateTime successTime, - String outTradeNo, Object rawData) { - this.status = status; - this.channelOrderNo = channelOrderNo; - this.channelUserId = channelUserId; - this.successTime = successTime; + public static PayOrderRespDTO of(Integer status, String channelOrderNo, String channelUserId, LocalDateTime successTime, + String outTradeNo, Object rawData) { + PayOrderRespDTO respDTO = new PayOrderRespDTO(); + respDTO.status = status; + respDTO.channelOrderNo = channelOrderNo; + respDTO.channelUserId = channelUserId; + respDTO.successTime = successTime; // 相对通用的字段 - this.outTradeNo = outTradeNo; - this.rawData = rawData; + respDTO.outTradeNo = outTradeNo; + respDTO.rawData = rawData; + return respDTO; } /** * 创建【CLOSED】状态的订单返回,适合调用支付渠道失败时 - * - * 参数和 {@link #PayOrderRespDTO(String, String, String, Object)} 冲突,所以独立个方法出来 */ - public static PayOrderRespDTO build(String channelErrorCode, String channelErrorMsg, - String outTradeNo, Object rawData) { + public static PayOrderRespDTO closedOf(String channelErrorCode, String channelErrorMsg, + String outTradeNo, Object rawData) { PayOrderRespDTO respDTO = new PayOrderRespDTO(); respDTO.status = PayOrderStatusRespEnum.CLOSED.getStatus(); respDTO.channelErrorCode = channelErrorCode; diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java index 194432738..bd4580e2d 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java @@ -107,6 +107,20 @@ public abstract class AbstractPayClient implemen protected abstract PayOrderRespDTO doParseOrderNotify(Map params, String body) throws Throwable; + @Override + public PayOrderRespDTO getOrder(String outTradeNo) { + try { + return doGetOrder(outTradeNo); + } catch (Throwable ex) { + log.error("[getOrder][客户端({}) outTradeNo({}) 查询支付单异常]", + getId(), outTradeNo, ex); + throw buildPayException(ex); + } + } + + protected abstract PayOrderRespDTO doGetOrder(String outTradeNo) + throws Throwable; + // ============ 退款相关 ========== @Override diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java index 8c4a66b11..44dea94ce 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java @@ -17,9 +17,12 @@ import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayConfig; import com.alipay.api.AlipayResponse; import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.AlipayTradeQueryModel; import com.alipay.api.domain.AlipayTradeRefundModel; import com.alipay.api.internal.util.AlipaySignature; +import com.alipay.api.request.AlipayTradeQueryRequest; import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.response.AlipayTradeQueryResponse; import com.alipay.api.response.AlipayTradeRefundResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -63,7 +66,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient 0) { status = PayOrderStatusRespEnum.REFUND.getStatus(); @@ -87,10 +87,40 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient) () -> { throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); }); - return new PayOrderRespDTO(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")), + return PayOrderRespDTO.of(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")), bodyObj.get("out_trade_no"), body); } + @Override + protected PayOrderRespDTO doGetOrder(String outTradeNo) throws Throwable { + // 1.1 构建 AlipayTradeRefundModel 请求 + AlipayTradeQueryModel model = new AlipayTradeQueryModel(); + model.setOutTradeNo(outTradeNo); + // 1.2 构建 AlipayTradeQueryRequest 请求 + AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); + request.setBizModel(model); + + // 2.1 执行请求 + AlipayTradeQueryResponse response = client.execute(request); + if (!response.isSuccess()) { + return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), + outTradeNo, response); + } + // 2.2 解析订单的状态 + Integer status = parseStatus(response.getTradeStatus()); + Assert.notNull(status, (Supplier) () -> { + throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody())); + }); + return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()), + outTradeNo, response); + } + + private Integer parseStatus(String tradeStatus) { + return Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus() + : ObjectUtils.equalsAny(tradeStatus, "TRADE_FINISHED", "TRADE_SUCCESS") ? PayOrderStatusRespEnum.SUCCESS.getStatus() + : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null; + } + // ============ 退款相关 ========== /** diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java index eeef301c0..e15b06a5f 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -90,7 +90,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient