tenpay-node
Version: 
微信支付 for nodejs
693 lines (609 loc) • 24.1 kB
JavaScript
const urllib = require('urllib');
const util = require('./util');
const replyData = msg => util.buildXML(msg ? {return_code: 'FAIL', return_msg: msg} : {return_code: 'SUCCESS'});
class Payment {
  constructor({appid, mchid, partnerKey, pfx, notify_url, refund_url, spbill_create_ip, sandbox} = {}, debug = false) {
    if (!appid) throw new Error('appid fail');
    if (!mchid) throw new Error('mchid fail');
    if (!partnerKey) throw new Error('partnerKey fail');
    this.appid = appid;
    this.mchid = mchid;
    this.partnerKey = partnerKey;
    this.pfx = pfx;
    this.notify_url = notify_url;
    this.refund_url = refund_url;
    this.spbill_create_ip = spbill_create_ip || '127.0.0.1';
    this.urls = sandbox ? {
      micropay: 'https://api.mch.weixin.qq.com/sandboxnew/pay/micropay',
      reverse: 'https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/reverse',
      unifiedorder: 'https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder',
      orderquery: 'https://api.mch.weixin.qq.com/sandboxnew/pay/orderquery',
      closeorder: 'https://api.mch.weixin.qq.com/sandboxnew/pay/closeorder',
      refund: 'https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/refund',
      refundquery: 'https://api.mch.weixin.qq.com/sandboxnew/pay/refundquery',
      downloadbill: 'https://api.mch.weixin.qq.com/sandboxnew/pay/downloadbill',
      downloadfundflow: 'https://api.mch.weixin.qq.com/sandboxnew/pay/downloadfundflow',
      send_coupon: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/send_coupon',
      query_coupon_stock: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/query_coupon_stock',
      querycouponsinfo: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/querycouponsinfo',
      transfers: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/promotion/transfers',
      gettransferinfo: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/gettransferinfo',
      sendredpack: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/sendredpack',
      sendgroupredpack: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/sendgroupredpack',
      gethbinfo: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaymkttransfers/gethbinfo',
      paybank: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaysptrans/pay_bank',
      querybank: 'https://api.mch.weixin.qq.com/sandboxnew/mmpaysptrans/query_bank',
      profitsharingaddreceiver:"https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver",
      profitsharing: 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing'
    } : {
      micropay: 'https://api.mch.weixin.qq.com/pay/micropay',
      reverse: 'https://api.mch.weixin.qq.com/secapi/pay/reverse',
      unifiedorder: 'https://api.mch.weixin.qq.com/pay/unifiedorder',
      orderquery: 'https://api.mch.weixin.qq.com/pay/orderquery',
      closeorder: 'https://api.mch.weixin.qq.com/pay/closeorder',
      refund: 'https://api.mch.weixin.qq.com/secapi/pay/refund',
      refundquery: 'https://api.mch.weixin.qq.com/pay/refundquery',
      downloadbill: 'https://api.mch.weixin.qq.com/pay/downloadbill',
      downloadfundflow: 'https://api.mch.weixin.qq.com/pay/downloadfundflow',
      send_coupon: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/send_coupon',
      query_coupon_stock: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/query_coupon_stock',
      querycouponsinfo: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/querycouponsinfo',
      transfers: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers',
      gettransferinfo: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo',
      sendredpack: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack',
      sendgroupredpack: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack',
      gethbinfo: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo',
      paybank: 'https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank',
      querybank: 'https://api.mch.weixin.qq.com/mmpaysptrans/query_bank',
      getpublickey: 'https://fraud.mch.weixin.qq.com/risk/getpublickey',
      getsignkey: 'https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey',
      combinedorder: 'https://api.mch.weixin.qq.com/pay/combinedorder',
      profitsharingaddreceiver:"https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver",
      profitsharing: 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing',
    };
    this.debug = debug;
  }
  log(...args) {
    if (this.debug) console.log(...args);
  }
  static init(...args) {
    return new Payment(...args);
  }
  static async sandbox(config, debug) {
    let {sandbox_signkey} = await Payment.init(config).getSignkey();
    return new Payment({
      ...config,
      partnerKey: sandbox_signkey,
      sandbox: true
    }, debug);
  }
  async _parse(xml, type, signType) {
    let json = await util.parseXML(xml);
    // console.log('json----1',json)
    switch (type) {
      case 'middleware_nativePay':
        break;
      default:
        if (json.return_code !== 'SUCCESS') throw new Error(json.return_msg || 'XMLDataError', { cause: json });
    }
    switch (type) {
      case 'middleware_refund':
      case 'middleware_nativePay':
      case 'getsignkey':
        break;
      default:
        if (json.result_code !== 'SUCCESS') throw new Error(json.err_code || 'XMLDataError', { cause: json });
    }
    switch (type) {
      case 'getsignkey':
        break;
      case 'middleware_refund': {
        if (json.appid !== this.appid) throw new Error('appid不匹配');
        if (json.mch_id !== this.mchid) throw new Error('mch_id不匹配');
        let key = util.md5(this.partnerKey).toLowerCase();
        let info = util.decrypt(json.req_info, key);
        json.req_info = await util.parseXML(info);
        break;
      }
      case 'transfers':
        if (json.mchid !== this.mchid) throw new Error('mchid不匹配');
        break;
      case 'sendredpack':
      case 'sendgroupredpack':
        if (json.wxappid !== this.appid) throw new Error('wxappid不匹配');
        if (json.mch_id !== this.mchid) throw new Error('mchid不匹配');
        break;
      case 'gethbinfo':
      case 'gettransferinfo':
        if (json.mch_id !== this.mchid) throw new Error('mchid不匹配');
        break;
      case 'send_coupon':
      case 'query_coupon_stock':
      case 'querycouponsinfo':
        if (json.appid !== this.appid) throw new Error('appid不匹配');
        if (json.mch_id !== this.mchid) throw new Error('mch_id不匹配');
        break;
      case 'getpublickey':
        break;
      case 'paybank':
        if (json.mch_id !== this.mchid) throw new Error('mchid不匹配');
        break;
      case 'querybank':
        if (json.mch_id !== this.mchid) throw new Error('mchid不匹配');
        break;
      case 'combinedorder':
        if (json.combine_appid !== this.appid) throw new Error('appid不匹配');
        if (json.combine_mch_id !== this.mchid) throw new Error('mch_id不匹配');
        if (json.sign !== this._getSign(json, 'HMAC-SHA256')) throw new Error('sign签名错误');
        break;
      default:
        if (json.appid !== this.appid) throw new Error('appid不匹配');
        if (json.mch_id !== this.mchid) throw new Error('mch_id不匹配');
        if (json.sign !== this._getSign(json, json.sign_type || signType)) throw new Error('sign签名错误');
    }
    return json;
  }
  async _parseBill(xml, format = false) {
    if (util.checkXML(xml)) {
      let json = await util.parseXML(xml);
      throw new Error(json.err_code || json.return_msg || 'XMLDataError', { cause: json });
    }
    if (!format) return xml;
    let arr = xml.trim().split(/\r?\n/).filter(item => item.trim());
    let total_data = arr.pop().substr(1).split(',`');
    let total_title = arr.pop().split(',');
    let list_title = arr.shift().split(',');
    let list_data = arr.map(item => item.substr(1).split(',`'));
    return {total_title, total_data, list_title, list_data};
  }
  _getSign(params, type = 'MD5') {
    let str = util.toQueryString(params) + '&key=' + this.partnerKey;
    switch (type) {
      case 'MD5':
        return util.md5(str).toUpperCase();
      case 'HMAC-SHA256':
        return util.sha256(str, this.partnerKey).toUpperCase();
      default:
        throw new Error('signType Error');
    }
  }
  async _request(params, type, cert = false) {
    // 安全签名
    params.sign = this._getSign(params, params.sign_type);
    // 创建请求参数
    let pkg = {
      method: 'POST',
      dataType: 'text',
      data: util.buildXML(params),
      timeout: [10000, 15000]
    };
    if (cert) {
      pkg.pfx = this.pfx;
      pkg.passphrase = this.mchid;
    }
    this.log('post data =>\r\n%s\r\n', pkg.data);
    // console.log('安全签名-12--',JSON.stringify(pkg), this.urls[type])
    let {status, data} = await urllib.request(this.urls[type], pkg);
    if (status !== 200) throw new Error('request fail');
    this.log('receive data =>\r\n%s\r\n', data);
    return ['downloadbill', 'downloadfundflow'].indexOf(type) < 0 ? this._parse(data, type, params.sign_type) : data;
  }
  // Express中间件
  middlewareForExpress(type = 'pay') {
    return async (req, res, next) => {
      res.reply = msg => {
        res.header('Content-Type', 'application/xml; charset=utf-8');
        res.send(replyData(msg));
      };
      res.replyNative = (prepay_id, err_code_des) => {
        res.header('Content-Type', 'application/xml; charset=utf-8');
        res.send(this._getNativeReply(prepay_id, err_code_des));
      };
      try {
        if (typeof req.body !== 'string') throw new Error('XMLDataError');
        req.weixin = await this._parse(req.body, 'middleware_' + type);
      } catch (err) {
        return res.reply(err.message);
      }
      next();
    };
  }
  // Koa中间件
  middleware(type = 'pay') {
    return async (ctx, next) => {
      ctx.reply = msg => {
        ctx.type = 'application/xml; charset=utf-8';
        ctx.body = replyData(msg);
      };
      ctx.replyNative = (prepay_id, err_code_des) => {
        ctx.type = 'application/xml; charset=utf-8';
        ctx.body = this._getNativeReply(prepay_id, err_code_des);
      };
      try {
        if (typeof ctx.request.body !== 'string') throw new Error('XMLDataError');
        ctx.request.weixin = await this._parse(ctx.request.body, 'middleware_' + type);
      } catch (err) {
        return ctx.reply(err.message);
      }
      await next();
    };
  }
  // 获取沙盒密钥
  getSignkey() {
    let pkg = {
      mch_id: this.mchid,
      nonce_str: util.generate()
    };
    return this._request(pkg, 'getsignkey');
  }
  // 获取RSA公钥
  getPublicKey(params) {
    let pkg = {
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5'
    };
    return this._request(pkg, 'getpublickey', true);
  }
  // 获取JS支付参数(自动下单)
  async getPayParams(params) {
    params.trade_type = params.trade_type || 'JSAPI';
    let order = await this.unifiedOrder(params);
    return this.getPayParamsByPrepay(order, params.sign_type);
  }
  // 获取JS支付参数(通过预支付会话标志)
  getPayParamsByPrepay(params, signType) {
    let pkg = {
      appId: params.sub_appid || this.appid,
      timeStamp: '' + (Date.now() / 1000 | 0),
      nonceStr: util.generate(),
      package: 'prepay_id=' + params.prepay_id,
      signType: signType || 'MD5'
    };
    pkg.paySign = this._getSign(pkg, signType);
    pkg.timestamp = pkg.timeStamp;
    return pkg;
  }
  // 获取APP支付参数(自动下单)
  async getAppParams(params) {
    params.trade_type = params.trade_type || 'APP';
    let order = await this.unifiedOrder(params);
    return this.getAppParamsByPrepay(order, params.sign_type);
  }
  // 获取APP支付参数(通过预支付会话标志)
  getAppParamsByPrepay(params, signType) {
    let pkg = {
      appid: params.sub_appid || this.appid,
      partnerid: params.sub_mch_id || this.mchid,
      prepayid: params.prepay_id,
      package: 'Sign=WXPay',
      noncestr: util.generate(),
      timestamp: '' + (Date.now() / 1000 | 0)
    };
    pkg.sign = this._getSign(pkg, signType);
    return pkg;
  }
  // 扫码支付, 生成URL(模式一)
  getNativeUrl(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      time_stamp: '' + (Date.now() / 1000 | 0),
      nonce_str: util.generate()
    };
    let url = 'weixin://wxpay/bizpayurl'
            + '?sign=' + this._getSign(pkg)
            + '&appid=' + pkg.appid
            + '&mch_id=' + pkg.mch_id
            + '&product_id=' + encodeURIComponent(pkg.product_id)
            + '&time_stamp=' + pkg.time_stamp
            + '&nonce_str=' + pkg.nonce_str;
    return url;
  }
  // 拼装扫码模式一返回值
  _getNativeReply(prepay_id, err_code_des) {
    let pkg = {
      return_code: 'SUCCESS',
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      result_code: 'SUCCESS',
      prepay_id
    };
    if (err_code_des) {
      pkg.result_code = 'FAIL';
      pkg.err_code_des = err_code_des;
    }
    pkg.sign = this._getSign(pkg);
    return util.buildXML(pkg);
  }
  // 刷卡支付
  micropay(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5',
      spbill_create_ip: params.spbill_create_ip || this.spbill_create_ip
    };
    return this._request(pkg, 'micropay');
  }
  // 撤销订单
  reverse(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5'
    };
    return this._request(pkg, 'reverse', true);
  }
  // 统一下单
  unifiedOrder(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5',
      notify_url: params.notify_url || this.notify_url,
      spbill_create_ip: params.spbill_create_ip || this.spbill_create_ip,
      trade_type: params.trade_type || 'JSAPI'
    };
    return this._request(pkg, 'unifiedorder');
  }
  // 订单查询
  orderQuery(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5'
    };
    return this._request(pkg, 'orderquery');
  }
  // 关闭订单
  closeOrder(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5'
    };
    return this._request(pkg, 'closeorder');
  }
  // 申请退款
  refund(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5',
      op_user_id: params.op_user_id || this.mchid,
      notify_url: params.notify_url || this.refund_url
    };
    if (!pkg.notify_url) delete pkg.notify_url;
    return this._request(pkg, 'refund', true);
  }
  // 查询退款
  refundQuery(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5'
    };
    return this._request(pkg, 'refundquery');
  }
  // 合单支付
  combinedOrder(params) {
    let pkg = {
      ...params,
      combine_appid: this.appid,
      combine_mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: 'HMAC-SHA256',
      notify_url: params.notify_url || this.notify_url,
      spbill_create_ip: params.spbill_create_ip || this.spbill_create_ip,
      trade_type: params.trade_type || 'JSAPI'
    };
    return this._request(pkg, 'combinedorder');
  }
  // 下载对帐单
  async downloadBill(params, format = false) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'MD5',
      bill_type: params.bill_type || 'ALL'
    };
    let xml = await this._request(pkg, 'downloadbill');
    return this._parseBill(xml, format);
  }
  // 下载资金帐单
  async downloadFundflow(params, format = false) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      sign_type: params.sign_type || 'HMAC-SHA256',
      account_type: params.account_type || 'Basic'
    };
    let xml = await this._request(pkg, 'downloadfundflow', true);
    return this._parseBill(xml, format);
  }
  // 发放代金券
  sendCoupon(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      openid_count: params.openid_count || 1
    };
    return this._request(pkg, 'send_coupon', true);
  }
  // 查询代金券批次
  queryCouponStock(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate()
    };
    return this._request(pkg, 'query_coupon_stock');
  }
  // 查询代金券信息
  queryCouponInfo(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate()
    };
    return this._request(pkg, 'querycouponsinfo');
  }
  // 企业付款
  transfers(params) {
    let pkg = {
      ...params,
      mch_appid: this.appid,
      mchid: this.mchid,
      nonce_str: util.generate(),
      check_name: params.check_name || 'FORCE_CHECK',
      spbill_create_ip: params.spbill_create_ip || this.spbill_create_ip
    };
    return this._request(pkg, 'transfers', true);
  }
  // 查询企业付款
  transfersQuery(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate()
    };
    return this._request(pkg, 'gettransferinfo', true);
  }
  // 企业付款到银行卡
  async payBank(params) {
    const data = await this.getPublicKey(params);
    const pub_key = data && data.result_code === 'SUCCESS' ? data.pub_key : '';
    if (pub_key === '') throw new Error('get publickey fail');
    let pkg = {
      ...params,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      enc_bank_no: util.encryptRSA(pub_key, params.enc_bank_no),
      enc_true_name: util.encryptRSA(pub_key, params.enc_true_name)
    };
    return this._request(pkg, 'paybank', true);
  }
  // 查询企业付款到银行卡
  queryBank(params) {
    let pkg = {
      ...params,
      mch_id: this.mchid,
      nonce_str: util.generate()
    };
    return this._request(pkg, 'querybank', true);
  }
  // 发送普通红包
  sendRedpack(params) {
    let pkg = {
      ...params,
      wxappid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      client_ip: params.client_ip || this.spbill_create_ip,
      mch_billno: params.mch_billno || (params.mch_autono ? this.mchid + util.getFullDate() + params.mch_autono : ''),
      total_num: params.total_num || 1
    };
    delete pkg.mch_autono;
    return this._request(pkg, 'sendredpack', true);
  }
  // 发送裂变红包
  sendGroupRedpack(params) {
    let pkg = {
      ...params,
      wxappid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      mch_billno: params.mch_billno || (params.mch_autono ? this.mchid + util.getFullDate() + params.mch_autono : ''),
      total_num: params.total_num || 3,
      amt_type: params.amt_type || 'ALL_RAND'
    };
    delete pkg.mch_autono;
    return this._request(pkg, 'sendgroupredpack', true);
  }
  // 查询红包记录
  redpackQuery(params) {
    let pkg = {
      ...params,
      appid: this.appid,
      mch_id: this.mchid,
      nonce_str: util.generate(),
      bill_type: params.bill_type || 'MCHT'
    };
    return this._request(pkg, 'gethbinfo', true);
  }
   /**
   * 请求单次分账 params
   * @param { Object } receiver - 添加分账接收方
   * @param { String(32) } receivers.type - 分账接收方类型 MERCHANT_ID:商户号(mch_id或者sub_mch_id) PERSONAL_OPENID:个人openid
   * @param { String(64) } receivers.account - 分账接收方账号  类型是MERCHANT_ID时,是商户号(mch_id或者sub_mch_id)类型是PERSONAL_OPENID时,是个人openid
   * @param { Number } receivers.amount - 分账金额 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
   * @param { String(80) } receivers.name - 分账接收方全称 分账接收方类型是MERCHANT_ID时,是商户全称(必传),当商户是小微商户或个体户时,是开户人姓名 分账接收方类型是PERSONAL_OPENID时,是个人姓名(选传,传则校验)
   * @param { String(80) } receivers.relation_type - 与分账方的关系类型 子商户与接收方的关系。 本字段值为枚举: SERVICE_PROVIDER:服务商 STORE:门店  STAFF:员工 STORE_OWNER:店主 PARTNER:合作伙伴 HEADQUARTER:总部 BRAND:品牌方 DISTRIBUTOR:分销商 USER:用户 SUPPLIER:供应商 CUSTOM:自定义
   * @returns { Object }
   * 
   */
  profitsharingaddreceiver(params){
    let pkg = {
      ...params,
      appid: this.appid, // 公众账号ID
      mch_id: this.mchid, // 商户号
      nonce_str: util.generate(), // 随机字符串
      sign_type: 'HMAC-SHA256', // 签名类型
    };
    return this._request(pkg, 'profitsharingaddreceiver', false);
  }
  // 请求单次分账
  /** @name 请求单次分账 params
   * transaction_id string(32) 微信支付订单号
   * out_order_no   string(64) 商户分账单号
  */
   /**
   * 请求单次分账 params
   * @param { String(32) } transaction_id - 微信支付订单号
   * @param { String(64) } out_order_no - 商户分账单号
   * @param { Object } receivers - 分账接收方列表
   * @param { String(32) } receivers.type - 分账接收方类型 MERCHANT_ID:商户号(mch_id或者sub_mch_id)PERSONAL_OPENID:个人openid
   * @param { String(64) } receivers.account - 分账接收方账号  类型是MERCHANT_ID时,是商户号(mch_id或者sub_mch_id)类型是PERSONAL_OPENID时,是个人openid
   * @param { Number } receivers.amount - 分账金额 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
   * @param { String(80) } receivers.description - 分账描述 分账的原因描述,分账账单中需要体现
   * @param { String(80) } receivers.name - 分账个人接收方姓名 可选项,在接收方类型为个人的时可选填,若有值,会检查与 name 是否实名匹配,不匹配会拒绝分账请求 1、分账接收方类型是PERSONAL_OPENID时,是个人姓名(选传,传则校验)
   * @returns { Object }
   */
  profitsharing(params){
    let pkg = {
      ...params,
      appid: this.appid, // 公众账号ID
      mch_id: this.mchid, // 商户号
      nonce_str: util.generate(), // 随机字符串
      sign_type: 'HMAC-SHA256', // 签名类型
    };
    return this._request(pkg, 'profitsharing', true);
  }
}
module.exports = Payment;