先看一下微信支付的示意图,这是在微信开发者工具中的显示,真机中是调起微信付款界面(由于无法截屏,没有放上去)
1、小程序微信支付开发文档
CloudPay.unifiedOrder() | 微信开放文档
其中上述参数“functionName”是为了实现---用户付款后,即使不点击完成按钮,钱也会到账成功,并且返回已支付的状态给用户。如果不设定该参数会导致用户付钱后直接退出小程序,之后再进入小程序后,会显示未付款的情况。
这个参数是申请微信支付成功之后,微信平台给的商户号,必填项。
2、开始配置微信支付功能
创建订单数据库order_data: 自定义安全规则
{
"read": "doc._openid == auth.openid || auth.openid == 'oCK3J68Vb0qqGJel5RldEJp5z00c'",
"write": "doc._openid == auth.openid || auth.openid == 'oCK3J68Vb0qqGJel5RldEJp5z00c'"
}
此数据库权限是:用户只能读取其自己的订单数据,商户则可以读取所有用户的订单数据。
1. 资源提供方(shop-user)创建云函数
首先在manifest.json
文件中插入代码:"cloudfunctionRoot":"cloudfunctions/"
,然后再在微信开发者工具中创建cloudfunctions
文件夹存放云函数wx-pay
(创建nodejs云函数)
2. 安装依赖
选中package.json文件,并在终端中打开,并输入:
npm install
3. 配置微信支付功能
然后在index.js
中写入如下代码:
该代码是统一下单的云函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: 'shop-user-0girpywsc1855fd0' }) // 使用当前云环境
// 云函数入口函数
exports.main = async (event, context) => {
const res = await cloud.cloudPay.unifiedOrder({
"body" : "商户名称", // 商品描述
"outTradeNo" : 0, // 商户订单号
"spbillCreateIp" : "127.0.0.1", // 终端 IP
"subMchId" : "1669895289", // 商户号
"totalFee" : 100, // 总金额,单位为分
"envId": "shop-user-0girpywsc1855fd0", // 云函数环境名称
"functionName": "pay_cb", // 支付结果通知回调云函数名
"tradeType":'JSAPI' //小程序交易类型
})
return res
}
新建public.js
来处理商户订单号的随机数
const crypto = require('crypto')
// 随机字符串
let randomstr = function(){
const buf = crypto.randomBytes(16)
return buf.toString('hex')
}
module.exports = {randomstr}
-------------------------------------------------------------------------------------------------
之后就可以在index.js文件中调用该函数
// 云函数入口文件
const cloud = require('wx-server-sdk')
const {randomstr} = require('./config/public')
cloud.init({ env: 'shop-user-0girpywsc1855fd0' }) // 使用当前云环境
// 云函数入口函数
exports.main = async (event, context) => {
const res = await cloud.cloudPay.unifiedOrder({
"body" : "商户名称", // 商品描述
"nonceStr":randomstr(), //随机字符串
"outTradeNo" : event.outTradeno, // 商户订单号 -> 小程序端传来
"spbillCreateIp" : "127.0.0.1", // 终端 IP
"subMchId" : "1669895289", // 商户号
"totalFee" : event.price*100, // 要支付的总金额,单位为分->小程序端传来 "注意:小程序端返回的价格是元,故要乘以100"
"envId": "shop-user-0girpywsc1855fd0", // 云函数环境名称
"functionName": "pay_cb", // 支付结果通知回调云函数名,接收异步通知的云函数
"tradeType":'JSAPI' //小程序交易类型
})
console.log(res)
return res.payment
}
调试云函数,结果展示:
如果出现问题,记得授权商户号
4. 完善微信支付功能---完成“支付结果通知回调云函数”
创建并上传pay_cb
云函数
index.js
文件代码:
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: 'shop-user-0girpywsc1855fd0' }) // 使用当前云环境
// 云函数入口函数
exports.main = async (event, context) => {
// const wxContext = cloud.getWXContext()
console.log(event)
}
支付 / wx.requestPayment (qq.com)
5. 前端调用云函数并上传数据至数据库
5.1 编写商户订单号和订单编号
由于微信支付是公共功能,故创建新的文件wx-pay.js
写入ACC-config
文件夹中
WX-PAY.JS文件
// 商户订单号
let outTradeNo = function(){
let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
let maxPos = chars.length
let res = ''
for(let i=0;i<32;i++){
res+=chars.charAt(Math.floor(Math.random()*maxPos))
}
return res
}
// 订单编号
let order_code = function(){
let code = ''
for(let i=0; i<6; i++){
code+=Math.floor(Math.random()*10)
}
code = new Date().getTime()+code
return code
}
export {outTradeno,order_code}
5.2 编写统一下单接口
在ACC-config
文件夹中创建文件payment.js
class WXPay{
// 请求云函数:获取统一下单返回的数据
async place_cloud(price,outTradeno){
try{
//wx.cloud.callFunction()是调用云函数的方法
const res = await wx.cloud.callFunction({name:'wx-pay',data:{price,outTradeno}})
return res
}catch(e){
return {msg:'请求统一下单云函数出错',e}
}
}
}
export {WXPay}
5.3 提交订单到数据库
import { reactive } from 'vue'
const db = wx.cloud.database()
// 提交数据库所需要的订单数据
let order_data = reactive({
address:[],
order_time:'',
query_time:'',
pay_success:'not_pay',
deliver:'stay',
evaluate:false,
waybill_No:'',
payment:{},
Re_reason:'',
out_trade_no:'',
out_refund_no:''
})
class WXPay{
// 请求云函数:获取统一下单返回的数据
async place_cloud(price,outTradeno){
try{
const res = await wx.cloud.callFunction({name:'wx-pay',data:{price,outTradeno}})
return res
}catch(e){
return {msg:'请求统一下单云函数出错',e}
}
}
// 提交数据至数据库
order_sub(order,address,order_time,query_time,payment,out_trade_no){
order_data.address = address
order_data.order_time = order_time
order_data.query_time = query_time
order_data.payment = payment
order_data.out_trade_no = out_trade_no
// 需要考虑购物车的数据(如果购物车不止一条商品)
var new_order = order.map(item=>{
return {...item,...order_data}
})
return new Promise((resolve,reject)=>{
new_order.forEach((item,index)=>{
try{
db.collection('order_data').add({data:item})
if(index == new_order.length-1){
resolve('seccess')
}
}catch(e){
reject(e)
}
})
})
}
}
export {WXPay}
5.4 发起支付
import { reactive } from 'vue'
class WXPay{
// 发起支付
wxPayment(payment){
return new Promise((resolve,reject)=>{
wx.requestPayment({
...payment,
success(res){
resolve(res)
},
fail(err){
reject(err)
}
})
})
}
}
export {WXPay}
提交订单按钮函数 (要下载moment插件)
// 提交订单
async function pay_submit(){
// 下单时间:年月日时分秒
let order_time = moment().utcOffset(8).format('YYYY-MM-DD HH:mm:ss')
// 当天时间:年月日
let query_time = moment().utcOffset(8).format('YYYY-MM-DD')
// 对每个商品生成订单号
order_data.order.forEach(item=>item.order_num = order_code())
let out_trade_no = outTradeno()
try{
// 1.统一下单
let payment = await new WXPay().place_cloud(order_data.total_price,out_trade_no)
// 2.提交订单到数据库
let send_data = await new WXPay().order_sub(order_data.order,res_data.address,order_time,query_time,payment.result,out_trade_no)
// 3.发起支付
const pay = await new WXPay().wxPayment(payment.result)
console.log(pay)
}catch(e){
console.log(e)
}
}
5.5 处理支付回调函数
修改pay_cb
云函数中的index.js
文件
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: 'shop-user-0girpywsc1855fd0' }) // 使用当前云环境
const db = cloud.database()
const _ = db.command
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
console.log(event)
let {resultCode,returnCode} = event
// 判断该笔交易是否成功
if(resultCode == 'SUCCESS' && returnCode == 'SUCCESS'){
// 支付成功
await db.collection('user_infor').where({_openid:wxContext.OPENID}).update({data:{watch_num:_.inc(1),pay:true}})
return {errcode:0,errmsg:'支付成功'}
}
}