关于微信退款

一、官方文档

申请退款:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_4&index=6

二、退款流程图

注意:微信退款时候,需要证书服务,这里可以参见官方文档中的说明,包括证书的具体下载,解析等。(后面我也补充个证书解析的文件,方便理解)

一个百度文库的文档https://wenku.baidu.com/view/754c78e93186bceb19e8bbcc.html

三、项目中使用的代码

拿来作个参考吧,方便记忆和理解

/**
* 微信支付申请退款
*
* @param weChatPayRefund
* @return
*/
public boolean weChatPayRefundRequest(WeChatPayRefund weChatPayRefund, String source) {
try {
if (null == weChatPayRefund) {
throw new ArgumentException("参数异常");
}
if (Strings.isNullOrEmpty(weChatPayRefund.getRefund_fee())) {
throw new ArgumentException("退款金额为空");
}
if (Strings.isNullOrEmpty(weChatPayRefund.getOut_trade_no())) {
throw new ArgumentException("原交易编号为空");
} //退款金额,微信金额单位为分,系统为元,做换算
int refundFee = new BigDecimal(weChatPayRefund.getRefund_fee())
.multiply(new BigDecimal(100)).intValue();
weChatPayRefund.setRefund_fee(String.valueOf(refundFee));
//订单总金额单位为分
int totalFee = new BigDecimal(weChatPayRefund.getTotal_fee())
.multiply(new BigDecimal(100)).intValue();
weChatPayRefund.setTotal_fee(String.valueOf(totalFee));
//生成随机流水号
String timeStr = System.currentTimeMillis() + "";
weChatPayRefund.setOut_refund_no("TK" + timeStr);
//退款单号为UUID
weChatPayRefund.setNonce_str(UUIDUtil.randrom());
//生成退款参数XML
String xml = this.createRefundXml(weChatPayRefund, source);
String refundURL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
ClientCustomSSL clientCustomSSL = new ClientCustomSSL();
String result = "";
if ("01".equals(source)) {
result = clientCustomSSL.doRefund(refundURL, xml, weChatPkcs12, "B2B");
} else if ("02".equals(source)) {
result = clientCustomSSL.doRefund(refundURL, xml, b2cWeChatPkcs12, "B2C");
} else if ("03".equals(source)) {
result = clientCustomSSL.doRefund(refundURL, xml, b2cWeChatPkcs12_new, "B2C_NEW");
}
//请求返回结果
result = result.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "");
Document doc = DocumentHelper.parseText(result); Map<String, Object> resultMap = XmlMapHandle.Dom2Map(doc);
String applyId = weChatPayRefund.getApplyId();
StringHashMapper stringHashMapper = new StringHashMapper(WeChatPayRefund.class);
WeChatPayRefund weChatPay = (WeChatPayRefund) stringHashMapper.fromHash(resultMap);
ConvenienceRefund refund = createRefundInfo(weChatPayRefund);
        //根据返回结果,处理一些自己的业务
if (weChatPay.getReturn_code().equalsIgnoreCase("SUCCESS") && weChatPay.getResult_code().equalsIgnoreCase("SUCCESS")) {
weChatPay.setApplyId(applyId);
refund.setRefundStatus("1");
this.rechargeOrderWriteDao.saveRefundInfo(refund);//保存退款信息
int updateFlag = rechargeOrderWriteDao.updateOrderPayStatus(RedisType.PAY_STATUS2.getIndex(), weChatPayRefund.getOut_trade_no());
if (updateFlag >= 1) {
//退款成功
//订单日志保存
ConvenienceOrderLog orderLog = new ConvenienceOrderLog();
orderLog.setOrderId(String.valueOf(weChatPayRefund.getOut_trade_no()));
orderLog.setStatusCode(50);
orderLog.setStatusName("退款成功");
this.saveConvenienceOrderLog(orderLog);
return true;
} else {
//退款失败
return false;
}
} else {
refund.setRefundStatus("0");
this.rechargeOrderWriteDao.saveRefundInfo(refund);
ConvenienceOrderLog orderLog = new ConvenienceOrderLog();
orderLog.setOrderId(String.valueOf(weChatPayRefund.getOut_trade_no()));
orderLog.setStatusCode(99);
orderLog.setStatusName("退款失败");
throw new BusinessException("退款失败:" + weChatPayRefund.getReturn_msg());
}
} catch (Exception e) {
throw new BusinessException("退款失败:请联系管理员");
}
} /**
* 根据订单来源生成退款参数XML
*
* @param weChatPayRefund
* @param source
* @return
*/
public String createRefundXml(WeChatPayRefund weChatPayRefund, String source) {
String appId = "";
String mchId = "";
String key = "";
if ("01".equals(source)) {
appId = weChatPayRefund.getB2b_appid_new();
mchId = weChatPayRefund.getB2b_mch_id_new();
key = weChatPayRefund.getB2b_appKey_new();
} else if ("02".equals(source)) {
appId = weChatPayRefund.getB2c_appid();
mchId = weChatPayRefund.getB2c_mch_id();
key = weChatPayRefund.getB2c_appKey();
} else if ("03".equals(source)) {
appId = weChatPayRefund.getB2c_appid_new();
mchId = weChatPayRefund.getB2c_mch_id_new();
key = weChatPayRefund.getB2c_appKey_new();
}
//生成退款签名
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", appId);
packageParams.put("mch_id", mchId);
packageParams.put("nonce_str", weChatPayRefund.getNonce_str());
packageParams.put("out_trade_no", weChatPayRefund.getOut_trade_no());
packageParams.put("out_refund_no", weChatPayRefund.getOut_refund_no());
packageParams.put("total_fee", weChatPayRefund.getTotal_fee());
packageParams.put("refund_fee", weChatPayRefund.getRefund_fee());
packageParams.put("op_user_id", mchId); RequestHandler reqHandler = new RequestHandler(null, null); reqHandler.init(appId, "", key);
String sign = reqHandler.createSign(packageParams);
String xml = org.apache.commons.lang3.StringUtils.join("<xml>", "<appid>", appId,
"</appid>", "<mch_id>", mchId, "</mch_id>", "<nonce_str>",
weChatPayRefund.getNonce_str(), "</nonce_str>", "<sign><![CDATA[", sign,
"]]></sign>", "<out_trade_no>", weChatPayRefund.getOut_trade_no(),
"</out_trade_no>", "<out_refund_no>" + weChatPayRefund.getOut_refund_no(),
"</out_refund_no>", "<total_fee>", weChatPayRefund.getTotal_fee(), "</total_fee>",
"<refund_fee>" + weChatPayRefund.getRefund_fee(), "</refund_fee>",
"<op_user_id>" + mchId, "</op_user_id>", "</xml>");
return xml;
}

四、引申与其他

(待续..)

<正则吃饺子> :关于微信支付的简单总结说明(二)的更多相关文章

  1. <正则吃饺子>:关于集合的简单整理总结

    项目中用到的集合不可谓不多,对于自己的一次面试,要求说下自己用过的集合,自己开始说的并不系统也不完整,一直耿耿于怀,特整理一下,以备后期之用和帮助后来者. package com.love.malin ...

  2. <正则吃饺子>:关于java中垃圾回收技术的简单学习总结

    知识介绍来自网络,后面会根据继续学习进行补充和适当的修改,谢谢!原文地址:http://www.importnew.com/26821.html#comment-578355 java中的垃圾回收机制 ...

  3. <正则吃饺子> :关于微信支付的简单总结说明(一)

    关于支付,一直想参与开发,现在根据项目中已有及参见的微信开发文档,将自己对于微信开发的流程进行简单的总结,以备后用和帮助后来者. 一.相关官方文档 微信支付官方文档:https://pay.weixi ...

  4. 微信支付生成带logo的二维码

    利用到一个qrcode类 比较简洁 原作者没有加入二维码嵌入logo的功能 在这里我进行了小小的修改 可以实现生成微信支付二维码时打上logo 生成png格式的利用到该类中的png方法(我已经改好了) ...

  5. <正则吃饺子>:关于java中对内存部分的简单总结整理

    在项目和一些群讨论中,经常看到对内存的处理,但是,自己确是一知半解的,基于此,就把这部分的知识简单的整理了下,知识点来源于网络博文,也一一标明出处,谢谢. package com.love.malin ...

  6. <正则吃饺子> :关于 Matcher 的 replaceAll 的简单使用

    在线文档地址:http://tool.oschina.net/apidocs/apidoc?api=jdk-zh replaceAll public String replaceAll(String  ...

  7. <正则吃饺子> :关于oracle 中 with的简单使用

    oracle中 with的简单使用介绍,具体可以参见其他的博文介绍,在这里只是简单的介绍: with 构建了一个临时表,类似于存储过程中的游标,我是这么理解的. 一.数据准备: select * fr ...

  8. <正则吃饺子> :关于oracle 中 exists 、not exists 的简单使用

    话不多说,简单的总结而已.网络上很多很详细介绍. 例如,博文:http://blog.csdn.net/zhiweianran/article/details/7868894  当然这篇也是转载的,原 ...

  9. <正则吃饺子> :关于Guava中 Joiner 和 Splitter 的简单使用

    在现在项目中经常看到 这两个类的使用,开始时候不明白具体是做的什么事情,就单独拿出来学习下了,参照了网上的博文,这里主要是简单的讲讲用法. 具体对这两个类,不做过多介绍,有个在线文档,需要的可以自己去 ...

随机推荐

  1. android的Environment类 Android存储访问及目录

    http://www.cnblogs.com/mengdd/p/3742623.html http://blog.csdn.net/barnett_zhubo/article/details/6832 ...

  2. ASP.NET动态网站制作(0)

    前言:一直想系统地学习一下网站建设的相关内容,看过相关的书籍,也跟着视频学过,但总觉得效率不高,学过的东西印象不深刻,或许还是自己动手实践的少.无意中免费听了一堂讲ASP.NET网站建设的课,觉得性价 ...

  3. PeekMessage究竟做了什么?

    1.UI线程 2.工作线程 把Delphi里TThread的WaitFor函数转化成C++代码,就会是下面这个样子. BOOL TThread::WaitFor(HANDLE hThread) { M ...

  4. wamp环境配置;转自发瑞的博客(www.cnblogs.com/cyrfr/p/6483529.html)

    php手动搭建环境有好多种组合,版本号不一致,会导致搭建失败. 我搭建的组合是: php5.6+MySQL5.6+Apache2.4的组合. 一.PHP语言包下载 首先从官网上下载php5.6 htt ...

  5. ubuntu 安装 pygame 很好玩的东西

    1. 简介 pygame 是基于对 SDL库的python 封装,提供python接口.SDL(Simple DirectMedia Layer) 是一个跨平台的游戏开发库,方便游戏开发和移植.目前最 ...

  6. MongoDB的CRUD操作(java Util )

    1.保存插入操作: public static synchronized String insert(DBObject record) { DBCollection col = MongoDB.get ...

  7. 九度OJ 1052:找x (基础题)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:7335 解决:3801 题目描述: 输入一个数n,然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标(从0开始,若不在数 ...

  8. 九度OJ 1030:毕业bg (01背包、DP)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1814 解决:798 题目描述:     每年毕业的季节都会有大量毕业生发起狂欢,好朋友们相约吃散伙饭,网络上称为"bg" ...

  9. 【题解】P2279消防局的设立

    [题解][P2279 HNOI2003]消防局的设立 又是一道贪心. 随便指定一个点为根,可以知道在覆盖了一个节点的子树的情况下,消防站越高越好.那么我们就贪心吧.\(trick\)是按深度\(pus ...

  10. 单元測试中 Right-BICEP 和 CORRECT

    My Blog:http://www.outflush.com/ 在单元測试中,有6个总结出的值得測试的方面,这6个方面统称为 Right-BICEP.通过这6个方面的指导.能够较全然的測试出代码中的 ...