diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java index 2d6dd0b5..343e01be 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java @@ -74,44 +74,50 @@ public class AliAuthService { return json.getString("mobile"); } + + private void checkSign(String content, String sign) { + //编码格式 + String charset="utf-8"; + //支付宝公钥 + String alipayPublicCertPath= aliConfig.getAlipayCertPath(); + //签名方式 + String sign_type="RSA2"; + //验签方法 + try { + boolean signVerified= AlipaySignature.rsaCertCheck(content, sign, alipayPublicCertPath, charset, sign_type); + ServiceUtil.assertion(!signVerified, "验签未通过"); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + /** * 解密 * @param response 前端响应(密文) */ private String decrypt(String response) { - //1. 获取验签和解密所需要的参数 Map openapiResult = JSON.parseObject(response,new TypeReference>() {}, Feature.OrderedField); - String signType = "RSA2"; String charset = "UTF-8"; - String encryptType = "AES"; String sign = openapiResult.get("sign"); String content = openapiResult.get("response"); //判断是否为加密内容 boolean isDataEncrypted = !content.startsWith("{"); - boolean signCheckPass = false; + //2. 验签 String signContent = content; - // 你的小程序对应的支付宝公钥(为扩展考虑建议用appId+signType做密钥存储隔离) - String signVeriKey = aliConfig.getAlipayPublicKey(); - // 你的小程序对应的加解密密钥(为扩展考虑建议用appId+encryptType做密钥存储隔离) - String decryptKey = aliConfig.getAesPrivateKey();//如果是加密的报文则需要在密文的前后添加双引号 if (isDataEncrypted) { signContent = "\"" + signContent + "\""; - } try { - signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType); - } catch (AlipayApiException e) { - // 验签异常, 日志 - } if (!signCheckPass) { - //验签不通过(异常或者报文被篡改),终止流程(不需要做解密) - throw new ServiceException("验签失败"); } + this.checkSign(signContent, sign); + //3. 解密 + String encryptType = "AES"; String plainData = null; if (isDataEncrypted) { try { - plainData = AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset); + plainData = AlipayEncrypt.decryptContent(content, encryptType, aliConfig.getAesPrivateKey(), charset); } catch (AlipayApiException e) { //解密异常, 记录日志 throw new ServiceException("解密异常:" + e.getMessage()); diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliConfig.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliConfig.java index d626e014..3ca616a4 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliConfig.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliConfig.java @@ -25,13 +25,13 @@ public class AliConfig { @Value("${ali.privateKey}") private String privateKey; - // 应用公钥 - @Value("${ali.publicKey}") - private String publicKey; - - // 支付宝公钥 - @Value("${ali.alipayPublicKey}") - private String alipayPublicKey; +// // 应用公钥 +// @Value("${ali.publicKey}") +// private String publicKey; +// +// // 支付宝公钥 +// @Value("${ali.alipayPublicKey}") +// private String alipayPublicKey; @Value("${ali.aesPrivateKey}") private String aesPrivateKey; @@ -39,20 +39,53 @@ public class AliConfig { @Value("${ali.notifyUrl}") private String notifyUrl; - private AlipayConfig getAlipayConfig() { - AlipayConfig alipayConfig = new AlipayConfig(); - alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do"); - alipayConfig.setAppId(appId); - alipayConfig.setPrivateKey(privateKey); - alipayConfig.setAlipayPublicKey(alipayPublicKey); - alipayConfig.setFormat("json"); - alipayConfig.setCharset("UTF-8"); - alipayConfig.setSignType("RSA2"); - return alipayConfig; - } + @Value("${ali.transferNotifyUrl}") + private String transferNotifyUrl; + @Value("${ali.appCertPath}") + private String appCertPath; + + @Value("${ali.alipayCertPath}") + private String alipayCertPath; + + @Value("${ali.alipayRootCertPath}") + private String alipayRootCertPath; + +// private AlipayConfig getAlipayConfig() { +// AlipayConfig alipayConfig = new AlipayConfig(); +// alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do"); +// alipayConfig.setAppId(appId); +// alipayConfig.setPrivateKey(privateKey); +// alipayConfig.setAlipayPublicKey(alipayPublicKey); +// alipayConfig.setFormat("json"); +// alipayConfig.setCharset("UTF-8"); +// alipayConfig.setSignType("RSA2"); +// return alipayConfig; +// } + + // 证书模式 @Bean public AlipayClient alipayClient() throws AlipayApiException { - return new DefaultAlipayClient(getAlipayConfig()); + AlipayConfig alipayConfig = new AlipayConfig(); + //设置网关地址 + alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do"); + //设置应用APPID + alipayConfig.setAppId(this.getAppId()); + //设置应用私钥 + alipayConfig.setPrivateKey(this.getPrivateKey()); + //设置应用公钥证书路径 + alipayConfig.setAppCertPath(this.getAppCertPath()); + //设置支付宝公钥证书路径 + alipayConfig.setAlipayPublicCertPath(this.getAlipayCertPath()); + //设置支付宝根证书路径 + alipayConfig.setRootCertPath(this.alipayRootCertPath); + //设置请求格式,固定值json + alipayConfig.setFormat("json"); + //设置字符集 + alipayConfig.setCharset("UTF-8"); + //设置签名类型 + alipayConfig.setSignType("RSA2"); + + return new DefaultAlipayClient(alipayConfig); } } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/BatchTransferAble.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/BatchTransferAble.java new file mode 100644 index 00000000..753166b5 --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/BatchTransferAble.java @@ -0,0 +1,55 @@ +package com.ruoyi.common.pay; + +import com.alipay.api.domain.MultiStepTransOrderDetailRequest; +import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; + +/** + * 可批量转账的接口 + * @author wjh + * 2024/8/9 + */ +public interface BatchTransferAble { + + /** + * 转账总金额(分) + */ + Long transferTotalFen(); + + /** + * 转账总金额(元) + * @return + */ + default BigDecimal transferTotalYuan() { + return BigDecimal.valueOf(transferTotalFen()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP); + } + + /** + * 转账外部订单号 + */ + String transferOutBatchNo(); + + /** + * 转账名称 + */ + String transferBatchName(); + + /** + * 转账备注 + */ + String transferBatchRemark(); + + + /** + * 微信转账明细 + */ + List wxTransferDetailList(); + + /** + * 支付宝转账明细 + */ + List aliTransferDetailList(); +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/TransferApi.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/TransferApi.java new file mode 100644 index 00000000..5a632beb --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/TransferApi.java @@ -0,0 +1,9 @@ +package com.ruoyi.common.pay; + +/** + * 转账API + * @author wjh + * 2024/12/11 + */ +public interface TransferApi { +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/enums/AliTransferStatus.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/enums/AliTransferStatus.java new file mode 100644 index 00000000..c839d866 --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/enums/AliTransferStatus.java @@ -0,0 +1,35 @@ +package com.ruoyi.common.pay.ali.enums; + +import com.ruoyi.common.utils.collection.CollectionUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +/** + * @author wjh + * 2024/12/11 + */ +@Getter +@AllArgsConstructor +public enum AliTransferStatus { + + SUCCESS("SUCCESS", "成功"), + FAIL("FAIL", "失败"), + DEALING("DEALING", "处理中"), + REFUND("REFUND", "已退票"); + + private final String status; + private final String msg; + + // 成功的列表 + public static List successList() { + return CollectionUtils.map(AliTransferStatus::getStatus, SUCCESS); + } + + // 失败的列表 + public static List failList() { + return CollectionUtils.map(AliTransferStatus::getStatus, FAIL, REFUND); + } + +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java index 9a919834..c3181465 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java @@ -61,7 +61,7 @@ public class AliPayService implements PayApi { request.setNotifyUrl(aliConfig.getNotifyUrl()); try { - AlipayTradeCreateResponse response = alipayClient.execute(request); + AlipayTradeCreateResponse response = alipayClient.certificateExecute(request); ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); return response.getTradeNo(); } catch (Exception e) { @@ -78,7 +78,7 @@ public class AliPayService implements PayApi { bizContent.put("out_trade_no", outTradeNo); request.setBizContent(bizContent.toString()); try { - AlipayTradeCloseResponse response = alipayClient.execute(request); + AlipayTradeCloseResponse response = alipayClient.certificateExecute(request); ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); } catch (Exception e) { throw new ServiceException("调用支付宝关闭订单失败:" + e.getMessage()); @@ -96,7 +96,7 @@ public class AliPayService implements PayApi { request.setBizModel(model); try { - AlipayTradeQueryResponse response = alipayClient.execute(request); + AlipayTradeQueryResponse response = alipayClient.certificateExecute(request); ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); return response; } catch (Exception e) { @@ -126,7 +126,7 @@ public class AliPayService implements PayApi { request.setBizModel(model); try { - AlipayTradeRefundResponse response = alipayClient.execute(request); + AlipayTradeRefundResponse response = alipayClient.certificateExecute(request); ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); return response; } catch (Exception e) { diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliTransferService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliTransferService.java new file mode 100644 index 00000000..30a3837e --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliTransferService.java @@ -0,0 +1,164 @@ +package com.ruoyi.common.pay.ali.service; + +import com.alipay.api.AlipayClient; +import com.alipay.api.domain.*; +import com.alipay.api.request.AlipayFundTransCommonQueryRequest; +import com.alipay.api.request.AlipayFundTransMultistepTransferRequest; +import com.alipay.api.request.AlipayFundTransUniTransferRequest; +import com.alipay.api.response.AlipayFundTransCommonQueryResponse; +import com.alipay.api.response.AlipayFundTransMultistepTransferResponse; +import com.alipay.api.response.AlipayFundTransUniTransferResponse; +import com.ruoyi.common.auth.ali.AliConfig; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.pay.BatchTransferAble; +import com.ruoyi.common.utils.ServiceUtil; +import com.wechat.pay.java.service.transferbatch.model.TransferBatchEntity; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.awt.datatransfer.Transferable; +import java.util.ArrayList; +import java.util.List; + +/** + * 支付宝转账API + * @author wjh + * 2024/12/11 + */ +@Service +@Slf4j +public class AliTransferService { + + @Autowired + private AliConfig aliConfig; + + @Autowired + private AlipayClient alipayClient; + + /** + * 多笔转账 + */ + public boolean batchTransfer(BatchTransferAble batchTransferAble) { + + // 构造请求参数以调用接口 + AlipayFundTransMultistepTransferRequest request = new AlipayFundTransMultistepTransferRequest(); + AlipayFundTransMultistepTransferModel model = new AlipayFundTransMultistepTransferModel(); + + // 设置外部单号 + model.setOutBizNo(batchTransferAble.transferOutBatchNo()); + + // 设置产品码:BATCH_API_NO_PWD 批量无密 + model.setProductCode("BATCH_API_NO_PWD"); + + // 设置场景码:MULTI_STEP_TRANSFER 多步转账 + model.setBizScene("MULTI_STEP_TRANSFER"); + + // 设置总金额(元) + model.setTotalAmount(batchTransferAble.transferTotalYuan().toString()); + + // 设置总数量 + List detailList = batchTransferAble.aliTransferDetailList(); + model.setTotalCount(String.valueOf(detailList.size())); + + // 设置备注 + model.setRemark(batchTransferAble.transferBatchRemark()); + + // 设置多步转账明细 + model.setOrderDetails(detailList); + + // TODO 批量设置转账人(官方) + MultiStepTransferParticipant payerInfo = new MultiStepTransferParticipant(); + payerInfo.setIdentity("chuangtewulian@sina.com"); + payerInfo.setName("福鼎创特物联科技有限公司"); + payerInfo.setIdentityType("ALIPAY_USER_ID"); + for (MultiStepTransOrderDetailRequest detail : detailList) { + detail.setPayerInfo(payerInfo); + } + + request.setBizModel(model); + request.setNotifyUrl(aliConfig.getTransferNotifyUrl()); + + try { + AlipayFundTransMultistepTransferResponse response = alipayClient.certificateExecute(request); + log.info("转账结果:{}", response.getBody()); + ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); + return true; + } catch (Exception e) { + throw new ServiceException("批量转账到支付宝账户失败:" + e.getMessage()); + } + } + + public boolean transfer(BatchTransferAble batchTransferAble) { + + // 构造请求参数以调用接口 + AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); + AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); + + List detailList = batchTransferAble.aliTransferDetailList(); + ServiceUtil.assertion(detailList.size() > 1, "当前接口仅适用于单笔转账"); + MultiStepTransOrderDetailRequest detail = detailList.get(0); + + // 设置商家侧唯一订单号 + model.setOutBizNo(detail.getOutBizNo()); + + // 设置订单总金额 + model.setTransAmount(detail.getTransAmount()); + + // 设置描述特定的业务场景 + model.setBizScene("DIRECT_TRANSFER"); + + // 设置业务产品码 + model.setProductCode("TRANS_ACCOUNT_NO_PWD"); + + // 设置转账业务的标题 + model.setOrderTitle(detail.getOrderTitle()); + + // 设置收款方信息 + Participant payeeInfo = new Participant(); + payeeInfo.setIdentity(detail.getPayeeInfo().getIdentity()); + payeeInfo.setName(detail.getPayeeInfo().getName()); + payeeInfo.setIdentityType(detail.getPayeeInfo().getIdentityType()); + model.setPayeeInfo(payeeInfo); + + // 设置业务备注 + model.setRemark(detail.getRemark()); + + request.setBizModel(model); + request.setNotifyUrl(aliConfig.getTransferNotifyUrl()); + + try { + AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request); + ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); + return true; + } catch (Exception e) { + throw new ServiceException("转账到支付宝账户失败:" + e.getMessage()); + } + } + + public AlipayFundTransCommonQueryResponse getTransferBatchByOutNo(String outTradeNo) { + // 构造请求参数以调用接口 + AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest(); + AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel(); + + // 设置销售产品码 + model.setProductCode("TRANS_ACCOUNT_NO_PWD"); + + // 设置描述特定的业务场景 + model.setBizScene("DIRECT_TRANSFER"); + + // 设置商户转账唯一订单号 + model.setOutBizNo(outTradeNo); + + request.setBizModel(model); + + try { + AlipayFundTransCommonQueryResponse response = alipayClient.certificateExecute(request); + ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); + return response; + } catch (Exception e) { + log.error("查询支付宝转账单{}失败:{}", outTradeNo, e.getMessage()); + return null; + } + } +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/wx/domain/BatchTransferAble.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/wx/domain/BatchTransferAble.java deleted file mode 100644 index d27638c9..00000000 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/wx/domain/BatchTransferAble.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.ruoyi.common.pay.wx.domain; - -import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput; - -import java.util.List; - -/** - * 可批量转账的接口 - * @author wjh - * 2024/8/9 - */ -public interface BatchTransferAble { - - /** - * 转账总金额 - */ - Long transferTotalAmount(); - - /** - * 转账外部订单号 - */ - String transferOutBatchNo(); - - /** - * 转账名称 - */ - String transferBatchName(); - - /** - * 转账备注 - */ - String transferBatchRemark(); - - - /** - * 转账明细 - */ - List transferDetailList(); -} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/wx/service/WxTransferService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/wx/service/WxTransferService.java index 45b844d9..316d891a 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/wx/service/WxTransferService.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/wx/service/WxTransferService.java @@ -1,14 +1,18 @@ package com.ruoyi.common.pay.wx.service; +import com.alipay.api.domain.MultiStepTransferParticipant; import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.pay.TransferApi; import com.ruoyi.common.pay.wx.config.WxTransferConfig; -import com.ruoyi.common.pay.wx.domain.BatchTransferAble; +import com.ruoyi.common.pay.BatchTransferAble; import com.ruoyi.common.pay.wx.domain.request.MyInitiateBatchTransferRequest; import com.wechat.pay.java.service.transferbatch.TransferBatchService; import com.wechat.pay.java.service.transferbatch.model.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.List; + /** * @author wjh * 2024/8/12 @@ -26,14 +30,15 @@ public class WxTransferService { * 转账到零钱 */ public InitiateBatchTransferResponse batchTransfer(BatchTransferAble batchTransferAble) { + List detailList = batchTransferAble.wxTransferDetailList(); MyInitiateBatchTransferRequest request = new MyInitiateBatchTransferRequest(); request.setAppid(config.getAppId()); request.setOutBatchNo(batchTransferAble.transferOutBatchNo()); request.setBatchName(batchTransferAble.transferBatchName()); request.setBatchRemark(batchTransferAble.transferBatchRemark()); - request.setTotalAmount(batchTransferAble.transferTotalAmount()); - request.setTotalNum(batchTransferAble.transferDetailList().size()); - request.setTransferDetailList(batchTransferAble.transferDetailList()); + request.setTotalAmount(batchTransferAble.transferTotalFen()); + request.setTotalNum(detailList.size()); + request.setTransferDetailList(detailList); request.setNotifyUrl(config.getTransferNotifyUrl()); try { return transferBatchService.initiateBatchTransfer(request); diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/domain/TransferVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/domain/TransferVO.java index d6e26525..67c6cf7d 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/domain/TransferVO.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/domain/TransferVO.java @@ -1,6 +1,8 @@ package com.ruoyi.ss.transfer.domain; -import com.ruoyi.common.pay.wx.domain.BatchTransferAble; +import com.alipay.api.domain.MultiStepTransOrderDetailRequest; +import com.alipay.api.domain.MultiStepTransferParticipant; +import com.ruoyi.common.pay.BatchTransferAble; import com.ruoyi.common.utils.collection.CollectionUtils; import com.ruoyi.ss.transferDetail.domain.TransferDetailVO; import com.wechat.pay.java.service.transferbatch.model.TransferDetailInput; @@ -26,7 +28,7 @@ public class TransferVO extends Transfer implements BatchTransferAble { * 转账总金额 */ @Override - public Long transferTotalAmount() { + public Long transferTotalFen() { return new BigDecimal(100).multiply(this.getTotalAmount()).longValue(); } @@ -58,10 +60,43 @@ public class TransferVO extends Transfer implements BatchTransferAble { * 转账明细 */ @Override - public List transferDetailList() { + public List wxTransferDetailList() { return this.toTransferDetailInput(this.getDetailList()); } + /** + * 支付宝转账明细 + */ + @Override + public List aliTransferDetailList() { + if (CollectionUtils.isEmptyElement(detailList)) { + return Collections.emptyList(); + } + + List orderDetails = new ArrayList(); + + int seq = 1; + for (TransferDetailVO detail : detailList) { + MultiStepTransOrderDetailRequest orderDetail = new MultiStepTransOrderDetailRequest(); + orderDetail.setOrderSeq(String.valueOf(seq)); + orderDetail.setOrderTitle("转账到支付宝"); +// orderDetail.setBusinessParams("withdraw_timeliness=T0"); + orderDetail.setRemark(detail.getRemark()); + orderDetail.setOutBizNo(detail.getDetailNo()); + orderDetail.setTransAmount(detail.getAmount().toString()); + MultiStepTransferParticipant payeeInfo = new MultiStepTransferParticipant(); + payeeInfo.setIdentity(detail.getAccountNo()); + payeeInfo.setName(detail.getUserName()); + payeeInfo.setIdentityType("ALIPAY_OPEN_ID"); + orderDetail.setPayeeInfo(payeeInfo); + orderDetails.add(orderDetail); + seq ++; + } + + + return orderDetails; + } + /** * 转为明细 */ diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/service/impl/TransferServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/service/impl/TransferServiceImpl.java index 8dc28a19..7e661d10 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/service/impl/TransferServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transfer/service/impl/TransferServiceImpl.java @@ -1,6 +1,9 @@ package com.ruoyi.ss.transfer.service.impl; +import com.alipay.api.response.AlipayFundTransCommonQueryResponse; import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.pay.ali.enums.AliTransferStatus; +import com.ruoyi.common.pay.ali.service.AliTransferService; import com.ruoyi.common.pay.wx.domain.enums.WxTransferBatchStatus; import com.ruoyi.common.pay.wx.domain.enums.WxTransferDetailStatus; import com.ruoyi.common.pay.wx.service.WxPayService; @@ -32,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.support.TransactionTemplate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -65,6 +69,9 @@ public class TransferServiceImpl implements TransferService @Autowired private WxTransferService wxTransferService; + @Autowired + private AliTransferService aliTransferService; + /** * 查询转账 * @@ -197,6 +204,8 @@ public class TransferServiceImpl implements TransferService // 发起转账 if (AccountType.WECHAT.getType().equals(transfer.getAccountType())) { wxTransferService.batchTransfer(transfer); + } else if (AccountType.ALIPAY.getType().equals(transfer.getAccountType())) { + aliTransferService.transfer(transfer); } else { throw new ServiceException("暂不支持该方式进行线上转账"); } @@ -225,11 +234,95 @@ public class TransferServiceImpl implements TransferService // 微信 if (AccountType.WECHAT.getType().equals(transfer.getAccountType())) { return this.refreshTransferStatusWx(transfer); + } else if (AccountType.ALIPAY.getType().equals(transfer.getAccountType())) { + return this.refreshTransferStatusAli(transfer); } else { throw new ServiceException("该付款方式不支持刷新操作"); } } + private int refreshTransferStatusAli(TransferVO transfer) { + if (transfer == null) { + return 0; + } + + // 待更新的数据 + Transfer data = new Transfer(); + List detaiList = new ArrayList<>(); + + int success = 0; + for (TransferDetailVO detail : transfer.getDetailList()) { + AlipayFundTransCommonQueryResponse res = aliTransferService.getTransferBatchByOutNo(detail.getDetailNo()); + + TransferDetail updateDetail = new TransferDetail(); + updateDetail.setDetailId(detail.getDetailId()); + + // 成功的情况 + if (res != null && AliTransferStatus.successList().contains(res.getStatus())) { + updateDetail.setStatus(TransferDetailStatus.TRANSFER_SUCCESS.getStatus()); + detaiList.add(updateDetail); + success ++; + } + // 失败的情况 + else if (res == null || AliTransferStatus.failList().contains(res.getStatus())){ + updateDetail.setStatus(TransferDetailStatus.TRANSFER_FAIL.getStatus()); + if (res != null) { + updateDetail.setStatus(res.getFailReason()); + } else { + updateDetail.setStatus("未知错误,返回值为空"); + } + detaiList.add(updateDetail); + } + // 其余情况不处理 + } + + data.setUpdateTime(DateUtils.getNowDate()); + // 全部成功 + if (success == transfer.getDetailList().size()) { + data.setStatus(TransferStatus.TRANSFER_SUCCESS.getStatus()); + } + // 全部失败 + else if (success == 0) { + data.setStatus(TransferStatus.TRANSFER_FAIL.getStatus()); + } + // 部分成功 + else { + data.setStatus(TransferStatus.TRANSFER_PART_SUCCESS.getStatus()); + } + + // 保存到数据库 + return this.saveByRefresh(transfer.getBatchId(), data, detaiList); + } + + private void operatorBiz(Long batchId) { + // 查询最新的转账信息 + TransferVO dbTransfer = selectTransferByBatchId(batchId); + transferAssembler.assembleDetail(Collections.singletonList(dbTransfer)); + + TransferBstType bstType = TransferBstType.parse(dbTransfer.getBstType()); + ServiceUtil.assertion(bstType == null, "业务类型不存在"); + if (bstType.getAfterTransfer() != null) { + // 业务处理器 + AfterTransfer afterTransfer = SpringUtils.getBean(bstType.getAfterTransfer()); + + // 业务返回值 + int bstResult = 0; + // 成功 + if (TransferStatus.TRANSFER_SUCCESS.getStatus().equals(dbTransfer.getStatus())) { + bstResult = afterTransfer.onTransferSuccess(dbTransfer); + } + // 部分成功 + else if (TransferStatus.TRANSFER_PART_SUCCESS.getStatus().equals(dbTransfer.getStatus())) { + bstResult = afterTransfer.onTransferPartSuccess(dbTransfer); + } + // 失败 + else if (TransferStatus.TRANSFER_FAIL.getStatus().equals(dbTransfer.getStatus())) { + bstResult = afterTransfer.onTransferFail(dbTransfer); + } + ServiceUtil.assertion(bstResult == 0, "业务执行失败"); + } + } + @Override public int refreshTransferStatus(Long batchId) { TransferVO transfer = selectTransferByBatchId(batchId); @@ -294,11 +387,16 @@ public class TransferServiceImpl implements TransferService } // 保存到数据库 + return this.saveByRefresh(transfer.getBatchId(), data, detaiList); + + } + + private int saveByRefresh(Long batchId, Transfer data, List detaiList) { Integer result = transactionTemplate.execute(status -> { // 修改主表信息 TransferQuery query = new TransferQuery(); query.setStatus(TransferStatus.TRANSFER_ING.getStatus()); - query.setBatchId(transfer.getBatchId()); + query.setBatchId(batchId); int update = this.updateByQuery(data, query); ServiceUtil.assertion(update != 1, "修改转账批次失败,状态已发生变化"); @@ -311,33 +409,8 @@ public class TransferServiceImpl implements TransferService ServiceUtil.assertion(detailUpdate != 1, "转账明细修改失败,状态已发生变化"); } - // 修改业务信息 - TransferBstType bstType = TransferBstType.parse(transfer.getBstType()); - ServiceUtil.assertion(bstType == null, "业务类型不存在"); - if (bstType.getAfterTransfer() != null) { - // 业务处理器 - AfterTransfer afterTransfer = SpringUtils.getBean(bstType.getAfterTransfer()); - - // 查询最新的转账信息 - TransferVO dbTransfer = selectTransferByBatchId(transfer.getBatchId()); - transferAssembler.assembleDetail(Collections.singletonList(dbTransfer)); - - // 业务返回值 - int bstResult = 0; - // 成功 - if (TransferStatus.TRANSFER_SUCCESS.getStatus().equals(data.getStatus())) { - bstResult = afterTransfer.onTransferSuccess(dbTransfer); - } - // 部分成功 - else if (TransferStatus.TRANSFER_PART_SUCCESS.getStatus().equals(data.getStatus())) { - bstResult = afterTransfer.onTransferPartSuccess(dbTransfer); - } - // 失败 - else if (TransferStatus.TRANSFER_FAIL.getStatus().equals(data.getStatus())) { - bstResult = afterTransfer.onTransferFail(dbTransfer); - } - ServiceUtil.assertion(bstResult == 0, "业务执行失败"); - } + // 操作业务信息 + this.operatorBiz(batchId); return update; }); diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java index 3c0d017d..d9950655 100644 --- a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java +++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java @@ -230,4 +230,38 @@ public class AppPayController extends BaseController { } } + @ApiOperation("支付宝支付通知") + @PostMapping("/notify/ali") + @Anonymous + public ResponseEntity aliPayNotify(HttpServletRequest request) { + try { + log.info("收到支付宝支付通知{}", request); + String body = HttpUtils.getBody(request); + log.info("收到支付宝支付通知{}", body); + // todo + } catch (ValidationException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + return ResponseEntity.status(HttpStatus.OK).body(null); + } + + @ApiOperation("支付宝转账通知") + @PostMapping("/notify/ali/transfer") + @Anonymous + public ResponseEntity aliPayNotifyTransfer(HttpServletRequest request) { + try { + log.info("收到支付宝转账通知{}", request); + String body = HttpUtils.getBody(request); + log.info("收到支付宝转账通知{}", body); + // todo + } catch (ValidationException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + return ResponseEntity.status(HttpStatus.OK).body(null); + } + } diff --git a/smart-switch-web/src/main/resources/application-dev.yml b/smart-switch-web/src/main/resources/application-dev.yml index bd28c426..e1c2aa3c 100644 --- a/smart-switch-web/src/main/resources/application-dev.yml +++ b/smart-switch-web/src/main/resources/application-dev.yml @@ -141,12 +141,16 @@ ali: # 应用ID appId: 2021004193649611 # 应用私钥 - privateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCLmoyeJgMCIh5xeYOzg1mnRTTPplkBTJAeXozAV/dTCu6vaKNPPRXjDwYILFzpYGAVhe9NNw6mcVq9WU4WEh4k05unDQIFNg0gXFQ9RNmcrV7uokVYAbTpPzmJHHF0oNXddsj9J37fFymP9GJCVuVGEkTHGP2DA6Odgq0xuHPiqQeyDzSldzpSwiRiYW71U534aJGz1MZQx3aI8KlANr2Z0c4WPdmYKmd0x137zHFU5yclsginrZL2tE34nBS5OJHqZQ/WLZIKhv8nGSvcILHhxktU6ggNhhGyf2OdlO9dr0z1exIZPrTMtAUQTEh/X/KqV8DgwNMFtNtT2LC47F+pAgMBAAECggEAAoSRELEi0MEIx4cnhu9RiKDI6Q3ZARr+Zm3SIA32GftSfrtmZqF1aZj1xOP38QWZ9glqXXwmuX3F4zBfJirBfGyMnCCx7qIg7np70ncRba/6zFcE5Sdyudo4EW7/5NiZwtrHmTlDIobqavw/YW7rx63Aq86Zk+lW5BpdQU5QWMAot4aFEPq91eo10a7EVigZKs9vkxKuW7OX/mI/BixkK9YBuq1xS6lefKjQfPPMPCRis3QQtkJWOw2myKXn7qcmCsecQwc3XdrV+6iFpYLOR2V4V3ALVFrDuGFb/2PBThWTiijPAypxQdb/Onu86Z3ObWDXYnPNspBODVxCWBWM2QKBgQDqJ31c37ZXUIfavFMBKp86evF9J+6cjGUOoU4iOd7NWW5QkLvNGAjw138ZQo7OKZ26LtzM2+4bbRVgNjdkVmj4ebdF0kijs7ruF+UhFneodFbwGCBXkMc3yLDLlYjZdeI9B/npGrwFuZAnmM1z+La6z0TlZoQnWe+WED5EUiKbJwKBgQCYoNOOPjb2ysXS/CEM/wX4TUDZ9Ykn85wVLOOhW17LYiMLBJq+uZj8BdN/rzdQ4YO4XqBaDA/t7GhiphaYAfsyy7f1oGEp4jtsyHz21uOPOz4ITnbJ9SUPz5VVmFgsCBjyh6KxckiMXEovcoV1Xqd535BPSQg5q1Y/RbOcaIswrwKBgBtqHjJWeunEIvPIIsu7KsNVC5sEptorUdWhqx00u1I9iz3hhCtiCgHwqQ/TDBc1JiNbQzy07y7E2cDW+CtGNqoIzh1dnmWUMGmZ4Ji8IaxWWqtnl7nI2Jo+Y/yh+FDFjYRpv6e8GpFtBWStbjiKwRIkHEPjecuFqxhdtHyZRTX3AoGAYbogm6SUdwMxFb4gv3yPawS0MJs6Hh2q5BghDJE/qkSFIanqF5MpNL3aRZiAd8ZeG/BjBiVREcvcrsWgE+a43DZ67MirTjEwUaAx+69ud6i8OH9dKkVQXMZS3UK1ukPZDXnxn2MItu7lBWpzr8pSvAN9GHcv0BU4HT1ZGx4JebsCgYEAjIbfv7CwfTwyRbevwVscmjEnvH1r336rU3GfC1C8tvPHVdjzVOEezRHwliT/uPLcUWmTLVtwnEGCcwqoz8PUpgvWeriHXlEqBX3pPixYa2kMLm+5se4qDO32QG1EQXeLPs5UWgqfItgqNEsdeFdsE27LEIqjmRzHoPTEKaylUVs= - # 应用公钥 - publicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi5qMniYDAiIecXmDs4NZp0U0z6ZZAUyQHl6MwFf3Uwrur2ijTz0V4w8GCCxc6WBgFYXvTTcOpnFavVlOFhIeJNObpw0CBTYNIFxUPUTZnK1e7qJFWAG06T85iRxxdKDV3XbI/Sd+3xcpj/RiQlblRhJExxj9gwOjnYKtMbhz4qkHsg80pXc6UsIkYmFu9VOd+GiRs9TGUMd2iPCpQDa9mdHOFj3ZmCpndMdd+8xxVOcnJbIIp62S9rRN+JwUuTiR6mUP1i2SCob/Jxkr3CCx4cZLVOoIDYYRsn9jnZTvXa9M9XsSGT60zLQFEExIf1/yqlfA4MDTBbTbU9iwuOxfqQIDAQAB - # 支付宝公钥 - alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi1vuaEyUkCgagVodfOJp/rk1gwVzs8f/QzEXAEUwZZne+VE8be0rUv9SLY0uOjixanw0yhG9LinHJlePCvuK0Y31Cxx0BXgOt27nGTSqm4oINFYd5WL1vNMPzPE2gat+7ohO3h6FRlmsxsq9W5ZRkko+04Be4lEGZ+Ter/b2v3m4I3CzX6kr42e39QlDRUpD9l9ixpkmfEatdDf01Xp++Tvr/3EZcYoG3oPGztI7B8Kw8KV/6he3ZBlGROWz8ywZSBtR294Y1PRDv+3QXC3nr7J6OrTbnvj+MAtKmwjdkFHiFVr3gfenzeI87LnXrDPahda7Mn6ToQ1NU9tsWCcJgQIDAQAB + privateKey: MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYZr1VQ3FAD3PwcFMTC0sYWRRrxMu3bweEnXU2uK/o+3wxzrnax5l/SUvQJ3CeWUPC7X0cCNMhCVn0NYL08zIMyI9E5x42ry1qvKBRLhBUkctC9XTnIdTjuMbj5XqWuowLlVTP5EdGt4byyEUIh0wGa6WnS9yGn117jfFBii+E7MP+gDXe0HTmxafh8W+VOnAonaBIOLxV5h+AkkK5XKxn/S9EbiVsy/ce7QPkPLBBd1LvjxdHwJ267G9iH0aBhHIxfMKLcfG547Hug+gTcQRkp5Akk05jPiCPBPHYGETE5fAwSiQHsnCUa9AibqcbD1+9Dw1UkSoudeVqbgnB7KzhAgMBAAECggEAZho28J+9iQCRWV23moOvbQGJN+Zh4WQmckeXlvDHEd0iyK/KPnQJN4jgnPU/cyc0yayYbCbRZEnClWUgdoFUX9IigjQhPtvAHsl+0sR8tlvzBMoz5wH4ghRyU46TwdX7K2uBpcI3qn4ckB1yepNCcO6/zcR6W0r7s2JWZuVwjqmR++ixdV8jqg06kxWu39II68ormgflCvkOlJWhPbEeEDUqgRJUDx2r+iJZORlNIj0cT8BgCo4qfeyQWNpANhTBDpC3zXeBBmg5iG8JQTTokEeqwV8Ph1/JR6dOXT3Fn5Ok0tRndhS++XUB8Zqgc3q6F9Fe/za7225TBhV7TnOvvQKBgQDkMttCWNpZWSyQvjK/KMtd3c80XCC8ch0E3ReA1sZRSnsFfOwHb8+pdHeY54DgBtFohP9bmkb+tRtGwgpgWawSWD1iErX8FD78lqPHzJjUiQ+a1vJIkvfp1fJX4HlDTy3PuVW/OZgDL0udCSeTVmr/zBr1nLRdDkYlj9+Ra3bWAwKBgQCq9+NaX354pc6Qawtst4CNhV4NxSMiqefSXx8XV0hlzPnmb4PoBjj/lzdSKgcc7pxunLMmGK9pxDBDqi6y219ciPf5bZKlxoUo7GGHtt1yiMsRduAEHUaitQjXUAo5QXh0kqF4eu+JrXiGCjnNA6s3aQM2VK5szgicx+bbtpf+SwKBgB2Cgh4rVVk2ke/J2NAlm17xHyl7PHSCIUSOvspXe9/pTM1h4Tf4+pbES+8HCQBvgUcN4+PZqJKpovRchXD+R6U7qfxzxPrrN1X8uQNObvkVHGJ+p2hBMTQZCbTZf3T32UnCgtcuwHyw8gtFsst34nBf2aCneh+KiAG1gEjS59Q3AoGAH3oYL7FZNZlBWLF8nv2B+4xMbriW6XDir4a30LJPL/73G4f4fyV2JQiQNN5sBNWhk3PiP+dXlF98i1iv1FozSnQlQ5T65O6R4aDzq+rtBoNM7+A1Ckzhjl9KS2n/F9+H7953QBlSNMTtZbBISAie40rAPqaEnp+oUkUzqcwKW9UCgYAp+2aBq+lumJWGugoxkm8G3hJPO9B2Q/Ogn0+DrCL8GQFoiSYmF+x1d0K2fGglq8CjIK/HnzP7k3qn5ZQlkyn6UzVD0UbibWU2WSdh3100tJ9vpgngGkPaxx5+ZxDxzH8ljIwJZPWKK+xsbW+kX+DFIGBJ038zXwZ5TWKLPIasrw== + # 应用公钥证书地址 + appCertPath: D:\project\证书\alipay\appCertPublicKey_2021004193649611.crt + # 支付宝公钥证书地址 + alipayCertPath: D:\project\证书\alipay\alipayCertPublicKey_RSA2.crt + # 支付宝根证书地址 + alipayRootCertPath: D:\project\证书\alipay\alipayRootCert.crt # AES秘钥 aesPrivateKey: FGhCgOURrXkhGs36PUTHfg== # 通知地址 notifyUrl: http://124.221.246.124:2290/app/pay/notify/ali + # 转账回调地址 + transferNotifyUrl: http://124.221.246.124:2290/app/pay/notify/ali/transfer diff --git a/smart-switch-web/src/main/resources/application-prod.yml b/smart-switch-web/src/main/resources/application-prod.yml index b9b5f225..ae7443ba 100644 --- a/smart-switch-web/src/main/resources/application-prod.yml +++ b/smart-switch-web/src/main/resources/application-prod.yml @@ -150,3 +150,5 @@ ali: aesPrivateKey: FGhCgOURrXkhGs36PUTHfg== # 通知地址 notifyUrl: https://kg.chuangtewl.com/prod-api/app/pay/notify/ali + # 转账回调地址 + transferNotifyUrl: https://kg.chuangtewl.com/prod-api/app/pay/notify/ali/transfer