小程序支付

步驟:
1. Openid
在小程序初次加載的時候就已經獲取(詳情見 小程序登錄)
2. 生成商戶訂單
1.商品信息由小程序端提供
2.提供支付統一下單接口所需參數
3. 調用支付統一下單API
官方文檔
4. 拿到返回預付單信息並處理
5. 再次簽名
官方文檔
案例:
小程序端
test.wxml
<button bind:tap="pay">支付</button>
test.js
Page({
pay:function(){
wx.request({
url: "http://127.0.0.1:8000/pay/",
method: "POST",
data:{"login_key":wx.getStorageSync("login_key")},
header: { "content-type": "application/json" },
success: function (e) {
console.log(e)
// 簽權調起支付
wx.requestPayment({
'timeStamp': e.data.data.timeStamp,
'nonceStr': e.data.data.nonceStr,
'package': e.data.data.package,
'signType': e.data.data.signType,
'paySign': e.data.data.paySign,
'success': function (res)
{
console.log(res,"成功")
},
'fail': function (res)
{
console.log("支付失敗",res)
},
})
}
})
},
})
后端 django
wx
├── settings.py # 小程序id,code2Session等配置
├── wx_login.py # 用於調用code2Session拿到openid等
└── WXBizDataCrypt.py # 獲取用戶授權信息的解密算法,官方下載
wx/settings.py
AppId="..." 微信分配的小程序id
AppSecret="..."
code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"
pay_mchid ='...' 微信配的商戶id
pay_apikey = '...' 商戶平台設置的秘鑰key
項目/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.core.cache import cache
import hashlib,time
import random
from app01.wx import settings
import requests
class Pay(APIView):
def post(self,request):
param=request.data
if param.get("login_key"):
#從redis中拿到小程序端login_key所對應得opendi&session_key值
openid,session_key=cache.get(param.get("login_key")).split("&")
self.openid=openid
# 獲取用戶IP
# 1.如果是Nginx做的負載就要HTTP_X_FORWARDED_FOR
if request.META.get('HTTP_X_FORWARDED_FOR'):
self.ip =request.META['HTTP_X_FORWARDED_FOR']
else:
# 2.如果沒有用Nginx就用REMOTE_ADDR
self.ip = request.META['REMOTE_ADDR']
# 調用 生成商戶訂單 方法
data = self.pay()
return Response({"code":200,"msg":"ok","data":data})
else:
return Response({"code":200,"msg":"缺少參數"})
# 生成隨機字符串
def get_str(self):
str_all="1234567890abcdefghjklmasdwery" # 注意 開發活動功能時, 去掉1,i,0,o
nonce_str="".join(random.sample(str_all,20))
return nonce_str
# 生成訂單號
def get_order(self):
order_id=str(time.strftime("%Y%m%d%H%M%S"))
return order_id
# 處理返回預付單方法
def xml_to_dict(self,data):
import xml.etree.ElementTree as ET
xml_dict={}
data_dic=ET.fromstring(data)
for item in data_dic:
xml_dict[item.tag]=item.text
return xml_dict
# 獲取sign簽名方法
def get_sign(self):
data_dic = {
"nonce_str": self.nonce_str,
"out_trade_no": self.out_trade_no,
"spbill_create_ip": self.ip,
"notify_url": self.notify_url,
"openid": self.openid,
"body": self.body,
"trade_type": "JSAPI",
"appid": self.appid,
"total_fee": self.total_fee,
"mch_id": self.mch_id
}
sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
sign_str = f"{sign_str}&key={settings.pay_apikey}"
md5 = hashlib.md5()
md5.update(sign_str.encode("utf-8"))
return md5.hexdigest().upper()
# 1.生成商戶訂單 提供 支付統一下單 所需參數
def pay(self):
self.appid=settings.AppId # appid 微信分配的小程序ID
self.mch_id=settings.pay_mchid # mch_id 微信分配的商戶號
self.nonce_str=self.get_str() # 隨機字符串
self.body="商品名" # 商品名一般由小程序端傳到后端
self.out_trade_no=self.get_order() # 訂單號
self.total_fee=1 # 訂單總金額
self.spbill_create_ip=self.ip # 用戶ip
self.notify_url="http://www.baidu.com" # 異步接收微信支付結果通知的回調地址
self.trade_type="JSAPI" # 固定寫法
self.sign = self.get_sign() # 獲取sign 簽名
data=f'''
<xml>
<appid>{self.appid}</appid>
<body>{ self.body}</body>
<mch_id>{self.mch_id}</mch_id>
<nonce_str>{self.nonce_str}</nonce_str>
<notify_url>{self.notify_url}</notify_url>
<openid>{self.openid}</openid>
<out_trade_no>{self.out_trade_no}</out_trade_no>
<spbill_create_ip>{self.spbill_create_ip}</spbill_create_ip>
<total_fee>{self.total_fee}</total_fee>
<trade_type>{self.trade_type}</trade_type>
<sign>{self.sign}</sign>
</xml>
'''
# 2.支付統一下單接口
url="https://api.mch.weixin.qq.com/pay/unifiedorder"
# 3.返回預付單信息
response=requests.post(url,data.encode("utf-8"),headers={"content-type":"application/xml"})
res_data=self.xml_to_dict(response.content)
data=self.two_sign(res_data["prepay_id"]) # prepay_id 預支付訂單回話標識
return data
# 4.將組合數據再次簽名
def two_sign(self,prepay_id):
timeStamp=str(int(time.time()))
nonceStr=self.get_str()
data_dict={
"appId":settings.AppId,
"timeStamp":timeStamp,
"nonceStr":nonceStr,
"package":f"prepay_id={prepay_id}",
"signType":"MD5"
}
sign_str = "&".join([f"{k}={data_dict[k]}" for k in sorted(data_dict)])
sign_str = f"{sign_str}&key={settings.pay_apikey}"
md5 = hashlib.md5()
md5.update(sign_str.encode("utf-8"))
sign=md5.hexdigest().upper()
data_dict["paySign"]=sign
data_dict.pop("appId")
# 5.返回支付參數到小程序端,小程序端獲取所需參數向微信服務器發送 調起支付 方法
return data_dict
項目/urls.py
url(r'^pay/',views.Pay.as_view())