一、微信小程序支付流程

小程序支付管理后台(托管机构-小程序-云开发-073-小程序微信支付)(1)

根据微信小程序官方时序图,我们需要做的就是2/3/4/6/8/9/16步。前端就是toOrder方法,云端就是createOrder方法。其中要调用的CloudPay.unifiedOrder()方法我们封装到了payService中。

二、统一下单官网

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 }

三、业务层实现1、配置文件1)、payConfig.js

在 config 文件夹创建 payConfig.js,云开发环境就是小程序的环境ID

小程序支付管理后台(托管机构-小程序-云开发-073-小程序微信支付)(2)

// 支付参数配置文件 module.exports = { MCHID: '******', //商户号 ENV: 'cloud1-******', //云开发环境 }

2、service层1)、payService.js使用uuid包(不需要了)

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位字符

payService.js完整代码

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 }

2)、orderService.js

在 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 }

3、controller层1)、payController.js(不需要)

因为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(); } }

四、入口文件1、添加支付路由

注意这里需要传递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(); }

,