雲開發支付流程閉環
extends
在上述文章中,我們對支付結果的處理更多依賴於小程序端的操作
- 訂單號存儲在小程序端
- 支付結果採用小程序端定時觸發器輪詢
現在我對該流程進行了優化處理
1.流程介紹
2.小程序端
- 請求統一下單雲函數
- 調用支付接口
- 偵聽器獲取支付結果
// pages/index/details.js
const app = getApp();
const db = wx.cloud.database();
var watcher = null
Page({
/**
* 頁面的初始數據
*/
data: {
},
//付費解鎖
payUnlock() {
var that = this;
this.setData({
vis: true
})
//用戶ID 即爲OPENID
let userid = this.data.selfcard._id;
wx.cloud.callFunction({
name: 'userpay',
data: {
fee: 1,
paydata: {
userid
}
},
success: res => {
console.log(res)
//統一下單雲函數中需要返回偵聽器 需要的記錄id
that.payWatcher(res.result.docid);
that.setData({
vis: false
})
//根據統一下單參數 請求支付接口
const payment = res.result.payment
wx.requestPayment({
...payment,
success(ans) {
console.log(ans)
},
fail(ans) {
that.setData({
errMsg: '調用支付失敗'
})
}
})
}
})
},
payWatcher(docid){
var that = this;
//爲用戶支付記錄表設置偵聽器,偵聽docid信息的變動
this.watcher = db.collection('USERPAYLOG').doc(docid).watch({
onChange: async function (snapshot) {
//只打印變動的信息
// console.log(snapshot)
if (snapshot.docChanges.length != 0) {
console.log(snapshot.docChanges)
let paydoc = snapshot.docChanges[0].doc;
//偵聽到支付成功
if(paydoc.paystatus == 1){
that.setData({
succMsg:'支付成功',
locked:false,
bottom:0
})
}
// await that.watcher.close();
}
},
onError: function (err) {
console.error('the watch closed because of error', err)
}
})
},
/**
* 生命週期函數--監聽頁面加載
*/
onLoad: function (options) {
},
/**
* 生命週期函數--監聽頁面卸載
*/
onUnload: function () {
try {
this.watcher.close();
} catch (error) {
console.log('暫未啓動支付偵聽器')
}
}
})
3.雲函數端
userpay
- 雲調用統一下單【CloudPay.unifiedOrder】
- 數據庫中存入訂單記錄並設置爲未支付狀態
需要配置商戶(雲開發控制檯)
const cloud = require('wx-server-sdk')
//需要在此處修改你的雲環境ID
cloud.init({
env: ''
})
const db = cloud.database();
const _ = db.command;
// 雲函數入口函數
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
var openid = event.openid || wxContext.OPENID
//獲取統一下單金額
var fee = parseInt(event.fee);
let paydata = event.paydata;
//生成訂單號
let tradeno = GetTradeNo();
//調用統一下單接口
const res = await cloud.cloudPay.unifiedOrder({
//填寫你的商戶主體信息 例如 xx商貿
"body": "",
"outTradeNo": tradeno,
"spbillCreateIp": "127.0.0.1",
//填寫你的商戶ID -- 可在雲開發控制檯中綁定獲得(上圖所示)
"subMchId": "",
"totalFee": fee,
//填寫你的雲環境ID
"envId": "",
//填寫你的回調函數名稱
"functionName": "userpaynotify"
})
console.log(res)
res.outTradeNo = tradeno
res.totalFee = fee
//支付狀態 0 爲未支付
paydata.tradeno = tradeno
paydata.paystatus = 0
paydata.totalfee = fee
paydata.openid = openid
paydata.paytime = TimeCode()
//統一下單shuju
paydata.uniOrder = res
//攔截處理 爲保持數據庫字段一致性
if (res.returnCode == 'SUCCESS' && res.resultCode == 'SUCCESS') {
//在雲數據庫中寫入未支付的訂單信息
let tdata = await db.collection('USERPAYLOG').add({
data: paydata
})
console.log(tdata)
//將該記錄ID攜帶返回給小程序端
res.docid = tdata._id;
return res;
}else{
return res;
}
}
function GetTradeNo() {
var outTradeNo = ""; //訂單號
for (var i = 0; i < 6; i++) //6位隨機數,用以加在時間戳後面。
{
outTradeNo += Math.floor(Math.random() * 10);
}
outTradeNo = "COP" + new Date().getTime() + outTradeNo; //時間戳,用來生成訂單號。
return outTradeNo;
}
function TimeCode() {
var date = new Date();
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hour = date.getHours()
var minute = date.getMinutes()
var second = date.getSeconds()
return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
function formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
支付成功後觸發雲環境中該回調函數
回調函數攜帶的請求信息請在參考文檔中查看
userpaynotify
修改數據庫中訂單狀態
返回給回調請求SUCCESS數據【Cloud.paymentCallback】
訂單在支付成功時會觸發該回調函數
該回調函數必須有返回值,且必須是固定格式
根據回調函數攜帶的訂單號,修改對應訂單號的訂單狀態,並且返回對應格式的返回信息
字段名 變量名 必填 類型 描述 錯誤碼 errcode 是 Number 0 錯誤信息 errmsg 是 String
const cloud = require('wx-server-sdk')
//填寫你的雲環境ID
cloud.init({
env: ''
})
const db = cloud.database();
const _ = db.command;
// 雲函數入口函數
exports.main = async (event, context) => {
console.log('支付成功回調函數觸發')
console.log(event)
let tradeno = event.outTradeNo;
try {
//修改數據庫中訂單狀態 爲已支付
db.collection('USERPAYLOG').where({
tradeno:tradeno
}).update({
data:{
paystatus:1
}
})
} catch (error) {
return {
errmsg: 'SERVER_ERROR',
errcode: -1
}
}
return {
errmsg: 'SUCCESS',
errcode: 0
}
}
參考文檔
回調函數請求攜帶參數
{ appid: '', bankType: 'OTHERS', cashFee: 1, feeType: 'CNY', isSubscribe: 'N', mchId: '', nonceStr: '', openid: '', outTradeNo: '', resultCode: 'SUCCESS', returnCode: 'SUCCESS', subAppid: '', subIsSubscribe: 'N', subMchId: '', subOpenid: '', timeEnd: '', totalFee: 1, tradeType: 'JSAPI', transactionId: '', userInfo: { appId: '', openId: '' } }