说明
只是单纯的记录学习过程
官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
准备
1.当然已经有了已支付的订单
2.退款需要双向证书,证书下载可见官网
微信商户平台(pay.weixin.qq.com)–>账户中心–>账户设置–>API安全 。
那就开始吧
exports.miniRefund = function (req,res) {
let refundData = req.body;//获取数据 在这里我获取的其实就是该订单支付的时候的信息,因为当时存起来了,大家根据自己逻辑添加数据
let appid = refundData.appid;//公众账号ID
let mch_id = refundData.mch_id//商户号
let nonce_str = refundData.nonce_str//这是随机字符串,为了方便我用的是该订单在支付的时候的随机字符串
let out_trade_no = refundData.out_trade_no;//支付的订单号
let out_refund_no = refundData.out_refund_no;//退款订单号
let total_fee= refundData.total_fee;//支付金额
let refund_fee = total_fee;//退款金额 因为我的逻辑是全额退款所以退款金额等于支付金额
let refund_desc = refundData.refund_desc;//退款原因
let sign = wechatUtil.refundSign(appid,mch_id,nonce_str,out_trade_no,out_refund_no,total_fee,refund_fee,refund_desc);//最重要的一步 签名 这是调用了我自己封装的一个方法,后面也会贴出来,关于签名大家可以到网上看一下就不说了
let formData = "<xml>";
formData += "<appid>"+appid+"</appid>";
formData += "<mch_id>"+mch_id+"</mch_id>";
formData += "<nonce_str>"+nonce_str+"</nonce_str>";
formData += "<out_trade_no>"+out_trade_no+"</out_trade_no>";
formData += "<out_refund_no>"+out_refund_no+"</out_refund_no>";
formData += "<total_fee>"+total_fee+"</total_fee>";
formData += "<refund_fee>"+refund_fee+"</refund_fee>";
formData += "<refund_desc>"+refund_desc+"</refund_desc>";
formData += "<sign>"+sign+"</sign>";
formData += "</xml>";
/*==================================================*/
//接下来我们要用到一个request
let request = require('request');//当然我们引用要写在最上面,但为了看的清楚点就一步一步走吧
request({
//请求地址
url:'https://api.mch.weixin.qq.com/secapi/pay/refund',
//还记得准备的证书吗这里就用到啦
agentOptions: {
cert: fs.readFileSync(path1.join(__dirname,'../../cert/apiclient_cert.pem')),
key: fs.readFileSync(path1.join(__dirname,'../../cert/apiclient_key.pem' ))
},
method: 'POST',
//携带这我们拼接好的参数
body:formData
}, function (err,body) {
//getXMLNodeValue:因为微信返回的结果是xml形式的所以封装了一个解析的方法,会面会贴出来
let trade_state_desc = wechatUtil.getXMLNodeValue('return_code', body.body.toString('utf-8'));
let return_msg = wechatUtil.getXMLNodeValue('return_msg', body.body.toString('utf-8'));
let err_code_des = wechatUtil.getXMLNodeValue('err_code_des', body.body.toString('utf-8'));
//为什么要加上这个参数err_code_des....我也很是无奈前两个参数只能正面是真的访问成功了,但是我试了一下 瞎写的订单号提交
//这两个参数还是正常的,但会多出 err_code_des这个参数,返回的是提示信息.所以前两个参数正确且没有这个参数的时候我才能知道
//提交的信息没有问题,所以就这样写了,但肯定不是很好,我会想想解决办法. if(return_code=='SUCCESS'&&return_msg=='OK'&&err_code_des==undefined){
log.info("退款成功")
let data = {
result:'1',
msg:'已退款成功'
};
res.json(data)
}else {
let data = {
result:'0',
msg:err_code_des
};
res.json(data)
}
});
}
接下是加签的方法和解析xml的方法
//解析xml数据
exports.getXMLNodeValue = (node_name,xml)=>{
log.info(xml);
let tmp = xml.split("<"+node_name+">");
if(tmp[1]!=undefined){
let _tmp = tmp[1].split("</"+node_name+">");
let tmp1 = _tmp[0].split('[');
let _tmp1 = tmp1[2].split(']');
return _tmp1[0];
}
};
//退款签名
exports.refundSign=(appid,mch_id,nonce_str,out_trade_no,out_refund_no,total_fee,refund_fee,refund_desc)=>{
let ret = {
appid: appid,
mch_id: mch_id,
nonce_str:nonce_str,
out_trade_no:out_trade_no,//注意左边参数名,
out_refund_no:out_refund_no,
total_fee:total_fee,
refund_fee:refund_fee,
refund_desc:refund_desc
};
log.info("查询签名验证的参数",ret);
let string = raw(ret);
let key = "密钥*************";
string = string + '&key='+key;
return crypto.createHash('md5').update(string,'utf8').digest('hex').toUpperCase();
};
//排序PS : key toLowerCase
function raw(args) {
var keys = Object.keys(args);
keys = keys.sort();
var newArgs = {};
keys.forEach(function (key) {
newArgs[key.toLowerCase()] = args[key];
});
var string = '';
for (var k in newArgs) {
string += '&' + k + '=' + newArgs[k];
}
string = string.substr(1);
console.log(string);
return string;
};
结束
但还是有很多问题…可以看到商品详情是undefined,但我在文档中也没有找到商品详情的参数,
有点烦,希望尽快解决,当然我们还是少了一步,我们还应该通过查询退款来做验证,因为我还没弄,但感觉难度也不会很大,后面会补上