云開發(fā) 微信支付

2020-07-22 15:32 更新

微信支付云調用(云支付),可以免鑒權快速調用微信支付的開放能力,開發(fā)者無需關心證書、簽名、也無需依賴第三方模塊,免去了泄漏證書,支付等敏感信息的風險;還支持云函數作為微信支付進行支付和退款的回調地址,不再需要定時輪詢,更加高效。只需在開發(fā)者工具1.02.2005111 (2020年5月11日版)的云開發(fā)控制臺綁定微信支付商戶號,在綁定完成后可在云開發(fā)中原生接入微信支付。

一、云支付快速入門

1、開通微信支付云調用

要開通微信支付云調用,首先需要小程序已經開通了微信支付,而微信支付是不支持個人小程序的,需要企業(yè)賬戶才行,其次需要小程序已經綁定了商戶號。滿足這兩個條件之后,我們可以在云開發(fā)控制臺(注意開發(fā)者工具的版本)- 設置- 全局設置中開通。

點擊添加商戶號后進行賬號綁定,這時候綁定了微信支付的商戶號管理員的微信會收到一條授權確認的模板消息,點擊模板消息會彈出服務商助手小程序,確認授權之后就可以在云開發(fā)控制臺看到綁定狀態(tài)為“已綁定”,而JS API權限也會顯示“已授權”。

jsapi和api退款權限授權,需要前往微信支付商戶平臺-產品中心-我的授權產品中進行確認授權完成授權后才可以調用微信支付相關接口能力。如果你在你的產品中心看不到我的授權產品,可以點擊鏈接:授權產品

2、微信支付流程說明

用微信支付云調用來實現(xiàn)完整的支付功能,大體上會經過以下4個步驟(后面在代碼的寫法上有些步驟會整合到一起):

  • 1、用戶在小程序端點擊支付時使用wx.cloud.callFunction調用云函數(比如云函數名為pay),并將商品名稱、商品價格等信息傳遞給pay云函數;

  • 2、在pay云函數中調用統(tǒng)一下單接口CloudPay.unifiedOrder(),參數包括接收的商品信息、云函數環(huán)境id,以及需要填寫結果通知回調函數(比如函數名為paynotice)用來接收異步支付結果;pay云函數會返回的成功結果對象中會包含payment字段;

  • 3、在小程序端wx.cloud.callFunction的success回調函數(也就是拿到云函數返回的對象)里調用wx.requestPayment接口發(fā)起支付,而從pay云函數返回的payment對象(字段)就包含這個接口所需要的所有信息(參數);這時會彈出微信支付的界面;

  • 4、用戶在小程序端支付成功,paynotice就會接受到異步的支付結果,我們可以在paynotice云函數里進行發(fā)送訂閱消息以及將支付成功的信息更新到數據庫等操作

3、微信支付的簡單案例

我們可以在小程序的wxml頁面比如pay.wxml頁面,點擊某個button組件時,通過事件處理函數比如callPay,來調用pay云函數,代碼如下:

<button bindtap ="callPay">發(fā)起支付</button>

然后再在pay.js里輸入事件處理函數callPay,調用的支付云函數名稱為pay(名稱任意),注意成功的回調函數的寫法如下,這里把支付流程的第1步和第3步整到了一起:

尤其是const payment = res.result.paymentwx.requestPayment({...payment})不要改(僅對小白用戶而言)。因為有不少小白用戶啥基礎也沒有,但是對微信支付比較感興趣,所以本節(jié)內容,會介紹的比較瑣碎一些。

callPay(){
  wx.cloud.callFunction({
    name: 'pay',  //云函數的名稱,在后面我們會教大家怎么建
    success: res => {
      console.log(res)
      const payment = res.result.payment
      wx.requestPayment({
        ...payment,
        success (res) {
          console.log('支付成功', res) //為方便,只打印結果,如果要寫支付成功之后的處理函數,寫在這后面
        },
        fail (err) {
          console.error('支付失敗', err) 
          //支付失敗之后的處理函數,寫在這后面
        }
      })
    },
    fail: console.error,
  })
},

然后再在云函數根目錄文件夾cloudfunctions右鍵,選擇“新建Nodejs云函數”,新建一個云函數pay,然后再在index.js里輸入以下代碼,然后進行一些修改(注意參數名稱不要改,大小寫也要原樣寫,不懂你就復制):

  • body為你的商家名(店名)-銷售商品的類名,代碼里有參考;

  • outTradeNo是商戶訂單號,32個字符內,只能是數字、大小寫字母_-,如果你是在調試學習,注意每次都改一下這個,免得重復;

  • subMchId你的商戶ID或子商戶ID,填寫云開發(fā)控制臺- 設置- 全局設置- 微信支付配置里的商戶號也可以;

  • totalFee是支付的金額,單位是分,填寫100,就是一塊錢,注意這個是數值格式,不要寫成了字符串格式(不要加單引號或者雙引號);

  • envId是你的結果通知回調云函數所在的環(huán)境ID,functionName結果通知云函數的名稱(可以自定義);可以在云開發(fā)控制臺- 設置- 環(huán)境設置里看到,注意是環(huán)境ID,不是環(huán)境名稱,最好直接復制過來;

  • 其他地方,不懂的話,不要改,直接copy完事

修改完之后,點擊pay云函數目錄下的index.js,然后右鍵選擇“云函數增量上傳:更新文件”或者右鍵云函數根目錄文件夾cloudfunctions,選擇“上傳并部署:云端安裝依賴(不上傳Node_modules)

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": "HackWeek案例-教學費用",
    "outTradeNo" : "122775224070323234368128", //不能重復,否則報錯
    "spbillCreateIp" : "127.0.0.1", //就是這個值,不要改
    "subMchId" : "1520057521",  //你的商戶ID或子商戶ID
    "totalFee" : 100,  //單位為分
    "envId": "xly-xrlur",  //你的云開發(fā)環(huán)境ID
    "functionName": "paysuc",  //支付成功的回調云函數,先可以隨便寫,比如寫paysuc,后面會教你怎么建
    "nonceStr":"F8B31E62AD42045DFB4F2",  //隨便弄的32位字符串,建議自己生成
    "tradeType":"JSAPI"   //默認是JSAPI
  })
  return res
}

然后就可以在開發(fā)者工具的模擬器里點擊"發(fā)起支付"的按鈕了,這時會彈出支付的二維碼,掃碼支付就可以了;也可以使用預覽或真機調試。

這里的outTradeNo是自己生成的,我們可以使用時間戳Date.now().toString(),或者加隨機數Date.now().toString()+Math.floor(Math.random()*1000).toString()等來處理,而nonceStr是32位以內的字符串,我們可以使用用戶的openid和時間戳拼接而成(你也可以使用其他方法),比如下面是用戶的openid先替換掉-字符,然后將字母都大寫,最后加上時間戳的字符串"oUL-m5FuRmuVmxvbYOGuXbuEDsn8".replace('-','').toUpperCase()+Date.now().toString()

二、查詢訂單與申請退款

我們可以在云函數里調用cloudPay.queryOrder()來查詢訂單的支付狀態(tài),以及調用cloudPay.refund()來對已經支付成功的訂單發(fā)起退款。下面的代碼只是查詢訂單與申請退款簡單的demo,真正要在實際開發(fā)中使用這些接口,都是需要結合云開發(fā)數據庫的,尤其是申請退款開發(fā)時一定要慎重對待。

使用開發(fā)者工具新建一個queryorder的云函數,然后在index.js里輸入以下代碼,將云函數部署到云端之后,調用該云函數就能查詢訂單信息了:

const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async(event, context) => {
  const res = await cloud.cloudPay.queryOrder({
    "sub_mch_id":"1520057521",
    //商戶訂單號,需是云支付成功交易的訂單號
    "out_trade_no":"122775224070323234368128",
    //微信訂單號可以不必寫
    // "transaction_id":"4200000530202005179572346100",
    //任意的32位字符
    "nonce_str":"C380BEC2BFD727A4B6845133519F3AD6"
  })
  return res
}

使用開發(fā)者工具新建一個refundorder的云函數,然后在index.js里輸入以下代碼,退款的金額少于交易的金額時,可以實現(xiàn)部分退款;注意調用該云函數,退款會直接原路返回給用戶,因此一定要有管理員審核或只能管理員來調用該接口:

const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async(event, context) => {
  const res = await cloud.cloudPay.refund({
    "sub_mch_id":"1520057521",
    "nonce_str":"5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
    "out_trade_no":"122775224070323234368128",//商戶訂單號,需是云支付成功交易的訂單號
    "out_refund_no":"122775224070323234368128001",//退款單號,可以自定義,建議與訂單號相關聯(lián)
    "total_fee":100,
    "refund_fee":20,
  })
  return res
}

三、支付成功的回調函數

在前面發(fā)起支付的云函數里我們寫過一個參數functionName結果通知云函數paysuc,paysuc云函數在訂單支付成功之后才會被調用。我們可以在支付成功的回調函數里處理一些任務,比如把訂單支付的重要信息存儲到數據庫、給用戶發(fā)送支付成功的訂閱消息、以及獲取用戶的UnionID等等。要處理這些任務,首先需要了解訂單支付成功之后,paysuc云函數會接收到哪些數據。我們可以打印paysuc云函數的event對象,可以了解到event對象里包含類似于如下結構的信息,這些都是我們在paysuc云函數處理任務的關鍵:

"appid": "wxd2********65e", 
"bankType": "OTHERS",
"cashFee": 200,
"feeType": "CNY",
"isSubscribe": "N",
"mchId": "1800008281",
"nonceStr": "F8B31E62AD42045DFB4F2",
"openid": "oPoo44....t8gCOUKSncFI",
"outTradeNo": "1589720989221",
"resultCode": "SUCCESS",
"returnCode": "SUCCESS",
"subAppid": "wxda99a********57046",
"subIsSubscribe": "N",
"subMchId": "1520057521",
"subOpenid": "oUL********GuXbuEDsn8",
"timeEnd": "20200517211001",
"totalFee": 2,
"tradeType": "JSAPI",
"transactionId": "42000********178943055343",
"userInfo": {
    "appId": "wxd********046",
    "openId": "oUL-m5F********GuXbuEDsn8"
}

要發(fā)送訂閱消息,首先我們需要去申請訂單支付成功的訂閱消息模板,比如模板如下,我們需要注意訂閱消息里每一個屬性對應的具體的格式,以及格式的具體要求,比如支付金額以及支付時間的格式:

商品名稱{{thing6.DATA}}
支付金額{{amount7.DATA}}
訂單號{{character_string9.DATA}}
支付時間{{date10.DATA}}
溫馨提示{{thing5.DATA}}

要發(fā)訂閱消息,需要調用接口wx.requestSubscribeMessage來獲取用戶授權以及要有相應的授權次數,在前面我們已經了解到只有用戶發(fā)生點擊行為或者發(fā)起支付回調后,才可以調起訂閱消息界面,因此我們可以在上面的發(fā)起支付的回調函數里直接調用這個接口:

callPay(){
  wx.cloud.callFunction({
    name: 'pay',  //云函數的名稱,在后面我們會教大家怎么建
    success: res => {
      console.log(res)
      const payment = res.result.payment
      wx.requestPayment({
        ...payment,
        success (res) {
          console.log('支付成功', res) //為方便,只打印結果,如果要寫支付成功之后的處理函數,寫在這后面
          this.subscribeMessage() //調用subscribeMessage()函數,如果你不是箭頭函數,注意this指代的對象
        },
      })
    },
  })
},
subscribeMessage() {
  wx.requestSubscribeMessage({
    tmplIds: [
      //訂閱消息模板ID,一次可以寫三個,可以是同款通知、到貨通知、新品上新通知等,通常用戶不會拒絕,多寫幾個就能獲取更多授權
      "p5ypZiN4TcZrzke4Q_MBB1qri33rb80z-tb16Sg-Kpg",
    ],
    success(res) {
      console.log("訂閱消息API調用成功:",res)
    },
    fail(res) {
      console.log("訂閱消息API調用失敗:",res)
    }
  })
},

然后在paysuc云函數的index.js里寫如下代碼,訂閱消息所需的全部參數都是來自于event對象,我們只需要稍加修改格式即可。

const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})


exports.main = async (event, context) => {
  const {cashFee,subOpenid,outTradeNo,timeEnd} = event
  try {
    const result = await cloud.openapi.subscribeMessage.send({
      touser: subOpenid,
      page: 'index',
      templateId: "p5ypZiN4TcZrzke4Q_MBB1qri33rb80z-tb16Sg-Kpg",
      data: {
        "thing6": {
          "value": '零基礎小程序云開發(fā)訓練營'
        },
        "amount7": {
          "value": cashFee/100 +'元'
        },
        "character_string9": {
          "value": outTradeNo
        },
        "date10": {
          "value": timeEnd.slice(0,4)+'年'+timeEnd.slice(4,6)+'月'+timeEnd.slice(6,8)+'日'+' '+timeEnd.slice(8,10)+':'+timeEnd.slice(10,12)
        },
        "thing5": {
          "value": "多謝您的支持哦~愛你哦~"
        }
    }
    })
    return result
  } catch (err) {
    console.log(err)
    return err
  }
}

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號