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