Wechat mini program wechat Pay

The official flow chart is as follows:

Wechat mini program wechat Pay official flow chart link

The process I simplified:

  1. The cloud function is invoked and the data is transferred locally
  2. The cloud function processes the data and returns five parameters
  3. The local accepts five parameters to initiate a payment request
  4. End of the deal

Main code:

// The first step is to initiate an order request locally and transmit the data. This step, some element in your WXML
 With this pay function,
// Trigger the cloud function and pass some data
pay: function(){
	// Data that needs to be uploaded to the cloud function
	let uploadData = {
		// The amount to be paid this time, in minutes. Such as selections of 1.80 = 180
		"total_fee": "180".// IP address of the client
		"spbill_create_ip": "123.123.123.123"
	}
	// Call the cloud function
	wx.cloud.callFunction({
		// The name of the cloud function, which I define as Payment
		name: "payment".// Data to be uploaded
		data: uploadData
	}).then(res= > {
		// The res is the five parameters returned by the cloud function
		// Initiate payment with wx.requestPayment
		wx.requestPayment({
			timeStamp: res.result.data.timeStamp,
			nonceStr: res.result.data.nonceStr,
			package: res.result.data.package,
			signType: res.result.data.signType,
			paySign: res.result.data.paySign,
			success: res= > {
				// The payment was successful
			},
			fail: err= > {
				// Payment failed}})}Copy the code

That’s all the code on the local side, then we just need to get the cloud function code done.

The content of the cloud function is:

  1. Call applets login API -> Openid
  2. Generate merchant order
  3. Call uniform order API -> prepay_id
  4. The combined data is signed again, returning 5 parameters

The cloud function I created is called Payment, and the structure of the cloud function should be

payment
|__index.js
|__package.json
Copy the code

## Detailed practices for each step

1. Call applets to log in API -> Openid

The purpose of this step is to get the user’s Openid

Add the following code to the index.js of the cloud function

// Get the cloud instance
const cloud = require('wx-server-sdk')
// Cloud initialization
cloud.init()
// Get wechat call context information, including Openid, Appid, etc
const wxContext = cloud.getWXContext()
// Get user openID
const openid = wxContext.OPENID
Copy the code

Here we have achieved our first goal.

2. Generate merchant orders

Wechat Pay development document – unified order

The purpose of this step is to generate an order that calls the Payment unified order API. According to official documents, we need the following data:

  1. Appid (applets ID)

  2. Openid (User OpenID)

  3. McH_id (Merchant number)

  4. Nonce_str (random string)

  5. Product Description

  6. Out_trade_no (Merchant order Number)

  7. Total_fee

  8. Spbill_create_ip (terminal IP address)

  9. Notify_url (notification address)

  10. Trade_type (type of trade)

  11. Key (key)

  12. Sign your name

We’ll take it one at a time.

1. appid

After the administrator enters the public platform and logs in with the mini program account, click “Settings” in the menu on the left and check the AppID of the mini program under “Development Settings”.

The sample value wxd678efh567hg6787

Add the following code to the index.js of the cloud function:

const appid='wxwxd678efh567hg6787'
Copy the code

2. openid

The first step has been achieved.

The sample value oUpF8uMuAJO_M2pxb1Q9zNjWeS6o

3. mch_id

Login wechat payment merchant platform pay.weixin.qq.com, click the upper “Account Center”, in the “personal information” “login account” is McH_id.

Example is worth 1230000109

Add the following code to the index.js of the cloud function:

const mch_id='1230000109'
Copy the code

4. nonce_str

The value is a random number with a maximum of 32 bits. You can write your own function.

5 k8264iltkch16cq2502si8znmtm67vs sample values

I create a new JS file (random.js) in the cloud function to hold the function, and the structure of the cloud function is as follows

payment
|__index.js
|__package.json
|__random.js
Copy the code

Where the content of random.js is:

function random(){
  var result = ' '
  const wordList = ['a'.'b'.'c'.'d'.'e'.'f'.'g'.'h'.'i'.'j'.'k'.'l'.'m'.'n'.'o'.'p'.'q'.'r'.'s'.'t'.'u'.'v'.'w'.'x'.'y'.'z'.'1'.'2'.'3'.'4'.'5'.'6'.'7'.'8'.'9'.'0']
  for(let i=0; i<31; i++){ result += wordList[Math.round(Math.random()*36)]}return result
}

module.exports = random()

Copy the code

Then add the following code to the cloud function index.js:

const random = require("random.js")
Copy the code

5. body

Format: Vendor name – Vendor category

Example value Tencent – games

Add the following code to the cloud function index.js:

const body = "Tencent - Games"
Copy the code

6. out_trade_no

Merchants system internal order number to 32 characters, only Numbers, upper and lower case letters _ – | * and only under the same merchant number. It is recommended to use the current time + product number.

Example is worth 20150806125346

Add the following code to the exports.main function in the cloud function index.js:

// I'm only using the present time here. As long as the number is not repeated.
const out_trade_no = Date.parse(new Date()).toString()
Copy the code

7. total_fee

The total amount of the order, in minutes. For example, if the current payment is ¥6.80, the total_fee is 680.

Example is worth 88

We're going to use the value that we uploaded, so let's just ignore it

8. spbill_create_ip

The IP address can be IPV4 or IPV6. The IP of the machine that invokes the wechat Pay API.

The sample value 123.12.12.123

We're going to use the value that we uploaded, so let's just ignore it

9. notify_url

Callback address for receiving the notification of wechat payment result asynchronously. The notification URL must be accessible to the external network and cannot carry parameters. You can fill in the URL of your own server here.

The sample value http://www.weixin.qq.com/wxpay/pay.php

Add the following code to the cloud function index.js:

// Just fill in the server. I have no problems with it
const notify_url = 'http://www.weixin.qq.com/wxpay/pay.php'
Copy the code

10. trade_type

Trade_type of applets is JSAPI.

The sample value JSAPI

Add the following code to the cloud function index.js:

const trade_type = 'JSAPI'
Copy the code

11. key

Key Key for merchant platform. It is set by you. Key setting path: wechat merchant platform (pay.weixin.qq.com)–> Account setting –>API security –> key setting.

1 a79a4d60de6718e8e5b326e338ae533 sample values

Add the following code to the cloud function index.js:

const key = '1a79a4d60de6718e8e5b326e338ae533'
Copy the code

12. sign

All the above information except the key is concatenated into a string according to the ASCII characters of the parameter name from large to small, split with &, and put the key at the end.

Example string values:

Appid = wxd678efh567hg6787 & body = WeChat - game & MCH_ id = 1230000109 & nonce_str k8264iltkch16cq2502si8znmtm6 = 5 7VS&notify_url=http://www.weixin.qq.com/wxpay/pay.php& openid=oUpF8uMuAJO_M2pxb1Q9zNjWeS6o&out_trade_no=2015080 6125346 & spbill_create_ip = 123.12.12.123 & total_fee = 88 & trad e_type a79a4d60de6718e8e5b326e338ae533 = JSAPI&key = 1Copy the code

The UPPERcase MD5 code for this string is sign. Since the above total_fee and spbill_create_IP have not been processed, this data will be processed below.

MD5 code C380BEC2BFD727A4B6845133519F3AD6 sample values

At this point your cloud function structure should look like:

payment
|__index.js
|__package.json
|__random.js
Copy the code

The contents of index.js should be:

// Cloud function entry file
const cloud = require('wx-server-sdk')
cloud.init()
const openid = cloud.getWXContext().OPENID
const appid = 'wxwxd678efh567hg6787'
const mch_id = '1230000109'
const random = require('random.js')
const body = "Tencent - Games"
const notify_url = 'http://www.weixin.qq.com/wxpay/pay.php'
const trade_type = 'JSAPI'
const key = '1a79a4d60de6718e8e5b326e338ae533'

// Cloud function entry function
exports.main = async (event, content) => {
	const out_trade_no = Date.parse(new Date()).toString()
}
Copy the code

Next we deal with total_fee and spbill_create_IP, which were not dealt with above, and sign. Where total_fee and spbill_create_IP are uploaded by the client, these two data are in the parameter event of the entry function of the cloud function, so we add the following code to the entry function of the cloud function

const total_fee = event.total_fee
const spbill_create_ip = event.spbill_create_ip
Copy the code

Finally, we need to deal with sign and add the following code to the cloud function entry function as mentioned in 12.sign

let stringA = `appid=${appid}&body=${body}&
mch_id=${mch_id}&nonce_str=${random}&
notify_url=${notify_url}&openid=${openid}&
out_trade_no=${out_trade_no}&
spbill_create_ip=${spbill_create_ip}&
total_fee=${total_fee}&trade_type=${trade_type}&
key=1a79a4d60de6718e8e5b326e338ae533`
Copy the code

We now need to encrypt this string with MD5, so we need to install an NPM package to do this. Right click on the cloud function Pyament, select “Open on Terminal” and enter the following command:

npm install --save crypto
Copy the code

Add the following code to the cloud data entry file

const crypto = require("crypto")
Copy the code

So we’ve successfully introduced crypto into our cloud functions. Then we need to use it in the cloud function entry function to MD5 encrypt the stringA we just did. So let stringA =… Add the following code to this line

var sign = crypto.createHash('md5').update(stringA).digest('hex').toUpperCase()
Copy the code

The above 11 information except key is all the data we need to call the unified order API

We now need to convert this data into XML format, for example:

<xml>
<appid>wxd930ea5d5a258f4f</appid>
<mch_id>10000100</mch_id>
<device_info>1000</device_info>
<body>test</body>
<nonce_str>ibuaiVcKdpRxkhJA</nonce_str>
<sign>9A0A8659F005D6984697E2CA0A9CF3B7</sign>.</xml>
Copy the code

Create a new requestData.js function in the cloud and write the following function to convert the data to XML

function requestData(appid, mch_id, nonce_str, sign, body, out_trade_no, total_fee, spbill_create_ip, notify_url, trade_type, openid){
  let data = "<xml>"
  data += "<appid>"+appid+"</appid>"
  data += "<mch_id>"+mch_id+"</mch_id>"
  data += "<nonce_str>"+nonce_str+"</nonce_str>"
  data += "<sign>"+sign+"</sign>"
  data += "<body>"+body+"</body>"
  data += "<out_trade_no>"+out_trade_no+"</out_trade_no>"
  data += "<total_fee>"+total_fee+"</total_fee>"
  data += "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"
  data += "<notify_url>"+notify_url+"</notify_url>"
  data += "<trade_type>"+trade_type+"</trade_type>"
  data += "<openid>"+openid+"</openid>"
  data += "</xml>"
  return data
}

module.exports = requestData
Copy the code

At this point, the structure of the cloud function is

Payment | index. Js | __package. Json | __package - lock. Json / / by NPM install the file | __random. Js | __requestData. JsCopy the code

We need to import the requestData.js file into our project. Add the following code to the cloud function entry file

const requestData = require("requestData.js")
Copy the code

Now we can generate an order that calls the Payment unified order API, and the dataBody is the order.

let dataBody = reqData(
    appid,
    mch_id,
    random,
    sign,
    body,
    out_trade_no,
    total_fee,
    spbill_create_ip,
    notify_url,
    trade_type,
    openid
  )
Copy the code

At this point we’ve achieved our goal for part two.

3. Call unified order API -> prepay_id

The official documentation

We need to provide links to the official https://api.mch.weixin.qq.com/pay/unifiedorder launched a unified order, so we need a NPM package here to help us to finish the request requests, and due to a request after the return value is the XML format, So we also need an NPM package to help us parse XML format files. So right click on the cloud payment function, select “Open on Terminal” and type the following command:

npm install --save request
npm install --save xmlreader
Copy the code

Introduce the above two packages in the cloud function entry file:

const request = require("request")
const xmlreader = require("xmlreader")
Copy the code

We can then make a request to the unified single API in the cloud function entry function. Since the request is an asynchronous request, we need to return a Promise.

return new Promise(reslove= > {
	request({
		// The url of the official unified order API
		url: 'https://api.mch.weixin.qq.com/pay/unifiedorder'.// Request method, post
		method: "POST".// The order that needs to be sent is the dataBody we just generated
		body: dataBody
	}, body => {
		// Body is the data we received, and we need to get the prepay_id
		// Parse the body with xmlReader to get the prepay_id
		xmlreader.read(body, res => {
			// At this point we have completed the purpose of step 3
			let prepay_id = res.xml.prepay_id.text()
		}
	}
}
Copy the code

Step 3 Goal completion

4. Sign the combined data again and return five parameters

Wx.requestpayment () requires five parameters

  1. timeStamp
  2. nonceStr
  3. package
  4. signType
  5. paySign

TimeStamp is the timeStamp and can be obtained by date.parse (new Date()).tostring (). NonceStr is a random string that can be retrieved by our random function. Package is the prepay_id obtained in the previous step, signType is the signature type, and MD5 is selected. So now we are left with paySign unknown, and the method to get paySign is

paySign = MD5(appId=wxd678efh567hg6787&nonceStr=5K826
4ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=wx20170
33010242291fcfe0db70013231072&signType=MD5&timeStamp=
1490840662&key=qazwsxedcrfvtgbyhnujmikolp111111) = 22D
9B4E54AB1950F51E0649E8810ACD6
Copy the code

So let’s pick up where we left off

return new Promise(reslove= > {
	request({
		url: 'https://api.mch.weixin.qq.com/pay/unifiedorder'.method: "POST".body: dataBody
	}, body => {
		xmlreader.read(body, res => {
			let prepay_id = res.xml.prepay_id.text()
			let timeStamp = Date.parse(new Date()).toString()
			let str = `appId=${appid}&nonceStr=${random}&package=prepay_id=${prepay_id}&signType=MD5&timeStamp=${timeStamp}&key=1a79a4d60de6718e8e5b326e338ae533`
			let paySign = crypto.createHash('md5').update(str).digest('hex')
			// Return the five arguments above
			reslove({
				data: {
					timeStamp: timeStamp,
            		nonceStr: random,
            		package: `prepay_id=${prepay_id}`.signType: 'MD5'.paySign: paySign
            	}
            })
		}
	}
}
Copy the code

At this point, the wechat mini program payment process ends.

At this point, the cloud function structure is:

payment
|__index.js
|__package.json
|__package-lock.json
|__random.js
|__requestData.js
Copy the code

index.js:

// Cloud function entry file
const cloud = require('wx-server-sdk')
cloud.init()
const openid = cloud.getWXContext().OPENID
const appid = 'wxwxd678efh567hg6787'
const mch_id = '1230000109'
const random = require('random.js')
const body = "Tencent - Games"
const notify_url = 'http://www.weixin.qq.com/wxpay/pay.php'
const trade_type = 'JSAPI'
const key = '1a79a4d60de6718e8e5b326e338ae533'
const crypto = require("crypto")
const requestData = require("requestData")
const request = require("request")
const xmlreader = require("xmlreader")

// Cloud function entry function
exports.main = async (event, content) => {
    const out_trade_no = Date.parse(new Date()).toString()
    const total_fee = event.total_fee
    const spbill_create_ip = event.spbill_create_ip
    let stringA = `appid=${appid}&body=${body}&mch_id=${mch_id}&nonce_str=${random}&notify_url=${notify_url}&openid=${openid}&out_trade_no=${out_trade_no}&spbill_create_ip=${spbill_create_ip}&total_fee=${total_fee}&trade_type=${trade_type}&key=1a79a4d60de6718e8e5b326e338ae533`
    var sign = crypto.createHash('md5').update(stringA).digest('hex').toUpperCase()
    let dataBody = reqData(
	    appid,
	    mch_id,
	    random,
	    sign,
	    body,
	    out_trade_no,
	    total_fee,
	    spbill_create_ip,
	    notify_url,
	    trade_type,
	    openid
	  )
	return new Promise(reslove= > {
	    request({
	        url: 'https://api.mch.weixin.qq.com/pay/unifiedorder'.method: "POST".body: dataBody
	    }, body => {
	        xmlreader.read(body, res => {
	            let prepay_id = res.xml.prepay_id.text()
	            let timeStamp = Date.parse(new Date()).toString()
	            let str = `appId=${appid}&nonceStr=${random}&package=prepay_id=${prepay_id}&signType=MD5&timeStamp=${timeStamp}&key=1a79a4d60de6718e8e5b326e338ae533`
	            let paySign = crypto.createHash('md5').update(str).digest('hex')
	            // Return the five arguments above
	            reslove({
	                data: {
	                    timeStamp: timeStamp,
	                    nonceStr: random,
	                    package: `prepay_id=${prepay_id}`.signType: 'MD5'.paySign: paySign
	                }
	            })
	        }
	    }
}
Copy the code

random.js:

function random(){
  var result = ' '
  const wordList = ['a'.'b'.'c'.'d'.'e'.'f'.'g'.'h'.'i'.'j'.'k'.'l'.'m'.'n'.'o'.'p'.'q'.'r'.'s'.'t'.'u'.'v'.'w'.'x'.'y'.'z'.'1'.'2'.'3'.'4'.'5'.'6'.'7'.'8'.'9'.'0']
  for(let i=0; i<31; i++){ result += wordList[Math.round(Math.random()*36)]}return result
}

module.exports = random()
Copy the code

requestData.js:

function requestData(appid, mch_id, nonce_str, sign, body, out_trade_no, total_fee, spbill_create_ip, notify_url, trade_type, openid){
  let data = "<xml>"
  data += "<appid>"+appid+"</appid>"
  data += "<mch_id>"+mch_id+"</mch_id>"
  data += "<nonce_str>"+nonce_str+"</nonce_str>"
  data += "<sign>"+sign+"</sign>"
  data += "<body>"+body+"</body>"
  data += "<out_trade_no>"+out_trade_no+"</out_trade_no>"
  data += "<total_fee>"+total_fee+"</total_fee>"
  data += "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"
  data += "<notify_url>"+notify_url+"</notify_url>"
  data += "<trade_type>"+trade_type+"</trade_type>"
  data += "<openid>"+openid+"</openid>"
  data += "</xml>"
  return data
}

module.exports = requestData
Copy the code