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