微信公众号支付之退款

Posted Mr_伍先生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信公众号支付之退款相关的知识,希望对你有一定的参考价值。

这一篇紧接着上面支付的那篇。

参考文档:

申请退款

https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_4&index=4 

 

退款结果通知

https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_16&index=10

 

 

1.退款的时候需要配置认证的证书如图

技术分享图片

 

2.申请退款接口

                FileInputStream instream = null;
                CloseableHttpClient httpclient = null;
                try {
                    StringBuffer xml = new StringBuffer();
                    String data = null;
                    String nonceStr = WXPayUtil.generateNonceStr();
                    xml.append("</xml>");
                    SortedMap<String,String> parameters = new TreeMap<String,String>();
                    parameters.put("appid", weixinConfig.getWeiXinPayAppId());
                    parameters.put("mch_id", weixinConfig.getMchId());
                    parameters.put("sign_type","MD5");  
                    parameters.put("nonce_str", nonceStr);
                    parameters.put("out_refund_no", or.getCart().getId());
                    parameters.put("out_trade_no", orderNo);
                    parameters.put("refund_fee", WXPayUtil.getMoney(or.getPrice().setScale(2, BigDecimal.ROUND_DOWN).toString()));
                    parameters.put("total_fee", WXPayUtil.getMoney(orderPayment.getTotalPrice().setScale(2, BigDecimal.ROUND_DOWN).toString()));
                    parameters.put("fee_type", "CNY");
                    parameters.put("op_user_id", weixinConfig.getMchId());
                    parameters.put("notify_url", weixinConfig.getWeiXinRefundNotifyUrl());
                    parameters.put("transaction_id", orderPayment.getBusinessOrderNo());
                    String createSign1 = WXPayUtil.createSign(parameters, weixinConfig.getWeiXinPayAppSecret());
                    parameters.put("sign", createSign1);
                    data =WXPayUtil.SortedMaptoXml(parameters);
                    logger.info("微信申请退款请求数据信息:"+data);
                    KeyStore keyStore  = KeyStore.getInstance("PKCS12");
                    instream = new FileInputStream(new File(weixinConfig.getWeiXinPayKey()));
                    try {
                        keyStore.load(instream, weixinConfig.getMchId().toCharArray());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally{
                        instream.close();
                    }
                    SSLContext sslcontext = SSLContexts.custom()
                            .loadKeyMaterial(keyStore, weixinConfig.getMchId().toCharArray())
                            .build();
                    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                            sslcontext,
                            new String[] { "TLSv1" },
                            null,
                            SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
                    httpclient = HttpClients.custom()
                            .setSSLSocketFactory(sslsf)
                            .build();
                    HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
                    StringEntity entitys = new StringEntity(data, "UTF-8");
                    httppost.setEntity(entitys);
                    CloseableHttpResponse response = httpclient.execute(httppost);
                    HttpEntity entity = response.getEntity();
                    StringBuilder sb2 = new StringBuilder();
                    String xmlStr2 = null;//读入响应流中字符串的引用
                    if (entity != null) {
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
                        while ((xmlStr2 = bufferedReader.readLine()) != null) {
                            sb2.append(xmlStr2);
                        }
                    }
                    //关闭流对象
                    EntityUtils.consume(entity);
                    logger.info("微信申请退款响应数据信息:"+sb2.toString());
                    //处理返回的结果XML
                    Map<String, String> refundOrderMap = WXPayUtil.xmlToMap(sb2.toString());
                    if(refundOrderMap.size()>0){
                        if(refundOrderMap.get("return_code").equals("SUCCESS") && refundOrderMap.get("result_code").equals("SUCCESS")){
                            //退款申请请求发送成功   处理自己项目的业务逻辑 TODO
                            
                        }else{
                 //处理自己项目的业务逻辑 TODO
} }else{ //TODO } } catch(Exception e){ //TODO }finally { try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } }

 

3.微信退款结果通知

/**
     * 退款成功异步回调接口
     * 
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/refundNotice", produces = "text/html;charset=utf-8")
    @ResponseBody
    public String weiXinRefundNotice(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ServletInputStream instream = request.getInputStream();
        StringBuffer sb = new StringBuffer();
        int len = -1;
        byte[] buffer = new byte[1024];
        while ((len = instream.read(buffer)) != -1) {
            sb.append(new String(buffer, 0, len));
        }
        instream.close();
        log.info("退款通知信息:" + sb.toString());
        Map<String, String> map = WXPayUtil.xmlToMap(sb.toString());// 接受微信的回调的通知参数
        Map<String, String> return_data = new HashMap<String, String>();
        // 判断returnCode状态
        if (map.get("return_code").toString().equals("FAIL")) {
            return_data.put("return_code", "FAIL");
            return_data.put("return_msg", map.get("return_msg"));
        } else if (map.get("return_code").toString().equals("SUCCESS")) {
            String reqInfo = map.get("req_info");
            byte[] decode = Base64.decodeBase64(reqInfo);
            String key = MD5Util.MD5(weixinConfig.getWeiXinPayAppSecret()).toLowerCase();
            String decryptData = WXPayUtil.getRefundDecrypt(decode,key);
            log.info("退款通知信息解密数据:"+decryptData);
            Map<String, String> mm = WXPayUtil.xmlToMap(decryptData);
            if (mm.get("refund_status").equals("SUCCESS")){//退款成功
                  //处理自己的业务逻辑  TODO
              }else if (map.get("refund_status").equals("CHANGE")) {//退款异常
              
              }else if (map.get("refund_status").equals("REFUNDCLOSE")) {//退款关闭
              
              }
             
        }
        String xml = WXPayUtil.GetMapToXML(return_data);
        log.info("退款通知回调结果:" + xml);
        return xml;
    }

 

 

总结:

1.官方文档给的传值参数一定要注意看

2.官方文档里面的有一个方法的字符集有问题,导致返回的信息乱码,无法快速的定位到问题点,上述示例代码已更正

 

上述两篇关于微信支付的实现,只是最基础的功能实现,欢迎大家一起讨论和纠正。

 


以上是关于微信公众号支付之退款的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序支付开发之申请退款

微信公众号退款开发

申请退款

微信支付-小程序H5 公众号 Payment SDK

php 处理微信账单

微信支付之JSAPI公众号支付