• 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();
    }
  • 相关阅读:
    Python中所有的关键字
    关于selenium的8种元素定位
    对提示框的操作
    selenium+webservice进行百度登录
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled...报错解决
    Vue中使用echarts
    npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142解决方法
    插入排序
    冒泡排序优化
    roject 'org.springframework.boot:spring-boot-starter-parent:XXX' not found 解决
  • 原文地址:https://www.cnblogs.com/naturl/p/15393459.html
Copyright © 2020-2023  润新知