Commit 183206e2d3e442fff824b9dab4fae522ce66ba6e
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 | 50 | clientClass.put(ALIPAY_APP, AlipayAppPayClient.class); |
| 51 | 51 | clientClass.put(ALIPAY_PC, AlipayPcPayClient.class); |
| 52 | 52 | clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class); |
| 53 | - // 支付包转账客户端 | |
| 54 | - clientClass.put(ALIPAY_TRANSFER, AlipayTransferClient.class); | |
| 55 | 53 | // Mock 支付客户端 |
| 56 | 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 | 6 | import cn.hutool.core.map.MapUtil; |
| 7 | 7 | import cn.hutool.core.util.StrUtil; |
| 8 | 8 | import cn.hutool.http.HttpUtil; |
| 9 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 9 | 10 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 10 | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 11 | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 12 | 13 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 13 | 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 | 17 | import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; |
| 15 | 18 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; |
| 19 | +import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; | |
| 16 | 20 | import com.alipay.api.AlipayApiException; |
| 17 | 21 | import com.alipay.api.AlipayConfig; |
| 18 | 22 | import com.alipay.api.AlipayResponse; |
| 19 | 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 | 25 | import com.alipay.api.internal.util.AlipaySignature; |
| 26 | +import com.alipay.api.request.AlipayFundTransUniTransferRequest; | |
| 24 | 27 | import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; |
| 25 | 28 | import com.alipay.api.request.AlipayTradeQueryRequest; |
| 26 | 29 | import com.alipay.api.request.AlipayTradeRefundRequest; |
| 30 | +import com.alipay.api.response.AlipayFundTransUniTransferResponse; | |
| 27 | 31 | import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; |
| 28 | 32 | import com.alipay.api.response.AlipayTradeQueryResponse; |
| 29 | 33 | import com.alipay.api.response.AlipayTradeRefundResponse; |
| ... | ... | @@ -39,6 +43,9 @@ import java.util.Objects; |
| 39 | 43 | import java.util.function.Supplier; |
| 40 | 44 | |
| 41 | 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 | 112 | // 1.2 构建 AlipayTradeQueryRequest 请求 |
| 106 | 113 | AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); |
| 107 | 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 | 122 | if (!response.isSuccess()) { // 不成功,例如说订单不存在 |
| 112 | 123 | return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), |
| 113 | 124 | outTradeNo, response); |
| 114 | 125 | } |
| 115 | 126 | // 2.2 解析订单的状态 |
| 116 | 127 | Integer status = parseStatus(response.getTradeStatus()); |
| 117 | - Assert.notNull(status, (Supplier<Throwable>) () -> { | |
| 128 | + Assert.notNull(status, () -> { | |
| 118 | 129 | throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody())); |
| 119 | 130 | }); |
| 120 | 131 | return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()), |
| ... | ... | @@ -148,7 +159,13 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 148 | 159 | request.setBizModel(model); |
| 149 | 160 | |
| 150 | 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 | 169 | if (!response.isSuccess()) { |
| 153 | 170 | // 当出现 ACQ.SYSTEM_ERROR, 退款可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询 |
| 154 | 171 | if (ObjectUtils.equalsAny(response.getSubCode(), "ACQ.SYSTEM_ERROR", "SYSTEM_ERROR")) { |
| ... | ... | @@ -185,7 +202,13 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 185 | 202 | request.setBizModel(model); |
| 186 | 203 | |
| 187 | 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 | 212 | if (!response.isSuccess()) { |
| 190 | 213 | // 明确不存在的情况,应该就是失败,可进行关闭 |
| 191 | 214 | if (ObjectUtils.equalsAny(response.getSubCode(), "TRADE_NOT_EXIST", "ACQ.TRADE_NOT_EXIST")) { |
| ... | ... | @@ -202,7 +225,69 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa |
| 202 | 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 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 4 | 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 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 9 | 7 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -58,9 +56,4 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { |
| 58 | 56 | return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), |
| 59 | 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 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 7 | 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 | 8 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 11 | 9 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 12 | 10 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -16,9 +14,11 @@ import com.alipay.api.response.AlipayTradePayResponse; |
| 16 | 14 | import lombok.extern.slf4j.Slf4j; |
| 17 | 15 | |
| 18 | 16 | import java.time.LocalDateTime; |
| 17 | +import java.util.Objects; | |
| 19 | 18 | |
| 20 | 19 | import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; |
| 21 | 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 | 24 | * 支付宝【条码支付】的 PayClient 实现类 |
| ... | ... | @@ -61,7 +61,13 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { |
| 61 | 61 | request.setReturnUrl(reqDTO.getReturnUrl()); |
| 62 | 62 | |
| 63 | 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 | 71 | // 2.2 处理结果 |
| 66 | 72 | if (!response.isSuccess()) { |
| 67 | 73 | return buildClosedPayOrderRespDTO(reqDTO, response); |
| ... | ... | @@ -76,9 +82,4 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { |
| 76 | 82 | return PayOrderRespDTO.waitingOf(displayMode, "", |
| 77 | 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 | 4 | import cn.hutool.http.Method; |
| 5 | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 6 | 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 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 10 | 8 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 11 | 9 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -68,9 +66,4 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { |
| 68 | 66 | return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), |
| 69 | 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 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 4 | 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 | 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 8 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 9 | 7 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -12,6 +10,10 @@ import com.alipay.api.request.AlipayTradePrecreateRequest; |
| 12 | 10 | import com.alipay.api.response.AlipayTradePrecreateResponse; |
| 13 | 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 | 18 | * 支付宝【扫码支付】的 PayClient 实现类 |
| 17 | 19 | * |
| ... | ... | @@ -47,7 +49,13 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { |
| 47 | 49 | request.setReturnUrl(reqDTO.getReturnUrl()); |
| 48 | 50 | |
| 49 | 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 | 59 | // 2.2 处理结果 |
| 52 | 60 | if (!response.isSuccess()) { |
| 53 | 61 | return buildClosedPayOrderRespDTO(reqDTO, response); |
| ... | ... | @@ -55,9 +63,4 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { |
| 55 | 63 | return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(), |
| 56 | 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 | 3 | import cn.hutool.http.Method; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 5 | 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 | 6 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 9 | 7 | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; |
| 10 | 8 | import com.alipay.api.AlipayApiException; |
| ... | ... | @@ -57,9 +55,4 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient { |
| 57 | 55 | return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), |
| 58 | 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 | 28 | ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class), |
| 29 | 29 | ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), |
| 30 | 30 | ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), |
| 31 | - // TODO @jason:是不是按照微信聊的,合并回 ALIPAY_PC;因为支付宝、微信都是多种支付方式,选择其中的一种即可; | |
| 32 | - ALIPAY_TRANSFER("alipay_transfer", "支付宝转账", AlipayPayClientConfig.class), | |
| 33 | - | |
| 34 | 31 | MOCK("mock", "模拟支付", NonePayClientConfig.class), |
| 35 | 32 | |
| 36 | 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 | 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 | 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 | 66 | |
| 67 | 67 | // TODO @jason:可以参考 AppBrokerageWithdrawCreateReqVO 搞下字段哈,进行校验 |
| 68 | 68 | private void validatePayeeInfo(Integer transferType, Map<String, String> payeeInfo) { |
| 69 | - PayTransferTypeEnum transferTypeEnum = ofType(transferType); | |
| 69 | + PayTransferTypeEnum transferTypeEnum = typeOf(transferType); | |
| 70 | 70 | switch (transferTypeEnum) { |
| 71 | 71 | case ALIPAY_BALANCE: { |
| 72 | 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 | 214 | } |
| 215 | 215 | |
| 216 | 216 | private void validateChannelCodeAndTypeMatch(String channelCode, Integer type) { |
| 217 | - PayTransferTypeEnum transferType = PayTransferTypeEnum.ofType(type); | |
| 217 | + PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type); | |
| 218 | 218 | PayChannelEnum payChannel = PayChannelEnum.getByCode(channelCode); |
| 219 | 219 | switch (transferType) { |
| 220 | 220 | case ALIPAY_BALANCE: { |
| 221 | - if (payChannel != PayChannelEnum.ALIPAY_TRANSFER) { | |
| 221 | + if (!payChannel.getCode().startsWith("alipay")) { | |
| 222 | 222 | throw exception(PAY_TRANSFER_TYPE_AND_CHANNEL_NOT_MATCH); |
| 223 | 223 | } |
| 224 | 224 | break; | ... | ... |