Commit 183206e2d3e442fff824b9dab4fae522ce66ba6e

Authored by jason
1 parent 00e18a48

转账 - 支付宝转账修改, 支付宝 Client 支持公钥证书模式

Showing 12 changed files with 118 additions and 163 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java
@@ -50,8 +50,6 @@ public class PayClientFactoryImpl implements PayClientFactory { @@ -50,8 +50,6 @@ public class PayClientFactoryImpl implements PayClientFactory {
50 clientClass.put(ALIPAY_APP, AlipayAppPayClient.class); 50 clientClass.put(ALIPAY_APP, AlipayAppPayClient.class);
51 clientClass.put(ALIPAY_PC, AlipayPcPayClient.class); 51 clientClass.put(ALIPAY_PC, AlipayPcPayClient.class);
52 clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class); 52 clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class);
53 - // 支付包转账客户端  
54 - clientClass.put(ALIPAY_TRANSFER, AlipayTransferClient.class);  
55 // Mock 支付客户端 53 // Mock 支付客户端
56 clientClass.put(MOCK, MockPayClient.class); 54 clientClass.put(MOCK, MockPayClient.class);
57 } 55 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
@@ -6,24 +6,28 @@ import cn.hutool.core.lang.Assert; @@ -6,24 +6,28 @@ import cn.hutool.core.lang.Assert;
6 import cn.hutool.core.map.MapUtil; 6 import cn.hutool.core.map.MapUtil;
7 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
8 import cn.hutool.http.HttpUtil; 8 import cn.hutool.http.HttpUtil;
  9 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
9 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 10 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
10 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
11 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 12 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
12 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; 13 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
13 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; 14 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
  15 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
  16 +import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
14 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 17 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
15 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; 18 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
  19 +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
16 import com.alipay.api.AlipayApiException; 20 import com.alipay.api.AlipayApiException;
17 import com.alipay.api.AlipayConfig; 21 import com.alipay.api.AlipayConfig;
18 import com.alipay.api.AlipayResponse; 22 import com.alipay.api.AlipayResponse;
19 import com.alipay.api.DefaultAlipayClient; 23 import com.alipay.api.DefaultAlipayClient;
20 -import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;  
21 -import com.alipay.api.domain.AlipayTradeQueryModel;  
22 -import com.alipay.api.domain.AlipayTradeRefundModel; 24 +import com.alipay.api.domain.*;
23 import com.alipay.api.internal.util.AlipaySignature; 25 import com.alipay.api.internal.util.AlipaySignature;
  26 +import com.alipay.api.request.AlipayFundTransUniTransferRequest;
24 import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; 27 import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
25 import com.alipay.api.request.AlipayTradeQueryRequest; 28 import com.alipay.api.request.AlipayTradeQueryRequest;
26 import com.alipay.api.request.AlipayTradeRefundRequest; 29 import com.alipay.api.request.AlipayTradeRefundRequest;
  30 +import com.alipay.api.response.AlipayFundTransUniTransferResponse;
27 import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; 31 import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
28 import com.alipay.api.response.AlipayTradeQueryResponse; 32 import com.alipay.api.response.AlipayTradeQueryResponse;
29 import com.alipay.api.response.AlipayTradeRefundResponse; 33 import com.alipay.api.response.AlipayTradeRefundResponse;
@@ -39,6 +43,9 @@ import java.util.Objects; @@ -39,6 +43,9 @@ import java.util.Objects;
39 import java.util.function.Supplier; 43 import java.util.function.Supplier;
40 44
41 import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; 45 import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
  46 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  47 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
  48 +import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE;
42 49
43 /** 50 /**
44 * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) 51 * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款)
@@ -105,16 +112,20 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa @@ -105,16 +112,20 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
105 // 1.2 构建 AlipayTradeQueryRequest 请求 112 // 1.2 构建 AlipayTradeQueryRequest 请求
106 AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); 113 AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
107 request.setBizModel(model); 114 request.setBizModel(model);
108 -  
109 - // 2.1 执行请求  
110 - AlipayTradeQueryResponse response = client.execute(request); 115 + AlipayTradeQueryResponse response;
  116 + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
  117 + // 证书模式
  118 + response = client.certificateExecute(request);
  119 + } else {
  120 + response = client.execute(request);
  121 + }
111 if (!response.isSuccess()) { // 不成功,例如说订单不存在 122 if (!response.isSuccess()) { // 不成功,例如说订单不存在
112 return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), 123 return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
113 outTradeNo, response); 124 outTradeNo, response);
114 } 125 }
115 // 2.2 解析订单的状态 126 // 2.2 解析订单的状态
116 Integer status = parseStatus(response.getTradeStatus()); 127 Integer status = parseStatus(response.getTradeStatus());
117 - Assert.notNull(status, (Supplier<Throwable>) () -> { 128 + Assert.notNull(status, () -> {
118 throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody())); 129 throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody()));
119 }); 130 });
120 return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()), 131 return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()),
@@ -148,7 +159,13 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -148,7 +159,13 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
148 request.setBizModel(model); 159 request.setBizModel(model);
149 160
150 // 2.1 执行请求 161 // 2.1 执行请求
151 - AlipayTradeRefundResponse response = client.execute(request); 162 + AlipayTradeRefundResponse response;
  163 + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
  164 + // 证书模式
  165 + response = client.certificateExecute(request);
  166 + } else {
  167 + response = client.execute(request);
  168 + }
152 if (!response.isSuccess()) { 169 if (!response.isSuccess()) {
153 // 当出现 ACQ.SYSTEM_ERROR, 退款可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询 170 // 当出现 ACQ.SYSTEM_ERROR, 退款可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询
154 if (ObjectUtils.equalsAny(response.getSubCode(), "ACQ.SYSTEM_ERROR", "SYSTEM_ERROR")) { 171 if (ObjectUtils.equalsAny(response.getSubCode(), "ACQ.SYSTEM_ERROR", "SYSTEM_ERROR")) {
@@ -185,7 +202,13 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -185,7 +202,13 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
185 request.setBizModel(model); 202 request.setBizModel(model);
186 203
187 // 2.1 执行请求 204 // 2.1 执行请求
188 - AlipayTradeFastpayRefundQueryResponse response = client.execute(request); 205 + AlipayTradeFastpayRefundQueryResponse response;
  206 + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
  207 + // 证书模式
  208 + response = client.certificateExecute(request);
  209 + } else {
  210 + response = client.execute(request);
  211 + }
189 if (!response.isSuccess()) { 212 if (!response.isSuccess()) {
190 // 明确不存在的情况,应该就是失败,可进行关闭 213 // 明确不存在的情况,应该就是失败,可进行关闭
191 if (ObjectUtils.equalsAny(response.getSubCode(), "TRADE_NOT_EXIST", "ACQ.TRADE_NOT_EXIST")) { 214 if (ObjectUtils.equalsAny(response.getSubCode(), "TRADE_NOT_EXIST", "ACQ.TRADE_NOT_EXIST")) {
@@ -202,7 +225,69 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa @@ -202,7 +225,69 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
202 return PayRefundRespDTO.waitingOf(null, outRefundNo, response); 225 return PayRefundRespDTO.waitingOf(null, outRefundNo, response);
203 } 226 }
204 227
  228 + @Override
  229 + protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {
  230 + // 1.1 校验公钥类型 必须使用公钥证书模式
  231 + if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
  232 + throw new IllegalStateException("支付宝单笔转账必须使用公钥证书模式");
  233 + }
205 234
  235 + // 1.2 构建 AlipayFundTransUniTransferModel
  236 + AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
  237 + // ① 通用的参数
  238 + model.setTransAmount(formatAmount(reqDTO.getPrice())); // 转账金额
  239 + model.setOrderTitle(reqDTO.getTitle()); // 转账业务的标题,用于在支付宝用户的账单里显示。
  240 + model.setOutBizNo(reqDTO.getOutTransferNo());
  241 + model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD
  242 + model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER
  243 + model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras()));
  244 + PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType());
  245 + switch (transferType) {
  246 + // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦?
  247 + // @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试??
  248 + case ALIPAY_BALANCE: {
  249 + // ② 个性化的参数
  250 + Participant payeeInfo = new Participant();
  251 + payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
  252 + String logonId = MapUtil.getStr(reqDTO.getPayeeInfo(), "ALIPAY_LOGON_ID");
  253 + if (StrUtil.isEmpty(logonId)) {
  254 + throw exception0(BAD_REQUEST.getCode(), "支付包登录 ID 不能为空");
  255 + }
  256 + String accountName = MapUtil.getStr(reqDTO.getPayeeInfo(), "ALIPAY_ACCOUNT_NAME");
  257 + if (StrUtil.isEmpty(accountName)) {
  258 + throw exception0(BAD_REQUEST.getCode(), "支付包账户名称不能为空");
  259 + }
  260 + payeeInfo.setIdentity(logonId); // 支付宝登录号
  261 + payeeInfo.setName(accountName); // 支付宝账号姓名
  262 + model.setPayeeInfo(payeeInfo);
  263 + // 1.3 构建 AlipayFundTransUniTransferRequest
  264 + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
  265 + request.setBizModel(model);
  266 + // 执行请求
  267 + AlipayFundTransUniTransferResponse response = client.certificateExecute(request);
  268 + // 处理结果
  269 + if (!response.isSuccess()) {
  270 + // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询
  271 + if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
  272 + return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);
  273 + }
  274 + return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),
  275 + reqDTO.getOutTransferNo(), response);
  276 + }
  277 + return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),
  278 + response.getOutBizNo(), response);
  279 + }
  280 + case BANK_CARD: {
  281 + Participant payeeInfo = new Participant();
  282 + payeeInfo.setIdentityType("BANKCARD_ACCOUNT");
  283 + // TODO 待实现
  284 + throw new UnsupportedOperationException("待实现");
  285 + }
  286 + default: {
  287 + throw new IllegalStateException("不正确的转账类型: " + transferType);
  288 + }
  289 + }
  290 + }
206 291
207 // ========== 各种工具方法 ========== 292 // ========== 各种工具方法 ==========
208 293
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java
@@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; @@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
3 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 3 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
5 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;  
6 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;  
7 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 5 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
8 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 6 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
9 import com.alipay.api.AlipayApiException; 7 import com.alipay.api.AlipayApiException;
@@ -58,9 +56,4 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { @@ -58,9 +56,4 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
58 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), 56 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
59 reqDTO.getOutTradeNo(), response); 57 reqDTO.getOutTradeNo(), response);
60 } 58 }
61 -  
62 - @Override  
63 - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {  
64 - throw new UnsupportedOperationException("支付宝【App 支付】不支持转账操作");  
65 - }  
66 } 59 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java
@@ -5,8 +5,6 @@ import cn.hutool.core.map.MapUtil; @@ -5,8 +5,6 @@ import cn.hutool.core.map.MapUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
8 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;  
9 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;  
10 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
11 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 9 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
12 import com.alipay.api.AlipayApiException; 10 import com.alipay.api.AlipayApiException;
@@ -16,9 +14,11 @@ import com.alipay.api.response.AlipayTradePayResponse; @@ -16,9 +14,11 @@ import com.alipay.api.response.AlipayTradePayResponse;
16 import lombok.extern.slf4j.Slf4j; 14 import lombok.extern.slf4j.Slf4j;
17 15
18 import java.time.LocalDateTime; 16 import java.time.LocalDateTime;
  17 +import java.util.Objects;
19 18
20 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; 19 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; 20 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
  21 +import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE;
22 22
23 /** 23 /**
24 * 支付宝【条码支付】的 PayClient 实现类 24 * 支付宝【条码支付】的 PayClient 实现类
@@ -61,7 +61,13 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { @@ -61,7 +61,13 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
61 request.setReturnUrl(reqDTO.getReturnUrl()); 61 request.setReturnUrl(reqDTO.getReturnUrl());
62 62
63 // 2.1 执行请求 63 // 2.1 执行请求
64 - AlipayTradePayResponse response = client.execute(request); 64 + AlipayTradePayResponse response;
  65 + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
  66 + // 证书模式
  67 + response = client.certificateExecute(request);
  68 + } else {
  69 + response = client.execute(request);
  70 + }
65 // 2.2 处理结果 71 // 2.2 处理结果
66 if (!response.isSuccess()) { 72 if (!response.isSuccess()) {
67 return buildClosedPayOrderRespDTO(reqDTO, response); 73 return buildClosedPayOrderRespDTO(reqDTO, response);
@@ -76,9 +82,4 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { @@ -76,9 +82,4 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
76 return PayOrderRespDTO.waitingOf(displayMode, "", 82 return PayOrderRespDTO.waitingOf(displayMode, "",
77 reqDTO.getOutTradeNo(), response); 83 reqDTO.getOutTradeNo(), response);
78 } 84 }
79 -  
80 - @Override  
81 - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {  
82 - throw new UnsupportedOperationException("支付宝【条码支付】不支持转账操作");  
83 - }  
84 } 85 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
@@ -4,8 +4,6 @@ import cn.hutool.core.util.ObjectUtil; @@ -4,8 +4,6 @@ import cn.hutool.core.util.ObjectUtil;
4 import cn.hutool.http.Method; 4 import cn.hutool.http.Method;
5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
7 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;  
8 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;  
9 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 7 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
10 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 8 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
11 import com.alipay.api.AlipayApiException; 9 import com.alipay.api.AlipayApiException;
@@ -68,9 +66,4 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { @@ -68,9 +66,4 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
68 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), 66 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
69 reqDTO.getOutTradeNo(), response); 67 reqDTO.getOutTradeNo(), response);
70 } 68 }
71 -  
72 - @Override  
73 - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {  
74 - throw new UnsupportedOperationException("支付宝【PC 网站】不支持转账操作");  
75 - }  
76 } 69 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
@@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; @@ -2,8 +2,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
3 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 3 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
5 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;  
6 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;  
7 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 5 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
8 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 6 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
9 import com.alipay.api.AlipayApiException; 7 import com.alipay.api.AlipayApiException;
@@ -12,6 +10,10 @@ import com.alipay.api.request.AlipayTradePrecreateRequest; @@ -12,6 +10,10 @@ import com.alipay.api.request.AlipayTradePrecreateRequest;
12 import com.alipay.api.response.AlipayTradePrecreateResponse; 10 import com.alipay.api.response.AlipayTradePrecreateResponse;
13 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
14 12
  13 +import java.util.Objects;
  14 +
  15 +import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE;
  16 +
15 /** 17 /**
16 * 支付宝【扫码支付】的 PayClient 实现类 18 * 支付宝【扫码支付】的 PayClient 实现类
17 * 19 *
@@ -47,7 +49,13 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { @@ -47,7 +49,13 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
47 request.setReturnUrl(reqDTO.getReturnUrl()); 49 request.setReturnUrl(reqDTO.getReturnUrl());
48 50
49 // 2.1 执行请求 51 // 2.1 执行请求
50 - AlipayTradePrecreateResponse response = client.execute(request); 52 + AlipayTradePrecreateResponse response;
  53 + if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
  54 + // 证书模式
  55 + response = client.certificateExecute(request);
  56 + } else {
  57 + response = client.execute(request);
  58 + }
51 // 2.2 处理结果 59 // 2.2 处理结果
52 if (!response.isSuccess()) { 60 if (!response.isSuccess()) {
53 return buildClosedPayOrderRespDTO(reqDTO, response); 61 return buildClosedPayOrderRespDTO(reqDTO, response);
@@ -55,9 +63,4 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { @@ -55,9 +63,4 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
55 return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(), 63 return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(),
56 reqDTO.getOutTradeNo(), response); 64 reqDTO.getOutTradeNo(), response);
57 } 65 }
58 -  
59 - @Override  
60 - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {  
61 - throw new UnsupportedOperationException("支付宝【扫码支付】不支持转账操作");  
62 - }  
63 } 66 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayTransferClient.java deleted
1 -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;  
2 -  
3 -import cn.hutool.core.map.MapUtil;  
4 -import cn.hutool.core.util.StrUtil;  
5 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
6 -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;  
7 -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;  
8 -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;  
9 -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;  
10 -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;  
11 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;  
12 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;  
13 -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;  
14 -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;  
15 -import com.alipay.api.AlipayApiException;  
16 -import com.alipay.api.domain.AlipayFundTransUniTransferModel;  
17 -import com.alipay.api.domain.Participant;  
18 -import com.alipay.api.request.AlipayFundTransUniTransferRequest;  
19 -import com.alipay.api.response.AlipayFundTransUniTransferResponse;  
20 -import lombok.extern.slf4j.Slf4j;  
21 -  
22 -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;  
23 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;  
24 -  
25 -// TODO @jason:看看能不能融合到 AbstractAlipayPayClient 中。  
26 -/**  
27 - * 支付宝转账的 PayClient 实现类  
28 - *  
29 - * @author jason  
30 - */  
31 -@Slf4j  
32 -public class AlipayTransferClient extends AbstractAlipayPayClient {  
33 - // TODO @jason:方法之间,要有空格噢  
34 - public AlipayTransferClient(Long channelId, AlipayPayClientConfig config) {  
35 - super(channelId, PayChannelEnum.ALIPAY_TRANSFER.getCode(), config);  
36 - }  
37 - @Override  
38 - protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {  
39 - throw new UnsupportedOperationException("支付宝转账不支持统一下单请求");  
40 - }  
41 - @Override  
42 - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {  
43 - throw new UnsupportedOperationException("支付宝转账不支持统一退款请求");  
44 - }  
45 - @Override  
46 - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {  
47 - // 1.1 构建 AlipayFundTransUniTransferModel  
48 - AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();  
49 - // ① 通用的参数  
50 - model.setTransAmount(formatAmount(reqDTO.getPrice())); // 转账金额  
51 - model.setOrderTitle(reqDTO.getTitle()); // 转账业务的标题,用于在支付宝用户的账单里显示。  
52 - model.setOutBizNo(reqDTO.getOutTransferNo());  
53 - model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD  
54 - model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER  
55 - model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras()));  
56 - PayTransferTypeEnum transferType = PayTransferTypeEnum.ofType(reqDTO.getType());  
57 - switch(transferType) {  
58 - case WX_BALANCE:  
59 - case WALLET_BALANCE: {  
60 - log.error("[doUnifiedTransfer],支付宝转账不支持的转账类型{}", transferType);  
61 - throw new UnsupportedOperationException(String.format("支付宝转账不支持转账类型: %s",transferType.getName()));  
62 - }  
63 - // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦?  
64 - case ALIPAY_BALANCE: {  
65 - // ② 个性化的参数  
66 - Participant payeeInfo = new Participant();  
67 - payeeInfo.setIdentityType("ALIPAY_LOGON_ID");  
68 - String logonId = MapUtil.getStr(reqDTO.getPayeeInfo(), "ALIPAY_LOGON_ID");  
69 - if (StrUtil.isEmpty(logonId)) {  
70 - throw exception0(BAD_REQUEST.getCode(), "支付包登录 ID 不能为空");  
71 - }  
72 - String accountName = MapUtil.getStr(reqDTO.getPayeeInfo(), "ALIPAY_ACCOUNT_NAME");  
73 - if (StrUtil.isEmpty(accountName)) {  
74 - throw exception0(BAD_REQUEST.getCode(), "支付包账户名称不能为空");  
75 - }  
76 - payeeInfo.setIdentity(logonId); // 支付宝登录号  
77 - payeeInfo.setName(accountName); // 支付宝账号姓名  
78 - model.setPayeeInfo(payeeInfo);  
79 - // 1.2 构建 AlipayFundTransUniTransferRequest  
80 - AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();  
81 - request.setBizModel(model);  
82 - // 执行请求  
83 - AlipayFundTransUniTransferResponse response = client.certificateExecute(request);  
84 - // 处理结果  
85 - if (!response.isSuccess()) {  
86 - // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询  
87 - if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {  
88 - return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);  
89 - }  
90 - return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(),  
91 - reqDTO.getOutTransferNo(), response);  
92 - }  
93 - return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),  
94 - response.getOutBizNo(), response);  
95 - }  
96 - case BANK_CARD: {  
97 - Participant payeeInfo = new Participant();  
98 - payeeInfo.setIdentityType("BANKCARD_ACCOUNT");  
99 - throw new UnsupportedOperationException("待实现");  
100 - }  
101 - default: {  
102 - throw new IllegalStateException("不正确的转账类型: " + transferType);  
103 - }  
104 - }  
105 - }  
106 -  
107 -}  
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
@@ -3,8 +3,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; @@ -3,8 +3,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
3 import cn.hutool.http.Method; 3 import cn.hutool.http.Method;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; 4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
6 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;  
7 -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;  
8 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; 6 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
9 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; 7 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
10 import com.alipay.api.AlipayApiException; 8 import com.alipay.api.AlipayApiException;
@@ -57,9 +55,4 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient { @@ -57,9 +55,4 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
57 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), 55 return PayOrderRespDTO.waitingOf(displayMode, response.getBody(),
58 reqDTO.getOutTradeNo(), response); 56 reqDTO.getOutTradeNo(), response);
59 } 57 }
60 -  
61 - @Override  
62 - public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {  
63 - throw new UnsupportedOperationException("支付宝【Wap 网站】不支持转账操作");  
64 - }  
65 } 58 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java
@@ -28,9 +28,6 @@ public enum PayChannelEnum { @@ -28,9 +28,6 @@ public enum PayChannelEnum {
28 ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class), 28 ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class),
29 ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), 29 ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class),
30 ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), 30 ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class),
31 - // TODO @jason:是不是按照微信聊的,合并回 ALIPAY_PC;因为支付宝、微信都是多种支付方式,选择其中的一种即可;  
32 - ALIPAY_TRANSFER("alipay_transfer", "支付宝转账", AlipayPayClientConfig.class),  
33 -  
34 MOCK("mock", "模拟支付", NonePayClientConfig.class), 31 MOCK("mock", "模拟支付", NonePayClientConfig.class),
35 32
36 WALLET("wallet", "钱包支付", NonePayClientConfig.class); 33 WALLET("wallet", "钱包支付", NonePayClientConfig.class);
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java
@@ -34,8 +34,7 @@ public enum PayTransferTypeEnum implements IntArrayValuable { @@ -34,8 +34,7 @@ public enum PayTransferTypeEnum implements IntArrayValuable {
34 return ARRAYS; 34 return ARRAYS;
35 } 35 }
36 36
37 - // TODO @jason:是不是 typeOf 更符合预期哈?  
38 - public static PayTransferTypeEnum ofType(Integer type) { 37 + public static PayTransferTypeEnum typeOf(Integer type) {
39 return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); 38 return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
40 } 39 }
41 40
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoTransferServiceImpl.java
@@ -66,7 +66,7 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService { @@ -66,7 +66,7 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
66 66
67 // TODO @jason:可以参考 AppBrokerageWithdrawCreateReqVO 搞下字段哈,进行校验 67 // TODO @jason:可以参考 AppBrokerageWithdrawCreateReqVO 搞下字段哈,进行校验
68 private void validatePayeeInfo(Integer transferType, Map<String, String> payeeInfo) { 68 private void validatePayeeInfo(Integer transferType, Map<String, String> payeeInfo) {
69 - PayTransferTypeEnum transferTypeEnum = ofType(transferType); 69 + PayTransferTypeEnum transferTypeEnum = typeOf(transferType);
70 switch (transferTypeEnum) { 70 switch (transferTypeEnum) {
71 case ALIPAY_BALANCE: { 71 case ALIPAY_BALANCE: {
72 if (StrUtil.isEmpty(MapUtil.getStr(payeeInfo, ALIPAY_LOGON_ID))) { 72 if (StrUtil.isEmpty(MapUtil.getStr(payeeInfo, ALIPAY_LOGON_ID))) {
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
@@ -214,11 +214,11 @@ public class PayTransferServiceImpl implements PayTransferService { @@ -214,11 +214,11 @@ public class PayTransferServiceImpl implements PayTransferService {
214 } 214 }
215 215
216 private void validateChannelCodeAndTypeMatch(String channelCode, Integer type) { 216 private void validateChannelCodeAndTypeMatch(String channelCode, Integer type) {
217 - PayTransferTypeEnum transferType = PayTransferTypeEnum.ofType(type); 217 + PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type);
218 PayChannelEnum payChannel = PayChannelEnum.getByCode(channelCode); 218 PayChannelEnum payChannel = PayChannelEnum.getByCode(channelCode);
219 switch (transferType) { 219 switch (transferType) {
220 case ALIPAY_BALANCE: { 220 case ALIPAY_BALANCE: {
221 - if (payChannel != PayChannelEnum.ALIPAY_TRANSFER) { 221 + if (!payChannel.getCode().startsWith("alipay")) {
222 throw exception(PAY_TRANSFER_TYPE_AND_CHANNEL_NOT_MATCH); 222 throw exception(PAY_TRANSFER_TYPE_AND_CHANNEL_NOT_MATCH);
223 } 223 }
224 break; 224 break;