node-koa2 微信支付,企業付款到零錢

微信支付用的V2版本

 微信支付說明文檔:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2    參數詳細說明請自行查看

 

微信支付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();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章