首页 > 编程语言 >java 微信支付v3 —7.微信支付之申请退款

java 微信支付v3 —7.微信支付之申请退款

时间:2023-03-22 14:59:29浏览次数:60  
标签:java 微信 param paramsMap 支付 new 退款

正文

不得不说,申请退款和创建订单是非常相似的,流程都一样,只是请求的数据变了,那么我们第一步就是封装请求数据成对象形式,方便后续调用。

1. 申请退款请求对象

微信支付订单号,微信支付订单号和商家订单号二选一,这个是必不可少的,原订单金额也是必填的,微信会做二次验证。

@Data
public class WeChatRefundParam {

    /**
     * 微信支付订单号,微信支付订单号和商家订单号二选一
     */
    private String transactionId;

    /**
     * 商家订单号,对应 out_trade_no,
     */
    private String orderId;

    /**
     * 商户退款单号,对应out_refund_no
     */
    private String refundOrderId;

    /**
     * 退款原因,选填
     */
    private String reason;

    /**
     * 回调地址
     */
    private WxNotifyType notify;

    /**
     * 退款金额
     */
    private BigDecimal refundMoney;

    /**
     * 原订单金额,必填
     */
    private BigDecimal totalMoney;
}

 

2. 将请求参数封装成Map集合

@Slf4j
public class WxPayRefundUtil {

	/**
	  * 封装微信支付申请退款请求参数
	  * @param param 微信支付申请退款请求参数
	  * @return 封装后的map微信支付申请退款请求参数对象
	  */
	private static Map<String, Object> getRefundParams(WxPayConfig wxPayConfig, WeChatRefundParam param) {
	    Map<String, Object> paramsMap = new HashMap<>();
	    if (StringUtils.isNoneBlank(param.getTransactionId())) {
	        paramsMap.put("transaction_id", param.getTransactionId());
	    } else if (StringUtils.isNoneBlank(param.getOrderId())) {
	        paramsMap.put("out_trade_no", param.getOrderId());
	    } else {
	        throw new DefaultException("微信支付订单号和商户订单号必须填写一个");
	    }
	    paramsMap.put("out_refund_no", param.getRefundOrderId());
	    if (StringUtils.isNoneBlank(param.getReason())) {
	        paramsMap.put("reason", param.getReason());
	    }
	    paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(param.getNotify().getType()));
	    Map<String, Object> amountMap = new HashMap<>();
	    amountMap.put("refund", param.getRefundMoney().multiply(new BigDecimal("100")).intValue());
	    amountMap.put("total", param.getTotalMoney().multiply(new BigDecimal("100")).intValue());
	    amountMap.put("currency", "CNY");
	    paramsMap.put("amount", amountMap);
	
	    return paramsMap;
	}
}

 

3. 申请退款工具类

剩下的就和创建订单一样了,我也不罗嗦了,可以拿去直接用。

@Slf4j
public class WxPayRefundUtil {

    /**
     * 发起微信退款申请
     *
     * @param wxPayConfig 微信配置信息
     * @param param       微信支付申请退款请求参数
     * @param wxPayClient 微信请求客户端()
     * @return 微信支付二维码地址
     */
    public static String refundPay(WxPayConfig wxPayConfig, WeChatRefundParam param, CloseableHttpClient wxPayClient) {
        // 1.获取请求参数的Map格式
        Map<String, Object> paramsMap = getRefundParams(wxPayConfig, param);

        // 2.获取请求对象
        HttpPost httpPost = getHttpPost(wxPayConfig, WxApiType.DOMESTIC_REFUNDS, paramsMap);

        // 3.完成签名并执行请求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
            throw new DefaultException("微信支付请求失败");
        }

        // 4.解析response对象
        HashMap<String, String> resultMap = resolverResponse(response);
        log.info("发起退款参数:{}",resultMap);
        if (resultMap != null) {
            // 返回微信支付退款单号
            return resultMap.get("refund_id");
        }
        return null;
    }

    /**
     * 解析响应数据
     *
     * @param response 发送请求成功后,返回的数据
     * @return 微信返回的参数
     */
    private static HashMap<String, String> resolverResponse(CloseableHttpResponse response) {
        try {
            // 1.获取请求码
            int statusCode = response.getStatusLine().getStatusCode();
            // 2.获取返回值 String 格式
            final String bodyAsString = EntityUtils.toString(response.getEntity());

            Gson gson = new Gson();
            if (statusCode == 200) {
                // 3.如果请求成功则解析成Map对象返回
                HashMap<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
                return resultMap;
            } else {
                if (StringUtils.isNoneBlank(bodyAsString)) {
                    log.error("微信支付请求失败,提示信息:{}", bodyAsString);
                    // 4.请求码显示失败,则尝试获取提示信息
                    HashMap<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
                    throw new DefaultException(resultMap.get("message"));
                }
                log.error("微信支付请求失败,未查询到原因,提示信息:{}", response);
                // 其他异常,微信也没有返回数据,这就需要具体排查了
                throw new IOException("request failed");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new DefaultException(e.getMessage());
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 获取请求对象(Post请求)
     *
     * @param wxPayConfig 微信配置类
     * @param apiType     接口请求地址
     * @param paramsMap   请求参数
     * @return Post请求对象
     */
    private static HttpPost getHttpPost(WxPayConfig wxPayConfig, WxApiType apiType, Map<String, Object> paramsMap) {
        // 1.设置请求地址
        HttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(apiType.getType()));

        // 2.设置请求数据
        Gson gson = new Gson();
        String jsonParams = gson.toJson(paramsMap);

        // 3.设置请求信息
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        return httpPost;
    }

    /**
     * 封装微信支付申请退款请求参数
     *
     * @param param 微信支付申请退款请求参数
     * @return 封装后的map微信支付申请退款请求参数对象
     */
    private static Map<String, Object> getRefundParams(WxPayConfig wxPayConfig, WeChatRefundParam param) {
        Map<String, Object> paramsMap = new HashMap<>();
        if (StringUtils.isNoneBlank(param.getTransactionId())) {
            paramsMap.put("transaction_id", param.getTransactionId());
        } else if (StringUtils.isNoneBlank(param.getOrderId())) {
            paramsMap.put("out_trade_no", param.getOrderId());
        } else {
            throw new DefaultException("微信支付订单号和商户订单号必须填写一个");
        }
        paramsMap.put("out_refund_no", param.getRefundOrderId());
        if (StringUtils.isNoneBlank(param.getReason())) {
            paramsMap.put("reason", param.getReason());
        }
        paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(param.getNotify().getType()));
        Map<String, Object> amountMap = new HashMap<>();
        amountMap.put("refund", param.getRefundMoney().multiply(new BigDecimal("100")).intValue());
        amountMap.put("total", param.getTotalMoney().multiply(new BigDecimal("100")).intValue());
        amountMap.put("currency", "CNY");
        paramsMap.put("amount", amountMap);

        return paramsMap;
    }
}

 

4.申请退款使用

@ApiOperation("退款申请测试")
@GetMapping("/refund/{orderId}")
public String refund(@PathVariable String orderId) {
    WeChatRefundParam param = new WeChatRefundParam();
    param.setOrderId(orderId);
    String refundOrderId = IdWorker.getIdStr();
    log.info("refundOrderId:{}",refundOrderId);
    param.setRefundOrderId(refundOrderId);
    param.setReason("商品售罄");
    param.setNotify(WxNotifyType.TEST_REFUND_NOTIFY);
    param.setRefundMoney(new BigDecimal("0.01"));
    param.setTotalMoney(new BigDecimal("0.01"));
    return  WxPayRefundUtil.refundPay(wxPayConfig,param,wxPayClient);
}

 

当交易发生之后一年内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付金额退还给买家,微信支付将在收到退款请求并且验证成功之后,将支付款按原路退还至买家账号上。

注意:

1、交易时间超过一年的订单无法提交退款
2、微信支付退款支持单笔交易分多次退款(不超50次),多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总>金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号
3、错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次
4、每个支付订单的部分退款次数不能超过50次
5、如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失败
6、申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果
7、一个月之前的订单申请退款频率限制为:5000/min
8、同一笔订单多次退款的请求需相隔1分钟

 

 

————————————————————————————————

java微信支付v3系列——1.微信支付准备工作
java微信支付v3系列——2.微信支付基本配置
java微信支付v3系列——3.订单创建准备操作
java微信支付v3系列——4.创建订单的封装及使用
java微信支付v3系列——5.微信支付成功回调
java微信支付v3系列——6.微信支付查询订单API
java微信支付v3系列——7.微信支付之申请退款
java微信支付v3系列——8.微信支付之退款成功回调
java微信支付v3系列——9.微信支付之商家转账API
————————————————————————————————
版权声明:本文为CSDN博主「CV大魔王」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45740561/article/details/128402504

标签:java,微信,param,paramsMap,支付,new,退款
From: https://www.cnblogs.com/Fooo/p/17243902.html

相关文章

  • JAVA~适合新手和复习~基础三(集合所有常用方法)
    Java集合框架  1Set和List的区别21.Set接口实例存储的是无序的,不重复的数据。List接口实例存储的是有序的,可以重复的元素。342.Set检索效率低下,删除和......
  • java 微信支付v3 —5.微信支付成功回调
    正文同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已......
  • java 微信支付v3 —6.微信支付查询订单API
    正文什么时候会用到这个API?常规情况下,回调接口已经足够我们使用,用户支付成功后,微信会自动调用我们的回调接口进行回调,那么还需要这个API吗?使用场景:微信服务器故障,我们的服......
  • java 微信支付v3 —3.订单创建准备操作
    正文微信支付的下单操作分为了5种,分别是JSAPI、APP、H5以及Native支付及小程序支付,之所以将支付放在单独一个章节,而不是按照支付类型划分一个章节,是因为支付所传递的数据都......
  • Java 使用 POI 导出Excel,设置同一个单元格的内容显示不同的文字颜色
    要在Java中导出Excel并设置同一单元格的内容显示不同的文字颜色,可以使用ApachePOI库来实现。下面是一个示例代码,演示如何在单元格中设置不同颜色的文本:1//创建......
  • Java基础语法2
    顺序结构程序从上到下依次地执行,中间没有任何判断和跳转。System.out.println("程序开始");System.out.println("起床");System.out.print......
  • java8读取Access数据库
       添加pom配置文件<dependency><groupId>net.sf.ucanaccess</groupId><artifactId>ucanaccess</artifactId><version>4.0.4</version></dependency......
  • linux 后台运行 Java 程序
    一、进入程序所在目录cd/cdhome/joincallcc/注:cd/中间有一个空格二、关闭已经运行的程序(如这个程序已经在运行应先关闭它)查看所有进程psux杀死进程kil......
  • JavaScript对象中常见的方法和不常见的方法
    常见的方法:Object.assign()-将一个或多个对象的属性复制到目标对象。Object.keys()-返回对象中所有属性的名称。Object.values()-返回对象中所有属性的值。Obje......
  • 微信小程序之wx.getLocation再次授权问题解决
    首先,在page外定义一个公共函数用于发送获取位置的请求vargetLocation=function(that){wx.getLocation({type:'wgs84',success:function(res){......