New file |
| | |
| | | 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.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 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 certFileBs 私钥文件内容 |
| | | * @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环境不支持RSA", e); |
| | | } catch (InvalidKeySpecException e) { |
| | | throw new RuntimeException("无效的密钥格式"); |
| | | } |
| | | }*/ |
| | | public PrivateKey getPrivateKey(byte[] certFileBs) throws IOException { |
| | | String content = new String(certFileBs, "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环境不支持RSA", 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 certBs 私钥证书文件内容 |
| | | * @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()); |
| | | }*/ |
| | | public String sign(byte[] message, byte[] certBs) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException, Exception { |
| | | Signature sign = Signature.getInstance("SHA256withRSA"); |
| | | sign.initSign(getPrivateKey(certBs)); |
| | | sign.update(message); |
| | | return Base64.getEncoder().encodeToString(sign.sign()); |
| | | } |
| | | |
| | | /** |
| | | * 获取签名信息 |
| | | * @param method |
| | | * @param url |
| | | * @param body |
| | | * @return 签名信息,HTTP头中的签名信息 |
| | | * HTTP头:Authorization: 认证类型 签名信息 |
| | | * 认证类型,WECHATPAY2-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 + "\""; |
| | | }*/ |
| | | public String getToken(String method, String url, String body, String nonceStr, Long timestamp, byte[] certFileBs) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, Exception { |
| | | 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 请求返回的body |
| | | * @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[] certFileBs) 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, certFileBs); |
| | | |
| | | 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分钟时才将证书存储map |
| | | 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[] certFileBs) throws Exception { |
| | | if(CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) { |
| | | CERTIFICATE_MAP.clear(); |
| | | refreshCertificate(certFileBs); |
| | | } |
| | | Certificate certificate = (Certificate)CERTIFICATE_MAP.get(wechatpaySerial); |
| | | if(certificate == null) { |
| | | return false; |
| | | } |
| | | |
| | | // 获取公钥 |
| | | PublicKey publicKey = certificate.getPublicKey(); |
| | | |
| | | // 初始化SHA256withRSA前面器 |
| | | Signature signature = Signature.getInstance("SHA256withRSA"); |
| | | // 用微信平台公钥对前面器进行初始化 |
| | | signature.initVerify(certificate); |
| | | |
| | | // 将构造的验签名串更新到签名器中 |
| | | signature.update(signatureStr.getBytes(StandardCharsets.UTF_8)); |
| | | |
| | | // 请求头中微信服务器返回的签名用Base64解码,使用签名器进行验证 |
| | | 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, byte[] certFileBs) throws SignatureException, InvalidKeyException, Exception{ |
| | | String tradeNo = po.getTradeNo(); |
| | | String refundNo = po.getRefundNo(); |
| | | Integer refund = po.getRefund(); |
| | | |
| | | // 生成body |
| | | Double 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, certFileBs); |
| | | |
| | | 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()); |
| | | } |
| | | } |
| | | } |