From cbc61184bd399666cfa0fe7d0d789068a8cab636 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 6 Jul 2023 19:11:32 +0800 Subject: [PATCH] mall + pay: 1、优化微信公众号 MP 支付的实现 --- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayOrderNotifyRespDTO.java | 10 ---------- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java | 26 ++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java | 6 +++--- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java | 12 ++++++------ yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java | 115 ------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java | 2 +- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java | 2 +- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java | 2 +- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java | 2 +- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java | 2 +- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXLitePayClient.java | 14 ++++++-------- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXNativePayClient.java | 8 ++++---- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPayClientConfig.java | 111 --------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPubPayClient.java | 201 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelEnum.java | 10 +++++----- yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java | 16 ++++++++-------- yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceTest.java | 18 +++++++++--------- 21 files changed, 566 insertions(+), 485 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPayClientConfig.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPubPayClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayOrderNotifyRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayOrderNotifyRespDTO.java index 97e9672..239ddda 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayOrderNotifyRespDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/notify/PayOrderNotifyRespDTO.java @@ -35,14 +35,4 @@ public class PayOrderNotifyRespDTO { */ private LocalDateTime successTime; - /** - * TODO @jason 结合其他的渠道定义成枚举, - * - * alipay - * TRADE_CLOSED,未付款交易超时关闭,或支付完成后全额退款。 - * TRADE_SUCCESS, 交易支付成功 - * TRADE_FINISHED 交易结束,不可退款。 - */ - private String tradeStatus; - } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java new file mode 100644 index 0000000..95fe7fb --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.framework.pay.core.client.exception; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 业务逻辑异常 Exception + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +public class PayException extends RuntimeException { + + /** + * 第三方平台的错误码 + */ + private String code; + /** + * 第三方平台的错误提示 + */ + private String message; + +} 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 88fa4b1..262f9ab 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 @@ -7,18 +7,18 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDT import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; -import com.alipay.api.AlipayResponse;import lombok.extern.slf4j.Slf4j; +import com.alipay.api.AlipayResponse; +import lombok.extern.slf4j.Slf4j; import javax.validation.Validation; import java.time.LocalDateTime; import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; -import static cn.hutool.core.date.DatePattern.NORM_DATETIME_MS_FORMATTER; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants.PAY_EXCEPTION; +// TODO 芋艿:优化下,替换异常; /** * 支付客户端的抽象类,提供模板方法,减少子类的冗余代码 * diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java index 9abb1b6..c6ebd4f 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java @@ -7,8 +7,8 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.*; import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXLitePayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXNativePayClient; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPubPayClient; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPubPayClient; import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import lombok.extern.slf4j.Slf4j; @@ -60,10 +60,10 @@ public class PayClientFactoryImpl implements PayClientFactory { // 创建客户端 // TODO @芋艿 WX_LITE WX_APP 如果不添加在 项目启动的时候去初始化会报错无法启动。所以我手动加了两个,具体需要你来配 switch (channelEnum) { - case WX_PUB: return (AbstractPayClient) new WXPubPayClient(channelId, (WXPayClientConfig) config); - case WX_LITE: return (AbstractPayClient) new WXLitePayClient(channelId, (WXPayClientConfig) config); //微信小程序请求支付 - case WX_APP: return (AbstractPayClient) new WXPubPayClient(channelId, (WXPayClientConfig) config); - case WX_NATIVE: return (AbstractPayClient) new WXNativePayClient(channelId, (WXPayClientConfig) config); + case WX_PUB: return (AbstractPayClient) new WxPubPayClient(channelId, (WxPayClientConfig) config); + case WX_LITE: return (AbstractPayClient) new WXLitePayClient(channelId, (WxPayClientConfig) config); //微信小程序请求支付 + case WX_APP: return (AbstractPayClient) new WxPubPayClient(channelId, (WxPayClientConfig) config); + case WX_NATIVE: return (AbstractPayClient) new WXNativePayClient(channelId, (WxPayClientConfig) config); case ALIPAY_WAP: return (AbstractPayClient) new AlipayWapPayClient(channelId, (AlipayPayClientConfig) config); case ALIPAY_QR: return (AbstractPayClient) new AlipayQrPayClient(channelId, (AlipayPayClientConfig) config); case ALIPAY_APP: return (AbstractPayClient) new AlipayAppPayClient(channelId, (AlipayPayClientConfig) config); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java deleted file mode 100644 index 3e73cdc..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClient.java +++ /dev/null @@ -1,115 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.http.HttpUtil; -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; -import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.AlipayConfig; -import com.alipay.api.DefaultAlipayClient; -import com.alipay.api.domain.AlipayTradeRefundModel; -import com.alipay.api.internal.util.AlipaySignature; -import com.alipay.api.request.AlipayTradeRefundRequest; -import com.alipay.api.response.AlipayTradeRefundResponse; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; - -import java.nio.charset.StandardCharsets; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; - -/** - * 支付宝抽象类, 实现支付宝统一的接口。如退款 - * - * @author jason - */ -@Slf4j -public abstract class AbstractAlipayClient extends AbstractPayClient { - - protected DefaultAlipayClient client; - - public AbstractAlipayClient(Long channelId, String channelCode, AlipayPayClientConfig config) { - super(channelId, channelCode, config); - } - - @Override - @SneakyThrows - protected void doInit() { - AlipayConfig alipayConfig = new AlipayConfig(); - BeanUtil.copyProperties(config, alipayConfig, false); - this.client = new DefaultAlipayClient(alipayConfig); - } - - /** - * 支付宝统一的退款接口 alipay.trade.refund - * @param reqDTO 退款请求 request DTO - * @return 退款请求 Response - */ - @Override - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { - AlipayTradeRefundModel model=new AlipayTradeRefundModel(); - model.setTradeNo(reqDTO.getChannelOrderNo()); - model.setOutTradeNo(reqDTO.getPayTradeNo()); - - model.setOutRequestNo(reqDTO.getMerchantRefundId()); - model.setRefundAmount(formatAmount(reqDTO.getAmount()).toString()); - model.setRefundReason(reqDTO.getReason()); - - AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest(); - refundRequest.setBizModel(model); - refundRequest.setNotifyUrl(reqDTO.getNotifyUrl()); - refundRequest.setReturnUrl(reqDTO.getNotifyUrl()); - try { - AlipayTradeRefundResponse response = client.execute(refundRequest); - log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response)); - if (response.isSuccess()) { - //退款导致触发的异步通知是发送到支付接口中设置的notify_url - //支付宝不返回退款单号,设置为空 - PayRefundUnifiedRespDTO respDTO = new PayRefundUnifiedRespDTO(); - respDTO.setChannelRefundId(""); -// return PayCommonResult.build(response.getCode(), response.getMsg(), respDTO, codeMapping); TODO - return null; - } - // 失败。需要抛出异常 -// return PayCommonResult.build(response.getCode(), response.getMsg(), null, codeMapping); TODO - return null; - } catch (AlipayApiException e) { - // TODO 记录异常日志 - log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e); -// return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); TODO - return null; - } - } - - @Override - @SneakyThrows - public Object parseNotify(PayNotifyReqDTO rawNotify) { - // 1. 校验回调数据 - String body = rawNotify.getBody(); - Map params = rawNotify.getParams(); - Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); - AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), - StandardCharsets.UTF_8.name(), "RSA2"); - - // 2.1 退款的情况 - if (bodyObj.containsKey("refund_fee")) { - return PayRefundNotifyRespDTO.builder().channelOrderNo(bodyObj.get("trade_no")) - .tradeNo(bodyObj.get("out_trade_no")).reqNo(bodyObj.get("out_biz_no")) - .status(PayNotifyRefundStatusEnum.SUCCESS) - .refundSuccessTime(parseTime(params.get("gmt_refund"))) - .build(); - } - // 2.2 支付的情况 - return PayOrderNotifyRespDTO.builder().orderExtensionNo(bodyObj.get("out_trade_no")) - .channelOrderNo(bodyObj.get("trade_no")).channelUserId(bodyObj.get("seller_id")) - .tradeStatus(bodyObj.get("trade_status")).successTime(parseTime(params.get("notify_time"))) - .build(); - } - -} 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 new file mode 100644 index 0000000..c326c2b --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; +import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayConfig; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.domain.AlipayTradeRefundModel; +import com.alipay.api.internal.util.AlipaySignature; +import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.response.AlipayTradeRefundResponse; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) + * + * @author jason + */ +@Slf4j +public abstract class AbstractAlipayPayClient extends AbstractPayClient { + + protected DefaultAlipayClient client; + + public AbstractAlipayPayClient(Long channelId, String channelCode, AlipayPayClientConfig config) { + super(channelId, channelCode, config); + } + + @Override + @SneakyThrows + protected void doInit() { + AlipayConfig alipayConfig = new AlipayConfig(); + BeanUtil.copyProperties(config, alipayConfig, false); + this.client = new DefaultAlipayClient(alipayConfig); + } + + /** + * 支付宝统一的退款接口 alipay.trade.refund + * @param reqDTO 退款请求 request DTO + * @return 退款请求 Response + */ + @Override + protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { + AlipayTradeRefundModel model=new AlipayTradeRefundModel(); + model.setTradeNo(reqDTO.getChannelOrderNo()); + model.setOutTradeNo(reqDTO.getPayTradeNo()); + + model.setOutRequestNo(reqDTO.getMerchantRefundId()); + model.setRefundAmount(formatAmount(reqDTO.getAmount()).toString()); + model.setRefundReason(reqDTO.getReason()); + + AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest(); + refundRequest.setBizModel(model); + refundRequest.setNotifyUrl(reqDTO.getNotifyUrl()); + refundRequest.setReturnUrl(reqDTO.getNotifyUrl()); + try { + AlipayTradeRefundResponse response = client.execute(refundRequest); + log.info("[doUnifiedRefund][response({}) 发起退款 渠道返回", toJsonString(response)); + if (response.isSuccess()) { + //退款导致触发的异步通知是发送到支付接口中设置的notify_url + //支付宝不返回退款单号,设置为空 + PayRefundUnifiedRespDTO respDTO = new PayRefundUnifiedRespDTO(); + respDTO.setChannelRefundId(""); +// return PayCommonResult.build(response.getCode(), response.getMsg(), respDTO, codeMapping); TODO + return null; + } + // 失败。需要抛出异常 +// return PayCommonResult.build(response.getCode(), response.getMsg(), null, codeMapping); TODO + return null; + } catch (AlipayApiException e) { + // TODO 记录异常日志 + log.error("[doUnifiedRefund][request({}) 发起退款失败,网络读超时,退款状态未知]", toJsonString(reqDTO), e); +// return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); TODO + return null; + } + } + + @Override + @SneakyThrows + public Object parseNotify(PayNotifyReqDTO rawNotify) { + // 1. 校验回调数据 + String body = rawNotify.getBody(); + Map params = rawNotify.getParams(); + Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); + AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), + StandardCharsets.UTF_8.name(), "RSA2"); + + // 2.1 退款的情况 + if (bodyObj.containsKey("refund_fee")) { + return PayRefundNotifyRespDTO.builder().channelOrderNo(bodyObj.get("trade_no")) + .tradeNo(bodyObj.get("out_trade_no")).reqNo(bodyObj.get("out_biz_no")) + .status(PayNotifyRefundStatusEnum.SUCCESS) + .refundSuccessTime(parseTime(params.get("gmt_refund"))) + .build(); + } + // 2.2 支付的情况 + return PayOrderNotifyRespDTO.builder() + .orderExtensionNo(bodyObj.get("out_trade_no")) + .channelOrderNo(bodyObj.get("trade_no")) + .channelUserId(bodyObj.get("seller_id")) + .successTime(parseTime(params.get("notify_time"))) + .build(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java index eaf3e78..4c70b5d 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java @@ -20,7 +20,7 @@ import lombok.extern.slf4j.Slf4j; * @author 芋道源码 */ @Slf4j -public class AlipayAppPayClient extends AbstractAlipayClient { +public class AlipayAppPayClient extends AbstractAlipayPayClient { public AlipayAppPayClient(Long channelId, AlipayPayClientConfig config) { super(channelId, PayChannelEnum.ALIPAY_APP.getCode(), config); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java index 23ac6de..7ce5563 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java @@ -24,7 +24,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU * @author 芋道源码 */ @Slf4j -public class AlipayBarPayClient extends AbstractAlipayClient { +public class AlipayBarPayClient extends AbstractAlipayPayClient { public AlipayBarPayClient(Long channelId, AlipayPayClientConfig config) { super(channelId, PayChannelEnum.ALIPAY_BAR.getCode(), config); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java index 591b02d..5a3dfd1 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java @@ -22,7 +22,7 @@ import java.util.Objects; * @author XGD */ @Slf4j -public class AlipayPcPayClient extends AbstractAlipayClient { +public class AlipayPcPayClient extends AbstractAlipayPayClient { public AlipayPcPayClient(Long channelId, AlipayPayClientConfig config) { super(channelId, PayChannelEnum.ALIPAY_PC.getCode(), config); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java index 4080824..a769f6e 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java @@ -18,7 +18,7 @@ import lombok.extern.slf4j.Slf4j; * @author 芋道源码 */ @Slf4j -public class AlipayQrPayClient extends AbstractAlipayClient { +public class AlipayQrPayClient extends AbstractAlipayPayClient { public AlipayQrPayClient(Long channelId, AlipayPayClientConfig config) { super(channelId, PayChannelEnum.ALIPAY_QR.getCode(), config); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java index 23291a7..3b83997 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; * @author 芋道源码 */ @Slf4j -public class AlipayWapPayClient extends AbstractAlipayClient { +public class AlipayWapPayClient extends AbstractAlipayPayClient { public AlipayWapPayClient(Long channelId, AlipayPayClientConfig config) { super(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config); 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 new file mode 100644 index 0000000..77903eb --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java @@ -0,0 +1,183 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.date.TemporalAccessorUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.io.FileUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + +/** + * 微信支付抽象类,实现微信统一的接口、以及部分实现(退款) + * + * @author 遇到源码 + */ +@Slf4j +public abstract class AbstractWxPayClient extends AbstractPayClient { + + protected WxPayService client; + + public AbstractWxPayClient(Long channelId, String channelCode, WxPayClientConfig config) { + super(channelId, channelCode, config); + } + + /** + * 初始化 client 客户端 + * + * @param tradeType 交易类型 + */ + protected void doInit(String tradeType) { + // 创建 config 配置 + WxPayConfig payConfig = new WxPayConfig(); + BeanUtil.copyProperties(config, payConfig, "keyContent"); + payConfig.setTradeType(tradeType); + if (StrUtil.isNotEmpty(config.getPrivateKeyContent())) { + // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 + payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath()); + } + if (StrUtil.isNotEmpty(config.getPrivateCertContent())) { + // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 + payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath()); + } + + // 创建 client 客户端 + client = new WxPayServiceImpl(); + client.setConfig(payConfig); + } + + @Override + protected PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) + throws Throwable { + try { + switch (config.getApiVersion()) { + case WxPayClientConfig.API_VERSION_V2: + return doUnifiedOrderV2(reqDTO); + case WxPayClientConfig.API_VERSION_V3: + return doUnifiedOrderV3(reqDTO); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + log.error("[doUnifiedOrder][request({}) 发起支付失败]", toJsonString(reqDTO), e); + throw buildPayException(e); + } + } + + /** + * 【V2】调用支付渠道,统一下单 + * + * @param reqDTO 下单信息 + * @return 各支付渠道的返回结果 + */ + protected abstract PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) + throws WxPayException; + + /** + * 【V3】调用支付渠道,统一下单 + * + * @param reqDTO 下单信息 + * @return 各支付渠道的返回结果 + */ + protected abstract PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) + throws WxPayException; + + + @Override + public Object parseNotify(PayNotifyReqDTO rawNotify) { + log.info("[parseNotify][微信支付回调 data 数据: {}]", rawNotify.getBody()); + try { + // 微信支付 v2 回调结果处理 + switch (config.getApiVersion()) { + case WxPayClientConfig.API_VERSION_V2: + return parseOrderNotifyV2(rawNotify); + case WxPayClientConfig.API_VERSION_V3: + return parseOrderNotifyV3(rawNotify); + default: + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); + } + } catch (WxPayException e) { + log.error("[parseNotify][rawNotify({}) 解析失败]", toJsonString(rawNotify), e); + throw buildPayException(e); + } + } + + private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyReqDTO data) throws WxPayException { + WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getBody()); + Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS"); + // 转换结果 + return PayOrderNotifyRespDTO + .builder() + .orderExtensionNo(notifyResult.getOutTradeNo()) + .channelOrderNo(notifyResult.getTransactionId()) + .channelUserId(notifyResult.getOpenid()) + .successTime(parseDateV2(notifyResult.getTimeEnd())) + .build(); + } + + private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyReqDTO data) throws WxPayException { + WxPayOrderNotifyV3Result notifyResult = client.parseOrderNotifyV3Result(data.getBody(), null); + WxPayOrderNotifyV3Result.DecryptNotifyResult result = notifyResult.getResult(); + // 转换结果 + Assert.isTrue(Objects.equals(notifyResult.getResult().getTradeState(), "SUCCESS"), + "支付结果非 SUCCESS"); + return PayOrderNotifyRespDTO.builder() + .orderExtensionNo(result.getOutTradeNo()) + .channelOrderNo(result.getTradeState()) + .channelUserId(result.getPayer() != null ? result.getPayer().getOpenid() : null) + .successTime(parseDateV3(result.getSuccessTime())) + .build(); + } + + // ========== 各种工具方法 ========== + + static String getOpenid(PayOrderUnifiedReqDTO reqDTO) { + String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid"); + if (StrUtil.isEmpty(openid)) { + throw new IllegalArgumentException("支付请求的 openid 不能为空!"); + } + return openid; + } + + static PayException buildPayException(WxPayException e) { + return new PayException(ObjectUtils.defaultIfNull(e.getErrCode(), e.getReturnCode()), + ObjectUtils.defaultIfNull(e.getErrCodeDes(), e.getCustomErrorMsg())); + } + + static String formatDateV2(LocalDateTime time) { + return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyyMMddHHmmss"); + } + + static LocalDateTime parseDateV2(String time) { + return LocalDateTimeUtil.parse(time, "yyyyMMddHHmmss"); + } + + static String formatDateV3(LocalDateTime time) { + return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyy-MM-dd'T'HH:mm:ssXXX"); + } + + static LocalDateTime parseDateV3(String time) { + return LocalDateTimeUtil.parse(time, "yyyy-MM-dd'T'HH:mm:ssXXX"); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXLitePayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXLitePayClient.java index 65d087a..99ae9d0 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXLitePayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXLitePayClient.java @@ -39,11 +39,11 @@ import java.util.Objects; * @author zwy */ @Slf4j -public class WXLitePayClient extends AbstractPayClient { +public class WXLitePayClient extends AbstractPayClient { private WxPayService client; - public WXLitePayClient(Long channelId, WXPayClientConfig config) { + public WXLitePayClient(Long channelId, WxPayClientConfig config) { super(channelId, PayChannelEnum.WX_LITE.getCode(), config); } @@ -99,7 +99,7 @@ public class WXLitePayClient extends AbstractPayClient { WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() .outTradeNo(reqDTO.getMerchantOrderId()) .body(reqDTO.getBody()) - .totalFee(reqDTO.getAmount().intValue()) // 单位分 + .totalFee(reqDTO.getAmount()) // 单位分 .timeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyyMMddHHmmss")) // v2的时间格式 .spbillCreateIp(reqDTO.getUserIp()) .openid(getOpenid(reqDTO)) @@ -117,9 +117,7 @@ public class WXLitePayClient extends AbstractPayClient { request.setDescription(reqDTO.getBody()); request.setAmount(new WxPayUnifiedOrderV3Request .Amount() - .setTotal(reqDTO - .getAmount() - .intValue())); // 单位分 + .setTotal(reqDTO.getAmount())); // 单位分 request.setTimeExpire(DateUtil.format(Date.from(reqDTO.getExpireTime().atZone(ZoneId.systemDefault()).toInstant()), "yyyy-MM-dd'T'HH:mm:ssXXX")); // v3的时间格式 request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); @@ -149,9 +147,9 @@ public class WXLitePayClient extends AbstractPayClient { log.info("[parseOrderNotify][微信支付回调data数据:{}]", data.getBody()); // 微信支付 v2 回调结果处理 switch (config.getApiVersion()) { - case WXPayClientConfig.API_VERSION_V2: + case WxPayClientConfig.API_VERSION_V2: return parseOrderNotifyV2(data); - case WXPayClientConfig.API_VERSION_V3: + case WxPayClientConfig.API_VERSION_V3: return parseOrderNotifyV3(data); default: throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXNativePayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXNativePayClient.java index a4f1807..f15c8b7 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXNativePayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXNativePayClient.java @@ -37,11 +37,11 @@ import java.util.Objects; * @author zwy */ @Slf4j -public class WXNativePayClient extends AbstractPayClient { +public class WXNativePayClient extends AbstractPayClient { private WxPayService client; - public WXNativePayClient(Long channelId, WXPayClientConfig config) { + public WXNativePayClient(Long channelId, WxPayClientConfig config) { super(channelId, PayChannelEnum.WX_NATIVE.getCode(), config); } @@ -134,9 +134,9 @@ public class WXNativePayClient extends AbstractPayClient { log.info("微信支付回调data数据:{}", data.getBody()); // 微信支付 v2 回调结果处理 switch (config.getApiVersion()) { - case WXPayClientConfig.API_VERSION_V2: + case WxPayClientConfig.API_VERSION_V2: return parseOrderNotifyV2(data); - case WXPayClientConfig.API_VERSION_V3: + case WxPayClientConfig.API_VERSION_V3: return parseOrderNotifyV3(data); default: throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPayClientConfig.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPayClientConfig.java deleted file mode 100644 index 462f47a..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPayClientConfig.java +++ /dev/null @@ -1,111 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.hutool.core.io.IoUtil; -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import lombok.Data; - -import javax.validation.ConstraintViolation; -import javax.validation.Validator; -import javax.validation.constraints.NotBlank; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.util.Set; - -/** - * 微信支付的 PayClientConfig 实现类 - * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性 - * - * @author 芋道源码 - */ -@Data -public class WXPayClientConfig implements PayClientConfig { - - /** - * API 版本 - V2 - * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1 - */ - public static final String API_VERSION_V2 = "v2"; - /** - * API 版本 - V3 - * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml - */ - public static final String API_VERSION_V3 = "v3"; - - /** - * 公众号或者小程序的 appid - */ - @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class}) - private String appId; - /** - * 商户号 - */ - @NotBlank(message = "商户号 不能为空", groups = {V2.class, V3.class}) - private String mchId; - /** - * API 版本 - */ - @NotBlank(message = "API 版本 不能为空", groups = {V2.class, V3.class}) - private String apiVersion; - - // ========== V2 版本的参数 ========== - - /** - * 商户密钥 - */ - @NotBlank(message = "商户密钥 不能为空", groups = V2.class) - private String mchKey; - /** - * apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. - * 对应的字符串 - * - * 注意,可通过 {@link #main(String[])} 读取 - */ - /// private String keyContent; - - // ========== V3 版本的参数 ========== - /** - * apiclient_key.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. - * 对应的字符串 - * 注意,可通过 {@link #main(String[])} 读取 - */ - @NotBlank(message = "apiclient_key 不能为空", groups = V3.class) - private String privateKeyContent; - /** - * apiclient_cert.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. - * 对应的字符串 - *

- * 注意,可通过 {@link #main(String[])} 读取 - */ - @NotBlank(message = "apiclient_cert 不能为空", groups = V3.class) - private String privateCertContent; - /** - * apiV3 密钥值 - */ - @NotBlank(message = "apiV3 密钥值 不能为空", groups = V3.class) - private String apiV3Key; - - /** - * 分组校验 v2版本 - */ - public interface V2 { - } - - /** - * 分组校验 v3版本 - */ - public interface V3 { - } - - @Override - public Set> verifyParam(Validator validator) { - return validator.validate(this, this.getApiVersion().equals(API_VERSION_V2) ? V2.class : V3.class); - } - - public static void main(String[] args) throws FileNotFoundException { - String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"; - /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_key.pem"; - /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"; - System.out.println(IoUtil.readUtf8(new FileInputStream(path))); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPubPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPubPayClient.java deleted file mode 100644 index 390428b..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXPubPayClient.java +++ /dev/null @@ -1,201 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.date.TemporalAccessorUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.io.FileUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.PayDisplayModeEnum; -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; -import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; -import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; -import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; -import com.github.binarywang.wxpay.config.WxPayConfig; -import com.github.binarywang.wxpay.constant.WxPayConstants; -import com.github.binarywang.wxpay.exception.WxPayException; -import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Objects; - -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; - -/** - * 微信支付(公众号)的 PayClient 实现类 - * - * @author 芋道源码 - */ -@Slf4j -public class WXPubPayClient extends AbstractPayClient { - - private WxPayService client; - - public WXPubPayClient(Long channelId, WXPayClientConfig config) { - super(channelId, PayChannelEnum.WX_PUB.getCode(), config); - } - - @Override - protected void doInit() { - WxPayConfig payConfig = new WxPayConfig(); - BeanUtil.copyProperties(config, payConfig, "keyContent"); - payConfig.setTradeType(WxPayConstants.TradeType.JSAPI); // 设置使用 JS API 支付方式 -// if (StrUtil.isNotEmpty(config.getKeyContent())) { -// payConfig.setKeyContent(config.getKeyContent().getBytes(StandardCharsets.UTF_8)); -// } - if (StrUtil.isNotEmpty(config.getPrivateKeyContent())) { - // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 - payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath()); - } - if (StrUtil.isNotEmpty(config.getPrivateCertContent())) { - // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 - payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath()); - } - // 真实客户端 - this.client = new WxPayServiceImpl(); - client.setConfig(payConfig); - } - - @Override - public PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { - WxPayMpOrderResult response = null; - try { - switch (config.getApiVersion()) { - case WXPayClientConfig.API_VERSION_V2: - response = this.unifiedOrderV2(reqDTO); - break; - case WXPayClientConfig.API_VERSION_V3: - WxPayUnifiedOrderV3Result.JsapiResult responseV3 = this.unifiedOrderV3(reqDTO); - // 将 V3 的结果,统一转换成 V2。返回的字段是一致的 - response = new WxPayMpOrderResult(); - BeanUtil.copyProperties(responseV3, response, true); - break; - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } catch (WxPayException e) { - log.error("[unifiedOrder][request({}) 发起支付失败,原因({})]", toJsonString(reqDTO), e); -// return PayCommonResult.build(ObjectUtils.defaultIfNull(e.getErrCode(), e.getReturnCode(), "CustomErrorCode"), -// ObjectUtils.defaultIfNull(e.getErrCodeDes(), e.getCustomErrorMsg()),null, codeMapping); - System.out.println(); - } - return new PayOrderUnifiedRespDTO().setDisplayMode(PayDisplayModeEnum.CUSTOM.getMode()) - .setDisplayContent(JsonUtils.toJsonString(response)); - } - - - private WxPayMpOrderResult unifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() - .outTradeNo(reqDTO.getMerchantOrderId()) - .body(reqDTO.getBody()) - .totalFee(reqDTO.getAmount()) // 单位分 - .timeExpire(formatDate(reqDTO.getExpireTime())) - .spbillCreateIp(reqDTO.getUserIp()) - .openid(getOpenid(reqDTO)) - .notifyUrl(reqDTO.getNotifyUrl()) - .build(); - // 执行请求 - return client.createOrder(request); - } - - private WxPayUnifiedOrderV3Result.JsapiResult unifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); - request.setOutTradeNo(reqDTO.getMerchantOrderId()); - request.setDescription(reqDTO.getBody()); - request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount())); // 单位分 - request.setTimeExpire(formatDate(reqDTO.getExpireTime())); - request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); - request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); - request.setNotifyUrl(reqDTO.getNotifyUrl()); - // 执行请求 - return client.createOrderV3(TradeTypeEnum.JSAPI, request); - } - - private static String getOpenid(PayOrderUnifiedReqDTO reqDTO) { - String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid"); - if (StrUtil.isEmpty(openid)) { - throw new IllegalArgumentException("支付请求的 openid 不能为空!"); - } - return openid; - } - - /** - * - * 微信支付回调 分v2 和v3 的处理方式 - * - * @param data 通知结果 - * @return 支付回调对象 - * @throws WxPayException 微信异常类 - */ -// @Override - public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyReqDTO data) throws WxPayException { - log.info("[parseOrderNotify][微信支付回调data数据: {}]", data.getBody()); - // 微信支付 v2 回调结果处理 - switch (config.getApiVersion()) { - case WXPayClientConfig.API_VERSION_V2: - return parseOrderNotifyV2(data); - case WXPayClientConfig.API_VERSION_V3: - return parseOrderNotifyV3(data); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } - - private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyReqDTO data) throws WxPayException { - WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = client.parseOrderNotifyV3Result(data.getBody(), null); - WxPayOrderNotifyV3Result.DecryptNotifyResult result = wxPayOrderNotifyV3Result.getResult(); - // 转换结果 - Assert.isTrue(Objects.equals(wxPayOrderNotifyV3Result.getResult().getTradeState(), "SUCCESS"), - "支付结果非 SUCCESS"); - return PayOrderNotifyRespDTO - .builder() - .orderExtensionNo(result.getOutTradeNo()) - .channelOrderNo(result.getTradeState()) - .successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX")) - .build(); - } - - private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyReqDTO data) throws WxPayException { - WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getBody()); - Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS"); - // 转换结果 - return PayOrderNotifyRespDTO - .builder() - .orderExtensionNo(notifyResult.getOutTradeNo()) - .channelOrderNo(notifyResult.getTransactionId()) - .channelUserId(notifyResult.getOpenid()) - .successTime(LocalDateTimeUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss")) - .build(); - - } - - @Override - protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { - // TODO 需要实现 - throw new UnsupportedOperationException(); - } - - private static String formatDate(LocalDateTime time) { -// return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyy-MM-dd'T'HH:mm:ssXXX"); - return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyyMMddHHmmss"); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java new file mode 100644 index 0000000..48228f3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import lombok.Data; + +import javax.validation.ConstraintViolation; +import javax.validation.Validator; +import javax.validation.constraints.NotBlank; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.Set; + +/** + * 微信支付的 PayClientConfig 实现类 + * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性 + * + * @author 芋道源码 + */ +@Data +public class WxPayClientConfig implements PayClientConfig { + + /** + * API 版本 - V2 + * + * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1 + */ + public static final String API_VERSION_V2 = "v2"; + /** + * API 版本 - V3 + * + * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml + */ + public static final String API_VERSION_V3 = "v3"; + + /** + * 公众号或者小程序的 appid + */ + @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class}) + private String appId; + /** + * 商户号 + */ + @NotBlank(message = "商户号 不能为空", groups = {V2.class, V3.class}) + private String mchId; + /** + * API 版本 + */ + @NotBlank(message = "API 版本 不能为空", groups = {V2.class, V3.class}) + private String apiVersion; + + // ========== V2 版本的参数 ========== + + /** + * 商户密钥 + */ + @NotBlank(message = "商户密钥 不能为空", groups = V2.class) + private String mchKey; + /** + * apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. + * 对应的字符串 + * + * 注意,可通过 {@link #main(String[])} 读取 + */ + /// private String keyContent; + + // ========== V3 版本的参数 ========== + /** + * apiclient_key.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. + * 对应的字符串 + * 注意,可通过 {@link #main(String[])} 读取 + */ + @NotBlank(message = "apiclient_key 不能为空", groups = V3.class) + private String privateKeyContent; + /** + * apiclient_cert.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. + * 对应的字符串 + *

+ * 注意,可通过 {@link #main(String[])} 读取 + */ + @NotBlank(message = "apiclient_cert 不能为空", groups = V3.class) + private String privateCertContent; + /** + * apiV3 密钥值 + */ + @NotBlank(message = "apiV3 密钥值 不能为空", groups = V3.class) + private String apiV3Key; + + /** + * 分组校验 v2版本 + */ + public interface V2 { + } + + /** + * 分组校验 v3版本 + */ + public interface V3 { + } + + @Override + public Set> verifyParam(Validator validator) { + return validator.validate(this, this.getApiVersion().equals(API_VERSION_V2) ? V2.class : V3.class); + } + + public static void main(String[] args) throws FileNotFoundException { + String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"; + /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_key.pem"; + /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"; + System.out.println(IoUtil.readUtf8(new FileInputStream(path))); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java new file mode 100644 index 0000000..0d508b7 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import cn.iocoder.yudao.framework.pay.core.enums.PayDisplayModeEnum; +import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.constant.WxPayConstants; +import com.github.binarywang.wxpay.exception.WxPayException; +import lombok.extern.slf4j.Slf4j; + +/** + * 微信支付(公众号)的 PayClient 实现类 + * + * @author 芋道源码 + */ +@Slf4j +public class WxPubPayClient extends AbstractWxPayClient { + + public WxPubPayClient(Long channelId, WxPayClientConfig config) { + super(channelId, PayChannelEnum.WX_PUB.getCode(), config); + } + + @Override + protected void doInit() { + super.doInit(WxPayConstants.TradeType.JSAPI); + } + + @Override + protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() + .outTradeNo(reqDTO.getMerchantOrderId()) + .body(reqDTO.getBody()) + .totalFee(reqDTO.getAmount()) // 单位分 + .timeExpire(formatDateV2(reqDTO.getExpireTime())) + .spbillCreateIp(reqDTO.getUserIp()) + .openid(getOpenid(reqDTO)) + .notifyUrl(reqDTO.getNotifyUrl()) + .build(); + // 执行请求 + WxPayMpOrderResult response = client.createOrder(request); + + // 转换结果 + return new PayOrderUnifiedRespDTO().setDisplayMode(PayDisplayModeEnum.CUSTOM.getMode()) + .setDisplayContent(JsonUtils.toJsonString(response)); + } + + @Override + protected PayOrderUnifiedRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { + // 构建 WxPayUnifiedOrderRequest 对象 + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); + request.setOutTradeNo(reqDTO.getMerchantOrderId()); + request.setDescription(reqDTO.getBody()); + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount())); // 单位分 + request.setTimeExpire(formatDateV3(reqDTO.getExpireTime())); + request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); + request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); + request.setNotifyUrl(reqDTO.getNotifyUrl()); + // 执行请求 + WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request); + + // 转换结果 + return new PayOrderUnifiedRespDTO().setDisplayMode(PayDisplayModeEnum.CUSTOM.getMode()) + .setDisplayContent(JsonUtils.toJsonString(response)); + } + + @Override + protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { + // TODO 需要实现 + throw new UnsupportedOperationException(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelEnum.java index d018495..506ac89 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelEnum.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelEnum.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.pay.core.enums; import cn.hutool.core.util.ArrayUtil; import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; import lombok.AllArgsConstructor; import lombok.Getter; @@ -17,10 +17,10 @@ import lombok.Getter; @AllArgsConstructor public enum PayChannelEnum { - WX_PUB("wx_pub", "微信 JSAPI 支付", WXPayClientConfig.class), // 公众号网页 - WX_LITE("wx_lite", "微信小程序支付", WXPayClientConfig.class), - WX_APP("wx_app", "微信 App 支付", WXPayClientConfig.class), - WX_NATIVE("wx_native", "微信 native 支付", WXPayClientConfig.class), + WX_PUB("wx_pub", "微信 JSAPI 支付", WxPayClientConfig.class), // 公众号网页 + WX_LITE("wx_lite", "微信小程序支付", WxPayClientConfig.class), + WX_APP("wx_app", "微信 App 支付", WxPayClientConfig.class), + WX_NATIVE("wx_native", "微信 native 支付", WxPayClientConfig.class), ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付", AlipayPayClientConfig.class), ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付", AlipayPayClientConfig.class), diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java index 4d560d8..ce16cba 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java @@ -7,8 +7,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDT import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPubPayClient; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPubPayClient; import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -27,15 +27,15 @@ public class PayClientFactoryImplIntegrationTest { private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl(); /** - * {@link WXPubPayClient} 的 V2 版本 + * {@link WxPubPayClient} 的 V2 版本 */ @Test public void testCreatePayClient_WX_PUB_V2() { // 创建配置 - WXPayClientConfig config = new WXPayClientConfig(); + WxPayClientConfig config = new WxPayClientConfig(); config.setAppId("wx041349c6f39b268b"); config.setMchId("1545083881"); - config.setApiVersion(WXPayClientConfig.API_VERSION_V2); + config.setApiVersion(WxPayClientConfig.API_VERSION_V2); config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); // 创建客户端 Long channelId = RandomUtil.randomLong(); @@ -48,15 +48,15 @@ public class PayClientFactoryImplIntegrationTest { } /** - * {@link WXPubPayClient} 的 V3 版本 + * {@link WxPubPayClient} 的 V3 版本 */ @Test public void testCreatePayClient_WX_PUB_V3() throws FileNotFoundException { // 创建配置 - WXPayClientConfig config = new WXPayClientConfig(); + WxPayClientConfig config = new WxPayClientConfig(); config.setAppId("wx041349c6f39b268b"); config.setMchId("1545083881"); - config.setApiVersion(WXPayClientConfig.API_VERSION_V3); + config.setApiVersion(WxPayClientConfig.API_VERSION_V3); config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"))); config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"))); config.setApiV3Key("joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase"); diff --git a/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceTest.java b/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceTest.java index 50f12ba..eb621ea 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceTest.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceTest.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WXPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelCreateReqVO; @@ -49,7 +49,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { @Test public void testCreateWechatVersion2Channel_success() { // 准备参数 - WXPayClientConfig v2Config = getV2Config(); + WxPayClientConfig v2Config = getV2Config(); PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { o.setCode(PayChannelEnum.WX_PUB.getCode()); o.setStatus(CommonStatusEnum.ENABLE.getStatus()); @@ -70,7 +70,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { @Test public void testCreateWechatVersion3Channel_success() { // 准备参数 - WXPayClientConfig v3Config = getV3Config(); + WxPayClientConfig v3Config = getV3Config(); PayChannelCreateReqVO reqVO = randomPojo(PayChannelCreateReqVO.class, o -> { o.setCode(PayChannelEnum.WX_PUB.getCode()); o.setStatus(CommonStatusEnum.ENABLE.getStatus()); @@ -346,22 +346,22 @@ public class PayChannelServiceTest extends BaseDbUnitTest { assertPojoEquals(payClientConfig, list.get(0).getConfig()); } - public WXPayClientConfig getV2Config() { - return new WXPayClientConfig() + public WxPayClientConfig getV2Config() { + return new WxPayClientConfig() .setAppId("APP00001") .setMchId("MCH00001") - .setApiVersion(WXPayClientConfig.API_VERSION_V2) + .setApiVersion(WxPayClientConfig.API_VERSION_V2) .setMchKey("dsa1d5s6a1d6sa16d1sa56d15a61das6") .setApiV3Key("") .setPrivateCertContent("") .setPrivateKeyContent(""); } - public WXPayClientConfig getV3Config() { - return new WXPayClientConfig() + public WxPayClientConfig getV3Config() { + return new WxPayClientConfig() .setAppId("APP00001") .setMchId("MCH00001") - .setApiVersion(WXPayClientConfig.API_VERSION_V3) + .setApiVersion(WxPayClientConfig.API_VERSION_V3) .setMchKey("") .setApiV3Key("sdadasdsadadsa") .setPrivateKeyContent("dsa445das415d15asd16ad156as") -- libgit2 0.21.4