<正则吃饺子> :关于微信支付的简单总结说明(二)
关于微信退款
一、官方文档
申请退款: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;
}
四、引申与其他
(待续..)
<正则吃饺子> :关于微信支付的简单总结说明(二)的更多相关文章
- <正则吃饺子>:关于集合的简单整理总结
项目中用到的集合不可谓不多,对于自己的一次面试,要求说下自己用过的集合,自己开始说的并不系统也不完整,一直耿耿于怀,特整理一下,以备后期之用和帮助后来者. package com.love.malin ...
- <正则吃饺子>:关于java中垃圾回收技术的简单学习总结
知识介绍来自网络,后面会根据继续学习进行补充和适当的修改,谢谢!原文地址:http://www.importnew.com/26821.html#comment-578355 java中的垃圾回收机制 ...
- <正则吃饺子> :关于微信支付的简单总结说明(一)
关于支付,一直想参与开发,现在根据项目中已有及参见的微信开发文档,将自己对于微信开发的流程进行简单的总结,以备后用和帮助后来者. 一.相关官方文档 微信支付官方文档:https://pay.weixi ...
- 微信支付生成带logo的二维码
利用到一个qrcode类 比较简洁 原作者没有加入二维码嵌入logo的功能 在这里我进行了小小的修改 可以实现生成微信支付二维码时打上logo 生成png格式的利用到该类中的png方法(我已经改好了) ...
- <正则吃饺子>:关于java中对内存部分的简单总结整理
在项目和一些群讨论中,经常看到对内存的处理,但是,自己确是一知半解的,基于此,就把这部分的知识简单的整理了下,知识点来源于网络博文,也一一标明出处,谢谢. package com.love.malin ...
- <正则吃饺子> :关于 Matcher 的 replaceAll 的简单使用
在线文档地址:http://tool.oschina.net/apidocs/apidoc?api=jdk-zh replaceAll public String replaceAll(String ...
- <正则吃饺子> :关于oracle 中 with的简单使用
oracle中 with的简单使用介绍,具体可以参见其他的博文介绍,在这里只是简单的介绍: with 构建了一个临时表,类似于存储过程中的游标,我是这么理解的. 一.数据准备: select * fr ...
- <正则吃饺子> :关于oracle 中 exists 、not exists 的简单使用
话不多说,简单的总结而已.网络上很多很详细介绍. 例如,博文:http://blog.csdn.net/zhiweianran/article/details/7868894 当然这篇也是转载的,原 ...
- <正则吃饺子> :关于Guava中 Joiner 和 Splitter 的简单使用
在现在项目中经常看到 这两个类的使用,开始时候不明白具体是做的什么事情,就单独拿出来学习下了,参照了网上的博文,这里主要是简单的讲讲用法. 具体对这两个类,不做过多介绍,有个在线文档,需要的可以自己去 ...
随机推荐
- 机器学习三 -- 用Python实现K-近邻算法
Python语言实现机器学习的K-近邻算法 写在前面 额...最近开始学习机器学习嘛,网上找到一本关于机器学习的书籍,名字叫做<机器学习实战>.很巧的是,这本书里的算法是用Python语言 ...
- js 检测客户端网速
<!doctype html> <html> <head> <meta http-equiv=Content-Type content="text/ ...
- webpy使用mysql数据库操作(web.database)
webpy_web.database模块 webpy框架中使用mysql管理数据库有两种方法,一种是使用python里面的MySQLdb模块: import MySQLdb 还有一种就是用webpy自 ...
- CAS实现单点登录理解
CAS 是 Yale 大学发起的一个企业级的.开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法(属于 Web SSO ),CAS 开始于 2001 年, 并在 2004 年 12 月 ...
- springcloud微服务实战--笔记
目前对Springcloud对了解仅限于:“用[注册服务.配置服务]来统一管理其他微服务” 这个水平.有待提高 Springcloud微服务实战这本书是翟永超2017年5月写的,时间已经过去了两年,略 ...
- java基本类型和包装类的区别(转)
int 是基本类型,直接存数值 Integer是类,产生对象时用一个引用指向这个对象 Java把内存划分成两种:一种是栈内存,另一种是堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数 ...
- 九度OJ 1011:最大连续子序列 (DP)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5615 解决:2668 题目描述: 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, N ...
- ios 7 Autolayout bug
ios 7 Autolayout bug 错误类型:NSInternalInconsistencyException(SIGABRT) 详情:Auto Layout still required af ...
- webpack三种代码
在使用webpack时,主要有三种代码类型: 1.你或你的团队写的源码 2.第三方library或vendor代码 3.管理模块交互的runtime和manifest 什么是manifest文件? 通 ...
- c# CODE REVIEW (13-11 TO 14-01)
一. 松耦合