作用:让小程序可以微信支付
如果是虚拟商品,IOS平台暂时不允许
收入也是要合法啊
登录微信公众平台,也就是小程序后台
功能 — 微信支付
2种情况:
1、已经有的就直接走起
2、没有的就去注册一个(注释:微信商户平台也就是微信支付,这里巨坑,名字会乱的,微信商户平台是旧名)
3个表
1、订单表
2、订单商品数据表
3、支付回调数据表
openid不要发送到前端,这是可以做到的
.wxml:
<button bindtap="pay">支付</button>
.js:
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,"成功")
//小程序轮询服务器订单信息
that.checkThePayInfo(e.data.out_trade_no)
},
'fail': function (res)
{
console.log("支付失败",res)
},
})
}
})
},
1、url,后端/商户系统/服务器的路由
2、data传一个可以识别openid的编号
from flask import Flask, jsonify, request, url_for,render_template,flash,make_response
#蓝图config
from flask import current_app as app
import hashlib,time,random
#向微信服务器发送https请求
import requests
@app.route('/pay', methods=['POST'])
def pay1():
pay = Pay()#1、实例化Pay类
data = pay.post(request)#2、使用Pay类的post方法
return data #26、返回
class Pay():
def post(self,request):
id = request.json.get('login_key') # 3、读取json,id用来获得openid
print(id)
openid = User.query.filter_by(pk=id).first().openid # 4、id获得openid
self.openid=openid #5、写入这个类里
self.ip = request.remote_addr # 6、获取ip地址
data = self.pay()# 7、调用 生成商户订单 方法
return jsonify({"code":200,"msg":"ok","data":data,"out_trade_no":self.out_trade_no})#25、返回
# 生成商户订单 提供 支付统一下单 所需参数
def pay(self):
#8、准备一下参数
self.appid=app.config["WEIXIN_APP_ID"]#9、小程序应用id
self.mch_id=app.config["WEIXIN_APP_MCH_ID"]#10、商户号id
self.nonce_str=self.get_str()#11、服务器自己获得一个随机数
self.body="商品名" # 12、商品名一般由小程序端传到后端
self.out_trade_no=self.get_order()#13、服务器生成一个订单
self.total_fee=1 #14、价格:一般用服务器里的价格,不用小程序的
self.spbill_create_ip=self.ip #15、ip
self.notify_url=app.config["WEIXIN_NOTIFY_URL"]# 16、返回支付成功/失败的地址
self.trade_type="JSAPI" #17、交易类型JSAPI
self.sign = self.get_sign() # 18、获取sign 签名
#19、写成XML格式
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>
'''
# 20、支付统一下单
url="https://api.mch.weixin.qq.com/pay/unifiedorder"
# 21、返回预付单信息
# response = urllib.request.urlopen(url,data.encode("utf-8"))
response = requests.post(url,data.encode("utf-8"))
print("微信返回信息")
# print(response.read())
# 22、xml转dict
res_data=self.xml_to_dict(response.text)
# print(res_data)
# 23、二次签名
data = self.two_sign(res_data["prepay_id"])
return data #24、返回
#11、服务器自己获得一个随机数
def get_str(self):
str_all="1234567890abcdefghjklmasdwery" # 注意 开发活动功能时, 去掉1,i,0,o
nonce_str="".join(random.sample(str_all,20))
return nonce_str
# 13、服务器生成一个订单:包括时间+随机数
def get_order(self):
str_all = "1234567890abcdefghjklmasdwery"
nonce_str = "".join(random.sample(str_all, 10))
order_id = str(time.strftime("\\\\\\\\\\\\%Y\\\\\\\\\\\\%m\\\\\\\\\\\\%d\\\\\\\\\\\\%H\\\\\\\\\\\\%M\\\\\\\\\\\\%S") + nonce_str)
return order_id
# 18、获取sign 签名MD5
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={app.config['WEIXIN_APP_MCH_KEY']}"
md5 = hashlib.md5()
md5.update(sign_str.encode("utf-8"))
return md5.hexdigest().upper()
# 23、二次签名,将组合数据再次签名
def two_sign(self,prepay_id):
timeStamp=str(int(time.time()))
nonceStr=self.get_str()
data_dict={
"appId":app.config["WEIXIN_APP_ID"],
"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={app.config['WEIXIN_APP_MCH_KEY']}"
md5 = hashlib.md5()
md5.update(sign_str.encode("utf-8"))
sign=md5.hexdigest().upper()
data_dict["paySign"]=sign#加入paySign
data_dict.pop("appId")#去掉appId
# 返回支付参数到小程序端,小程序端获取所需参数向微信服务器发送 调起支付 方法
return data_dict
# 22、xml转dict处理,返回预付单方法
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
也就是上面小程序的代码
这里是设置notify_url的路由是啥,这里是/payback
算是示例代码
@app.route('/payback', methods=['POST'])
def Payback():
print("微信回调来的数据")
data = request.data
print(data)
dict = xml_to_dict2(data)
print(dict)
return_code = dict['return_code']
if return_code == "SUCCESS":
##
#这里是判断,详细看微信文档:API列表:支付结果通知
##
print("succ")
data = f'''
< xml >
< return_code > <![CDATA[SUCCESS]] > < / return_code >
< return_msg > <![CDATA[OK]] > < / return_msg >
< / xml >
'''
return data
else:
print("fail")
data = f'''
< xml >
< return_code > <![CDATA[FAIL]] > < / return_code >
< return_msg > <![CDATA[OK]] > < / return_msg >
< / xml >
'''
return data
# 处理返回预付单方法
def xml_to_dict2(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
1、蓝图命名
2、对比判断有无出错
小程序轮询
//轮询服务器订单信息
checkThePayInfo(out_trade_no) {
const requestTask = wx.request({
url: Config.restUrl + '/checkThePayInfo', //仅为示例,并非真实的接口地址
data: {
x: out_trade_no,
y: ''
},
header: {
'content-type': 'application/json'
},
success(res) {
console.log(res.data.info)
requestTask.abort() // 取消请求任务
//返回墙页和刷新
wx.navigateBack({
url: '../logs/logs',
})
}
})
}
#小程序轮询
@app.route('/checkThePayInfo', methods=['GET'])
def checkThePayInfo():
return {"info":"ok"}