下单

通过下单获取prepay_id,然后返回给小程序发起支付

若是服务商,mch_id:传入服务的商户号;sub_mch_id:传入子商户的商户号,算法签名的秘钥是服务商的秘钥。

'use strict';


const Service = require('egg').Service;

class wxPayment extends Service {
// 小程序支付
  async unifiedorder(data) {
    const { ctx } = this;

    const wxpayUitls = ctx.service.payment.helper.paymentUitls;
    // 微信支付调用ip
    const ip = ctx.request.ip.replace(/::ffff:/, '');

    const params = {
      // 小程序appid
      appid: this.config.wxampPayConfig.appid,
      // 商户号
      mch_id: this.config.wechatPayConfig.mch_id,
      // 子商户号
      sub_mch_id: this.config.wechatPayConfig.sub_mch_id,
      // 32位以内随机字符串
      nonce_str: wxpayUitls.createNonceStr(),
      // 商品描述
      body: data.body,
      // 商户订单号,32个字符内
      out_trade_no: wxpayUitls.getTradeNo(),
      // 金额,分;正式上线时启用
      // total_fee: wxpayUitls.regYuanToFen(data.total, 100),
      total_fee: 1,
      // 终端ip
      spbill_create_ip: ip,
      // 通知地址
      notify_url: 'http://baidu.com',

      // 交易类型
      trade_type: 'JSAPI',
      // 用户标识
      openid: data.openID,
    };

    // 算法签名,传入参数及服务商商户的秘钥
    params.sign = wxpayUitls.getSign(params, this.config.wechatPayConfig.wxPaykey);
    const url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    const res = await ctx.curl(url, {
      method: 'POST',
      dataType: 'text/xml', // 注意接口数据类型
      data: wxpayUitls.createXML(params), // 动态生成的xml
    });


    const result = await wxpayUitls.parserXML(res.data.toString());

    // 返回的参数
    const r = {
      appId: this.config.wxampPayConfig.appid, // 当前小程序的appid
      timeStamp: wxpayUitls.createTimeStamp(), // 注意类型String
      nonceStr: result.xml.nonce_str,
      package: 'prepay_id=' + result.xml.prepay_id,
      signType: 'MD5',
    };
    r.paySign = wxpayUitls.getSign(r, this.config.wechatPayConfig.wxPaykey);
    r.tradeNo = params.out_trade_no;
    return r;
  }
}

module.exports = wxPayment;

helper.js

'use strict';
// eslint-disable-next-line strict
const QueryString = require('querystring');
const Crypto = require('crypto');
const XmlToJs = require('xml2js');
exports.paymentUitls = {
  // 订单号
  getTradeNo: () => {
    let No = '';
    for (let i = 0; i < 5; i++) {
      No += Math.floor(Math.random() * 10);
    }
    No = new Date().getTime() + No;
    return No;
  },

  /**
   * 元的转化
   * @param yuan {number} 金额
   * @param digit {number} 放大倍数,如果元转分则为100
   * */
  regYuanToFen(yuan, digit) {
    let m = 0;
    const s1 = yuan.toString();
    const s2 = digit.toString();
    try {

      m += s1.split('.')[1].length;
      m += s2.split('.')[1].length;

    } catch (e) {
      // console.log(e);
    }

    return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m);
  },
  // 时间戳产生函数
  createTimeStamp() {
    return parseInt(new Date().getTime() / 1000) + '';
  },

  // 生成随机的NonceStr,随机字符串,不长于32位。
  createNonceStr: () => {
    return Math.random()
      .toString(36)
      .substr(2, 15);
  },

  // 获取微信支付的签名
  /**
   * @param signParams {object} 请求参数的集合
   * @param key {string} 商户号
   * */
  getSign: (signParams, key) => {
    // 按 key 值的ascll 排序
    let keys = Object.keys(signParams);
    keys = keys.sort();
    const newArguments = {};
    // eslint-disable-next-line no-unused-vars
    keys.forEach(function(val, key) {
      if (signParams[val]) {
        newArguments[val] = signParams[val];
      }
    });

    const string = QueryString.stringify(newArguments) + '&key=' + key;
    // 生成签名
    return Crypto.createHash('md5')
      .update(QueryString.unescape(string), 'utf8')
      .digest('hex')
      .toUpperCase();
  },
  // 根据对象生成xml
  createXML: params => {
    const builder = new XmlToJs.Builder();
    return builder.buildObject(params);
  },
  // 解析xml
  parserXML: xml => {
    const Parser = new XmlToJs.Parser({ explicitArray: false, ignoreAttrs: false });
    return new Promise((resolve, reject) => {
      Parser.parseString(xml, function(err, result) {
        if (err) reject(err);
        resolve(result);
      });
    });
  },
};

微信小程序获取返回的prepay_id,发起支付

// 发起支付
wx.requestPayment({
 timeStamp: r.data.result.timeStamp,
 nonceStr: r.data.result.nonceStr,
 package: r.data.result.package,
 signType: 'MD5',
 paySign: r.data.result.paySign,
 success(res) {
  console.log('成功', res)
 },
 fail(res) {
 
 }
})

欢迎关注公众号【无聊猿】,共同学习探讨

image

posted on 2021-11-11 21:31  无聊猿  阅读(207)  评论(0编辑  收藏  举报