From d20d38e22b06559d758c568769017e2acf632583 Mon Sep 17 00:00:00 2001
From: zuoxiao <470321431@qq.com>
Date: 星期三, 23 四月 2025 14:06:48 +0800
Subject: [PATCH] Merge branch 'master' of http://8.140.179.55:20000/r/pipIrr-SV
---
pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/util/PayHelper.java | 564 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 564 insertions(+), 0 deletions(-)
diff --git a/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/util/PayHelper.java b/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/util/PayHelper.java
new file mode 100644
index 0000000..d4180ef
--- /dev/null
+++ b/pipIrr-platform/pipIrr-web/pipIrr-web-sell/src/main/java/com/dy/pipIrrSell/util/PayHelper.java
@@ -0,0 +1,564 @@
+package com.dy.pipIrrSell.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.cert.WxCertUtil;
+import com.dy.pipIrrGlobal.pojoSe.SeVirtualCard;
+import com.dy.pipIrrGlobal.voSe.VoOrders;
+import com.dy.pipIrrSell.result.SellResultCode;
+import com.dy.pipIrrSell.virtualCard.VirtualCardSv;
+import com.dy.pipIrrSell.wechatpay.PayInfo;
+import com.dy.pipIrrSell.wechatpay.dto.Refund;
+import com.dy.pipIrrSell.wechatpay.dto.RefundRequest;
+import com.dy.pipIrrSell.wechatpay.dto.RefundResponse;
+import com.dy.pipIrrSell.wechatpay.dto.ToRefund;
+import lombok.RequiredArgsConstructor;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.NoSuchPaddingException;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+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-03-06 11:47
+ * @LastEditTime 2024-03-06 11:47
+ * @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 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 bs 绉侀挜鏂囦欢鍐呭
+ * @return 绉侀挜瀵硅薄
+ * @throws IOException
+ */
+ public PrivateKey getPrivateKey(byte[] bs) throws IOException {
+ String content = new String(bs, "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 message 琚鍚嶄俊鎭�
+ * @param certFileBs 绉侀挜璇佷功鏂囦欢鍐呭
+ * @return signature绛惧悕鍊硷紝绛惧悕淇℃伅涓殑涓�椤癸紝鍙備笌鐢熸垚绛惧悕淇℃伅
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ * @throws SignatureException
+ * @throws IOException
+ */
+ public String sign(byte[] message, byte[] certFileBs) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException {
+ Signature sign = Signature.getInstance("SHA256withRSA");
+ sign.initSign(getPrivateKey(certFileBs));
+ 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 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, byte[] certFileBs) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, NoSuchPaddingException {
+ String message = buildMessage_order(method, url, timestamp, nonceStr, body);
+ String signature = sign(message.getBytes("utf-8"), certFileBs);
+
+ 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(byte[] keyPemBs) throws GeneralSecurityException, IOException, Exception {
+ String method = "GET";
+ String httpUrl = "/v3/certificates";
+ String nonceStr = generateRandomString();
+ Long timestamp = System.currentTimeMillis() / 1000;
+
+ String header = PayInfo.schema + " " + getToken(method, httpUrl, "", nonceStr, timestamp, keyPemBs);
+
+ 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, byte[] keyPemBs) throws GeneralSecurityException, IOException, Exception {
+ if(CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
+ CERTIFICATE_MAP.clear();
+ refreshCertificate(keyPemBs);
+ }
+ 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, ResourceLoader resourceLoader) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, Exception {
+ String tradeNo = po.getTradeNo();
+ String refundNo = po.getRefundNo();
+ Integer refund = po.getRefund();
+
+ // 鐢熸垚body锛岄噾棰濆崟浣嶇敱鍏冩敼涓哄垎
+ //Integer total = virtualCardSv.getRechargeAmountByOrderNumber(tradeNo);
+ Integer total = (int)(virtualCardSv.getRechargeAmountByOrderNumber(tradeNo)*100);
+ 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, WxCertUtil.getKey_pemBytes(resourceLoader));
+
+ 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(SellResultCode.PROCESSING.getMessage());
+ } else {
+ // 閫�娆惧紓甯�
+ return BaseResponseUtils.buildError(SellResultCode.ABNORMAL.getMessage());
+ }
+ }
+}
--
Gitblit v1.8.0