基于node.js实现微信支付退款功能

缘起

有付款就会有退款

注意,退款支持部分退款

左口袋的钱退到右口袋罗

这次发起的退款请求0.01元是实时到账的,因此,用户在小程序端发起的退款只是一个请求到后台,后台审核人员审核无误后才后微信发起退款操作。

引入第三方module

在package.json 中加入"weixin-pay": "^1.1.7"这一条

代码目录结构

入参

{ transaction_id: '4200000005201712165508745023', // 交易
 out_trade_no: '5b97cba0ae164bd58dfe9e77891d3aaf', // 自己这头的交易号
 out_refund_no: '6f3240c353934105be34eb9f2d364cec', // 退款订单,自己生成
 total_fee: 1, // 退款总额
 nonce_str: '1xSZW0op0KcdKoMYxnyxhEuF1fAQefhU', // 随机串
 appid: 'wxff154ce14ad59a55', // 小程序 appid
 mch_id: '1447716902', // 微信支付商户id
 sign: '416FCB62F9B8F03C82E83052CC77524B' // 签名,weixin-pay这个module帮助生成 }

然后由wxpay为我们生成其余字段,比如nonce_str,sign,当然还少不了p12证书,

这个早选在wxpay初始代码里已经配置了,pfx: fs.readFileSync(__dirname + '/../../../cert/apiclient_cert.p12'), //微信商户平台证书

lib/wechat/utils/wxpay.js的源码

const WXPay = require('weixin-pay'); // 引入weixin-pay这个第三方模块
const {weapp} = require('../../../utils/config'); // 我自己的全局配置文件,包括了appid key 等
const fs = require('fs');
const wxpay = WXPay({
 appid: weapp.APPID,
 mch_id: weapp.MCHID,
 partner_key: weapp.KEY, //微信商户平台 API secret,非小程序 secret
 pfx: fs.readFileSync(__dirname + '/../../../cert/apiclient_cert.p12'),
});

module.exports = wxpay;

另外还有一个util.js工具类

用于验证与错误回调

const wxpay = require('./wxpay');

const validateSign = results => {
 const sign = wxpay.sign(results);
 if (sign !== results.sign) {
 const error = new Error('微信返回参数签名结果不正确');
 error.code = 'INVALID_RESULT_SIGN';
 throw error;
 };
 return results;
};

const handleError = results => {
 if (results.return_code === 'FAIL') {
 throw new Error(results.return_msg);
 }
 if (results.result_code !== 'SUCCESS') {
 const error = new Error(results.err_code_des);
 error.code = results.err_code;
 throw error;
 }
 return results;
};

module.exports = {
 validateSign,
 handleError,
};

发起退款请求

退款逻辑是这样的,先从自己这边的Order数据表中查出transaction_id/out_trade_no/total_fee,再拼上自己生成的out_refund_no退款单号,本次退款部分金额refund_fee,最后由weixin-pay这个模块下的wxpay.refund调起就可以了,成功就把订单状态改成"退款成功"

// 退款
router.post('/refund', function(req, res) {
 Order.findById(req.body._id, (err, order) => {
  if (err) {
   console.log(err);
  }
  console.log(order);
  // 生成微信设定的订单格式
  var data = {
   transaction_id: order.transactionId,
   out_trade_no: order.tradeId,
   out_refund_no: uuid().replace(/-/g, ''),
   total_fee: order.amount,
   refund_fee: order.amount
  };
  console.log(data);
  // 先查询订单,再退订单
  wxpay.refund(data, (err, result) => {
   if (err) {
    console.log(err);
    res.send(
     utils.json({
      code: 500,
      msg: '退款失败'
     })
    );
   }
   // 返回退款请求成功后,要将订单状态改成REFUNDED
   if (result.result_code === 'SUCCESS') {
    console.log(result);
    order.status = 'REFUNDED';
    order.save((err, response) => {
     res.send(
      utils.json({
       msg: '退款成功'
      })
     );
    });
   } else {
    res.send(
     utils.json({
      code: 500,
      msg: result.err_code_des
     })
    );
   }

  });
 });
});

入参的坑

1.这次遇到的坑是refund_fee忘记传值,也就是说微信退款是支持部分退款的,如果是全额退款,那么将它赋值为total_fee相同

2.网上说的op_user_id: weapp.MCHID这个参数是非必选的

3.transaction_id 与 out_trade_no 二选一即可,这样在没有记录transaction_id的情况(比如没有写支付成功的callback)下,也能发起退款;其中优先级前者大于后者,在我在分别前其一故意给错的过程中得到了验证。

4.报了一个appid与商户号不匹配的报错,return_code: 'FAIL', return_msg: '商户号mch_id与appid不匹配'原来是小程序还没绑定公众号微信支付,这真是一个乌龙。

成功退款微信返回的数据

 appid:"wxff154ce14ad59a55"
 cash_fee:"1"
 cash_refund_fee:"1"
 coupon_refund_count:"0"
 coupon_refund_fee:"0"
 mch_id:"1447716902"
 nonce_str:"c44wOvB6a4bQJfRk"
 out_refund_no:"9ace1466432a4d548065dc8df95d904a"
 out_trade_no:"5b97cba0ae164bd58dfe9e77891d3aaf"
 refund_channel:""
 refund_fee:"1"
 refund_id:"50000705182017121702756172970"
 result_code:"SUCCESS"
 return_code:"SUCCESS"
 return_msg:"OK"
 sign:"5C2E67B3250054E8A665BF1AE2E9BDA3"
 total_fee:"1"
 transaction_id:”4200000005201712165508745023”

重复退款将返回如下

 appid:"wxff154ce14ad59a55"
 err_code:"ERROR"
 err_code_des:"订单已全额退款"
 mch_id:"1447716902"
 nonce_str:"KP1YWlU7a5viZEgK"
 result_code:"FAIL"
 return_code:"SUCCESS"
 return_msg:"OK"
 sign:”C2A7DED787BEA644C325E37D96E9F41C”

最后

如果没有写退款功能或者不想写退款功能怎么办,其实可以从微信支付的后台pay.weixin.qq.com,也是能退款出去的,只是不想忘记了要人工将订单状态置为退款状态。

总结

以上所述是小编给大家介绍的基于node.js实现微信支付退款功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 基于node.js实现微信支付退款功能

    缘起 有付款就会有退款 注意,退款支持部分退款 左口袋的钱退到右口袋罗 这次发起的退款请求0.01元是实时到账的,因此,用户在小程序端发起的退款只是一个请求到后台,后台审核人员审核无误后才后微信发起退款操作. 引入第三方module 在package.json 中加入"weixin-pay": "^1.1.7"这一条 代码目录结构 入参 { transaction_id: '4200000005201712165508745023', // 交易 out_trade

  • 详解基于Node.js的微信JS-SDK后端接口实现代码

    做了一个网站,放到线上,用微信打开,点击分享,可是分享后发给朋友的链接卡片是微信默认自带的,如下: 这标题,描述以及图片是默认自带的,丑不说,分享给别人还以为是盗号网站呢,而接入微信的JSSDK后,分享可以自定义内容,如下: 我承认,虽然这分享的标题和内容也并不正经,但这不妨碍我表达我们可以通过微信JSSDK定义分享内容,接下来我们将一步一步从零实现JSSDK从后端Node.js的接入. 成为测试公众号开发者 登录测试公众号后台 首先我们需要在微信公众平台申请测试接口,地址:https://mp

  • 详解基于 Node.js 的轻量级云函数功能实现

    导语 在万物皆可云的时代,你的应用甚至不需要服务器.云函数功能在各大云服务中均有提供,那么,如何用"无所不能"的 node.js 实现呢? 一.什么是云函数? 云函数是诞生于云服务的一个新名词,顾名思义,云函数就是在云端(即服务端)执行的函数.各个云函数相互独立,简单且目的单一,执行环境相互隔离.使用云函数时,开发者只需要关注业务代码本身,其它的诸如环境变量.计算资源等,均由云服务提供. 二.为什么需要云函数? 程序员说不想买服务器,于是便有了云服务: 程序员又说连 server 都不

  • JS实现仿微信支付弹窗功能

    先奉上效果图 html代码 <!DOCTYPE html> <html> <head> <title>仿手机微信支付输入密码界面效果</title> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1.0, width=device-width, user-scalable=no"

  • 使用node.js实现微信小程序实时聊天功能

    在微信这个聊天工具里的小程序上实现聊天功能,总感觉怪怪的.但领导要求了,总是要干的. 然后就实时通讯这个关键词展开搜索,穿梭于网页之间.不过粘贴复制的真的太多了,找了半天也没找到想要的,不过还是提取到了关键词的WebSocket和node.js的,然后搜索这两是啥,什么关系,总算明白了一点. 最后确定了第一步需要干的是用node.js搭建服务(我是装在自己的windows下的): 1.首先到官网下载node.js,下载链接 安装很简单,双击下载好的文件,直接下一步一步,没什么特殊的选择,路径默认

  • 基于aotu.js实现微信自动添加通讯录中的联系人功能

    什么是Auto.JS? Auto.JS是Android平台上的JavaScript自动化工具. 它的本质是可执行自己编写的简易Javascript脚本的,尤其可以在开启"无障碍模式"的情况下对其他App进行一些操作的一个Android App,便于进行自动化操作.学习成本非常低. Auto.JS已被黑产广泛使用,以至于作者关闭了官方下载通道. 官网:https://github.com/hyb1996/Auto.js 下面通过代码给大家介绍下基于aotu.js实现微信自动添加通讯录中的

  • 基于node.js制作简单爬虫教程

    前言:最近想学习node.js,突然在网上看到基于node的爬虫制作教程,所以简单学习了一下,把这篇文章分享给同样初学node.js的朋友. 目标:爬取 http://tweixin.yueyishujia.com/webapp/build/html/ 网站的所有门店发型师的基本信息. 思路:访问上述网站,通过chrome浏览器的network对网页内容分析,找到获取各个门店发型师的接口,对参数及返回数据进行分析,遍历所有门店的所有发型师,直到遍历完毕,同事将信息存储到本地. 步骤一:安装nod

  • 基于node.js的fs核心模块读写文件操作(实例讲解)

    node.js 里fs模块 常用的功能 实现文件的读写 目录的操作 - 同步和异步共存 ,有异步不用同步 - fs.readFile 都不能读取比运行内存大的文件,如果文件偏大也不会使用readFile方法 - 文件大分流读取,stream - 引入fs模块 - let fs=require('fs') 同步读取文件 -fs.readFileSync('路径',utf8); let result=fs.readFileSync('./1.txt','utf8'); 异步读取文件,用参数err捕获

  • 基于thinkPHP实现的微信自定义分享功能示例

    本文实例讲述了基于thinkPHP实现的微信自定义分享功能.分享给大家供大家参考,具体如下: 在许多大的网站我们都会看到点击分享就可以把数据分享到微信或QQ或其它的平台了,下面我们来看一段php版微信自定义分享代码,代码参考官方开发的没有任何问题. 分享需要认证微信订阅号或者服务号. php 代码(thinkphp): $appid='xxx'; $appsecret='xxxx'; $timestamp = time(); $noncestr = $this->getRandStr(15);

  • 推荐一个基于Node.js的表单验证库

    API 在执行过程中的一个基本任务是数据验证. 在本文中,我想向你展示如何为你的数据添加防弹验证,同时返回风格良好的格式. 在 Node.js 中进行自定义数据验证既不容易也不快. 为了覆盖所有类型的数据,需要写许多函数. 虽然我已经尝试了一些 Node.js 的表单库 -- Express 和 Koa --他们从未满足我的项目需求. 这些扩展库要么不兼容复杂的数据结构,要么在异步验证出现问题. 使用 Datalize 在 Node.js 中进行表单验证 这就是为什么我最终决定编写自己的小巧而强

随机推荐