Explorar o código

支付、提现功能

pengcheng hai 1 día
pai
achega
c8909e1711

+ 31 - 17
ruoyi-admin/src/main/resources/application-dev.yml

@@ -196,23 +196,37 @@ wx:
         msgDataFormat: JSON
         version: develop  # release   develop   trial
   pay:
-    appId: wxcea8ce8b537d83a5 #公司的:wxd15dbb580e6f1cd3  客户的:wx3f5fa98c5edf8718
-    mchId: 1703980824 #公司的:1640577480  客户的:1703980824
-    mchKey: #微信支付商户密钥
-    subAppId: #服务商模式下的子商户公众账号ID
-    subMchId: #服务商模式下的子商户号
-    keyPath: "ruoyi-admin/src/main/resources/cert/apiclient_cert.p12" # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
-    #keyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/apiclient_cert.p12" # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
-    apiv3: 5Bc8eR7zQ1X9gK3lMp2vN6sD4hJ0fAqW #公司的:7f279a5423a15118e9cb1fc381631f61   客户的:5Bc8eR7zQ1X9gK3lMp2vN6sD4hJ0fAqW
-    certSerialNo: 5C8AB18A9CC11514B1343E422C0C57D620B157DC #证书序列号公司的:5DDEE5F70C50743B6B3BFC92263696D2A68AC951,客户的:5C8AB18A9CC11514B1343E422C0C57D620B157DC
-    privateKeyPath: "ruoyi-admin/src/main/resources/cert/apiclient_key.pem"
-    #privateKeyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/apiclient_key.pem"
-    publicKeyId: PUB_KEY_ID_0117039808242025041700351608000401   #公司的:PUB_KEY_ID_0116405774802025022100326400001700 客户的:PUB_KEY_ID_0117039808242025041700351608000401
-    publicKeyPath: "ruoyi-admin/src/main/resources/cert/pub_key.pem"
-    #publicKeyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/pub_key.pem"
-    payNotifyUrl: "https://frp.songlanyun.com/api/pay/wx/notify"
-    refundNotifyUrl: "https://frp.songlanyun.com/api/wx/refund/notify"
-    transferNotifyUrl: "https://frp.songlanyun.com/api/wx/transfer/notify"
+    merchant:
+      appId: wxcea8ce8b537d83a5 #公司的:wxd15dbb580e6f1cd3  客户的:wx3f5fa98c5edf8718
+      mchId: 1703980824 #公司的:1640577480  客户的:1703980824
+      keyPath: "ruoyi-admin/src/main/resources/cert/apiclient_cert.p12" # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+      #keyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/apiclient_cert.p12" # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+      apiv3: 5Bc8eR7zQ1X9gK3lMp2vN6sD4hJ0fAqW #公司的:7f279a5423a15118e9cb1fc381631f61   客户的:5Bc8eR7zQ1X9gK3lMp2vN6sD4hJ0fAqW
+      certSerialNo: 5C8AB18A9CC11514B1343E422C0C57D620B157DC #证书序列号公司的:5DDEE5F70C50743B6B3BFC92263696D2A68AC951,客户的:5C8AB18A9CC11514B1343E422C0C57D620B157DC
+      privateKeyPath: "ruoyi-admin/src/main/resources/cert/apiclient_key.pem"
+      #privateKeyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/apiclient_key.pem"
+      publicKeyId: PUB_KEY_ID_0117039808242025041700351608000401   #公司的:PUB_KEY_ID_0116405774802025022100326400001700 客户的:PUB_KEY_ID_0117039808242025041700351608000401
+      publicKeyPath: "ruoyi-admin/src/main/resources/cert/pub_key.pem"
+      #publicKeyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/pub_key.pem"
+      transferNotifyUrl: "https://frp.songlanyun.com/api/wx/transfer/notify"
+    partner:
+      appId: wxcea8ce8b537d83a5 #公司的:wxd15dbb580e6f1cd3  客户的:wx3f5fa98c5edf8718
+      mchId: 1703980824 #公司的:1640577480  客户的:1703980824
+      mchKey: #微信支付商户密钥
+      subAppId: #服务商模式下的子商户公众账号ID
+      subMchId: #服务商模式下的子商户号
+      keyPath: "ruoyi-admin/src/main/resources/cert/apiclient_cert.p12" # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+      #keyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/apiclient_cert.p12" # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+      apiv3: 5Bc8eR7zQ1X9gK3lMp2vN6sD4hJ0fAqW #公司的:7f279a5423a15118e9cb1fc381631f61   客户的:5Bc8eR7zQ1X9gK3lMp2vN6sD4hJ0fAqW
+      certSerialNo: 5C8AB18A9CC11514B1343E422C0C57D620B157DC #证书序列号公司的:5DDEE5F70C50743B6B3BFC92263696D2A68AC951,客户的:5C8AB18A9CC11514B1343E422C0C57D620B157DC
+      privateKeyPath: "ruoyi-admin/src/main/resources/cert/apiclient_key.pem"
+      #privateKeyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/apiclient_key.pem"
+      publicKeyId: PUB_KEY_ID_0117039808242025041700351608000401   #公司的:PUB_KEY_ID_0116405774802025022100326400001700 客户的:PUB_KEY_ID_0117039808242025041700351608000401
+      publicKeyPath: "ruoyi-admin/src/main/resources/cert/pub_key.pem"
+      #publicKeyPath: "E:/工作/所有项目/全民霸王猜/overlord-guess-admin/ruoyi-admin/src/main/resources/cert/pub_key.pem"
+      payNotifyUrl: "https://frp.songlanyun.com/api/pay/wx/notify"
+      refundNotifyUrl: "https://frp.songlanyun.com/api/wx/refund/notify"
+      transferNotifyUrl: "https://frp.songlanyun.com/api/wx/transfer/notify"
 
 # 支付宝
 alipay:

+ 72 - 28
ruoyi-newwxpay/src/main/java/com/ruoyi/newwxpay/config/NewWxPayProperties.java

@@ -2,6 +2,7 @@ package com.ruoyi.newwxpay.config;
 
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
 import org.springframework.stereotype.Component;
 
 @Data
@@ -15,74 +16,117 @@ public class NewWxPayProperties
     public static final String WECHAT_PAY_NONCE = "Wechatpay-Nonce";
     public static final String WECHAT_PAY_SERIAL = "Wechatpay-Serial";
     public static final String WECHAT_PAY_SIGNATURE = "Wechatpay-Signature";
+
+    @NestedConfigurationProperty
+    private Merchant merchant = new Merchant();
+
+    // ----------------------
+    // 自动映射:pay.partner.xxx
+    // ----------------------
+    @NestedConfigurationProperty
+    private Partner partner = new Partner();
+
+    // 内部类只建一次,不影响你现有结构
+    @Data
+    public static class Merchant {
+        private String appId;
+        private String mchId;
+        private String mchKey;
+        private String keyPath;
+        private String apiv3;
+        private String certSerialNo;
+        private String privateKeyPath;
+        private String publicKeyId;
+        private String publicKeyPath;
+        private String transferNotifyUrl;
+    }
+
+    @Data
+    public static class Partner {
+        private String appId;
+        private String mchId;
+        private String mchKey;
+        private String subAppId;
+        private String subMchId;
+        private String keyPath;
+        private String apiv3;
+        private String certSerialNo;
+        private String privateKeyPath;
+        private String publicKeyId;
+        private String publicKeyPath;
+        private String payNotifyUrl;
+        private String refundNotifyUrl;
+        private String transferNotifyUrl;
+    }
+
     /**
      * 设置微信公众号或者小程序等的appid
-     */
+     *//*
     private String appId;
 
-    /**
+    *//**
      * 微信支付商户号
-     */
+     *//*
     private String mchId;
 
-    /**
+    *//**
      * 微信支付商户密钥
-     */
+     *//*
     private String mchKey;
 
-    /**
+    *//**
      * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除
-     */
+     *//*
     private String subAppId;
 
-    /**
+    *//**
      * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
-     */
+     *//*
     private String subMchId;
 
-    /**
+    *//**
      * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
-     */
+     *//*
     private String keyPath;
 
-    /**
+    *//**
      * apiV3
-     */
+     *//*
     private String apiv3;
 
-    /**
+    *//**
      * 证书序列号
-     */
+     *//*
     private String certSerialNo;
 
-    /**
+    *//**
      * 私钥证书路径
-     */
+     *//*
     private String privateKeyPath;
 
-    /**
+    *//**
      * 公有证书ID
-     */
+     *//*
     private String publicKeyId;
 
-    /**
+    *//**
      * 公有证书
-     */
+     *//*
     private String publicKeyPath;
 
-    /**
+    *//**
      * 支付回调地址
-     */
+     *//*
     private String payNotifyUrl;
 
-    /**
+    *//**
      * 退款回调地址
-     */
+     *//*
     private String refundNotifyUrl;
 
-    /**
+    *//**
      * 转账回调地址
-     */
-    private String transferNotifyUrl;
+     *//*
+    private String transferNotifyUrl;*/
 
 }

+ 5 - 5
ruoyi-newwxpay/src/main/java/com/ruoyi/newwxpay/service/NewWxPayService.java

@@ -98,8 +98,8 @@ public class NewWxPayService {
 
         // 2. 构建统一下单请求参数
         com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayRequest request = new com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayRequest();
-        request.setSpAppid(newWxPayProperties.getAppId());
-        request.setSpMchid(newWxPayProperties.getMchId());
+        request.setSpAppid(newWxPayProperties.getPartner().getAppId());
+        request.setSpMchid(newWxPayProperties.getPartner().getMchId());
         request.setSubMchid(param.getSubMchId());
         request.setDescription(param.getDescription());
         request.setOutTradeNo(param.getOutTradeNo());
@@ -107,7 +107,7 @@ public class NewWxPayService {
         DateTime dateTime = DateUtil.offsetMinute(new Date(), 10);
         request.setTimeExpire(DateUtil.format(dateTime, DatePattern.UTC_PATTERN));
 
-        request.setNotifyUrl(newWxPayProperties.getPayNotifyUrl()); // 回调地址
+        request.setNotifyUrl(newWxPayProperties.getPartner().getPayNotifyUrl()); // 回调地址
         com.wechat.pay.java.service.partnerpayments.jsapi.model.SettleInfo settleInfo = new com.wechat.pay.java.service.partnerpayments.jsapi.model.SettleInfo();
         settleInfo.setProfitSharing(true);
         request.setSettleInfo(settleInfo);
@@ -133,7 +133,7 @@ public class NewWxPayService {
         com.wechat.pay.java.service.partnerpayments.jsapi.JsapiServiceExtension jsapiServiceExtension =
             new com.wechat.pay.java.service.partnerpayments.jsapi.JsapiServiceExtension.Builder().config(rsaPublicKeyConfig).build();
         com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse =
-            jsapiServiceExtension.prepayWithRequestPayment(request,newWxPayProperties.getAppId());
+            jsapiServiceExtension.prepayWithRequestPayment(request,newWxPayProperties.getPartner().getAppId());
         return prepayWithRequestPaymentResponse;
     }
 
@@ -193,7 +193,7 @@ public class NewWxPayService {
         amountReq.setRefund(param.getRefund().multiply(BigDecimal.valueOf(100)).longValue());
         amountReq.setCurrency("CNY");
         createRequest.setAmount(amountReq);
-        createRequest.setNotifyUrl(newWxPayProperties.getRefundNotifyUrl());
+        createRequest.setNotifyUrl(newWxPayProperties.getPartner().getRefundNotifyUrl());
         try {
             Refund refundRes = service.create(createRequest);
             if(Status.SUCCESS.equals(refundRes.getStatus()) || Status.PROCESSING.equals(refundRes.getStatus()))

+ 2 - 2
ruoyi-newwxpay/src/main/java/com/ruoyi/newwxpay/share/service/impl/ProfitSharingOrderServiceImpl.java

@@ -48,7 +48,7 @@ public class ProfitSharingOrderServiceImpl implements ProfitSharingOrderService
         List<CreateOrderReceiver> receivers = new ArrayList();
         CreateOrderReceiver createOrderReceiver = new CreateOrderReceiver();
         createOrderReceiver.setType("MERCHANT_ID");
-        createOrderReceiver.setAccount(newWxPayProperties.getMchId());
+        createOrderReceiver.setAccount(newWxPayProperties.getPartner().getMchId());
         createOrderReceiver.setAmount(profitSharingOrder.getAmount());
         //createOrderReceiver.setName(encrypt(profitSharingOrder.getName()));
         createOrderReceiver.setDescription("分账给平台");
@@ -75,6 +75,6 @@ public class ProfitSharingOrderServiceImpl implements ProfitSharingOrderService
      * @return
      */
     public String encrypt(String plainText) {
-        return WXPayUtility.encrypt(WXPayUtility.loadPublicKeyFromPath(newWxPayProperties.getPublicKeyPath()), plainText);
+        return WXPayUtility.encrypt(WXPayUtility.loadPublicKeyFromPath(newWxPayProperties.getPartner().getPublicKeyPath()), plainText);
     }
 }

+ 10 - 10
ruoyi-newwxpay/src/main/java/com/ruoyi/newwxpay/transfer/service/impl/TransferServiceImpl.java

@@ -63,15 +63,15 @@ public class TransferServiceImpl implements TransferService {
     public TransferToUser.TransferToUserResponse transferBills(WithdrawBo withdrawBo) {
 
         TransferToUser client = new TransferToUser(
-            newWxPayProperties.getMchId(),                    // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
-            newWxPayProperties.getCertSerialNo(),         // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
-            newWxPayProperties.getPrivateKeyPath(),     // 商户API证书私钥文件路径,本地文件路径
-            newWxPayProperties.getPublicKeyId(),      // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
-            newWxPayProperties.getPublicKeyPath()           // 微信支付公钥文件路径,本地文件路径
+            newWxPayProperties.getMerchant().getMchId(),                    // 商户号,是由微信支付系统生成并分配给每个商户的唯一标识符,商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
+            newWxPayProperties.getMerchant().getCertSerialNo(),         // 商户API证书序列号,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
+            newWxPayProperties.getMerchant().getPrivateKeyPath(),     // 商户API证书私钥文件路径,本地文件路径
+            newWxPayProperties.getMerchant().getPublicKeyId(),      // 微信支付公钥ID,如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
+            newWxPayProperties.getMerchant().getPublicKeyPath()           // 微信支付公钥文件路径,本地文件路径
         );
 
         TransferToUser.TransferToUserRequest request = new TransferToUser.TransferToUserRequest();
-        request.appid = newWxPayProperties.getAppId();
+        request.appid = newWxPayProperties.getMerchant().getAppId();
         request.outBillNo = withdrawBo.getBusinessCode();
         request.transferSceneId = "1005";
         request.openid = withdrawBo.getOpenid();
@@ -79,7 +79,7 @@ public class TransferServiceImpl implements TransferService {
         BigDecimal amount = withdrawBo.getMoney();
         request.transferAmount = amount.multiply(new BigDecimal("100")).longValue();
         request.transferRemark = "佣金报酬";
-        request.notifyUrl = newWxPayProperties.getTransferNotifyUrl();
+        request.notifyUrl = newWxPayProperties.getMerchant().getTransferNotifyUrl();
         request.transferSceneReportInfos = new ArrayList<>();
         {
             TransferToUser.TransferSceneReportInfo transferSceneReportInfosItem0 = new TransferToUser.TransferSceneReportInfo();
@@ -94,8 +94,8 @@ public class TransferServiceImpl implements TransferService {
         try {
             TransferToUser.TransferToUserResponse response = client.run(request);
             // TODO: 请求成功,继续业务逻辑
-            response.appid = newWxPayProperties.getAppId();
-            response.mchid = newWxPayProperties.getMchId();
+            response.appid = newWxPayProperties.getMerchant().getAppId();
+            response.mchid = newWxPayProperties.getMerchant().getMchId();
             return response;
         } catch (WXPayUtility.ApiException e) {
             // TODO: 请求失败,根据状态码执行不同的逻辑
@@ -136,7 +136,7 @@ public class TransferServiceImpl implements TransferService {
         WxCallbackResourceDTO resource = callbackDTO.getResource();
         log.info("商家转账到用户零钱回调 resource={}",JSONObject.toJSONString(resource));
 
-        AesUtil aesUtil = new AesUtil(newWxPayProperties.getApiv3().getBytes(StandardCharsets.UTF_8));
+        AesUtil aesUtil = new AesUtil(newWxPayProperties.getMerchant().getApiv3().getBytes(StandardCharsets.UTF_8));
         String plainText = aesUtil.decryptToString(
             resource.getAssociatedData().getBytes(),
             resource.getNonce().getBytes(),