The business scenario of the company needs to use the function of wechat account distribution. After debugging the official website documents for a whole afternoon, the process of using Nodejs wechat account distribution is recorded.

The premise condition

  • Open the function of account splitting in my product and payment extension tool in the product Center of wechat merchant platform
  • Add the ledger receiver. If this step is not set, return a * sub-ledger receiver relationship does not exist. Please check the relationship of each receiver in the parameter. * error
  • Get the merchant ID and Secrect from the merchant platform
  • You need to upload apiclient_cert.pem and apiclient_key to a directory on the server

The specific implementation


// @router post -> share -> /common/payment/share
async share() {
  const { ctx } = this
  const nonce_str = ctx.service.wx.randomStr()
  / / merchant id
  const mch_id = '123456'
  // x applet appid
  const appid = 'wx123456'
  / / order number
  const out_order_no = '1609745196755nFvdMaYub2'
  // wechat Pay order number
  const transaction_id = '4200000801202101044301662433'
  / / merchants secrect
  const key = '9813490da1ffb80afaa36f6f1265e490'

  // The parameters of this section are explained in detail on the official website documentation
  const params = {
    appid,
    mch_id,
    nonce_str,
    out_order_no,
    receivers: `[{"account": "123qwe","amount": 1,"description": "description","type": "PERSONAL_OPENID"}]`.sign_type: 'HMAC-SHA256',
    transaction_id,
  }

  // The signature must be hMAC-sha256
  const sign = ctx.service.wx.sign(params, key, 'HMAC-SHA256')

  // xmlString
  const formData = `<xml>
    <appid>${appid}</appid>
    <mch_id>${mch_id}</mch_id>
    <nonce_str>${nonce_str}</nonce_str> 
    <out_order_no>${out_order_no}</out_order_no>
    <transaction_id>${transaction_id}</transaction_id>
    <sign>${sign}</sign>
    <sign_type>HMAC-SHA256</sign_type>
    <receivers>${params.receivers}</receivers>
  </xml>`

  const res = await ctx.curl(
    "https://api.mch.weixin.qq.com/secapi/pay/profitsharing",
    {
      // Apiclient_cert is required
      cert: fs.readFileSync(path.join(__dirname,'.. /.. /.. /cert/apiclient_cert.pem')),
      // The apiclient_key certificate is required
      key: fs.readFileSync(path.join(__dirname,'.. /.. /.. /cert/apiclient_key.pem')),
      method: "post".data: formData,
    }
  )

  const datastring = res.data.toString()
  xml2js.parseString(datastring, (err, result) = > {
    if (err) {
      ctx.throw(422, err)
    }

    console.log(result)
  })
}


// randomStr
// Generate random strings
randomStr(len = 24) {
  const str =
    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  let result = ' ';
  for (let i = 0; i < len; i++) {
    result += str[Math.floor(Math.random() * str.length)];
  }
  return result;
}

/ / signature
// McHKey is the merchant secrect, otherwise the signature will not pass
sign(data, mchKey, signType = 'MD5') {
  const keys = [];
  for (const key in data) {
    if(data[key] ! = =undefined) { keys.push(key); }}// Dictionary sort =>key=value
  const stringA = keys
    .sort()
    .map(key= > `${key}=The ${decodeURIComponent(data[key])}`)
    .join('&');
  // Splice the merchant key
  const stringSignTemp = stringA + '&key=' + mchKey;
  / / encryption
  let hash;
  if (signType === 'MD5') {
    hash = crypto.createHash('md5').update(stringSignTemp);
  } else {
    hash = crypto.createHmac('sha256', mchKey).update(stringSignTemp, 'utf8');
  }
  
  const paySign = hash.digest('hex').toUpperCase();
  return paySign;
}
Copy the code

If you encounter a signature failure. You can step your formData into the interface signature verification tool for verification.

Other common problems of the ledger interface