微信支付云調(diào)用(云支付),可以免鑒權(quán)快速調(diào)用微信支付的開(kāi)放能力,開(kāi)發(fā)者無(wú)需關(guān)心證書(shū)、簽名、也無(wú)需依賴(lài)第三方模塊,免去了泄漏證書(shū),支付等敏感信息的風(fēng)險(xiǎn);還支持云函數(shù)作為微信支付進(jìn)行支付和退款的回調(diào)地址,不再需要定時(shí)輪詢(xún),更加高效。只需在開(kāi)發(fā)者工具1.02.2005111 (2020年5月11日版)的云開(kāi)發(fā)控制臺(tái)綁定微信支付商戶(hù)號(hào),在綁定完成后可在云開(kāi)發(fā)中原生接入微信支付。
要開(kāi)通微信支付云調(diào)用,首先需要小程序已經(jīng)開(kāi)通了微信支付,而微信支付是不支持個(gè)人小程序的,需要企業(yè)賬戶(hù)才行,其次需要小程序已經(jīng)綁定了商戶(hù)號(hào)。滿(mǎn)足這兩個(gè)條件之后,我們可以在云開(kāi)發(fā)控制臺(tái)(注意開(kāi)發(fā)者工具的版本)- 設(shè)置- 全局設(shè)置中開(kāi)通。
點(diǎn)擊添加商戶(hù)號(hào)后進(jìn)行賬號(hào)綁定,這時(shí)候綁定了微信支付的商戶(hù)號(hào)管理員的微信會(huì)收到一條授權(quán)確認(rèn)的模板消息,點(diǎn)擊模板消息會(huì)彈出服務(wù)商助手小程序,確認(rèn)授權(quán)之后就可以在云開(kāi)發(fā)控制臺(tái)看到綁定狀態(tài)為“已綁定”,而JS API權(quán)限也會(huì)顯示“已授權(quán)”。
jsapi和api退款權(quán)限授權(quán),需要前往微信支付商戶(hù)平臺(tái)-產(chǎn)品中心-我的授權(quán)產(chǎn)品中進(jìn)行確認(rèn)授權(quán)完成授權(quán)后才可以調(diào)用微信支付相關(guān)接口能力。如果你在你的產(chǎn)品中心看不到我的授權(quán)產(chǎn)品,可以點(diǎn)擊鏈接:授權(quán)產(chǎn)品
用微信支付云調(diào)用來(lái)實(shí)現(xiàn)完整的支付功能,大體上會(huì)經(jīng)過(guò)以下4個(gè)步驟(后面在代碼的寫(xiě)法上有些步驟會(huì)整合到一起):
wx.cloud.callFunction
調(diào)用云函數(shù)(比如云函數(shù)名為pay),并將商品名稱(chēng)、商品價(jià)格等信息傳遞給pay云函數(shù);CloudPay.unifiedOrder()
,參數(shù)包括接收的商品信息、云函數(shù)環(huán)境id,以及需要填寫(xiě)結(jié)果通知回調(diào)函數(shù)(比如函數(shù)名為paynotice)用來(lái)接收異步支付結(jié)果;pay云函數(shù)會(huì)返回的成功結(jié)果對(duì)象中會(huì)包含payment字段;wx.cloud.callFunction
的success回調(diào)函數(shù)(也就是拿到云函數(shù)返回的對(duì)象)里調(diào)用wx.requestPayment
接口發(fā)起支付,而從pay云函數(shù)返回的payment對(duì)象(字段)就包含這個(gè)接口所需要的所有信息(參數(shù));這時(shí)會(huì)彈出微信支付的界面;我們可以在小程序的wxml頁(yè)面比如pay.wxml頁(yè)面,點(diǎn)擊某個(gè)button組件時(shí),通過(guò)事件處理函數(shù)比如callPay,來(lái)調(diào)用pay云函數(shù),代碼如下:
<button bindtap ="callPay">發(fā)起支付</button>
然后再在pay.js里輸入事件處理函數(shù)callPay,調(diào)用的支付云函數(shù)名稱(chēng)為pay(名稱(chēng)任意),注意成功的回調(diào)函數(shù)的寫(xiě)法如下,這里把支付流程的第1步和第3步整到了一起:
尤其是
const payment = res.result.payment
和wx.requestPayment({...payment})
不要改(僅對(duì)小白用戶(hù)而言)。因?yàn)橛胁簧傩“子脩?hù)啥基礎(chǔ)也沒(méi)有,但是對(duì)微信支付比較感興趣,所以本節(jié)內(nèi)容,會(huì)介紹的比較瑣碎一些。
callPay(){
wx.cloud.callFunction({
name: 'pay', //云函數(shù)的名稱(chēng),在后面我們會(huì)教大家怎么建
success: res => {
console.log(res)
const payment = res.result.payment
wx.requestPayment({
...payment,
success (res) {
console.log('支付成功', res) //為方便,只打印結(jié)果,如果要寫(xiě)支付成功之后的處理函數(shù),寫(xiě)在這后面
},
fail (err) {
console.error('支付失敗', err)
//支付失敗之后的處理函數(shù),寫(xiě)在這后面
}
})
},
fail: console.error,
})
},
然后再在云函數(shù)根目錄文件夾cloudfunctions右鍵,選擇“新建Nodejs云函數(shù)”,新建一個(gè)云函數(shù)pay,然后再在index.js里輸入以下代碼,然后進(jìn)行一些修改(注意參數(shù)名稱(chēng)不要改,大小寫(xiě)也要原樣寫(xiě),不懂你就復(fù)制):
body
為你的商家名(店名)-銷(xiāo)售商品的類(lèi)名,代碼里有參考;outTradeNo
是商戶(hù)訂單號(hào),32個(gè)字符內(nèi),只能是數(shù)字、大小寫(xiě)字母_-,如果你是在調(diào)試學(xué)習(xí),注意每次都改一下這個(gè),免得重復(fù);subMchId
你的商戶(hù)ID或子商戶(hù)ID,填寫(xiě)云開(kāi)發(fā)控制臺(tái)- 設(shè)置- 全局設(shè)置- 微信支付配置里的商戶(hù)號(hào)也可以;totalFee
是支付的金額,單位是分,填寫(xiě)100,就是一塊錢(qián),注意這個(gè)是數(shù)值格式,不要寫(xiě)成了字符串格式(不要加單引號(hào)或者雙引號(hào));envId
是你的結(jié)果通知回調(diào)云函數(shù)所在的環(huán)境ID,functionName
結(jié)果通知云函數(shù)的名稱(chēng)(可以自定義);可以在云開(kāi)發(fā)控制臺(tái)- 設(shè)置- 環(huán)境設(shè)置里看到,注意是環(huán)境ID,不是環(huán)境名稱(chēng),最好直接復(fù)制過(guò)來(lái);修改完之后,點(diǎn)擊pay云函數(shù)目錄下的index.js,然后右鍵選擇“云函數(shù)增量上傳:更新文件”或者右鍵云函數(shù)根目錄文件夾cloudfunctions,選擇“上傳并部署:云端安裝依賴(lài)(不上傳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案例-教學(xué)費(fèi)用",
"outTradeNo" : "122775224070323234368128", //不能重復(fù),否則報(bào)錯(cuò)
"spbillCreateIp" : "127.0.0.1", //就是這個(gè)值,不要改
"subMchId" : "1520057521", //你的商戶(hù)ID或子商戶(hù)ID
"totalFee" : 100, //單位為分
"envId": "xly-xrlur", //你的云開(kāi)發(fā)環(huán)境ID
"functionName": "paysuc", //支付成功的回調(diào)云函數(shù),先可以隨便寫(xiě),比如寫(xiě)paysuc,后面會(huì)教你怎么建
"nonceStr":"F8B31E62AD42045DFB4F2", //隨便弄的32位字符串,建議自己生成
"tradeType":"JSAPI" //默認(rèn)是JSAPI
})
return res
}
然后就可以在開(kāi)發(fā)者工具的模擬器里點(diǎn)擊"發(fā)起支付"的按鈕了,這時(shí)會(huì)彈出支付的二維碼,掃碼支付就可以了;也可以使用預(yù)覽或真機(jī)調(diào)試。
這里的outTradeNo是自己生成的,我們可以使用時(shí)間戳
Date.now().toString()
,或者加隨機(jī)數(shù)Date.now().toString()+Math.floor(Math.random()*1000).toString()
等來(lái)處理,而nonceStr是32位以?xún)?nèi)的字符串,我們可以使用用戶(hù)的openid和時(shí)間戳拼接而成(你也可以使用其他方法),比如下面是用戶(hù)的openid先替換掉-
字符,然后將字母都大寫(xiě),最后加上時(shí)間戳的字符串"oUL-m5FuRmuVmxvbYOGuXbuEDsn8".replace('-','').toUpperCase()+Date.now().toString()
我們可以在云函數(shù)里調(diào)用cloudPay.queryOrder()
來(lái)查詢(xún)訂單的支付狀態(tài),以及調(diào)用cloudPay.refund()
來(lái)對(duì)已經(jīng)支付成功的訂單發(fā)起退款。下面的代碼只是查詢(xún)訂單與申請(qǐng)退款簡(jiǎn)單的demo,真正要在實(shí)際開(kāi)發(fā)中使用這些接口,都是需要結(jié)合云開(kāi)發(fā)數(shù)據(jù)庫(kù)的,尤其是申請(qǐng)退款開(kāi)發(fā)時(shí)一定要慎重對(duì)待。
使用開(kāi)發(fā)者工具新建一個(gè)queryorder的云函數(shù),然后在index.js里輸入以下代碼,將云函數(shù)部署到云端之后,調(diào)用該云函數(shù)就能查詢(xún)訂單信息了:
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",
//商戶(hù)訂單號(hào),需是云支付成功交易的訂單號(hào)
"out_trade_no":"122775224070323234368128",
//微信訂單號(hào)可以不必寫(xiě)
// "transaction_id":"4200000530202005179572346100",
//任意的32位字符
"nonce_str":"C380BEC2BFD727A4B6845133519F3AD6"
})
return res
}
使用開(kāi)發(fā)者工具新建一個(gè)refundorder的云函數(shù),然后在index.js里輸入以下代碼,退款的金額少于交易的金額時(shí),可以實(shí)現(xiàn)部分退款;注意調(diào)用該云函數(shù),退款會(huì)直接原路返回給用戶(hù),因此一定要有管理員審核或只能管理員來(lái)調(diào)用該接口:
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",//商戶(hù)訂單號(hào),需是云支付成功交易的訂單號(hào)
"out_refund_no":"122775224070323234368128001",//退款單號(hào),可以自定義,建議與訂單號(hào)相關(guān)聯(lián)
"total_fee":100,
"refund_fee":20,
})
return res
}
在前面發(fā)起支付的云函數(shù)里我們寫(xiě)過(guò)一個(gè)參數(shù)functionName
結(jié)果通知云函數(shù)paysuc,paysuc云函數(shù)在訂單支付成功之后才會(huì)被調(diào)用。我們可以在支付成功的回調(diào)函數(shù)里處理一些任務(wù),比如把訂單支付的重要信息存儲(chǔ)到數(shù)據(jù)庫(kù)、給用戶(hù)發(fā)送支付成功的訂閱消息、以及獲取用戶(hù)的UnionID等等。要處理這些任務(wù),首先需要了解訂單支付成功之后,paysuc云函數(shù)會(huì)接收到哪些數(shù)據(jù)。我們可以打印paysuc云函數(shù)的event對(duì)象,可以了解到event對(duì)象里包含類(lèi)似于如下結(jié)構(gòu)的信息,這些都是我們?cè)趐aysuc云函數(shù)處理任務(wù)的關(guān)鍵:
"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ā)送訂閱消息,首先我們需要去申請(qǐng)訂單支付成功的訂閱消息模板,比如模板如下,我們需要注意訂閱消息里每一個(gè)屬性對(duì)應(yīng)的具體的格式,以及格式的具體要求,比如支付金額以及支付時(shí)間的格式:
商品名稱(chēng){{thing6.DATA}}
支付金額{{amount7.DATA}}
訂單號(hào){{character_string9.DATA}}
支付時(shí)間{{date10.DATA}}
溫馨提示{{thing5.DATA}}
要發(fā)訂閱消息,需要調(diào)用接口wx.requestSubscribeMessage
來(lái)獲取用戶(hù)授權(quán)以及要有相應(yīng)的授權(quán)次數(shù),在前面我們已經(jīng)了解到只有用戶(hù)發(fā)生點(diǎn)擊行為或者發(fā)起支付回調(diào)后,才可以調(diào)起訂閱消息界面,因此我們可以在上面的發(fā)起支付的回調(diào)函數(shù)里直接調(diào)用這個(gè)接口:
callPay(){
wx.cloud.callFunction({
name: 'pay', //云函數(shù)的名稱(chēng),在后面我們會(huì)教大家怎么建
success: res => {
console.log(res)
const payment = res.result.payment
wx.requestPayment({
...payment,
success (res) {
console.log('支付成功', res) //為方便,只打印結(jié)果,如果要寫(xiě)支付成功之后的處理函數(shù),寫(xiě)在這后面
this.subscribeMessage() //調(diào)用subscribeMessage()函數(shù),如果你不是箭頭函數(shù),注意this指代的對(duì)象
},
})
},
})
},
subscribeMessage() {
wx.requestSubscribeMessage({
tmplIds: [
//訂閱消息模板ID,一次可以寫(xiě)三個(gè),可以是同款通知、到貨通知、新品上新通知等,通常用戶(hù)不會(huì)拒絕,多寫(xiě)幾個(gè)就能獲取更多授權(quán)
"p5ypZiN4TcZrzke4Q_MBB1qri33rb80z-tb16Sg-Kpg",
],
success(res) {
console.log("訂閱消息API調(diào)用成功:",res)
},
fail(res) {
console.log("訂閱消息API調(diào)用失?。?,res)
}
})
},
然后在paysuc云函數(shù)的index.js里寫(xiě)如下代碼,訂閱消息所需的全部參數(shù)都是來(lái)自于event對(duì)象,我們只需要稍加修改格式即可。
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": '零基礎(chǔ)小程序云開(kāi)發(fā)訓(xùn)練營(yíng)'
},
"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": "多謝您的支持哦~愛(ài)你哦~"
}
}
})
return result
} catch (err) {
console.log(err)
return err
}
}
更多建議: