Commit e31b40eefa84abb75b153153e2312b55f150b87a

Authored by YunaiV
1 parent 4014137a

mall + pay:

1. 实现 WxBarPayClient 的支付功能
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -169,7 +169,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC @@ -169,7 +169,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
169 if (Objects.equals(e.getErrCode(), "PARAM_ERROR")) { 169 if (Objects.equals(e.getErrCode(), "PARAM_ERROR")) {
170 throw invalidParamException(e.getErrCodeDes()); 170 throw invalidParamException(e.getErrCodeDes());
171 } 171 }
172 - throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getReturnMsg()); 172 + throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getErrCodeDes());
173 } 173 }
174 // 情况二:状态码结果为 FAIL 174 // 情况二:状态码结果为 FAIL
175 if (Objects.equals(e.getReturnCode(), "FAIL")) { 175 if (Objects.equals(e.getReturnCode(), "FAIL")) {
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WXNativePayClient.java
@@ -34,6 +34,8 @@ import java.util.Objects; @@ -34,6 +34,8 @@ import java.util.Objects;
34 /** 34 /**
35 * 微信 App 支付 35 * 微信 App 支付
36 * 36 *
  37 + * TODO 芋艿:待测试,可能实现也不太对;
  38 + *
37 * @author zwy 39 * @author zwy
38 */ 40 */
39 @Slf4j 41 @Slf4j
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; 1 package cn.iocoder.yudao.framework.pay.core.client.impl.weixin;
2 2
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
  4 +import cn.hutool.core.thread.ThreadUtil;
4 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 7 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 8 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; 9 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
@@ -9,15 +11,34 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq @@ -9,15 +11,34 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq
9 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
10 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 12 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
11 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 13 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
  14 +import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
12 import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; 15 import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest;
13 import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; 16 import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
14 import com.github.binarywang.wxpay.constant.WxPayConstants; 17 import com.github.binarywang.wxpay.constant.WxPayConstants;
15 import com.github.binarywang.wxpay.exception.WxPayException; 18 import com.github.binarywang.wxpay.exception.WxPayException;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +
  21 +import java.time.Duration;
  22 +import java.time.LocalDateTime;
  23 +import java.util.concurrent.TimeUnit;
16 24
17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; 25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
18 26
  27 +/**
  28 + * 微信支付【付款码支付】的 PayClient 实现类
  29 + *
  30 + * 文档:<a href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1">付款码支付</a>
  31 + *
  32 + * @author 芋道源码
  33 + */
  34 +@Slf4j
19 public class WxBarPayClient extends AbstractWxPayClient { 35 public class WxBarPayClient extends AbstractWxPayClient {
20 36
  37 + /**
  38 + * 微信付款码的过期时间
  39 + */
  40 + private static final Duration AUTH_CODE_EXPIRE = Duration.ofMinutes(3);
  41 +
21 public WxBarPayClient(Long channelId, WxPayClientConfig config) { 42 public WxBarPayClient(Long channelId, WxPayClientConfig config) {
22 super(channelId, PayChannelEnum.WX_BAR.getCode(), config); 43 super(channelId, PayChannelEnum.WX_BAR.getCode(), config);
23 } 44 }
@@ -29,23 +50,44 @@ public class WxBarPayClient extends AbstractWxPayClient { @@ -29,23 +50,44 @@ public class WxBarPayClient extends AbstractWxPayClient {
29 50
30 @Override 51 @Override
31 protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { 52 protected PayOrderUnifiedRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException {
  53 + // 由于付款码需要不断轮询,所以需要在较短的时间完成支付
  54 + LocalDateTime expireTime = LocalDateTimeUtils.addTime(AUTH_CODE_EXPIRE);
  55 + if (expireTime.isAfter(reqDTO.getExpireTime())) {
  56 + expireTime = reqDTO.getExpireTime();
  57 + }
32 // 构建 WxPayMicropayRequest 对象 58 // 构建 WxPayMicropayRequest 对象
33 WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder() 59 WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder()
34 .outTradeNo(reqDTO.getMerchantOrderId()) 60 .outTradeNo(reqDTO.getMerchantOrderId())
35 .body(reqDTO.getSubject()) 61 .body(reqDTO.getSubject())
36 .detail(reqDTO.getBody()) 62 .detail(reqDTO.getBody())
37 .totalFee(reqDTO.getAmount()) // 单位分 63 .totalFee(reqDTO.getAmount()) // 单位分
38 - .timeExpire(formatDateV2(reqDTO.getExpireTime())) 64 + .timeExpire(formatDateV2(expireTime))
39 .spbillCreateIp(reqDTO.getUserIp()) 65 .spbillCreateIp(reqDTO.getUserIp())
40 .authCode(getAuthCode(reqDTO)) 66 .authCode(getAuthCode(reqDTO))
41 .build(); 67 .build();
42 - // 执行请求  
43 - WxPayMicropayResult response = client.micropay(request);  
44 -  
45 - // 转换结果  
46 - // TODO 芋艿:这里后面要看看  
47 - return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.CUSTOM.getMode(),  
48 - JsonUtils.toJsonString(response)); 68 + // 执行请求,重试直到失败(过期),或者成功
  69 + for (int i = 1; i < Byte.MAX_VALUE; i++) {
  70 + try {
  71 + WxPayMicropayResult response = client.micropay(request);
  72 + // 支付成功(例如说,用户输入了密码)
  73 + return new PayOrderUnifiedRespDTO(PayOrderDisplayModeEnum.BAR_CODE.getMode(),
  74 + JsonUtils.toJsonString(response),
  75 + PayOrderStatusRespEnum.SUCCESS.getStatus());
  76 + } catch (WxPayException ex) {
  77 + // 如果不满足这 3 种任一的,则直接抛出 WxPayException 异常,不仅需处理
  78 + // 1. SYSTEMERROR:接口返回错误:请立即调用被扫订单结果查询API,查询当前订单状态,并根据订单的状态决定下一步的操作。
  79 + // 2. USERPAYING:用户支付中,需要输入密码:等待 5 秒,然后调用被扫订单结果查询 API,查询当前订单的不同状态,决定下一步的操作。
  80 + // 3. BANKERROR:银行系统异常:请立即调用被扫订单结果查询 API,查询当前订单的不同状态,决定下一步的操作。
  81 + if (!StrUtil.equalsAny(ex.getErrCode(), "SYSTEMERROR", "USERPAYING", "BANKERROR")) {
  82 + throw ex;
  83 + }
  84 + // 等待 5 秒,继续下一轮重新发起支付
  85 + log.info("[doUnifiedOrderV2][发起微信 Bar 支付第({})失败,等待下一轮重试,请求({}),响应({})]", i,
  86 + JsonUtils.toJsonString(request), ex.getMessage());
  87 + ThreadUtil.sleep(5, TimeUnit.SECONDS);
  88 + }
  89 + }
  90 + throw new IllegalStateException("微信 Bar 支付,重试多次失败");
49 } 91 }
50 92
51 @Override 93 @Override
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java
@@ -4,10 +4,12 @@ import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; @@ -4,10 +4,12 @@ import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
4 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
5 5
6 /** 6 /**
7 - * 微信支付(小程序)的 PayClient 实现类 7 + * 微信支付【小程序】的 PayClient 实现类
8 * 8 *
9 * 由于公众号和小程序的微信支付逻辑一致,所以直接进行继承 9 * 由于公众号和小程序的微信支付逻辑一致,所以直接进行继承
10 * 10 *
  11 + * 文档:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml">JSAPI 下单</>
  12 + *
11 * @author zwy 13 * @author zwy
12 */ 14 */
13 @Slf4j 15 @Slf4j
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java
@@ -23,20 +23,21 @@ public class WxPayClientConfig implements PayClientConfig { @@ -23,20 +23,21 @@ public class WxPayClientConfig implements PayClientConfig {
23 /** 23 /**
24 * API 版本 - V2 24 * API 版本 - V2
25 * 25 *
26 - * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1 26 + * <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1">V2 协议说明</a>
27 */ 27 */
28 public static final String API_VERSION_V2 = "v2"; 28 public static final String API_VERSION_V2 = "v2";
29 /** 29 /**
30 * API 版本 - V3 30 * API 版本 - V3
31 * 31 *
32 - * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml 32 + * <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml">V3 协议说明</a>
33 */ 33 */
34 public static final String API_VERSION_V3 = "v3"; 34 public static final String API_VERSION_V3 = "v3";
35 35
36 /** 36 /**
37 * 公众号或者小程序的 appid 37 * 公众号或者小程序的 appid
  38 + *
  39 + * 只有公众号或小程序需要该字段
38 */ 40 */
39 - @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class})  
40 private String appId; 41 private String appId;
41 /** 42 /**
42 * 商户号 43 * 商户号
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java
@@ -23,6 +23,8 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @@ -23,6 +23,8 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
23 /** 23 /**
24 * 微信支付(公众号)的 PayClient 实现类 24 * 微信支付(公众号)的 PayClient 实现类
25 * 25 *
  26 + * 文档:<a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml">JSAPI 下单</>
  27 + *
26 * @author 芋道源码 28 * @author 芋道源码
27 */ 29 */
28 @Slf4j 30 @Slf4j
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.http
@@ -19,7 +19,7 @@ tenant-id: {{appTenentId}} @@ -19,7 +19,7 @@ tenant-id: {{appTenentId}}
19 "id": 202, 19 "id": 202,
20 "channelCode": "wx_bar", 20 "channelCode": "wx_bar",
21 "channelExtras": { 21 "channelExtras": {
22 - "authCode": "132527737910208222" 22 + "authCode": "132990241553789274"
23 } 23 }
24 } 24 }
25 25