From 740de92b22fe7e4742bd0f46e3f57debf8370f2f Mon Sep 17 00:00:00 2001
From: Administrator <zhubaomin>
Date: 星期一, 15 七月 2024 14:49:01 +0800
Subject: [PATCH] 2024-07-15 朱宝民 农户修改接口、补卡是否已退款判断条件

---
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/AesUtil.java                 |   50 +
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/Refund.java         |   39 +
 pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/cardOperate/CardOperateCtrl.java      |    2 
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/ToRefund.java       |   35 +
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundRequest.java  |   70 ++
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/result/WechatResultCode.java      |   15 
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/PayHelper.java               |  508 ++++++++++++++++++
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardCtrl.java  |  269 +++++++++
 pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/client/ClientCtrl.java                |    3 
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundResponse.java |  114 ++++
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/HmacSha256.java              |   43 +
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/PayInfo.java            |  176 ++++++
 pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardSv.java    |  352 ++++++++++++
 13 files changed, 1,672 insertions(+), 4 deletions(-)

diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/cardOperate/CardOperateCtrl.java b/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/cardOperate/CardOperateCtrl.java
index 502c1e9..5cb744f 100644
--- a/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/cardOperate/CardOperateCtrl.java
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/cardOperate/CardOperateCtrl.java
@@ -229,7 +229,7 @@
         // 濡傛灉浼犲叆浜嗛��杩橀噾棰濓紝闇�瑕佸垽鏂�佸崱锛堣鎸傚け鐨勬按鍗★級鎸傚け鏃舵槸鍚﹀凡缁忛��娆撅紝鏃犺閫�娆惧灏戦兘鎻愮ず鐢ㄦ埛鎸傚け鏃跺凡閫�娆�
         if(reissueAmount != null && reissueAmount > 0) {
             Double tradeAmount = cardOperateSv.getTradeAmountByCardNo(cardNum);
-            if(tradeAmount != null) {
+            if(tradeAmount != null && tradeAmount > 0) {
                 return BaseResponseUtils.buildErrorMsg(SellResultCode.THE_FEE_CANNOT_BE_REFUNDED.getMessage());
             }
         }
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/client/ClientCtrl.java b/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/client/ClientCtrl.java
index 447a341..48d718c 100644
--- a/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/client/ClientCtrl.java
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/client/ClientCtrl.java
@@ -253,7 +253,8 @@
         String villageName = map_districts.get("villageName").toString();
 
         // 鐢熸垚8浣嶈鏀垮尯鍒掔紪鐮侊紝鐢熸垚鍐滄埛缂栧彿鐢�
-        String district8 = countyNum + townNum + villageNum;
+        //String district8 = countyNum + townNum + villageNum;
+        String district8 = String.format("%02d", Integer.parseInt(countyNum))  + String.format("%03d", Integer.parseInt(townNum)) + String.format("%03d", Integer.parseInt(villageNum));
         // 鐢熸垚鍐滄埛缂栧彿
         String clientNum = generateClientNum(district8);
         // 鐢熸垚12浣�5绾ц鏀垮尯鍒掔紪鐮佷覆鍙婂悕绉颁覆
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/result/WechatResultCode.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/result/WechatResultCode.java
index df5e385..ee429dc 100644
--- a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/result/WechatResultCode.java
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/result/WechatResultCode.java
@@ -29,7 +29,6 @@
      */
     RTU_NOT_EXIST(20001, "闃�鎺у櫒涓嶅瓨鍦�"),
     //RTU_ADDR_CANNOT_BE_NULL(20002, "闃�鎺у櫒鍦板潃涓嶈兘涓虹┖");
-
     CLIENT_CARD_NOT_EXIST(30001, "姘村崱涓嶅瓨鍦�"),
 
     /**
@@ -45,7 +44,19 @@
     VALIDATION_TIMEOUT(20004, "楠岃瘉瓒呮椂"),
     PHONE_NUMBER_IS_ERROR(20004, "鎵嬫満鍙烽敊璇紝闈炴敞鍐屽啘鎴�"),
     INVALID_CODE(20004, "鏃犳晥鐨勪复鏃剁櫥褰曞嚟璇�"),
-    LOGIN_FAIL(20004, "鐧诲綍澶辫触");
+    LOGIN_FAIL(20004, "鐧诲綍澶辫触"),
+
+    /**
+     * 铏氭嫙鍗�
+     */
+    ABNORMAL(10001, "閫�娆惧紓甯�"),
+    PROCESSING(10001, "閫�娆惧鐞嗕腑"),
+    VC_OPEN_ACCOUNT_FAIL(90002, "铏氭嫙鍗¤处鎴锋敞鍐屽け璐�"),
+    CARD_NUMBER_OVERRUN(10002, "姘村崱缂栧彿宸叉弧"),
+    VIRTUAL_CARD_NOT_EXIST(90006, "铏氭嫙鍗¤处鎴蜂笉瀛樺湪"),
+    RECHARGE_NOT_EXIST(90006, "鍏呭�艰褰曚笉瀛樺湪"),
+    RECHARGE_FAIL(90006, "鍏呭�煎け璐�"),
+    NO_ACCOUNT(40001, "鎮ㄦ寚瀹氱殑铏氭嫙鍗℃湭娉ㄥ唽");
 
     private final Integer code;
     private final String message;
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/AesUtil.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/AesUtil.java
new file mode 100644
index 0000000..7a629c2
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/AesUtil.java
@@ -0,0 +1,50 @@
+package com.dy.pipIrrWechat.util;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:18
+ * @LastEditTime 2024-07-15 10:18
+ * @Description
+ */
+public class AesUtil {
+    static final int KEY_LENGTH_BYTE = 32;
+    static final int TAG_LENGTH_BIT = 128;
+
+    /**
+     * 瑙e瘑
+     * @param apiV3Key apiV3瀵嗛挜
+     * @param associatedData 闄勫姞鏁版嵁
+     * @param nonce 闅忔満涓�
+     * @param ciphertext 鏁版嵁瀵嗘枃
+     * @return 瑙e瘑鍚庡瓧绗︿覆
+     * @throws GeneralSecurityException
+     * @throws IOException
+     */
+    public static String decryptToString(byte[] apiV3Key, byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
+        try {
+            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+            SecretKeySpec key = new SecretKeySpec(apiV3Key, "AES");
+            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
+
+            cipher.init(Cipher.DECRYPT_MODE, key, spec);
+            cipher.updateAAD(associatedData);
+
+            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
+        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+            throw new IllegalStateException(e);
+        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/HmacSha256.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/HmacSha256.java
new file mode 100644
index 0000000..9f5e7c2
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/HmacSha256.java
@@ -0,0 +1,43 @@
+package com.dy.pipIrrWechat.util;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:19
+ * @LastEditTime 2024-07-15 10:19
+ * @Description
+ */
+public class HmacSha256 {
+    public static String getSignature(String secretKey, String data) throws NoSuchAlgorithmException, InvalidKeyException {
+        // 鍒涘缓瀵嗛挜瀵硅薄
+        byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
+        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "HmacSHA256");
+
+        // 鍒涘缓Mac瀵硅薄骞跺垵濮嬪寲
+        Mac mac = Mac.getInstance("HmacSHA256");
+        mac.init(secretKeySpec);
+
+        // 灏嗗緟鍔犲瘑鐨勬暟鎹浆鎹负瀛楄妭鏁扮粍
+        byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
+
+        // 浣跨敤瀵嗛挜瀵规暟鎹繘琛屽姞瀵�
+        byte[] encryptedBytes = mac.doFinal(dataBytes);
+
+        // 灏嗗姞瀵嗗悗鐨勭粨鏋滆浆鎹负鍗佸叚杩涘埗瀛楃涓�
+        StringBuilder hexString = new StringBuilder();
+        for (byte b : encryptedBytes) {
+            String hex = Integer.toHexString(0xff & b);
+            if (hex.length() == 1) {
+                hexString.append('0');
+            }
+            hexString.append(hex);
+        }
+        String hmacSha256 = hexString.toString();
+        return hmacSha256;
+    }
+}
\ No newline at end of file
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/PayHelper.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/PayHelper.java
new file mode 100644
index 0000000..3aa2522
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/PayHelper.java
@@ -0,0 +1,508 @@
+package com.dy.pipIrrWechat.util;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.dy.common.webUtil.BaseResponse;
+import com.dy.common.webUtil.BaseResponseUtils;
+import com.dy.pipIrrGlobal.pojoSe.SeVirtualCard;
+import com.dy.pipIrrGlobal.voSe.VoOrders;
+import com.dy.pipIrrWechat.result.WechatResultCode;
+import com.dy.pipIrrWechat.virtualCard.VirtualCardSv;
+import com.dy.pipIrrWechat.wechatpay.PayInfo;
+import com.dy.pipIrrWechat.wechatpay.dto.Refund;
+import com.dy.pipIrrWechat.wechatpay.dto.RefundRequest;
+import com.dy.pipIrrWechat.wechatpay.dto.RefundResponse;
+import com.dy.pipIrrWechat.wechatpay.dto.ToRefund;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.NoSuchPaddingException;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.*;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:11
+ * @LastEditTime 2024-07-15 10:11
+ * @Description
+ */
+
+@Component
+@RequiredArgsConstructor
+public class PayHelper {
+    private final VirtualCardSv virtualCardSv;
+    private final RestTemplateUtil restTemplateUtil;
+
+    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+    private String checkSessionUrl = PayInfo.checkSessionUrl;
+    private String tokenUrl = PayInfo.tokenUrl;
+    private String resetUserSessionKeyUrl = PayInfo.resetUserSessionKeyUrl;
+    private String notifyUrl = PayInfo.notifyUrl;
+    private String schema = PayInfo.schema;
+    private String privateCertFileName = PayInfo.privateCertFileName;
+    private String refundUrl = PayInfo.refundUrl;
+
+    // 骞冲彴璇佷功鍏挜
+    public Map<String, Certificate> CERTIFICATE_MAP = new HashMap();
+
+    /**
+     * 鑾峰彇32浣嶉殢鏈哄瓧绗︿覆
+     * @return 闅忔満涓�
+     */
+    public String generateRandomString() {
+        Random random = new Random();
+        StringBuilder sb = new StringBuilder(32);
+        for (int i = 0; i < 32; i++) {
+            int index = random.nextInt(CHARACTERS.length());
+            sb.append(CHARACTERS.charAt(index));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 鑾峰彇鍟嗘埛璇佷功绉侀挜瀵硅薄
+     * @param filename 绉侀挜鏂囦欢璺緞
+     * @return 绉侀挜瀵硅薄
+     * @throws IOException
+     */
+    public PrivateKey getPrivateKey(String filename) throws IOException {
+        String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
+        try {
+            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
+                    .replace("-----END PRIVATE KEY-----", "")
+                    .replaceAll("\\s+", "");
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("褰撳墠Java鐜涓嶆敮鎸丷SA", e);
+        } catch (InvalidKeySpecException e) {
+            throw new RuntimeException("鏃犳晥鐨勫瘑閽ユ牸寮�");
+        }
+    }
+
+    /**
+     * 妫�楠岀櫥褰曟��
+     * @param appid 灏忕▼搴� appId
+     * @param secret 灏忕▼搴� appSecret
+     * @param openid 鐢ㄦ埛鍞竴鏍囪瘑绗�
+     * @param sessionKey 浼氳瘽瀵嗛挜
+     * @return
+     * @throws IOException
+     */
+    public JSONObject checkSessionKey(String appid, String secret, String openid, String sessionKey) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
+        String accessToken = "";
+        Integer expiresIn = 0;
+        String signature = HmacSha256.getSignature(sessionKey, "");
+        String sigMethod = "hmac_sha256";
+
+        JSONObject job_token = getAccessToken(appid, secret);
+        if(job_token != null) {
+            accessToken = job_token.getString("access_token");
+            expiresIn = job_token.getInteger("expires_in");
+        }
+
+        Map<String, Object> queryParams = new HashMap<>();
+        queryParams.put("access_token", accessToken);
+        queryParams.put("openid", openid);
+        queryParams.put("signature", signature);
+        queryParams.put("sig_method", sigMethod);
+        Map<String, String> headerParams = new HashMap<>();
+        JSONObject result = restTemplateUtil.get(checkSessionUrl, queryParams, headerParams);
+        return result;
+    }
+
+    /**
+     * 閲嶇疆鐧诲綍鎬�
+     * @param appid 灏忕▼搴� appId
+     * @param secret 灏忕▼搴� appSecret
+     * @param openid 鐢ㄦ埛鍞竴鏍囪瘑绗�
+     * @param sessionKey 浼氳瘽瀵嗛挜
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeyException
+     * @throws IOException
+     */
+    public JSONObject resetUserSessionKey(String appid, String secret, String openid, String sessionKey) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
+        String accessToken = "";
+        Integer expiresIn = 0;
+        String signature = HmacSha256.getSignature(sessionKey, "");
+        String sigMethod = "hmac_sha256";
+
+        JSONObject job_token = getAccessToken(appid, secret);
+        if(job_token != null) {
+            accessToken = job_token.getString("access_token");
+            expiresIn = job_token.getInteger("expires_in");
+        }
+
+        Map<String, Object> queryParams = new HashMap<>();
+        queryParams.put("access_token", accessToken);
+        queryParams.put("openid", openid);
+        queryParams.put("signature", signature);
+        queryParams.put("sig_method", sigMethod);
+        Map<String, String> headerParams = new HashMap<>();
+        JSONObject result = restTemplateUtil.get(resetUserSessionKeyUrl, queryParams, headerParams);
+        return result;
+    }
+
+    /**
+     * 鑾峰彇鎺ュ彛璋冪敤鍑嵁
+     * @param appid 灏忕▼搴� appId
+     * @param secret 灏忕▼搴� appSecret
+     * @return 鍑嵁鍙婂嚟鎹湁鏁堟椂闂�
+     * @throws IOException
+     */
+    public JSONObject getAccessToken(String appid, String secret) throws IOException {
+        Map<String, Object> queryParams = new HashMap<>();
+        queryParams.put("grant_type", "client_credential");
+        queryParams.put("appid", appid);
+        queryParams.put("secret", secret);
+        Map<String, String> headerParams = new HashMap<>();
+        JSONObject job_result = restTemplateUtil.get(tokenUrl, queryParams, headerParams);
+        return job_result;
+    }
+
+    /**
+     * 鏋勯�犵鍚嶄覆_涓嬪崟
+     * @param method HTTP璇锋眰鏂规硶
+     * @param url URL
+     * @param timestamp 鏃堕棿鎴�
+     * @param nonceStr 闅忔満涓�
+     * @param body 鎶ユ枃涓婚
+     * @return 绛惧悕涓�
+     */
+    public String buildMessage_order(String method, String url, long timestamp, String nonceStr, String body) {
+        return method + "\n"
+                + url + "\n"
+                + timestamp + "\n"
+                + nonceStr + "\n"
+                + body + "\n";
+    }
+
+    /**
+     * 鏋勯�犵鍚嶄覆_鍐嶆涓嬪崟
+     * @param appid 灏忕▼搴忓敮涓�鏍囪瘑
+     * @param timestamp 鏃堕棿鎴�
+     * @param nonceStr 闅忔満涓�
+     * @param pkg package
+     * @return 绛惧悕涓�
+     */
+    public String buildMessage_signAgain(String appid, String timestamp, String nonceStr, String pkg) {
+        return appid + "\n"
+                + timestamp + "\n"
+                + nonceStr + "\n"
+                + pkg + "\n";
+    }
+
+    /**
+     * 绛惧悕
+     * @param message 琚鍚嶄俊鎭�
+     * @param certFileName 绉侀挜璇佷功鏂囦欢璺緞
+     * @return signature绛惧悕鍊硷紝绛惧悕淇℃伅涓殑涓�椤癸紝鍙備笌鐢熸垚绛惧悕淇℃伅
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeyException
+     * @throws SignatureException
+     * @throws IOException
+     */
+    public String sign(byte[] message, String certFileName) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException {
+        Signature sign = Signature.getInstance("SHA256withRSA");
+        sign.initSign(getPrivateKey(certFileName));
+        sign.update(message);
+        return Base64.getEncoder().encodeToString(sign.sign());
+    }
+
+    /**
+     * 鑾峰彇绛惧悕淇℃伅
+     * @param method
+     * @param url
+     * @param body
+     * @return 绛惧悕淇℃伅锛孒TTP澶翠腑鐨勭鍚嶄俊鎭�
+     * HTTP澶达細Authorization: 璁よ瘉绫诲瀷 绛惧悕淇℃伅
+     * 璁よ瘉绫诲瀷锛學ECHATPAY2-SHA256-RSA2048
+     */
+    public String getToken(String method, String url, String body, String nonceStr, Long timestamp, String certFileName) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, NoSuchPaddingException {
+        String message = buildMessage_order(method, url, timestamp, nonceStr, body);
+        String signature = sign(message.getBytes("utf-8"), certFileName);
+
+        return "mchid=\"" + PayInfo.mchid + "\","
+                + "nonce_str=\"" + nonceStr + "\","
+                + "timestamp=\"" + timestamp + "\","
+                + "serial_no=\"" + PayInfo.serial_no + "\","
+                + "signature=\"" + signature + "\"";
+    }
+
+    /**
+     * 鏋勯�犻獙閫犵鍚嶄覆
+     * @param wechatpayTimestamp 璇锋眰澶翠腑杩斿洖鐨勬椂闂存埑
+     * @param wechatpayNonce 璇锋眰澶翠腑杩斿洖鐨勯殢鏈轰覆
+     * @param boey 璇锋眰杩斿洖鐨刡ody
+     * @return signatureStr鏋勯�犵殑楠岀鍚嶄覆
+     */
+    public String responseSign(String wechatpayTimestamp, String wechatpayNonce, String boey) {
+        String signatureStr = wechatpayTimestamp + "\n"
+                + wechatpayNonce + "\n"
+                + boey + "\n";
+        return signatureStr;
+    }
+
+    /**
+     * 閲嶆柊涓嬭浇璇佷功
+     */
+    public void refreshCertificate() throws GeneralSecurityException, IOException {
+        String method = "GET";
+        String httpUrl = "/v3/certificates";
+        String nonceStr = generateRandomString();
+        Long timestamp = System.currentTimeMillis() / 1000;
+
+        String header = PayInfo.schema + " " + getToken(method, httpUrl, "", nonceStr, timestamp, PayInfo.privateCertFileName);
+
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Authorization", header);
+        headers.put("Accept", "application/json");
+        //headers.put("User-Agent", "https://zh.wikipedia.org/wiki/User_agent");
+
+        JSONObject job_result = restTemplateUtil.getHeaders(PayInfo.certificates,null, headers);
+        JSONObject job_headers = job_result.getJSONObject("headers");
+
+        String wechatpayNonce = job_headers.getJSONArray("Wechatpay-Nonce").getString(0);
+        String wechatpaySerial = job_headers.getJSONArray("Wechatpay-Serial").getString(0);
+        String signature_h = job_headers.getJSONArray("Wechatpay-Signature").getString(0);
+        String signatureType_h = job_headers.getJSONArray("Wechatpay-Signature-Type").getString(0);
+        String wechatpayTimestamp = job_headers.getJSONArray("Wechatpay-Timestamp").getString(0);
+
+        JSONObject job_body = job_result.getJSONObject("body");
+        if(job_body != null) {
+            JSONArray array = job_body.getJSONArray("data");
+            if(array != null && array.size() > 0) {
+                for(int i = 0; i < array.size(); i++) {
+                    JSONObject job_data = array.getJSONObject(i);
+                    String certificateSerial = job_data.getString("serial_no");
+                    String effective_time  = job_data.getString("effective_time");
+                    String expire_time  = job_data.getString("expire_time");
+                    JSONObject job_certificate = job_data.getJSONObject("encrypt_certificate");
+                    String algorithm = job_certificate.getString("algorithm");
+                    String nonce  = job_certificate.getString("nonce");
+                    String associated_data  = job_certificate.getString("associated_data");
+                    String ciphertext  = job_certificate.getString("ciphertext");
+
+                    //瀵硅瘉涔﹀瘑鏂囪繘琛岃В瀵嗗緱鍒板钩鍙拌瘉涔﹀叕閽�
+                    String publicKey = AesUtil.decryptToString(PayInfo.key.getBytes("utf-8"), associated_data.getBytes("utf-8"), nonce.getBytes("utf-8"), ciphertext);
+
+                    // 灏嗗钩鍙板叕閽ュ瓧绗︿覆杞垚Certificate瀵硅薄
+                    final CertificateFactory cf = CertificateFactory.getInstance("X509");
+                    ByteArrayInputStream inputStream = new ByteArrayInputStream(publicKey.getBytes(StandardCharsets.UTF_8));
+                    Certificate certificate = null;
+                    try {
+                        certificate = cf.generateCertificate(inputStream);
+                    } catch (CertificateException e) {
+                        e.printStackTrace();
+                    }
+
+                    // 鍝嶅簲澶磋瘉涔﹀簭鍙蜂笌鍝嶅簲浣撹瘉涔﹀簭鍒楀彿涓�鑷达紝涓旀椂闂村樊灏忎簬5鍒嗛挓鏃舵墠灏嗚瘉涔﹀瓨鍌╩ap
+                    Long timeDiff = (System.currentTimeMillis() / 1000 - Long.parseLong(wechatpayTimestamp))/60;
+                    if(wechatpaySerial.equals(certificateSerial) && timeDiff <= 5) {
+                        // 璇佷功鏀惧叆MAP
+                        CERTIFICATE_MAP.put(certificateSerial, certificate);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 浣跨敤寰俊骞冲彴璇佷功杩涜鍝嶅簲楠岀
+     * @param wechatpaySerial 鏉ヨ嚜鍝嶅簲澶寸殑寰俊骞冲彴璇佷功搴忓垪鍙�
+     * @param signatureStr 鏋勯�犵殑楠岀鍚嶄覆
+     * @param wechatpaySignature 鏉ヨ嚜鍝嶅簲澶寸殑寰俊骞冲彴绛惧悕
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeyException
+     * @throws SignatureException
+     */
+    public Boolean responseSignVerify(String wechatpaySerial, String signatureStr, String wechatpaySignature) throws GeneralSecurityException, IOException {
+        if(CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
+            CERTIFICATE_MAP.clear();
+            refreshCertificate();
+        }
+        Certificate certificate = (Certificate)CERTIFICATE_MAP.get(wechatpaySerial);
+        if(certificate == null) {
+            return false;
+        }
+
+        // 鑾峰彇鍏挜
+        PublicKey publicKey = certificate.getPublicKey();
+
+        // 鍒濆鍖朣HA256withRSA鍓嶉潰鍣�
+        Signature signature = Signature.getInstance("SHA256withRSA");
+        // 鐢ㄥ井淇″钩鍙板叕閽ュ鍓嶉潰鍣ㄨ繘琛屽垵濮嬪寲
+        signature.initVerify(certificate);
+
+        // 灏嗘瀯閫犵殑楠岀鍚嶄覆鏇存柊鍒扮鍚嶅櫒涓�
+        signature.update(signatureStr.getBytes(StandardCharsets.UTF_8));
+
+        // 璇锋眰澶翠腑寰俊鏈嶅姟鍣ㄨ繑鍥炵殑绛惧悕鐢˙ase64瑙g爜锛屼娇鐢ㄧ鍚嶅櫒杩涜楠岃瘉
+        boolean valid = signature.verify(Base64.getDecoder().decode(wechatpaySignature));
+        return valid;
+    }
+
+
+    /**
+     * 鑾峰彇寰呴��娆惧璞″垪琛�
+     *      寰呴��娆惧璞″寘鍚鍗曞彿鍜屽彲閫�娆鹃噾棰�
+     *      璁㈠崟瀵硅薄鍖呭惈璁㈠崟鍙枫�佸厖鍊奸噾棰濄�佸厖鍊煎畬鎴愭椂闂�
+     *      1. 鏍规嵁铏氭嫙鍗″彿鍒拌櫄鎷熷崱琛ㄤ腑鍙栧嚭璇ュ崱浣欓
+     *      2. 鏍规嵁铏氭嫙鍗″彿鍒板厖鍊艰〃鍙栧嚭璁㈠崟瀵硅薄鍒楄〃
+     * @param virtualId
+     * @param refundAmount
+     * @return
+     */
+    public List<ToRefund> getToRefunds(Long virtualId, Integer refundAmount) {
+        ToRefund toRefund = new ToRefund();
+        List<ToRefund> list = new ArrayList<>();
+        Double money = 0d;
+
+        // 鏍规嵁铏氭嫙鍗″彿鑾峰彇褰撳墠铏氭嫙鍗′綑棰�
+        SeVirtualCard seVirtualCard = virtualCardSv.selectVirtuCardById(virtualId);
+        if(seVirtualCard != null) {
+            money = seVirtualCard.getMoney();
+        }
+
+        // 瑕侀��閲戦澶т簬璇ュ崱浣欓锛岃繑鍥炵┖鍒楄〃
+        if(refundAmount > money) {
+            return list;
+        }
+
+        // 鏍规嵁铏氭嫙鍗″彿鑾峰彇璁㈠崟鍒楄〃锛堜粎闄愬厖鍊兼垚鍔熺殑锛�
+        List<VoOrders> list_Orders = virtualCardSv.selectOrders(virtualId);
+        // 閬嶅巻璁㈠崟鍒楄〃锛岃幏鍙�
+        if(list_Orders != null && list_Orders.size() > 0) {
+            JSONArray array_Orders = (JSONArray) JSON.toJSON(list_Orders);
+            for(int i = 0; i < array_Orders.size(); i++) {
+                JSONObject job_order = array_Orders.getJSONObject(i);
+                String orderNumber = job_order.getString("orderNumber");
+                Integer rechargeAmount = job_order.getInteger("rechargeAmount");
+                Date rechargeTime = job_order.getDate("rechargeTime");
+
+                // 璁$畻鍏呭�艰嚦浠婃椂闂村樊锛堝垎閽燂級
+                Long timestamp_Recharge = rechargeTime.getTime() / 1000;
+                Long timestamp_Current = System.currentTimeMillis() / 1000;
+                Long timeDiff_Minute = (timestamp_Current - timestamp_Recharge)/60;
+
+                // 鑾峰彇璇ヨ鍗曞凡閫�娆剧瑪鏁�
+                Integer refundCount = 0;
+                List<Integer> list_RefundAmount = virtualCardSv.selectRefundAmount(orderNumber);
+                if(list_RefundAmount != null && list_RefundAmount.size() > 0) {
+                    refundCount = list_RefundAmount.size();
+                }
+
+                // 鍏呭�艰嚦浠婃湭瓒呰繃涓�骞翠笖璇ヨ鍗曢��娆炬�绘鏁版湭瓒呰繃50娆�
+                if(timeDiff_Minute/(365*24*60) >= 1 && (refundCount + 1) > 50)
+                    return list;
+
+                /**
+                 * 1. 濡傛灉瑕侀��閲戦灏忎簬褰撳墠璁㈠崟鐨勫厖鍊奸噾棰濓紝瑕侀��閲戦鍗充负搴旈��閲戦骞惰繑鍥�
+                 * 2. 濡傛灉瑕佹帹閲戦澶т簬褰撳墠璁㈠崟鍏呭�奸噾棰濓紝褰撳墠璁㈠崟鍏呭�奸噾棰濆嵆涓哄簲閫�閲戦
+                 *      a. 鐢熸垚搴旈��娆惧璞�
+                 *      b. 璁$畻鏂扮殑浣欓
+                 *      c. 閲戣挏鏂扮殑瑕侀��娆鹃噾棰�
+                 *      d. 濡傛灉瑕侀��閲戦澶т簬0锛岄亶鍘嗕笅涓�涓鍗�
+                 */
+                if(refundAmount <= rechargeAmount) {
+                    toRefund = new ToRefund();
+                    toRefund.setOrderNumber(orderNumber);
+                    toRefund.setRefundAmount(refundAmount);
+                    list.add(toRefund);
+                    // 璁$畻鏂扮殑浣欓鍜屾柊鐨勮閫�閲戦
+                    money = money - refundAmount;
+                    refundAmount = refundAmount - refundAmount;
+                    return list;
+                }else {
+                    toRefund = new ToRefund();
+                    toRefund.setOrderNumber(orderNumber);
+                    toRefund.setRefundAmount(rechargeAmount);
+                    list.add(toRefund);
+                    // 璁$畻鏂扮殑浣欓鍜屾柊鐨勮閫�閲戦
+                    money = money - rechargeAmount;
+                    refundAmount = refundAmount - rechargeAmount;
+                    if(refundAmount > 0) {
+                        continue;
+                    }else {
+                        return list;
+                    }
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 閫�娆剧敵璇凤紝璋冪敤寰俊鏀粯閫�娆剧敵璇锋帴鍙�
+     * @param po 閫�娆捐姹傚璞★紝鍖呭惈璁㈠崟鍙枫�侀��娆惧崟鍙枫�侀��娆鹃噾棰�
+     * @return
+     * @throws NoSuchPaddingException
+     * @throws NoSuchAlgorithmException
+     * @throws InvalidKeySpecException
+     * @throws IOException
+     * @throws SignatureException
+     * @throws InvalidKeyException
+     */
+    public BaseResponse<Boolean> refunds(Refund po) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException {
+        String tradeNo = po.getTradeNo();
+        String refundNo = po.getRefundNo();
+        Integer refund = po.getRefund();
+
+        // 鐢熸垚body
+        Integer total = virtualCardSv.getRechargeAmountByOrderNumber(tradeNo);
+        RefundRequest.Amount amount = new RefundRequest.Amount();
+        amount.setRefund(refund);
+        amount.setTotal(total);
+        amount.setCurrency("CNY");
+
+        RefundRequest refundRequest = new RefundRequest();
+        refundRequest.setOut_trade_no(tradeNo);
+        refundRequest.setOut_refund_no(refundNo);
+        refundRequest.setNotify_url(notifyUrl);
+        refundRequest.setAmount(amount);
+
+        // 鐢熸垚header
+        String nonceStr = generateRandomString();
+        Long timestamp = System.currentTimeMillis() / 1000;
+
+        String method = "POST";
+        String httpUrl = "/v3/refund/domestic/refunds";
+
+        String body = JSONObject.toJSONString(refundRequest);
+        String header = schema + " " + getToken(method, httpUrl, body, nonceStr, timestamp, privateCertFileName);
+
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Authorization", header);
+        headers.put("Accept", "application/json");
+        headers.put("Content-Type", "application/json");
+
+        JSONObject job_refundResponse = restTemplateUtil.post(PayInfo.refundUrl, body, headers);
+        RefundResponse refundResponse = JSON.parseObject(job_refundResponse.toJSONString(), RefundResponse.class);
+
+        String status = refundResponse.getStatus();
+        if(status != null && status.equals("SUCCESS")) {
+            // 閫�娆剧敵璇峰凡鍙楃悊
+            return BaseResponseUtils.buildSuccess(true) ;
+        } else if(status != null && status.equals("PROCESSING")) {
+            // 閫�娆惧鐞嗕腑
+            return BaseResponseUtils.buildFail(WechatResultCode.PROCESSING.getMessage());
+        } else {
+            // 閫�娆惧紓甯�
+            return BaseResponseUtils.buildError(WechatResultCode.ABNORMAL.getMessage());
+        }
+    }
+}
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardCtrl.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardCtrl.java
new file mode 100644
index 0000000..e53ea94
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardCtrl.java
@@ -0,0 +1,269 @@
+package com.dy.pipIrrWechat.virtualCard;
+
+import com.dy.common.aop.SsoAop;
+import com.dy.common.webUtil.BaseResponse;
+import com.dy.common.webUtil.BaseResponseUtils;
+import com.dy.common.webUtil.QueryResultVo;
+import com.dy.pipIrrGlobal.pojoSe.SeVirtualCard;
+import com.dy.pipIrrGlobal.voSe.VoVcRecharge;
+import com.dy.pipIrrGlobal.voSe.VoVirtualCard;
+import com.dy.pipIrrWechat.util.PayHelper;
+import com.dy.pipIrrWechat.virtualCard.enums.LastOperateENUM;
+import com.dy.pipIrrWechat.result.WechatResultCode;
+import com.dy.pipIrrWechat.virtualCard.dto.DtoRegist;
+import com.dy.pipIrrWechat.virtualCard.dto.DtoVcRecharge;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 9:55
+ * @LastEditTime 2024-07-15 9:55
+ * @Description
+ */
+
+@Slf4j
+@Tag(name = "铏氭嫙鍗$鐞�", description = "铏氭嫙鍗$鐞�")
+@RestController
+@RequestMapping(path="virtual_card")
+@RequiredArgsConstructor
+@Validated
+public class VirtualCardCtrl {
+    private final VirtualCardSv virtualCardSv;
+    private final PayHelper payHelper;
+
+    /**
+     * 鑾峰彇鍐滄埛鍏ㄩ儴铏氭嫙鍗�
+     * @return
+     */
+    @GetMapping(path = "/get")
+    @SsoAop()
+    public BaseResponse<List<VoVirtualCard>> getVCs(Long clientId){
+        try {
+            List<VoVirtualCard> res = virtualCardSv.getVCs(clientId);
+            return BaseResponseUtils.buildSuccess(res);
+        } catch (Exception e) {
+            log.error("鑾峰彇鏀粯鏂瑰紡璁板綍寮傚父", e);
+            return BaseResponseUtils.buildException(e.getMessage()) ;
+        }
+    }
+
+    /**
+     * 鏍规嵁铏氭嫙鍗D鑾峰彇铏氭嫙鍗″璞�
+     * @param vcId
+     * @return
+     */
+    @GetMapping(path = "/getVcById")
+    @SsoAop()
+    public BaseResponse<VoVirtualCard> getVcById(@RequestParam Long vcId){
+        try {
+            return BaseResponseUtils.buildSuccess(virtualCardSv.getVcById(vcId));
+        } catch (Exception e) {
+            log.error("鑾峰彇鏀粯鏂瑰紡璁板綍寮傚父", e);
+            return BaseResponseUtils.buildException(e.getMessage()) ;
+        }
+    }
+
+    /**
+     * 铏氭嫙鍗¤处鍙锋敞鍐�
+     * @param po
+     * @param bindingResult
+     * @return
+     */
+    @PostMapping(path = "add_vc")
+    @SsoAop()
+    public BaseResponse<Boolean> addVC(@RequestBody @Valid DtoRegist po, BindingResult bindingResult){
+        if(bindingResult != null && bindingResult.hasErrors()){
+            return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
+        }
+        Long clientId = po.getClientId();
+
+        // 鑾峰彇5绾ц鏀垮尯鍒掍覆areaCode
+        String areaCode = String.valueOf(virtualCardSv.getAreaCodeById(clientId));
+        /**
+         * 鏍规嵁琛屾斂鍖哄垝涓诧紙areaCode锛夊湪铏氭嫙鍗¤〃涓拡瀵硅櫄鎷熷崱缂栧彿锛坴cNum锛夎繘琛屾ā绯婃煡璇�
+         * 濡傛灉5浣嶉『搴忓彿宸茬粡杈惧埌鏈�澶у�硷紝鎻愮ず鐢ㄦ埛鑱旂郴绯荤粺绠$悊鍛�
+         * 濡傛灉5浣嶉『搴忓彿鏈揪鍒版渶澶у�硷紝鍒欏姞1
+         * cardNum涓烘柊鐨勫崱鍙�
+         */
+        String vcNum = Optional.ofNullable(virtualCardSv.getVcCardNumOfMax(areaCode)).orElse("");
+        if(vcNum != null && vcNum.trim().length() > 0) {
+            Integer number = Integer.parseInt(vcNum.substring(12));
+            number = number + 1;
+            if(number > 65535) {
+                return BaseResponseUtils.buildFail(WechatResultCode.CARD_NUMBER_OVERRUN.getMessage());
+            }
+            vcNum = vcNum.substring(0, 12) + String.format("%05d", number);
+        } else {
+            vcNum = areaCode + "00001";
+        }
+
+        SeVirtualCard seVirtualCard = new SeVirtualCard();
+        seVirtualCard.setVcNum(Long.parseLong(vcNum));
+        seVirtualCard.setClientId(clientId);
+        seVirtualCard.setMoney(0d);
+        seVirtualCard.setLastOperate(LastOperateENUM.OPEN_ACCOUNT.getCode());
+        seVirtualCard.setLastOperateTime(new Date());
+        seVirtualCard.setInUse((byte) 0);
+        seVirtualCard.setCreateTime(new Date());
+        Long rec = virtualCardSv.insertVirtualCard(seVirtualCard);
+        if(rec == null) {
+            return BaseResponseUtils.buildFail(WechatResultCode.VC_OPEN_ACCOUNT_FAIL.getMessage());
+        }
+        return BaseResponseUtils.buildSuccess(true) ;
+    }
+
+    /**
+     * 鐢ㄦ埛鐢宠閫�娆�
+     * @param po
+     * @param bindingResult
+     * @return
+     */
+    //@Operation(summary = "铏氭嫙鍗$敵璇烽��娆�", description = "铏氭嫙鍗$敵璇烽��娆�")
+    //@ApiResponses(value = {
+    //        @ApiResponse(
+    //                responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE,
+    //                description = "鎿嶄綔缁撴灉锛歵rue锛氭垚鍔燂紝false锛氬け璐ワ紙BaseResponse.content锛�",
+    //                content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
+    //                        schema = @Schema(implementation = Boolean.class))}
+    //        )
+    //})
+    //@PostMapping(path = "add_refund", consumes = MediaType.APPLICATION_JSON_VALUE)
+    //@Transactional(rollbackFor = Exception.class)
+    //@SsoAop()
+    //public BaseResponse<Boolean> addRefund(@RequestBody @Valid DtoRefund po, BindingResult bindingResult){
+    //    if(bindingResult != null && bindingResult.hasErrors()){
+    //        return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
+    //    }
+    //
+    //    Long virtualId = po.getVirtualId();
+    //    Integer refundAmount = po.getRefundAmount();
+    //
+    //    // 鏍规嵁铏氭嫙鍗D鑾峰彇铏氭嫙鍗″璞�
+    //    SeVirtualCard seVirtualCard = virtualCardSv.selectVirtuCardById(virtualId);
+    //    if(seVirtualCard == null) {
+    //        return BaseResponseUtils.buildFail(WechatResultCode.VIRTUAL_CARD_NOT_EXIST.getMessage());
+    //    }
+    //    Long clientId = seVirtualCard.getClientId();
+    //    Double money = seVirtualCard.getMoney();
+    //
+    //    // 楠岃瘉閫�娆鹃噾棰濇槸鍚﹀ぇ浜庝綑棰�
+    //    if(refundAmount > money) {
+    //        return BaseResponseUtils.buildFail(WechatResultCode.REFUND_AMOUNT_CANNOT_GREATER_THAN_MONEY.getMessage());
+    //    }
+    //
+    //    // 璁$畻娑堣垂鍚庝綑棰�
+    //    Double afterRefund = money - refundAmount;
+    //
+    //    SeVcRefund seVcRefund = new SeVcRefund();
+    //    seVcRefund.setVcId(virtualId);
+    //    seVcRefund.setClientId(clientId);
+    //    seVcRefund.setMoney(money);
+    //    seVcRefund.setRefundAmount(refundAmount);
+    //    seVcRefund.setAfterRefund(afterRefund);
+    //    seVcRefund.setApplicationTime(new Date());
+    //    seVcRefund.setRefundStatus(RefundStateENUM.TO_AUDIT.getCode());
+    //
+    //    Long rec = virtualCardSv.addRefund(seVcRefund);
+    //    if(rec == 0) {
+    //        return BaseResponseUtils.buildFail(WechatResultCode.APPLICATION_REFUND_FAIL.getMessage());
+    //    }
+    //    return BaseResponseUtils.buildSuccess(true) ;
+    //}
+
+    /**
+     * 瀹℃牳閫�娆剧敵璇�
+     * @param po
+     * @param bindingResult
+     * @return
+     */
+    //@Operation(summary = "瀹℃牳閫�娆剧敵璇�", description = "瀹℃牳閫�娆剧敵璇�")
+    //@ApiResponses(value = {
+    //        @ApiResponse(
+    //                responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE,
+    //                description = "鎿嶄綔缁撴灉锛歵rue锛氭垚鍔燂紝false锛氬け璐ワ紙BaseResponse.content锛�",
+    //                content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
+    //                        schema = @Schema(implementation = Boolean.class))}
+    //        )
+    //})
+    //@PostMapping(path = "audit_refund", consumes = MediaType.APPLICATION_JSON_VALUE)
+    //@Transactional(rollbackFor = Exception.class)
+    //@SsoAop()
+    //public BaseResponse<Boolean> auditRefund(@RequestBody @Valid DtoAudit po, BindingResult bindingResult) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException {
+    //    if(bindingResult != null && bindingResult.hasErrors()){
+    //        return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
+    //    }
+    //
+    //    // 鏍规嵁閫�娆綢D鑾峰彇閫�娆惧璞★紝骞舵洿鏂板鏍镐汉銆佸鏍告椂闂淬�佸鏍稿娉ㄣ�侀��娆剧姸鎬佸瓧娈�
+    //    SeVcRefund seVcRefund = virtualCardSv.selectRefundByRefundId(po.getRefundId());
+    //    Long virtualId = seVcRefund.getVcId();
+    //    Integer refundAmount = seVcRefund.getRefundAmount();
+    //    seVcRefund.setAuditor(po.getAuditor());
+    //    seVcRefund.setAuditTime(new Date());
+    //    seVcRefund.setRemarks(po.getRemarks());
+    //    seVcRefund.setRefundStatus(RefundStateENUM.TO_REFUND.getCode());
+    //    Integer rec = virtualCardSv.updateRefund(seVcRefund);
+    //    if(rec == 0) {
+    //        return BaseResponseUtils.buildFail(WechatResultCode.AUDIT_REFUND_FAIL.getMessage());
+    //    }
+    //
+    //    // 瀹屾垚瀹℃牳鍚庤幏鍙栧緟閫�娆捐鍗曞垪琛�
+    //    List<ToRefund> list_ToRefund = payHelper.getToRefunds(virtualId, refundAmount);
+    //    if(list_ToRefund == null || list_ToRefund.size() <=0)
+    //        return BaseResponseUtils.buildFail(WechatResultCode.NOT_SUFFICIENT_FUNDS.getMessage());
+    //
+    //    //閬嶅巻寰呴��娆惧垪琛�
+    //    JSONArray array_ToRefund = (JSONArray) JSON.toJSON(list_ToRefund);
+    //    for(int i = 0; i < array_ToRefund.size(); i++) {
+    //        JSONObject job_ToRefund = array_ToRefund.getJSONObject(i);
+    //        String orderNumber_ToRefund = job_ToRefund.getString("orderNumber");
+    //        Integer refundAmount_ToRefund = job_ToRefund.getInteger("refundAmount");
+    //
+    //        // 鐢熸垚閫�娆惧垎椤硅褰�
+    //        SeVcRefundItem seVcRefundItem = new SeVcRefundItem();
+    //        seVcRefundItem.setRefundId(po.getRefundId());
+    //        seVcRefundItem.setOrderNumber(orderNumber_ToRefund);
+    //        String refundNumber = virtualCardSv.generateRefundNumber(orderNumber_ToRefund);
+    //        seVcRefundItem.setRefundNumber(refundNumber);
+    //        seVcRefundItem.setRefundAmount(refundAmount_ToRefund);
+    //        seVcRefundItem.setCreateTime(new Date());
+    //        seVcRefundItem.setRefundStatus(RefundItemStateENUM.NO_REFUND.getCode());
+    //        Long refundItemId = virtualCardSv.addRefundItem(seVcRefundItem);
+    //
+    //        // 璋冪敤寰俊閫�娆剧敵璇锋帴鍙�
+    //        Refund refund = new Refund();
+    //        refund.setTradeNo(orderNumber_ToRefund);
+    //        refund.setRefundNo(refundNumber);
+    //        refund.setRefund(refundAmount_ToRefund);
+    //        BaseResponse rep = payHelper.refunds(refund);
+    //    }
+    //
+    //    return BaseResponseUtils.buildSuccess(true) ;
+    //}
+
+    /**
+     * 鑾峰彇铏氭嫙鍗″厖鍊艰褰�
+     * @return
+     */
+    @GetMapping(path = "/getVcRechargeRecords")
+    @SsoAop()
+    public BaseResponse<QueryResultVo<List<VoVcRecharge>>> getVcRechargeRecords(DtoVcRecharge dtoVcRecharge){
+        try {
+            QueryResultVo<List<VoVcRecharge>> res = virtualCardSv.getVcRechargeRecords(dtoVcRecharge);
+            return BaseResponseUtils.buildSuccess(res);
+        } catch (Exception e) {
+            log.error("鑾峰彇铏氭嫙鍗″厖鍊艰褰曞紓甯�", e);
+            return BaseResponseUtils.buildException(e.getMessage()) ;
+        }
+    }
+}
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardSv.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardSv.java
new file mode 100644
index 0000000..2f4a5ff
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/virtualCard/VirtualCardSv.java
@@ -0,0 +1,352 @@
+package com.dy.pipIrrWechat.virtualCard;
+
+import com.dy.common.webUtil.BaseResponse;
+import com.dy.common.webUtil.BaseResponseUtils;
+import com.dy.common.webUtil.QueryResultVo;
+import com.dy.pipIrrGlobal.daoSe.*;
+import com.dy.pipIrrGlobal.pojoSe.SeVcRecharge;
+import com.dy.pipIrrGlobal.pojoSe.SeVcRefund;
+import com.dy.pipIrrGlobal.pojoSe.SeVcRefundItem;
+import com.dy.pipIrrGlobal.pojoSe.SeVirtualCard;
+import com.dy.pipIrrGlobal.voSe.VoOrders;
+import com.dy.pipIrrGlobal.voSe.VoVcRecharge;
+import com.dy.pipIrrGlobal.voSe.VoVirtualCard;
+import com.dy.pipIrrWechat.virtualCard.dto.DtoVcRecharge;
+import com.dy.pipIrrWechat.virtualCard.dto.DtoVirtualCard;
+import com.dy.pipIrrWechat.virtualCard.enums.LastOperateENUM;
+import com.dy.pipIrrWechat.virtualCard.enums.OrderStateENUM;
+import com.dy.pipIrrWechat.result.WechatResultCode;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.common.utils.PojoUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 9:39
+ * @LastEditTime 2024-07-15 9:39
+ * @Description
+ */
+
+@Slf4j
+@Service
+public class VirtualCardSv {
+    @Autowired
+    private SeVirtualCardMapper seVirtualCardMapper;
+
+    @Autowired
+    private SeVcRechargeMapper seVcRechargeMapper;
+
+    @Autowired
+    private SeVcRefundMapper seVcRefundMapper;
+
+    @Autowired
+    private SeVcRefundItemMapper seVcRefundItemMapper;
+
+    @Autowired
+    private SeClientMapper seClientMapper;
+
+    /**
+     * 鏍规嵁鍐滄埛ID鑾峰彇5绾ц鏀垮尯鍒掍唬鐮侊紝娉ㄥ唽铏氭嫙鍗′娇鐢�
+     * @param clientId 鍐滄埛ID
+     * @return 5绾ц鏀垮尯鍒掍唬鐮�
+     */
+    public Long getAreaCodeById(Long clientId) {
+        return seClientMapper.getAreaCodeById(clientId);
+    }
+
+    /**
+     * 鑾峰彇鍐滄埛鍏ㄩ儴铏氭嫙鍗�
+     * @return
+     */
+    public List<VoVirtualCard> getVCs(Long clientId) {
+        return seVirtualCardMapper.getVCs(clientId);
+    }
+
+    /**
+     * 鏍规嵁铏氭嫙鍗D鑾峰彇铏氭嫙鍗″璞�
+     * @param vcId
+     * @return
+     */
+    public VoVirtualCard getVcById(Long vcId) {
+        return seVirtualCardMapper.getVcById(vcId);
+    }
+
+    /**
+     * 娉ㄥ唽铏氭嫙鍗�
+     * @param po
+     * @return
+     */
+    public Long insertVirtualCard(SeVirtualCard po) {
+        seVirtualCardMapper.insert(po);
+        return po.getId();
+    }
+
+    /**
+     * 鏍规嵁琛屾斂鍖哄垝涓叉ā绯婃煡璇㈣櫄鎷熷崱缂栧彿锛屾敞鍐岃櫄鎷熷崱浣跨敤
+     * @param areaCode
+     * @return
+     */
+    String getVcCardNumOfMax(String areaCode) {
+        return seVirtualCardMapper.getVcCardNumOfMax(areaCode);
+    }
+
+    /** 搴熷純
+     * 楠岃瘉鍐滄埛鏄惁鎷ユ湁鎸囧畾鍚嶇О鐨勮櫄鎷熷崱
+     * @param po
+     * @return
+     */
+    //public Integer getRecordCountByName(DtoRegist po) {
+    //    return seVirtualCardMapper.getRecordCountByName(po.getClientId(), po.getVcName());
+    //}
+
+    /**
+     * 淇敼铏氭嫙鍗�
+     * 鍏呭�笺�佹秷璐广�佺敵璇烽��娆俱�佸鏍搁��娆炬椂闇�瑕佷慨鏀硅櫄鎷熷崱鐨勶細浣欓銆佹渶鍚庢搷浣溿�佹渶鍚庢搷浣滄椂闂�
+     * @param po
+     * @return
+     */
+    public Integer updateVirtualCard(SeVirtualCard po) {
+        return seVirtualCardMapper.updateByPrimaryKeySelective(po);
+    }
+
+    /**
+     * 鏍规嵁铏氭嫙鍗$紪鍙疯幏鍙栬櫄鎷熷崱瀵硅薄
+     * @param virtualId
+     * @return
+     */
+    public SeVirtualCard selectVirtuCardById(Long virtualId) {
+        return seVirtualCardMapper.selectByPrimaryKey(virtualId);
+    }
+
+    /**
+     * 娣诲姞铏氭嫙鍗″厖鍊艰褰�
+     * JSAPI涓嬪崟鍚庣敓鎴愰儴鍒嗗厖鍊艰褰�
+     * @param po
+     * @return
+     */
+    public BaseResponse<Boolean> insertVCRecharge(DtoVirtualCard po) {
+        String orderNumber = po.getOrderNumber();
+        Long virtualId = po.getVirtualId();
+        Long clientId = po.getClientId();
+        Integer rechargeAmount = po.getRechargeAmount();
+
+        // 楠岃瘉璇ヨ櫄鎷熷崱璐︽埛鏄惁瀛樺湪骞跺彇鍑哄綋鍓嶈处鎴蜂綑棰�
+        SeVirtualCard seVirtualCard = seVirtualCardMapper.selectByPrimaryKey(virtualId);
+        if(seVirtualCard == null) {
+            return BaseResponseUtils.buildFail(WechatResultCode.NO_ACCOUNT.getMessage());
+        }
+        Double money = seVirtualCard.getMoney();
+
+        // 娣诲姞鍏呭�艰褰�
+        SeVcRecharge seVcRecharge = new SeVcRecharge();
+        seVcRecharge.setVcId(virtualId);
+        seVcRecharge.setClientId(clientId);
+        seVcRecharge.setMoney(money);
+        seVcRecharge.setOrderNumber(orderNumber);
+        seVcRecharge.setRechargeAmount(rechargeAmount);
+        seVcRecharge.setOrderTime(new Date());
+        seVcRecharge.setOrderState(OrderStateENUM.NON_PAYMENT.getCode());
+        Integer rec = seVcRechargeMapper.insert(seVcRecharge);
+        if(rec == null) {
+            return BaseResponseUtils.buildFail(WechatResultCode.RECHARGE_FAIL.getMessage());
+        }
+        return BaseResponseUtils.buildSuccess(true) ;
+    }
+
+    /**
+     * 鏍规嵁璁㈠崟鍙疯幏鍙栬櫄鎷熷崱鍏呭�煎璞�
+     * @param orderNumber
+     * @return
+     */
+    public SeVcRecharge getVCRechargeByorderNumber(String orderNumber) {
+        return seVcRechargeMapper.getVCRechargeByorderNumber(orderNumber);
+    }
+
+    /**
+     * 淇敼铏氭嫙鍗″厖鍊艰褰�
+     * 寰俊鏀粯閫氱煡鍚庯細
+     *      1. 鏇存柊鍏呭�艰〃锛氬厖鍊煎悗浣欓銆佹敮浠樺畬鎴愭椂闂淬�佽鍗曠姸鎬�
+     *      2. 鏇存柊铏氭嫙鍗¤〃锛氳处鎴蜂綑棰濄�佹渶鍚庢搷浣溿�佹渶鍚庢搷浣滄椂闂�
+     * @param orderNumber 璁㈠崟缂栧彿
+     * @return
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public BaseResponse<Boolean> updateVCRecharge(String orderNumber, Date rechargeTime) {
+        SeVcRecharge seVcRecharge = seVcRechargeMapper.getVCRechargeByorderNumber(orderNumber);
+        if(seVcRecharge == null) {
+            return BaseResponseUtils.buildFail(WechatResultCode.RECHARGE_NOT_EXIST.getMessage());
+        }
+
+        Long virtualId = seVcRecharge.getVcId();
+        Double money = seVcRecharge.getMoney();
+        Integer rechargeAmount = seVcRecharge.getRechargeAmount();
+        Double afterRrecharge = money + rechargeAmount;
+
+        seVcRecharge.setAfterRecharge(afterRrecharge);
+        seVcRecharge.setRechargeTime(rechargeTime);
+        seVcRecharge.setOrderState(OrderStateENUM.PAID.getCode());
+        Integer rec = seVcRechargeMapper.updateByPrimaryKeySelective(seVcRecharge);
+        if(rec == null) {
+            return BaseResponseUtils.buildFail(WechatResultCode.RECHARGE_FAIL.getMessage());
+        }
+
+        SeVirtualCard seVirtualCard = seVirtualCardMapper.selectByPrimaryKey(virtualId);
+        if(seVirtualCard == null) {
+            return BaseResponseUtils.buildFail(WechatResultCode.VIRTUAL_CARD_NOT_EXIST.getMessage());
+        }
+        seVirtualCard.setMoney(afterRrecharge);
+        seVirtualCard.setLastOperate(LastOperateENUM.RECHARGE.getCode());
+        seVirtualCard.setLastOperateTime(new Date());
+        Integer rec2 = seVirtualCardMapper.updateByPrimaryKeySelective(seVirtualCard);
+        if(rec2 == null) {
+            return BaseResponseUtils.buildFail(WechatResultCode.RECHARGE_FAIL.getMessage());
+        }
+        return BaseResponseUtils.buildSuccess(true) ;
+    }
+
+    /**
+     * 淇敼铏氭嫙鍗″厖鍊艰褰曪紙搴熷純锛�
+     * 寰俊灏忕▼搴忔敮浠橀�氱煡鍚庝慨鏀癸細浣欓銆佸厖鍊煎悗浣欓銆佸厖鍊煎畬鎴愭椂闂�
+     * @param po
+     * @return
+     */
+    public Integer updateVCRecharge(SeVcRecharge po) {
+        return seVcRechargeMapper.updateByPrimaryKeySelective(po);
+    }
+
+    /**
+     * 鏍规嵁铏氭嫙鍗″彿鑾峰彇璁㈠崟鍒楄〃
+     * @param virtualId
+     * @return
+     */
+    public List<VoOrders> selectOrders(Long virtualId) {
+        List<VoOrders> rsVo = seVcRechargeMapper.getOrders(virtualId);
+        return rsVo ;
+    }
+
+    /**
+     * 鏍规嵁閫�娆綢D鑾峰彇閫�娆惧璞�
+     * @param refundId
+     * @return
+     */
+    public SeVcRefund selectRefundByRefundId(Long refundId) {
+        return seVcRefundMapper.selectByPrimaryKey(refundId);
+    }
+
+    /**
+     * 娣诲姞閫�娆剧敵璇�
+     * @param po
+     * @return
+     */
+    public Long addRefund(SeVcRefund po) {
+        seVcRefundMapper.insert(po);
+        return po.getId();
+    }
+
+    /**
+     * 淇敼閫�娆捐褰�
+     * @param po
+     * @return
+     */
+    public Integer updateRefund(SeVcRefund po) {
+        return seVcRefundMapper.updateByPrimaryKeySelective(po);
+    }
+
+    /**
+     * 鏍规嵁璁㈠崟鍙疯幏鍙栧叾鍚勭瑪閫�娆鹃噾棰�
+     * @param orderNumber
+     * @return
+     */
+    public List<Integer> selectRefundAmount(String orderNumber) {
+        List<Integer> rsVo = seVcRefundMapper.getRefundAmount(orderNumber);
+        return rsVo;
+    }
+
+    /**
+     * 娣诲姞閫�娆惧垎椤�
+     * @param po
+     * @return
+     */
+    public Long addRefundItem(SeVcRefundItem po) {
+        seVcRefundItemMapper.insert(po);
+        return po.getRefundId();
+    }
+
+    /**
+     * 缂栬緫閫�娆惧垎椤�
+     * @param po
+     * @return
+     */
+    public Integer updateRefundItem(SeVcRefundItem po) {
+        return seVcRefundItemMapper.updateByPrimaryKeySelective(po);
+    }
+
+    /**
+     * 鏍规嵁璁㈠崟鍙风敓鎴愰��娆惧崟鍙�
+     * @param orderNumber
+     * @return
+     */
+    public String generateRefundNumber(String orderNumber) {
+        String refundNumber = seVcRefundItemMapper.getLastRefundNumber(orderNumber);
+        if(refundNumber == null) {
+            refundNumber = orderNumber + "01";
+            return refundNumber;
+        }
+
+        String a = String.format("%02d", (Integer.parseInt(refundNumber.substring(29,30).trim()) + 1));
+        return  a;
+    }
+
+    /**
+     * 鏍规嵁璁㈠崟鍙疯幏鍙栧厖鍊奸噾棰濓紝璋冪敤閫�娆剧敵璇锋帴鍙d娇鐢�
+     * @param orderNumber
+     * @return
+     */
+    public Integer getRechargeAmountByOrderNumber(String orderNumber) {
+        return seVcRechargeMapper.getRechargeAmountByOrderNumber(orderNumber);
+
+    }
+
+    /**
+     * 鏍规嵁閫�娆鹃�氱煡鎺ュ彛杩斿洖鐨勯��娆惧崟鍙峰弽鏌ラ��娆綢D锛屾煡璇㈣閫�娆綢D涓嬫湭閫�娆捐褰曟暟閲�
+     * @param refundNumber
+     * @return
+     */
+    public Integer getNoRefundedCount(String refundNumber) {
+        return seVcRefundItemMapper.getNoRefundedCount(refundNumber);
+    }
+
+    /**
+     * 鏍规嵁閫�娆惧崟鍙疯幏鍙栭��娆綢D锛岄��娆鹃�氱煡鍚庢洿鏂伴��娆捐〃鎵�闇�
+     * @param refundNumber
+     * @return
+     */
+    public Long getRefundIdByRefundNumber(String refundNumber) {
+        return seVcRefundItemMapper.getRefundIdByRefundNumber(refundNumber);
+    }
+
+    /**
+     * 鑾峰彇铏氭嫙鍗″厖鍊艰褰�
+     * @param dtoVcRecharge
+     * @return
+     */
+    public QueryResultVo<List<VoVcRecharge>> getVcRechargeRecords(DtoVcRecharge dtoVcRecharge){
+        Map<String, Object> params = (Map<String, Object>) PojoUtils.generalize(dtoVcRecharge);
+        Long itemTotal = seVirtualCardMapper.getRechargeRecordCount(params);
+
+        QueryResultVo<List<VoVcRecharge>> rsVo = new QueryResultVo<>();
+        rsVo.pageSize = dtoVcRecharge.pageSize;
+        rsVo.pageCurr = dtoVcRecharge.pageCurr;
+
+        rsVo.calculateAndSet(itemTotal, params);
+        rsVo.obj = seVirtualCardMapper.getVcRechargeRecords(params);
+
+        return rsVo;
+    }
+}
\ No newline at end of file
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/PayInfo.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/PayInfo.java
new file mode 100644
index 0000000..690e30a
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/PayInfo.java
@@ -0,0 +1,176 @@
+package com.dy.pipIrrWechat.wechatpay;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:26
+ * @LastEditTime 2024-07-15 10:26
+ * @Description
+ */
+public class PayInfo {
+    /**
+     * 灏忕▼搴忕櫥褰旳PI
+     */
+    public static String loginUrl = "https://api.weixin.qq.com/sns/jscode2session";
+
+    /**
+     * 妫�楠岀櫥褰曟��
+     */
+    public static String checkSessionUrl = "https://api.weixin.qq.com/wxa/checksession";
+
+    /**
+     * 閲嶇疆鐧诲綍鎬�
+     */
+    public static String resetUserSessionKeyUrl = "https://api.weixin.qq.com/wxa/resetusersessionkey";
+
+    /**
+     * 鑾峰彇鎺ュ彛璋冪敤鍑嵁
+     */
+    public static String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
+
+    /**
+     * 缁熶竴涓嬪崟API
+     */
+    //public static String orderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+    public static String orderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
+
+    /**
+     * 骞冲彴璇佷功涓嬭浇URL
+     */
+    public static String certificates = "https://api.mch.weixin.qq.com/v3/certificates";
+
+    /*
+     * 鏀粯缁撴灉閫氱煡API
+     */
+    public static String notifyUrl = "https://44978f7456.imdo.co/sell/payment/orderNotify";
+
+    /*
+     * 鏌ヨ璁㈠崟API
+     */
+    public static String queryUrl = "https://api.mch.weixin.qq.com/pay/orderquery";
+
+    /**
+     * 鐢宠閫�娆続PI
+     */
+    public static String refundUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
+
+    /*
+     * 閫�娆鹃�氱煡API
+     */
+    public static String refundNotifyUrl = "https://www.muxiaobao.com/wxpay/pay.action";
+
+    /*
+     * 閫�娆炬煡璇PI
+     */
+    public static String refundQueryUrl = "https://api.mch.weixin.qq.com/pay/refundquery";
+
+    /*
+     * 灏忕▼搴忓敮涓�鏍囪瘑
+     */
+    //public static String appid = "wxbc2b6a00dd904ead";
+    public static String appid = "wxf773810cd5643196";
+
+    /*
+     * 灏忕▼搴忕殑 app secret
+     */
+    //public static String secret = "796ffe3e9921f756db0499e80d6ed0cd";
+    public static String secret = "080d4f947095551e988cfe9338e27f15";
+
+    /*
+     * 灏忕▼搴忕殑鎺堟潈绫诲瀷锛岀櫥褰曞嚟璇佹牎楠屼娇鐢�
+     */
+    public static String grantType = "authorization_code";
+
+    /*
+     * 鍟嗘埛鍙�(寰俊鏀粯鍒嗛厤鐨勫晢鎴峰彿)
+     */
+    public static String mchid = "1640721520";
+
+    /*
+     * 鍟嗘埛骞冲彴璁剧疆鐨勫瘑閽ey
+     */
+    public static String key = "DaYuJieShuiYanJiuYuan20230412ABC";
+
+    /**
+     * 鍟嗘埛API璇佷功搴忓垪鍙�
+     */
+    public static String serial_no = "52D65AA66405C738670377F467178F4C950E1606";
+
+    /*
+     * 缁堢IP锛岃皟鐢ㄥ井淇℃敮浠楢PI鐨勬満鍣↖P
+     */
+    public static String addrIp = "47.104.211.89";
+
+    /*
+     * 闅忔満瀛楃涓诧紝闀垮害瑕佹眰鍦�32浣嶄互鍐�
+     */
+    //public static String nonceStr = PayHelper.generateRandomString();
+
+    /*
+     * 鏃堕棿鎴� 浠�1970骞�1鏈�1鏃�00:00:00鑷充粖鐨勭鏁�,鍗冲綋鍓嶇殑鏃堕棿
+     */
+    //public static Long timeStamp = PayHelper.getTimeStamp();
+
+    /*
+     * 浜ゆ槗绫诲瀷锛屽皬绋嬪簭鍙栧�糐SAPI
+     */
+    public static String tradeType = "JSAPI";
+
+    /*
+     * 绛惧悕绫诲瀷
+     */
+    //public static String signType = "MD5";
+    public static String signType = "RSA";
+
+    /*
+     * 鍟嗗搧鎻忚堪 鍟嗗搧绠�鍗曟弿杩帮紝璇ュ瓧娈佃鎸夌収瑙勮寖浼犻��
+     */
+    //public static String body = "澶х鐮旂┒闄�-姘磋垂";
+    public static String description = "澶х鐮旂┒闄�-姘磋垂";
+
+    /*
+     * 闄勫姞鏁版嵁锛屽湪鏌ヨAPI鍜屾敮浠橀�氱煡涓師鏍疯繑鍥烇紝鍙綔涓鸿嚜瀹氫箟鍙傛暟浣跨敤
+     */
+    public static String attach = "澶╂触";
+
+    /*
+     * 绛惧悕锛屽弬涓庣鍚嶅弬鏁帮細appid銆乤ttach銆乵ch_id銆乶once_str銆乥ody銆乷ut_trade_no銆乼otal_fee銆乻pbill_create_ip銆乶otify_url銆乼rade_type銆乷penid
+     */
+    public String sign = "";
+
+    /**
+     * HTTP澶磋璇佺被鍨�
+     */
+    public static String schema = "WECHATPAY2-SHA256-RSA2048";
+
+    /**
+     * 绉侀挜鏂囦欢璺緞
+     */
+    public static String privateCertFileName = "C:\\webchat\\apiclient_key.pem";
+
+    public static String publicCertFileName = "C:\\webchat\\wxp_cert.pem";
+
+    /*
+     * 寰俊璁㈠崟鍙凤紝浼樺厛浣跨敤
+     */
+    public static String transactionid = "";
+
+    /*
+     * 鍟嗘埛绯荤粺鍐呴儴璁㈠崟鍙�
+     */
+    public static String out_trade_no = "";
+
+    /*
+     * 鍟嗘埛閫�娆惧崟鍙�
+     */
+    public static String out_refund_no = "";
+
+    /*
+     * 閫�娆鹃噾棰�
+     */
+    public static Float refundfee;
+
+    /*
+     * 璁㈠崟閲戦
+     */
+    public static Float totalfee;
+}
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/Refund.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/Refund.java
new file mode 100644
index 0000000..cfdff37
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/Refund.java
@@ -0,0 +1,39 @@
+package com.dy.pipIrrWechat.wechatpay.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:28
+ * @LastEditTime 2024-07-15 10:28
+ * @Description
+ */
+
+@Data
+@Schema(name = "閫�娆捐姹傚璞�")
+public class Refund {
+    public static final long serialVersionUID = 202403011607001L;
+
+    /**
+     * 鍟嗘埛璁㈠崟鍙�
+     */
+    @Schema(description = "鍟嗘埛璁㈠崟鍙�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    @NotBlank(message = "鍟嗘埛璁㈠崟鍙蜂笉鑳戒负绌�")
+    private String tradeNo;
+
+    /**
+     * 閫�娆惧崟鍙�
+     */
+    @Schema(description = "閫�娆惧崟鍙�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    private String refundNo;
+
+    /**
+     * 閫�娆鹃噾棰�
+     */
+    @Schema(description = "閫�娆鹃噾棰�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    @NotNull(message = "閫�娆鹃噾棰濅笉鑳戒负绌�")
+    private Integer refund;
+}
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundRequest.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundRequest.java
new file mode 100644
index 0000000..bf1f6f0
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundRequest.java
@@ -0,0 +1,70 @@
+package com.dy.pipIrrWechat.wechatpay.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:29
+ * @LastEditTime 2024-07-15 10:29
+ * @Description
+ */
+
+@Data
+@Schema(name = "閫�娆捐姹傚璞�")
+public class RefundRequest {
+    public static final long serialVersionUID = 202403011540001L;
+
+    /**
+     * 鍟嗘埛璁㈠崟鍙凤紝涓嬪崟鏃剁殑璁㈠崟鍙�
+     */
+    @Schema(description = "鍟嗘埛璁㈠崟鍙�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    @NotBlank(message = "鍟嗘埛璁㈠崟鍙蜂笉鑳戒负绌�")
+    private String out_trade_no;
+
+    /**
+     * 鍟嗘埛閫�娆惧崟鍙凤紝璁㈠崟鍙峰墠鍔犲墠缂�鈥淩鈥�
+     */
+    @Schema(description = "鍟嗘埛閫�娆惧崟鍙�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    @NotBlank(message = "鍟嗘埛閫�娆惧崟鍙蜂笉鑳戒负绌�")
+    private String out_refund_no;
+
+    /**
+     * 閫�娆剧粨鏋滃洖璋僽rl锛宺efundUrl
+     */
+    @Schema(description = "閫�娆剧粨鏋滃洖璋僽rl", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    @NotBlank(message = "閫�娆剧粨鏋滃洖璋僽rl涓嶈兘涓虹┖")
+    private String notify_url;
+
+    /**
+     * 閲戦淇℃伅
+     */
+    @Schema(description = "閲戦淇℃伅", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    private RefundRequest.Amount amount;
+
+    @Data
+    public static class Amount {
+        /**
+         * 閫�娆鹃噾棰�
+         */
+        @Schema(description = "閫�娆鹃噾棰�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+        @NotNull(message = "閫�娆鹃噾棰濅笉鑳戒负绌�")
+        private Integer refund;
+
+        /**
+         * 鍘熻鍗曢噾棰濓紝鏍规嵁璁㈠崟鍙锋煡璇�
+         */
+        @Schema(description = "鍘熻鍗曢噾棰�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+        @NotNull(message = "鍘熻鍗曢噾棰濅笉鑳戒负绌�")
+        private Integer total;
+
+        /**
+         * 閫�娆惧竵绉嶏紝鍥哄畾涓衡�淐NY鈥�
+         */
+        @Schema(description = "閫�娆惧竵绉�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+        @NotBlank(message = "閫�娆惧竵绉嶄笉鑳戒负绌�")
+        private String currency;
+    }
+}
\ No newline at end of file
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundResponse.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundResponse.java
new file mode 100644
index 0000000..6144eef
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/RefundResponse.java
@@ -0,0 +1,114 @@
+package com.dy.pipIrrWechat.wechatpay.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:30
+ * @LastEditTime 2024-07-15 10:30
+ * @Description
+ */
+
+@Data
+@Schema(name = "閫�娆剧敵璇疯繑鍥炲璞�")
+public class RefundResponse {
+    public static final long serialVersionUID = 202403011431001L;
+
+    /**
+     * 寰俊鏀粯閫�娆惧彿
+     */
+    private String refund_id;
+
+    /**
+     * 鍟嗘埛閫�娆惧崟鍙�
+     */
+    private String out_refund_no;
+
+    /**
+     * 寰俊鏀粯璁㈠崟鍙�
+     */
+    private String transaction_id;
+
+    /**
+     * 鍟嗘埛璁㈠崟鍙�
+     */
+    private String out_trade_no;
+
+    /**
+     * 閫�娆炬笭閬�
+     */
+    private String channel;
+
+    /**
+     * 閫�娆惧叆璐﹁处鎴�
+     */
+    private String user_received_account;
+
+    /**
+     * 閫�娆炬垚鍔熸椂闂�
+     */
+    private String success_time;
+
+    /**
+     * 閫�娆惧垱寤烘椂闂�
+     */
+    private String create_time;
+
+    /**
+     * 閫�娆剧姸鎬�
+     */
+    private String status;
+
+    /**
+     * 閲戦淇℃伅
+     */
+    private RefundResponse.Amount amount;
+
+
+    @Data
+    private static class Amount {
+
+        /**
+         * 璁㈠崟鎬婚噾棰�
+         */
+        private Integer total;
+
+        /**
+         * 閫�娆鹃噾棰�
+         */
+        private Integer refund;
+
+        /**
+         * 鐢ㄦ埛鏀粯閲戦
+         */
+        private Integer payer_total;
+
+        /**
+         * 鐢ㄦ埛閫�娆鹃噾棰�
+         */
+        private Integer payer_refund;
+
+        /**
+         * 搴旂粨閫�娆鹃噾棰�
+         */
+        private Integer settlement_refund;
+
+        /**
+         * 搴旂粨璁㈠崟閲戦
+         */
+        private Integer settlement_total;
+
+        /**
+         * 浼樻儬閫�娆鹃噾棰�
+         */
+        private Integer discount_refund;
+
+        /**
+         * 閫�娆惧竵绉�
+         */
+        private String currency;
+
+    }
+
+}
\ No newline at end of file
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/ToRefund.java b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/ToRefund.java
new file mode 100644
index 0000000..95765d5
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/wechatpay/dto/ToRefund.java
@@ -0,0 +1,35 @@
+package com.dy.pipIrrWechat.wechatpay.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
+import lombok.Data;
+
+/**
+ * @author ZhuBaoMin
+ * @date 2024-07-15 10:32
+ * @LastEditTime 2024-07-15 10:32
+ * @Description
+ */
+
+@Data
+@Schema(name = "寰呴��娆惧璞�")
+public class ToRefund {
+    public static final long serialVersionUID = 202403072144001L;
+
+    /**
+     * 璁㈠崟鍙�
+     */
+    @Schema(description = "璁㈠崟鍙�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    @NotBlank(message = "璁㈠崟鍙蜂笉鑳戒负绌�")
+    private String orderNumber;
+
+    /**
+     * 閫�娆鹃噾棰�
+     */
+    @Schema(description = "閫�娆鹃噾棰�", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
+    @NotNull(message = "閫�娆鹃噾棰濅笉鑳戒负绌�")
+    @Positive(message = "閫�娆鹃噾棰濆繀椤讳负澶т簬0鐨勬暣鏁�")
+    private Integer refundAmount;
+}

--
Gitblit v1.8.0