zoukankan      html  css  js  c++  java
  • 微信小程序--云开发支付闭环

    云开发支付流程闭环

    extends

    微信小程序--使用云开发完成支付闭环

    在上述文章中,我们对支付结果的处理更多依赖于小程序端的操作

    1. 订单号存储在小程序端
    2. 支付结果采用小程序端定时触发器轮询

    现在我对该流程进行了优化处理

    1.流程介绍

    2.小程序端

    1. 请求统一下单云函数
    2. 调用支付接口
    3. 侦听器获取支付结果
    // 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

    1. 云调用统一下单【CloudPay.unifiedOrder】
    2. 数据库中存入订单记录并设置为未支付状态

    需要配置商户(云开发控制台)

    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

    1. 修改数据库中订单状态

    2. 返回给回调请求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
      }
    }
    

    参考文档

    1. 云开发文档 Cloud.CloudPay | 微信开放文档 (qq.com)

    2. 回调函数请求携带参数

    {
    	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: ''
    	}
    }
    
    
  • 相关阅读:
    关于异步IO与同步IO的写操作区别
    慢慢开始记录一些技术心得吧
    写了placement new就要写placement delete
    关于针对class自定义new操作符失败的函数处理
    operator->和operator->*
    关于继承中的拷贝构造函数
    关于g++编译模板类的问题
    关于互斥锁,条件变量的内核源码解析
    关于sigwait
    观察者设计模式
  • 原文地址:https://www.cnblogs.com/masterchd/p/14840012.html
Copyright © 2011-2022 走看看