Commit d099ad2a8b655813ab7d6e0afacf0ed58b9afa22

Authored by zwy
1 parent 03ad548a

:bug:

【微信支付】:
WXLitePayClient.java 微信小程序支付模块:
!!前端必须传openid
PayClientFactoryImpl.java 支付客户端的工厂实现类:
添加 小程序支付模块
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
7 7 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig;
8 8 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient;
9 9 import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient;
  10 +import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXLitePayClient;
10 11 import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXNativePayClient;
11 12 import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig;
12 13 import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPubPayClient;
... ... @@ -62,7 +63,7 @@ public class PayClientFactoryImpl implements PayClientFactory {
62 63 // TODO @芋艿 WX_LITE WX_APP 如果不添加在 项目启动的时候去初始化会报错无法启动。所以我手动加了两个,具体需要你来配
63 64 switch (channelEnum) {
64 65 case WX_PUB: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config);
65   - case WX_LITE: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config);
  66 + case WX_LITE: return (AbstractPayClient<Config>) new WXLitePayClient(channelId, (WXPayClientConfig) config); //微信小程序请求支付
66 67 case WX_APP: return (AbstractPayClient<Config>) new WXPubPayClient(channelId, (WXPayClientConfig) config);
67 68 case WX_NATIVE: return (AbstractPayClient<Config>) new WXNativePayClient(channelId, (WXPayClientConfig) config);
68 69 case ALIPAY_WAP: return (AbstractPayClient<Config>) new AlipayWapPayClient(channelId, (AlipayPayClientConfig) config);
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXLitePayClient.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.pay.core.client.impl.wx;
  2 +
  3 +import cn.hutool.core.bean.BeanUtil;
  4 +import cn.hutool.core.date.DateUtil;
  5 +import cn.hutool.core.lang.Assert;
  6 +import cn.hutool.core.map.MapUtil;
  7 +import cn.hutool.core.util.StrUtil;
  8 +import cn.iocoder.yudao.framework.common.util.io.FileUtils;
  9 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  10 +import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult;
  11 +import cn.iocoder.yudao.framework.pay.core.client.dto.*;
  12 +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
  13 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
  14 +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
  15 +import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
  16 +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
  17 +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
  18 +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
  19 +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
  20 +import com.github.binarywang.wxpay.config.WxPayConfig;
  21 +import com.github.binarywang.wxpay.constant.WxPayConstants;
  22 +import com.github.binarywang.wxpay.exception.WxPayException;
  23 +import com.github.binarywang.wxpay.service.WxPayService;
  24 +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
  25 +import lombok.extern.slf4j.Slf4j;
  26 +
  27 +import java.util.Objects;
  28 +
  29 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  30 +import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.CODE_SUCCESS;
  31 +import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.MESSAGE_SUCCESS;
  32 +
  33 +
  34 +/**
  35 + *
  36 + * 微信小程序下支付
  37 + */
  38 +@Slf4j
  39 +public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> {
  40 +
  41 + private WxPayService client;
  42 +
  43 + public WXLitePayClient(Long channelId, WXPayClientConfig config) {
  44 + super(channelId, PayChannelEnum.WX_LITE.getCode(), config, new WXCodeMapping());
  45 + }
  46 +
  47 + @Override
  48 + protected void doInit() {
  49 + WxPayConfig payConfig = new WxPayConfig();
  50 + BeanUtil.copyProperties(config, payConfig, "keyContent");
  51 + payConfig.setTradeType(WxPayConstants.TradeType.JSAPI); // 设置使用 JS API 支付方式
  52 +// if (StrUtil.isNotEmpty(config.getKeyContent())) {
  53 +// payConfig.setKeyContent(config.getKeyContent().getBytes(StandardCharsets.UTF_8));
  54 +// }
  55 + if (StrUtil.isNotEmpty(config.getPrivateKeyContent())) {
  56 + // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决
  57 + payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath());
  58 + }
  59 + if (StrUtil.isNotEmpty(config.getPrivateCertContent())) {
  60 + // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决
  61 + payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath());
  62 + }
  63 + // 真实客户端
  64 + this.client = new WxPayServiceImpl();
  65 + client.setConfig(payConfig);
  66 + }
  67 +
  68 + @Override
  69 + public PayCommonResult<WxPayMpOrderResult> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
  70 + WxPayMpOrderResult response;
  71 + try {
  72 + switch (config.getApiVersion()) {
  73 + case WXPayClientConfig.API_VERSION_V2:
  74 + response = this.unifiedOrderV2(reqDTO);
  75 + break;
  76 + case WXPayClientConfig.API_VERSION_V3:
  77 + WxPayUnifiedOrderV3Result.JsapiResult responseV3 = this.unifiedOrderV3(reqDTO);
  78 + // 将 V3 的结果,统一转换成 V2。返回的字段是一致的
  79 + response = new WxPayMpOrderResult();
  80 + BeanUtil.copyProperties(responseV3, response, true);
  81 + break;
  82 + default:
  83 + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
  84 + }
  85 + } catch (WxPayException e) {
  86 + log.error("[unifiedOrder][request({}) 发起支付失败,原因({})]", toJsonString(reqDTO), e);
  87 + return PayCommonResult.build(ObjectUtils.defaultIfNull(e.getErrCode(), e.getReturnCode(), "CustomErrorCode"),
  88 + ObjectUtils.defaultIfNull(e.getErrCodeDes(), e.getCustomErrorMsg()), null, codeMapping);
  89 + }
  90 + return PayCommonResult.build(CODE_SUCCESS, MESSAGE_SUCCESS, response, codeMapping);
  91 + }
  92 +
  93 +
  94 + private WxPayMpOrderResult unifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException {
  95 + // 构建 WxPayUnifiedOrderRequest 对象
  96 + WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
  97 + .outTradeNo(reqDTO.getMerchantOrderId())
  98 + .body(reqDTO.getBody())
  99 + .totalFee(reqDTO.getAmount().intValue()) // 单位分
  100 + //v2的时间格式
  101 + .timeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyyMMddHHmmss"))
  102 + .spbillCreateIp(reqDTO.getUserIp())
  103 + .openid(getOpenid(reqDTO))
  104 + .notifyUrl(reqDTO.getNotifyUrl())
  105 + .build();
  106 + // 执行请求
  107 + return client.createOrder(request);
  108 + }
  109 +
  110 + private WxPayUnifiedOrderV3Result.JsapiResult unifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException {
  111 + // 构建 WxPayUnifiedOrderRequest 对象
  112 + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
  113 + request.setOutTradeNo(reqDTO.getMerchantOrderId());
  114 +
  115 + request.setDescription(reqDTO.getBody());
  116 + request.setAmount(new WxPayUnifiedOrderV3Request
  117 + .Amount()
  118 + .setTotal(reqDTO
  119 + .getAmount()
  120 + .intValue())); // 单位分
  121 + //v3的时间格式
  122 + request.setTimeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"));
  123 + request.setPayer(new WxPayUnifiedOrderV3Request
  124 + .Payer()
  125 + .setOpenid(getOpenid(reqDTO)));
  126 + request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp()));
  127 + request.setNotifyUrl(reqDTO.getNotifyUrl());
  128 + // 执行请求
  129 + return client.createOrderV3(TradeTypeEnum.JSAPI, request);
  130 + }
  131 +
  132 + private static String getOpenid(PayOrderUnifiedReqDTO reqDTO) {
  133 + String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid");
  134 + if (StrUtil.isEmpty(openid)) {
  135 + throw new IllegalArgumentException("支付请求的 openid 不能为空!");
  136 + }
  137 + return openid;
  138 + }
  139 +
  140 + @Override
  141 + public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws WxPayException {
  142 + WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getBody());
  143 + Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS");
  144 + // 转换结果
  145 + return PayOrderNotifyRespDTO.builder().orderExtensionNo(notifyResult.getOutTradeNo())
  146 + .channelOrderNo(notifyResult.getTransactionId()).channelUserId(notifyResult.getOpenid())
  147 + .successTime(DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
  148 + .data(data.getBody()).build();
  149 + }
  150 +
  151 + @Override
  152 + public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
  153 + //TODO 需要实现
  154 + throw new UnsupportedOperationException("需要实现");
  155 + }
  156 +
  157 +
  158 + @Override
  159 + protected PayCommonResult<PayRefundUnifiedRespDTO> doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
  160 + //TODO 需要实现
  161 + throw new UnsupportedOperationException();
  162 + }
  163 +
  164 +}
... ...