微信退款场景(抄微信api的场景描述)
当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。
注意:
1、交易时间超过一年的订单无法提交退款
2、微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号
3、请求频率限制:150qps,即每秒钟正常的申请退款请求次数不超过150次
错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次
4、每个支付订单的部分退款次数不能超过50次
微信退款API
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
我将微信退款写了一个工具类
/**
* @Description: 微信退款工具类
* @Author: cd
* @Date: 2018/9/5 20:26
* @Param setSum 退款金额
* @Param code 订单号
*/
public static Map<String,String> wxRefund(Float setSum, String code) throws Exception{
//根据订单号查询订单
//获得随机数
String nonce_str = WxUtil.getRandomString();
StringBuilder sb2 = new StringBuilder();
UUID uuid = UUID.randomUUID();
String out_refund_no = uuid.toString().replace("-", "");
//微信签名需要的参数
Map<String, String> signMap = new HashMap<String, String>();
signMap.put("appid", APPID);//公众账号ID
signMap.put("mch_id",MCHID);//微信支付商户号
signMap.put("nonce_str",nonce_str);//随机数
signMap.put("out_trade_no",code);//订单号out_refund_no
signMap.put("out_refund_no",out_refund_no);//订单号out_refund_no
signMap.put("refund_fee",WxUtil.YuanTofen(String.valueOf(setSum)));//退款金额
signMap.put("total_fee",WxUtil.YuanTofen(String.valueOf(setSum)));//总金额
String sign = WxUtil.getSign(signMap, PRIKEY);
//生成xml,微信要求的xml形式
StringBuffer xml =new StringBuffer();
xml.append("<xml>");
xml.append("<appid>"+APPID+"</appid>");//应用ID
xml.append("<mch_id>"+MCHID+"</mch_id>");//微信支付分配的商户号
xml.append("<nonce_str>"+nonce_str+"</nonce_str>");//随机字符串,不长于32位。
xml.append("<out_trade_no>"+code+"</out_trade_no>");//商户订单号
xml.append("<out_refund_no>"+out_refund_no+"</out_refund_no>");//商户退款单号,商户系统内部的退款单号,商户系统内部唯一
xml.append("<refund_fee>"+WxUtil.YuanTofen(String.valueOf(setSum))+"</refund_fee>");//退款金额
xml.append("<total_fee>"+WxUtil.YuanTofen(String.valueOf(setSum))+"</total_fee>");//订单金额
// xml.append("<transaction_id>"+"</transaction_id>");//微信订单号,微信生成的订单号,在支付通知中有返回
xml.append("<sign>"+ sign +"</sign>");//签名
xml.append("</xml>");
/**
* JAVA使用证书文件
*/
//指定读取证书格式为PKCS12
KeyStore keyStore = KeyStore.getInstance("PKCS12");
//读取本机存放的PKCS12证书文件
FileInputStream instream = new FileInputStream(new File("/data/cert/apiclient_cert.p12"));
try {
//指定PKCS12的密码(商户ID)
keyStore.load(instream, MCHID.toCharArray());
} finally {
instream.close();
}
//ssl双向验证发送http请求报文
SSLContext sslcontext = null;
sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, MCHID.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
StringEntity se = new StringEntity(xml.toString(), "UTF-8");
httppost.setEntity(se);
//定义响应实例对象
CloseableHttpResponse responseEntry = null;
String xmlStr2 = null;//读入响应流中字符串的引用
responseEntry = httpclient.execute(httppost);//发送请求
HttpEntity entity = responseEntry.getEntity();//获得响应实例对象
if (entity != null) {//读取响应流的内容
BufferedReader bufferedReader = null;
bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
while ((xmlStr2 = bufferedReader.readLine()) != null) {
sb2.append(xmlStr2);
}
}
Map<String, String> map = WxUtil.doXMLParse(sb2.toString());
return map;
}
Map<String, String> map = null;
try {
map = WxUtil.wxRefund(orderEntity.getSetSum(), orderEntity.getCode());
logger.info("申请退款接口返回的结果集======>" + map);
} catch (Exception e) {
e.printStackTrace();
logger.info("退款失败====");
return;
}
//return_code为微信返回的状态码,SUCCESS表示申请退款成功,return_msg 如非空,为错误原因 签名失败 参数格式校验错误
if (map.get("return_code").toString().equalsIgnoreCase("SUCCESS")
&& map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {
logger.info("****************退款申请成功!**********************");
//业务逻辑处理
} else {
out.close();
out.write("003");
logger.info("*****************退款申请失败!*********************");
}
此处的证书需要自己去下载