根据微信小程序官方时序图,我们需要做的就是2/3/4/6/8/9/16步。前端就是toOrder方法,云端就是createOrder方法。其中要调用的CloudPay.unifiedOrder()方法我们封装到了payService中。
- 1、用户在小程序端点击支付按钮时触发小程序端的toOrder方法(步骤2)。
- 2、调用云函数Router里面的createOrder方法(步骤3),并将商品名称、商品价格等信息传递给createOrder方法。
- 3、在createOrder中调用payService中的统一下单接口CloudPay.unifiedOrder()(步骤4),参数包括接收的商品信息、云函数环境id,以及需要填写结果通知回调函数(函数名为callback)用来接收异步支付结果。
- 4、createOrder方法接受返回的成功结果,包含payment字段(步骤6)
- 5、小程序端的toOrder方法接受createOrder方法返回的结果,包含payment字段(步骤8)
- 6、在小程序端里调用wx.requestPayment接口发起支付,参数就是createOrder返回的payment对象(步骤9);这时会弹出微信支付的界面
- 7、用户在小程序端支付成功,回调函数callback就会接受到异步的支付结果(步骤16),我们可以在callbak云函数里将支付成功的信息更新到数据库等操作
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/open/pay/CloudPay.unifiedOrder.html
CloudPay.unifiedOrder()商户在小程序中先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。
// 云函数代码
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => {
const res = await cloud.cloudPay.unifiedOrder({
"body" : "小秋 TIT 店-超市",
"outTradeNo" : "1217752501201407033233368018",
"spbillCreateIp" : "127.0.0.1",
"subMchId" : "1900009231",
"totalFee" : 1,
"envId": "test-f0b102",
"functionName": "pay_cb"
})
return res
}
在 config 文件夹创建 payConfig.js,云开发环境就是小程序的环境ID
// 支付参数配置文件
module.exports = {
MCHID: '******', //商户号
ENV: 'cloud1-******', //云开发环境
}
https://www.npmjs.com/package/uuid/v/8.3.0
在 service 文件夹创建 payService.js,在云函数index打开客户端安装uuid依赖,node-uuid 已经废弃了,在命令窗口输入以下命令:
npm install uuid --save
const uuid = require('uuid')
let noncestr = uuid.v1() // V1 是根据时间戳生成随机字符串
var reg = new RegExp( '-' , "g" )
var nonce_str = noncestr.replace( reg , '' ) //替换掉全部-,36位字符转为没有-的32位字符
const model = require('../models/BaseModel.js')
const { ORDER } = require('../config/tableConfig.js')
const { MCHID,ENV } = require('../config/payConfig.js')
/**
* //统一下单接口
* @param {*云环境} cloud
* @param {*商品名称} name
* @param {*订单号} order_id
* @param {*总金额,分单位} totalFee
* @returns
*/
async function unifiedOrder(cloud,name, order_id, totalFee) {
const paydata={
"body": name, //商品名称
"outTradeNo": order_id, //订单号
"spbillCreateIp": "127.0.0.1", //终端IP
"subMchId": MCHID, //商户号
"totalFee": totalFee, //总金额,分单位
"envId": ENV, //结果通知回调云函数环境
"functionName": "callback" //结果通知回调云函数名,必须是一个新的独立云函数
}
console.log('paydata=',paydata)
const res = await cloud.cloudPay.unifiedOrder(paydata)
console.log('unifiedOrder res=',res)
return res
}
module.exports = {
unifiedOrder
}
在 service 文件夹修改 orderService.js, 修改createOrder方法
const model = require('../models/BaseModel.js')
const { ORDER,COUPONINFO } = require('../config/tableConfig.js')
const { ORDERFIELD } = require('../fields/orderField.js')
const payService = require('./payService.js')
//创建订单,orderData,openId
const createOrder = async (cloud,openId,orderData) => {
// 添加订单详情
let current_time =(new Date()).getTime() //当前时间戳 ,毫秒
//多个商品用这个方法
//let order_detail_list = [] //订单商品详情数组
// for (let item of orderData.products) {
// let params_order_detail={
// product : item.product,
// sku : item.selectedSku,
// prodNum:item.prodNum
// }
// order_detail_list.push(params_order_detail)
// }
//单个商品用这个
let item= orderData.products[0]
//比较数据库中的商品价格和发送过来的价格是否相等(待完成)
// 订单信息
let params_order = {
buyer_openid:openId, //买家openid编号
buyer_studentname: orderData.child.studentname, //买家小孩姓名
buyer_phone: orderData.child.tel, //买家电话
buyer_schoolname: orderData.child.schoolname, //买家小孩学校
buyer_sexy: orderData.child.sexy, //买家小孩性别
order_product_id:item.product._id, //订单商品编号
order_product_price:item.product.product_price, //订单商品价格
order_product_img:item.product.product_img, //订单商品图片
order_product_name:item.product.product_name, //订单商品名称
order_product_brief:item.product.product_brief, //订单商品名称
order_product_prodNum:item.prodNum, //订单数量
order_totalPrice: orderData.totalPrice, //订单总价
order_status: 0,// 订单状态,默认未付款
query_number: 0,// 订单状态查询次数,默认为0
refund_status: false,// 是否提现,默认为false
create_time: current_time, //下单时间
update_time: current_time,
//order_detail_list: order_detail_list //订单商品详情数组
}
//如果有优惠券编号
if (orderData.coupon_id!=undefined){
//添加优惠券编号
params_order.order_coupon_id=orderData.coupon_id
}
//如果有规格信息
if (Object.keys(item.selectedSku).length >0 ){
params_order.order_sku_id=item.selectedSku._id
params_order.order_sku_name=item.selectedSku.sku_name
params_order.order_sku_selectedProp=item.selectedSku.selectedProp
}
// 添加定单记录,获取订单编号order_id
let res=await model.add(ORDER, params_order)
let order_id =res._id
if (orderData.coupon_id!=undefined){//如果有优惠券编号
//修改优惠券状态
let condition={}
condition._id=orderData.coupon_id
let data={}
data.coupon_status=4 //优惠券状态
data.order_id=order_id //订单编号
await model.updatebywhere(COUPONINFO,condition,data)
}
//开始调用支付服务层的统一下单服务
const name=item.product.product_name
const totalFee = Math.round(orderData.totalPrice * 100) //转成分为单位
let order=await payService.unifiedOrder(cloud,name, order_id, totalFee)
console.log('order=',order)
return order//返回统一下单结果
}
/**
* 根据订单id获取订单信息
* @param {*} orderId
*/
const getOrderById = (orderId) => {
return model.findById(ORDER, ORDERFIELD, orderId)
}
/**
* 根据用户openid获取信息
* @param {*} openId
*/
const getOrderList = (openId, status) => {
let order = {}
order.name = 'create_time'
order.orderBy = 'desc'
let page = 0
let size = 20
let options = { buyer_openid: openId }
if (status!=-1){
options.order_status=status
}
console.log('options=',options)
return model.query(ORDER, ORDERFIELD, options, page, size, order)
}
module.exports = {
createOrder,
getOrderById,
getOrderList
}
因为payService的unifiedOrder方法是在orderService中被调用的
2)、orderController.js
// 创建订单
function createOrder(cloud,openId,orderData){
return async function (ctx, next) {
ctx.data = {}
const data=await orderService.createOrder(cloud,openId,orderData) // 取出数据
ctx.data = data
ctx.body = await returnUtil.success(ctx)
await next();
}
}
注意这里需要传递openId和status参数,
其中的status来自于options中的event.data ,
/*************************** 订单 *****************************************/
app.router('order/createOrder', orderController.createOrder(cloud,openId,options.orderData))
// 云函数入口文件
const cloud = require('wx-server-sdk')
const TcbRouter = require('tcb-router')
const indexController = require('./controller/indexController')
const productController = require('./controller/productController')
const userController = require('./controller/userController')
const studentController = require('./controller/studentController')
const reservationController = require('./controller/reservationController')
const orderController = require('./controller/orderController')
const couponController = require('./controller/couponController')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const app = new TcbRouter({ event });
// app.use 表示该中间件会适用于所有的路由
app.use(async (ctx, next) => {
ctx.data = {};
await next(); // 执行下一中间件
});
let options = {}
options = event.data // event.data包含前台传过来的参数
console.log('options=',options)
//记录用户ip地址
const wxContext = cloud.getWXContext();
const ip = wxContext.CLIENTIP ? wxContext.CLIENTIP : wxContext.CLIENTIPV6
//记录用户openid
const openId=event.userInfo.openId
/*************************** 首页 *****************************************/
app.router('index/getBanner', indexController.getBanner()) // 获取轮播
app.router('index/getRoom', indexController.getRoom()) // 获取房间信息
/*************************** 我的孩子 *****************************************/
app.router('student/addStudent', studentController.addStudent(openId,options.student)) // 添加孩子
app.router('student/editStudent', studentController.editStudent(openId,options.student)) // 修改孩子
app.router('student/delStudent', studentController.delStudent(options._id)) // 删除孩子
app.router('student/getStudentList', studentController.getStudentList(openId)) // 获取孩子列表
app.router('student/getStudentById', studentController.getStudentById(options._id)) // 获取孩子详情
app.router('student/getStudent', studentController.getStudent(openId)) // 获取默认孩子
/*************************** 商品信息 *************************************/
app.router('product/getSkuById', productController.getSkuById(options._id)) // 获取商品规格
app.router('product/getProductById', productController.getProductById(options._id)) // 获取商品详情信息
app.router('product/getProductOrderById', productController.getProductOrderById(options._id)) // 获取商品订单资料
/******************** 用户登录 *******************************/
app.router('user/userLogin', userController.userLogin(ip, openId,options.userInfo))
app.router('user/getPhone', userController.getPhone( openId,options.cloudID))
/*************************** 预约 *****************************************/
app.router('reservation/addReservation', reservationController.addReservation(openId,options.student)) // 添加预约
/*************************** 订单 *****************************************/
app.router('order/createOrder', orderController.createOrder(cloud,openId,options.orderData))
app.router('order/getOrderList', orderController.getOrderList(openId,options.status))
/*************************** 优惠券 *****************************************/
app.router('coupon/getCouponList', couponController.getCouponList(openId,options.couponStatus))
app.router('coupon/receiveCoupon', couponController.receiveCoupon(openId,options.couponId))
return app.serve();
}
,