首页 » PHP教程 » 微信退款demophp技巧_微信退款开拓

微信退款demophp技巧_微信退款开拓

访客 2024-10-31 0

扫一扫用手机浏览

文章目录 [+]

条件:从微信"大众号那边获取appid,mchid,paternerKey三个参数备用。

1、微信申请退款的实现

运用处景:

微信退款demophp技巧_微信退款开拓

当交易发生之后一段韶光内,由于买家或者卖家的缘故原由须要退款时,卖家可以通过退延接口将支付款退还给买家,微信支付将在收到退款要求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。

微信退款demophp技巧_微信退款开拓
(图片来自网络侵删)

把稳:

1、交易韶光超过一年的订单无法提交退款

2、微信支付退款支持单笔交易分多次退款,多次退款须要提交原支付订单的商户订单号和设置不同的退款单号。
申请退款总金额不能超过订单金额。
一笔退款失落败后重新提交,请不要改换退款单号,请利用原商户退款单号

3、要求频率限定:150qps,即每秒钟正常的申请退款要求次数不超过150次

缺点或无效要求频率限定:6qps,即每秒钟非常或缺点的退款申请要求不超过6次

4、每个支付订单的部分退款次数不能超过50次

5、如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失落败

是否须要证书:

java开拓申请退款须要要用到双向证书(apiclient_cert.p12证书)。
登录微信商户平台(https://pay.weixin.qq.com/)如下图所示操作

申请退延接口调用:

@GET@Path(value = "refundOrder")@Produces(MediaType.APPLICATION_JSON)public Response refundOrder(@QueryParam("outTradeNo") String outTradeNo){ Map<String, Object> result = new HashMap<String, Object>(); try{ // 1、获取参数,再进行申请退款 Map<String, String> paramMap = new HashMap<String, String>(); paramMap.put("appid", appid); //"大众账号ID paramMap.put("mch_id", mchid); //商户号 paramMap.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串 paramMap.put("out_refund_no", WXPayUtil.generateNonceStr());//商户退款单号 paramMap.put("out_trade_no", outTradeNo);//商户订单号 paramMap.put("total_fee", price+""); //订单金额 paramMap.put("refund_fee", price+""); //退款金额 String sign = WXPayUtil.generateSignature(paramMap, paternerKey); paramMap.put("sign", sign); //署名 String requestXmlString = WXPayUtil.mapToXml(paramMap);//转为xml字符串 String refundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund";//微信申请退延接口 // 2、判断微信是否退款成功 HttpResponse resp = WeChatUtil.httpPost(refundUrl, requestXmlString); WeChatOrderResponse response = null; if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String entityStr = EntityUtils.toString(resp.getEntity(), "UTF-8"); response = (WeChatOrderResponse) WeChatUtil.xmlToPojo(entityStr,WeChatOrderResponse.class); } if("FAIL".equals(response.getReturn_code())){ throw new RuntimeException("return_code为fail, " + response.getReturn_msg()); } if("FAIL".equals(response.getResult_code())){ throw new RuntimeException("result_code为fail, " +response.getErr_code_des()); } //3、微信退款成功后的操作流程 ...... result.put("code", SUCCESS); }catch(Exception e){ result.put("code", ERROR); result.put("msg", e.getMessage()); } return Response.ok(result).build();}

WeChatOrderResponse类的参数与微信的申请退延接口的返回结果同等,下面是该类的详细实现:

@XmlRootElement(name = "xml")public class WeChatOrderResponse { private String return_code; private String return_msg; // 以下字段在return_code为SUCCESS的时候有返回 private String result_code; private String err_code; private String err_code_des; private String appid; private String mch_id; private String nonce_str; private String sign; private String transaction_id; private String out_trade_no; private String out_refund_no; private String refund_id; private String refund_fee; private String settlement_refund_fee; private String total_fee; private String settlement_total_fee; private String fee_type; private String cash_fee; private String cash_fee_type; private String cash_refund_fee; private String coupon_type_$n; private String coupon_refund_fee; private String coupon_refund_fee_$n; private String coupon_refund_count; private String coupon_refund_id_$n; // 以下字段在return_code 和result_code都为SUCCESS的时候有返回 private String trade_type; private String prepay_id; private String code_url; private String openid; //参数的get/set方法 ......}

WeChatUtil工具类(亲测有效)的详细构造如下:

public class WeChatUtil { / Post要求+证书 @param url 微信申请退延接口链接 @param entity 微信申请退延接口的参数 / public static HttpResponse httpPost(String url, String entity) { //把稳PKCS12证书 是从微信商户平台->账号设置->API安全 中下载的 KeyStore keyStore = KeyStore.getInstance("PKCS12"); //加载本地的证书进行https加密传输,keystorePath是证书的绝对路径 FileInputStream instream = new FileInputStream(new File(keystorePath)); try{ //设置证书密码,keystorePassword:下载证书时的密码,默认密码是你的mchid keyStore.load(instream, keystorePassword.toCharArray()); } finally { instream.close(); } //java 主动信赖证书 //keystorePassword:下载证书时的密码,默认密码是你的mchid SSLContext sslcontext = SSLContexts.custom() .loadKeyMaterial(keyStore, keystorePassword.toCharArray()).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); //CloseableHttpClient 加载证书来访问https网站 CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); try { // 设置相应头信息,发送post要求 HttpPost httpPost = new HttpPost(url); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(5000) .setConnectTimeout(5000) .setConnectionRequestTimeout(5000) .build(); httpPost.setConfig(requestConfig); httpPost.setEntity(new StringEntity(entity, "UTF-8")); httpPost.setHeader("Accept", "/"); httpPost.setHeader("Content-type", "application/xml"); HttpResponse resp = httpClient.execute(httpPost); return resp; } catch (Exception e) { e.printStackTrace(); return null; } } / 字符串转为工具 @param xml json字符串 @param clazz / public static Object xmlToPojo(String xml, Class<?> clazz){ try { JAXBContext context = JAXBContext.newInstance(clazz); Unmarshaller umMarshaller = context.createUnmarshaller(); Object pojo = umMarshaller.unmarshal(new ByteArrayInputStream(xml.getBytes("utf-8"))); }catch (Exception e ){ e.printStackTrace(); } }}2、查询退款的实现

运用处景:

提交退款申请后,通过调用该接口查询退款状态。
退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个事情日后重新查询退款状态。
(退款有延迟,可通过轮询来判断是否成功退款)

把稳:如果单个支付订单部分退款次数超过20次请利用退款单号查询

退款状态变革:

查询退延接口详细实现:

@GET@Path(value = "queryRefund")@Produces(MediaType.APPLICATION_JSON)public Response queryRefund(@QueryParam("outTradeNo") String outTradeNo){ Map<String, Object> result = new HashMap<String, Object>(); try{ // 1、查询退款 Map<String, String> paramMap = new HashMap<>(); paramMap.put("appid", appid);// "大众账号ID paramMap.put("mch_id", mchid);// 商户号 paramMap.put("nonce_str", WXPayUtil.generateNonceStr());// 随机字符串 paramMap.put("out_trade_no", outTradeNo + "");// 商户订单号 String sign = WXPayUtil.generateSignature(paramMap, paternerKey); paramMap.put("sign", sign);// 署名 WXPay wxpay = new WXPay(MyConfig.getInstance()); Map<String, String> resp = wxpay.refundQuery(paramMap); if("FAIL".equals(resp.get("return_code"))){ throw new RuntimeException("return_code为fail, " + resp.get("return_msg")); } if("FAIL".equals(resp.get("result_code")) && !"订单已全额退款".equals(resp.get("err_code_des"))){ throw new RuntimeException("result_code为fail, " + resp.get("err_code_des")); } // 2、成功退款后的操作流程 ...... result.put("code", SUCCESS); }catch(Exception e){ e.printStackTrace(); result.put("code", ERROR); result.put("msg", e.getMessage()); } return Response.ok(result).build();}

标签:

相关文章

执业药师试卷代码解码药师职业发展之路

执业药师在药品质量管理、用药安全等方面发挥着越来越重要的作用。而执业药师考试,作为进入药师行业的重要门槛,其试卷代码更是成为了药师...

PHP教程 2025-02-18 阅读1 评论0

心灵代码主题曲唤醒灵魂深处的共鸣

音乐,作为一种独特的艺术形式,自古以来就承载着人类情感的表达与传递。心灵代码主题曲,以其独特的旋律和歌词,唤醒了无数人的灵魂深处,...

PHP教程 2025-02-18 阅读1 评论0

探寻福建各市车牌代码背后的文化内涵

福建省,地处我国东南沿海,拥有悠久的历史和丰富的文化底蕴。在这片充满魅力的土地上,诞生了许多具有代表性的城市,每个城市都有自己独特...

PHP教程 2025-02-18 阅读1 评论0

探寻河北唐山历史与现代交融的城市之光

河北省唐山市,一座地处渤海之滨,拥有悠久历史和独特文化的城市。这里既是古丝绸之路的起点,也是中国近代工业的发源地。如今,唐山正以崭...

PHP教程 2025-02-18 阅读1 评论0