node-koa2 微信支付,企业付款到零钱

微信支付用的V2版本

 微信支付说明文档:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2    参数详细说明请自行查看

// https://github.com/klover2/wechatpay-node-v3-ts/blob/master/index.ts
 // https://blog.csdn.net/blackhost/article/details/100703911

微信支付2.0还是xml传输数据,用到了解析模块xml2js

接下来是请求微信支付,付款到零钱的主要代码,可以自行创建一个wxpay.js,将下面代码贴进去,

商户appid需要特别说明一下。如果你要是付款给公众号下的用户,就要填写公众号appid,付款给小程序下的用户,就要填写小程序的appid

我参与的项目,商户,小程序和公众号都有绑定,所以会稍稍复杂一点,当时我测试用的是小程序appid和小程序下的用户openid,大意了,应该是公众号的

const fs = require('fs')
const path = require('path')
const xml2js = require('xml2js')
const request = require('request')
const payUtil = require('./payUtil')
/**
 * 微信-企业付款到零钱
 * 
 * 注意的点是,企业付款到零钱,用的是公众号下的用户openid,所以appid要填成公众号的,保持一致,不能填小程序的
 */
 exports.transfers = async (map) => {
    let mapInfo = {}
    // 商户appid
    // 这里的商户appid是公众号appid
    mapInfo.mch_appid = ''
    // 商户id
    mapInfo.mchid = ''
    // 商户密钥
    mapInfo.mchkey = ''
    // 随机字符串
    mapInfo.nonce_str = payUtil.getRnd32()
    // 商户内部流水号
    mapInfo.partner_trade_no = map.recordId
    // 用户的openid
    mapInfo.openid = map.openid
    // 是否需要校验名字
    mapInfo.check_name = 'NO_CHECK'
    // 金额,单为是分
    mapInfo.amount = map.amount * 100
    // 描述
    mapInfo.desc = '企业付款到零钱'
    // ip,该IP同在商户平台设置的IP白名单中的IP没有关联,该IP可传用户端或者服务端的IP。
    mapInfo.spbill_create_ip = ''
    // 签名
    let sign = wxpay.transfersSign(mapInfo)

    // 拼接xm字符串
    let formData = "<xml>";
    formData += "<mch_appid>" + mapInfo.mch_appid + "</mch_appid>";
    formData += "<mchid>" + mapInfo.mchid + "</mchid>";
    formData += "<nonce_str>" + mapInfo.nonce_str + "</nonce_str>";
    formData += "<partner_trade_no>" + mapInfo.partner_trade_no + "</partner_trade_no>";
    formData += "<openid>" + mapInfo.openid + "</openid>";
    formData += "<check_name>" + mapInfo.check_name + "</check_name>";
    formData += "<amount>" + mapInfo.amount + "</amount>";
    formData += "<desc>" + mapInfo.desc + "</desc>";
    formData += "<spbill_create_ip>" + mapInfo.spbill_create_ip + "</spbill_create_ip>";
    formData += "<sign>" + sign + "</sign>";
    formData += "</xml>";
    console.log(formData)

  // 请求路径
    let url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'
    return new Promise((resolve, reject) => {
        request({
            url: url,
       // 需要证书
            agentOptions: {
                cert: fs.readFileSync(path.resolve(`./public/config/cert/${payConfig.wx_cert}`)),
                key: fs.readFileSync(path.resolve(`./public/config/cert/${payConfig.wx_key}`))
            },
            method: 'post',
            body: formData,
        }, function (err, response, body) {
            if (!err && response.statusCode == 200) {

                // 创建一个解析xml的对象
                let parser = new xml2js.Parser({
                    trim: true,
                    explicitArray: false,
                    explicitRoot: false
                }); 

                //解析签名结果xml转json
                parser.parseString(body, (err, res) => {
                    console.log(res)
                    let result = {}

                    // 判断return_code 为fail的时候,的错误信息
                    if (res.return_code == 'FAIL') {
                        result.msg = res.return_msg
                        reject(result)
                    }
                    
                    // return_code是success 的话, 只代表业务已受理, 并不代表已成功
                    // result_code是success 的话, 才算是付款成功, fail的话,返回错误信息
                    if (res.return_code == 'SUCCESS' && res.result_code == 'FAIL') {
                        result.msg = res.err_code_des
                        reject(result)
                    } else {
                        result.msg = ''
                        resolve(result)
                    }
                })
            }
            reject(err)
        })
    })
}

 

在其他地方调用付款到零钱transfers方法

// 微信支付方法路径自行修改成自己的
const { transfers } = require('./wxpay')
const { createOrderNumber } = require('./payUtil')

let map = {
    // 金额
    amount: 1,
    // 备注
    desc: '提现',
    // 用户openid
    openid: '',
    // 系统内部流水号
    recordId: createOrderNumber(),
}
try {
    let result = await transfers(map)
    ctx.body = {
        code: 200,
        msg: '提现到零钱成功,提醒用户稍后自行查看'
    }
} catch (err) {
    console.log(err)
    // 捕捉请求微信支付的错误
    ctx.body = {
        code: 500,
        msg: err.msg
    }
    return
}

 

下面贴一些工具方法,自行创建一个payUtil.js,将下面代码贴入即可

// 生成随机随机32 位  字符串
exports.getRnd32 = () => {
    let str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    let result = ''
    for (let i = 0; i < 32; i++) {
        let rnd = Math.floor(Math.random() * str.length)
        result += str[rnd]
    }
    return result
}


// 生成时间戳
exports.createTimeStamp = () => {
    return parseInt(new Date().getTime() / 1000) + '';
}


// 生成订单编号
exports.createOrderNumber = () => {
    let str = ''
    for (let i = 0; i < 10; i++) {
        let num = Math.floor(Math.random() * 10)
        str += num
    }
    let time = new Date()
    let year = time.getFullYear().toString()
    let month = time.getMonth().toString() + 1
    let day = time.getDate().toString()
    let hours = time.getHours().toString()
    let minutes = time.getMinutes().toString()
    let seconds = time.getSeconds().toString()
    let mill = time.getMilliseconds().toString()
    str += year += month += day += hours += minutes += seconds += mill
    return str;
}


// 按照ascll码排序
function raw(args) {
    var keys = Object.keys(args);
    keys = keys.sort()
    var newArgs = {};
    keys.forEach(function (key) {
        newArgs[key] = args[key];
    });
    var string = '';
    for (var k in newArgs) {
        string += '&' + k + '=' + newArgs[k];
    }
    string = string.substr(1);
    return string;
}


/**
 * 企业付款到零钱签名
 */
exports.transfersSign = (map) => {
    let ret = {
        mch_appid: map.mch_appid,
        mchid: map.mchid,
        nonce_str: map.nonce_str,
        partner_trade_no: map.partner_trade_no,
        openid: map.openid,
        check_name: map.check_name,
        amount: map.amount,
        desc: map.desc,
        spbill_create_ip: map.spbill_create_ip,
    }
    console.log(ret)
    var string = raw(ret);
    var key = map.mchkey;
    string = string + '&key=' + key;
    var crypto = require('crypto');
    return crypto.createHash('md5').update(string, 'utf8').digest('hex').toUpperCase();
}

 

posted @ 2021-10-11 15:08  时光凉忆  阅读(296)  评论(0编辑  收藏  举报