场景
当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。
注意:
1、交易时间超过一年的订单无法提交退款
2、微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号
3、请求频率限制:150qps,即每秒钟正常的申请退款请求次数不超过150次
错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次
4、每个支付订单的部分退款次数不能超过50次
5、如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失败
返回的接口地址
https://api.mch.weixin.qq.com/secapi/pay/refund
需要证书
如果证书不是自己配置的,在微信支付平台管理的地方是下载不了的。也可以换一种方法去找你的经理要一份就好了。
请求参数
使用jar包
<!--微信支付 -->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>3.0.9</version>
</dependency>
<!-- io读取 微信支付证书 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
代码部分
1.Service 方法
/**
*
* @param mchId 商户ID
* @param url 请求URL
* @param data 退款参数
* @return
* @throws Exception
*/
String doRefund(String mchId, String url, String data) throws Exception;
2.impl 此方法内要读取证书的位置
/**
*
* @param mchId 商户ID
* @param url 请求URL
* @param data 退款参数
* @return
* @throws Exception
*/
public String doRefund(String mchId, String url, String data) throws Exception {
/**
* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
*/
KeyStore keyStore = KeyStore.getInstance("PKCS12");
//这里读取.p12的文件是放在服务器中 使用nginx配置时指向的后端项目路径
FileInputStream inputStream = new FileInputStream(new File("apiclient_cert.p12"));//P12文件目录
try {
//这里写密码..默认是你的MCHID
keyStore.load(inputStream, mchId.toCharArray());
} finally {
inputStream.close();
}
SSLContext sslcontext = SSLContexts.custom()
//这里也是写密码的
.loadKeyMaterial(keyStore, mchId.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
HttpPost httpost = new HttpPost(url);
httpost.setEntity(new StringEntity(data, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
try {
HttpEntity entity = response.getEntity();
//接受到返回信息
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(jsonStr+"-====接收到返回的信息");
EntityUtils.consume(entity);
return jsonStr;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
3.controller
@RequestMapping("/refund")
public String refund() throws Exception {
System.out.println("进入退款----");
try {
//构建参数
Map<String, String> dataMap = new HashMap<>();
dataMap.put("appid","公众账号ID");
dataMap.put("mch_id","商户号");
//自行实现该随机串
dataMap.put("nonce_str",WXPayUtil.generateNonceStr());
//商户订单号
dataMap.put("out_trade_no","订单号");
//商户退款单号
dataMap.put("out_refund_no","订单号");
//订单金额
dataMap.put("total_fee","1");
//退款金额
dataMap.put("refund_fee","1");
//退款原因 (可写可不写)
dataMap.put("refund_desc","退款");
//生成签名
String sign = WXPayUtil.generateSignature(dataMap, "商户密钥");
dataMap.put("sign", sign);
System.out.println(dataMap+"=========dataMap");
//map数据转xml
String xmlString = XMLBeanUtil.map2XmlString(dataMap);
System.out.println("--------------map-->xml转换------------"+xmlString);
//发起退款
String result= weixinPayService.doRefund("商户号", "https://api.mch.weixin.qq.com/secapi/pay/refund", xmlString);
System.out.println(result.toString()+"----结果");
System.out.println("================退款===========");
//这里需要将发起退款的xml格式转换为map
Map<String, String> returnMap = WXPayUtil.xmlToMap(result);
System.out.println("--------------xml-->map转换"+result);
//用map取值返回的状态码来判断是否退款成功
//判断是否退款成功
if (returnMap.get("return_code").equals("SUCCESS")) {
return "微信已成功退款";
}
return "微信退款失败";
} catch (Exception e) {
e.printStackTrace();
}
return "失败";
}
结语
第一次写博客,写的不太好,还希望大家多多包涵。同时也希望这篇博客可以帮助到正在做退款这一块的码友们。有不懂的可以评论哦看到必回。