本文链接:https://blog.csdn.net/qq_41860162/article/details/89098694
Python3-django-微信小程序支付接口调用
工具类生成一系列微信官方文档需要的数据
import hashlib import datetime import xml.etree.ElementTree as ET #商户平台上设置、查询 Mch_id="商户Id" client_appid="微信小程序APPId" Mch_key="支付交易秘钥" # 生成签名的函数 def paysign(appid, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee): ret = { "appid": appid, "body": body, "mch_id": mch_id, "nonce_str": nonce_str, "notify_url": notify_url, "openid": openid, "out_trade_no": out_trade_no, "spbill_create_ip": spbill_create_ip, "total_fee": total_fee, "trade_type": 'JSAPI' } # 处理函数,对参数按照key=value的格式,并按照参数名ASCII字典序排序 stringA = '&'.join(["{0}={1}".format(k, ret.get(k)) for k in sorted(ret)]) stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key) sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest() return sign.upper() # 生成随机字符串 def getNonceStr(): import random data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP" nonce_str = ''.join(random.sample(data, 30)) return nonce_str # 生成商品订单号 def getWxPayOrdrID(): date = datetime.datetime.now() # 根据当前系统时间来生成商品订单号。时间精确到微秒 payOrdrID = date.strftime("%Y%m%d%H%M%S%f") return payOrdrID # 获取全部参数信息,封装成xml def get_bodyData(openid, client_ip, price): body = 'Mytest' # 商品描述 notify_url = 'https://127.0.0.1:8000/payOrder/' # 支付成功的回调地址 可访问 不带参数 nonce_str = getNonceStr() # 随机字符串 out_trade_no = getWxPayOrdrID() # 商户订单号 total_fee = str(price) # 订单价格 单位是 分 # 获取签名 sign = paysign(client_appid, body, Mch_id, nonce_str, notify_url, openid, out_trade_no, client_ip, total_fee) bodyData = '<xml>' bodyData += '<appid>' + client_appid + '</appid>' # 小程序ID bodyData += '<body>' + body + '</body>' # 商品描述 bodyData += '<mch_id>' + Mch_id + '</mch_id>' # 商户号 bodyData += '<nonce_str>' + nonce_str + '</nonce_str>' # 随机字符串 bodyData += '<notify_url>' + notify_url + '</notify_url>' # 支付成功的回调地址 bodyData += '<openid>' + openid + '</openid>' # 用户标识 bodyData += '<out_trade_no>' + out_trade_no + '</out_trade_no>' # 商户订单号 bodyData += '<spbill_create_ip>' + client_ip + '</spbill_create_ip>' # 客户端终端IP bodyData += '<total_fee>' + total_fee + '</total_fee>' # 总金额 单位为分 bodyData += '<trade_type>JSAPI</trade_type>' # 交易类型 小程序取值如下:JSAPI bodyData += '<sign>' + sign + '</sign>' bodyData += '</xml>' return bodyData def xml_to_dict(xml_data): ''' xml to dict :param xml_data: :return: ''' xml_dict = {} root = ET.fromstring(xml_data) for child in root: xml_dict[child.tag] = child.text return xml_dict def dict_to_xml(dict_data): ''' dict to xml :param dict_data: :return: ''' xml = ["<xml>"] for k, v in dict_data.iteritems(): xml.append("<{0}>{1}</{0}>".format(k, v)) xml.append("</xml>") return "".join(xml) # 获取返回给小程序的paySign def get_paysign(prepay_id, timeStamp, nonceStr): pay_data = { 'appId': client_appid, 'nonceStr': nonceStr, 'package': "prepay_id=" + prepay_id, 'signType': 'MD5', 'timeStamp': timeStamp } stringA = '&'.join(["{0}={1}".format(k, pay_data.get(k)) for k in sorted(pay_data)]) stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key) sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest() return sign.upper()
后台调用工具类来发起
def getOrder(request) if request.method == 'POST': #获取用户 user_id=request.POST.get('userid') # 获取价格 print(request.get_host()) price = request.POST.get('price') print(price) # 获取客户端ip client_ip, port = request.get_host().split(":") # 获取小程序openid cur=connection.cursor() sql="select openid from users where id=%s" %(user_id) print(sql) cur.execute(sql) openid = cur.fetchall()[0][0] print(openid) # 请求微信的url url = "https://api.mch.weixin.qq.com/pay/unifiedorder" # 拿到封装好的xml数据 body_data = pay.get_bodyData(openid, client_ip, price) print() # 获取时间戳 timeStamp = str(int(time.time())) # 请求微信接口下单 respone = requests.post(url, body_data.encode("utf-8"), headers={'Content-Type': 'application/xml'}) # 回复数据为xml,将其转为字典 content = pay.xml_to_dict(respone.content) print(content) if content["return_code"] == 'SUCCESS': # 获取预支付交易会话标识 prepay_id = content.get("prepay_id") # 获取随机字符串 nonceStr = content.get("nonce_str") # 获取paySign签名,这个需要我们根据拿到的prepay_id和nonceStr进行计算签名 paySign = pay.get_paysign(prepay_id, timeStamp, nonceStr) # 封装返回给前端的数据 data = {"prepay_id": prepay_id, "nonceStr": nonceStr, "paySign": paySign, "timeStamp": timeStamp} return ht(dumps(data)) else: return ht("请求支付失败") else: return ht("error")
微信小程序前端请求自己写的pay接口成功后调用wx.requestPayment接口成功发起支付请求
pay:function(){ var self = this wx.request({ url: app.data.url + '/pay', data: { userid: app.data.user.id, price: 1 //parseInt(self.data.totalprice)*100 // 这里修改价格 }, method: "POST", header: { 'Content-Type': 'application/x-www-form-urlencoded' }, success: function (res) { console.log(res) if (true) { var payModel = res.data; wx.requestPayment({ 'timeStamp': payModel.timeStamp, 'nonceStr': payModel.nonceStr, 'package': "prepay_id=" + payModel.prepay_id, 'signType': 'MD5', 'paySign': payModel.paySign, 'success': function (res) { console.log("asdsasdasdasd",res) wx.showToast({ title: '支付成功', icon: 'success', duration: 1500, success: function () { setTimeout(function () { wx.switchTab({ url: '/pages/list/list', }) }, 1500); } }) //上传订单 var uplist = [] console.log("lalal", uplist) console.log("订单信息", self.data.list) for (var i = 0; i < self.data.list.length; i++) { uplist.push({ "userid": app.data.user.id, "goodid": self.data.list[i].id, "addressid": self.data.address.id, "number": self.data.list[i].count, "totalPrice": self.data.list[i].total_price, "date": self.data.date }) wx.request({ url: app.data.url + '/shopping/insertRecord', method: "POST", header: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: uplist[i], success: function () { console.log('好了一个'); } }) console.log("上传订单", uplist) } }, 'fail': function (res) { } }) } }, fail: function () { }, complete: function () { } }) }