微信退款


业务场景:由于做的是C端的产品,社交电商。负责的是订单售后部分,微信部分是一个单独项目,另外一个项目基本都是业务实现,二个项目也是通过htpps 方式来交互。这里主要介绍微信退款,查询退款记录部分。不展开介绍订单售后部分的逻辑实现(如下图,已经上线)。



**
微信小程序查询退款与申请退款操作**

查询退款:官方文档

申请退款:官方文档

查询退款

1.主要是通过商户订单号 out_trade_no 也就是订单号来进行退款

2.四个必传的参数:appid,mch_id,nonce_str,sign

3.微信返回都是xml格式,将xml转换为map并用json形式返回

4.官方文档的参数

查询退款接口设计(如下):

查询退款接口

url: /weix/queryRefund
请求方式: POST
参数:

参数 类型 是否必传 说明 是否请求头
orderNo String yes 订单号 n

返回结果:

参数 类型 说明 示例
openId String 退款人的openid oii6K5fN9K5Q4wvuF8-hlA2q7TpY
outTradeNo String 订单号 154840066566078463640
refundFee int 退款金额 3(分)
totalFee int 订单总金额 3

controller 层

/**
   * 查询退款
   * @param params
   * @return
   */
  @RequestMapping("queryRefund")
  @ResponseBody
  public Object queryRefund(@RequestBody String params){
      String s = wxApiService.queryRefund(JSONObject.parseObject(params));
      Map<String, String> stringStringMap = null;
      try {
          stringStringMap = WXPayUtil.xmlToMap(s);
      } catch (Exception e) {
          e.printStackTrace();
      }
      return RespResult.respOK(stringStringMap);
  }

Service层的queryRefund 方法

/**
     * 查询退款
     *
     * @param jsonObject
     * @return
     */
    public String queryRefund(JSONObject jsonObject) {
        try {
            Map<String, String> map = new HashMap<>();
            map.put("appid", ConfigUtil.getProperty("appid"));
            map.put("mch_id", ConfigUtil.getProperty("mch_id"));
            map.put("nonce_str", StringUtils.getUUID());
            map.put("out_trade_no", jsonObject.getString("orderNo"));  //商户生成的订单号
            map.put("sign", WXPayUtil.generateSignature(map, ConfigUtil.getProperty("key"), WXPayConstants.SignType.MD5));
            String xml = WXPayUtil.mapToXml(map);
            String s = HttpTools.httpClientByPostXmlWithCert("https://api.mch.weixin.qq.com/pay/refundquery", xml, "utf-8");
            return s;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

申请退款 ---

退款接口

1.与付款相比,退款就简单多了,有6个必传参数如上图,付款是通过 out_trade_no 商户订单号 来进行,退款也根据商户订单号来退款。

2.total_fee 订单金额(也就是支付金额), refund_fee 退款金额,都是以分为单位。一般付款与退款都会有事物的,退款时退款金额是不允许超过支付金额的,可以小于支付金额。

3.这里也会有一个小坑,已经暴露在代码中。在测试环境商户余额不足的情况下,退款就会失败。

4.官方的退款接口参数如下图:



5.我厂设计的接口如下:

url: /weix/refund
请求方式: POST
参数:

参数 类型 是否必传 说明 是否请求头
orderNo String Y 订单号 N
total_fee int Y 退款金额 N

Controller 层
/**
   * 退款
   * @return
   */
  @RequestMapping("refund")
  @ResponseBody
  public Object refund(@RequestBody String params, HttpServletRequest request){
      boolean check = wxIpInterfaceService.check(request);
      if(check){
          return RespResult.respFailureMsg("ip不对哦 小伙子");
      }
      JSONObject jsonObject = JSONObject.parseObject(params);
      String orderNo = jsonObject.getString("orderNo");
      String ipAddress = getIpAddress(request);
      logger.info("退款ip=================="+ipAddress+"退款单号====="+ orderNo);
      WxOrder wxOrder = new WxOrder();
      wxOrder.setOutTradeNo(orderNo);
      List<WxOrder> orders = wxOrderService.queryRefuseByOutTradeNo(wxOrder);
      if(orders.isEmpty()){
          return RespResult.respFailureMsg("订单不存在");
      }
      String refund = "";
      for (WxOrder order: orders) {
          orderNo = order.getOutTradeNo();
          jsonObject.put("out_trade_no",orderNo);
          jsonObject.put("refund_fee",jsonObject.getString("total_fee"));
          jsonObject.put("total_fee", order.getTotalFee());
          refund = wxApiService.sendWxPayRefund(jsonObject);
          if(null == refund){
              return RespResult.respFailureMsg("商户号余额不足,请充值");
          }
          WxRefund wxRefund = new WxRefund();
          wxRefund.setOutTradeNo(orderNo);
          wxRefund.setRefundFee(order.getTotalFee());
          wxRefund.setTotalFee(jsonObject.getInteger("total_fee"));
          wxRefund.setOpenId(order.getOpenid());
          wxRefundService.save(wxRefund);
      }
      return RespResult.respOK();
  }

Service 层
/**
    * 退款
    *
    * @param jsonObject
    * @return
    */
   public String sendWxPayRefund(JSONObject jsonObject) {
       try {
           Map<String, String> map = new HashMap<>();
           map.put("appid", ConfigUtil.getProperty("appid"));
           map.put("mch_id", ConfigUtil.getProperty("mch_id"));
           map.put("nonce_str", StringUtils.getUUID());
           map.put("out_trade_no", jsonObject.getString("out_trade_no"));  //商户生成的订单号
           map.put("out_refund_no", StringUtils.getUUID());  //退款单号
           map.put("total_fee", jsonObject.getString("total_fee"));   //订单总额
           map.put("refund_fee", jsonObject.getString("refund_fee")); //退款金额
           map.put("sign", WXPayUtil.generateSignature(map, ConfigUtil.getProperty("key"), WXPayConstants.SignType.MD5));
           String xml = WXPayUtil.mapToXml(map);
           String s = HttpTools.httpClientByPostXmlWithCert("https://api.mch.weixin.qq.com/secapi/pay/refund", xml, "utf-8");
           if (s.contains("基本账号余额不足")) {
               return null;
           }
           return s;
       } catch (Exception e) {
           e.printStackTrace();
       }
       return "";
   }

文章作者: coderpwh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 coderpwh !
  目录