微信登录

功能 - 微信小程序支付

作用:让小程序可以微信支付

虚拟商品

如果是虚拟商品,IOS平台暂时不允许

注册商户号

收入也是要合法啊

小程序和商户号(微信支付)绑定

登录微信公众平台,也就是小程序后台
功能 — 微信支付
2种情况:
1、已经有的就直接走起
2、没有的就去注册一个(注释:微信商户平台也就是微信支付,这里巨坑,名字会乱的,微信商户平台是旧名)

服务器/框架 创建数据库

3个表
1、订单表
2、订单商品数据表
3、支付回调数据表

准备openid

openid不要发送到前端,这是可以做到的

小程序-下单-商户系统

.wxml:

  1. <button bindtap="pay">支付</button>

.js:

  1. pay:function(){
  2. wx.request({
  3. url: "http://127.0.0.1:8000/pay/",
  4. method: "POST",
  5. data:{"login_key":wx.getStorageSync("login_key")},
  6. header: { "content-type": "application/json" },
  7. success: function (e) {
  8. console.log(e)
  9. // 签权调起支付
  10. wx.requestPayment({
  11. 'timeStamp': e.data.data.timeStamp,
  12. 'nonceStr': e.data.data.nonceStr,
  13. 'package': e.data.data.package,
  14. 'signType': e.data.data.signType,
  15. 'paySign': e.data.data.paySign,
  16. 'success': function (res)
  17. {
  18. console.log(res,"成功")
  19. //小程序轮询服务器订单信息
  20. that.checkThePayInfo(e.data.out_trade_no)
  21. },
  22. 'fail': function (res)
  23. {
  24. console.log("支付失败",res)
  25. },
  26. })
  27. }
  28. })
  29. },

1、url,后端/商户系统/服务器的路由
2、data传一个可以识别openid的编号

Flask

  • 商户系统-登录-微信服务器
  • 微信服务器-返回登录-商户系统
  • 商户系统生成订单
  • 商户系统-统一支付-微信服务器
  • 微信服务器-预付单-商户系统
  • 签名
  • 商户系统-返回支付参数-小程序
  1. from flask import Flask, jsonify, request, url_for,render_template,flash,make_response
  2. #蓝图config
  3. from flask import current_app as app
  4. import hashlib,time,random
  5. #向微信服务器发送https请求
  6. import requests
  7. @app.route('/pay', methods=['POST'])
  8. def pay1():
  9. pay = Pay()#1、实例化Pay
  10. data = pay.post(request)#2、使用Pay类的post方法
  11. return data #26、返回
  12. class Pay():
  13. def post(self,request):
  14. id = request.json.get('login_key') # 3、读取json,id用来获得openid
  15. print(id)
  16. openid = User.query.filter_by(pk=id).first().openid # 4、id获得openid
  17. self.openid=openid #5、写入这个类里
  18. self.ip = request.remote_addr # 6、获取ip地址
  19. data = self.pay()# 7、调用 生成商户订单 方法
  20. return jsonify({"code":200,"msg":"ok","data":data,"out_trade_no":self.out_trade_no})#25、返回
  21. # 生成商户订单 提供 支付统一下单 所需参数
  22. def pay(self):
  23. #8、准备一下参数
  24. self.appid=app.config["WEIXIN_APP_ID"]#9、小程序应用id
  25. self.mch_id=app.config["WEIXIN_APP_MCH_ID"]#10、商户号id
  26. self.nonce_str=self.get_str()#11、服务器自己获得一个随机数
  27. self.body="商品名" # 12、商品名一般由小程序端传到后端
  28. self.out_trade_no=self.get_order()#13、服务器生成一个订单
  29. self.total_fee=1 #14、价格:一般用服务器里的价格,不用小程序的
  30. self.spbill_create_ip=self.ip #15、ip
  31. self.notify_url=app.config["WEIXIN_NOTIFY_URL"]# 16、返回支付成功/失败的地址
  32. self.trade_type="JSAPI" #17、交易类型JSAPI
  33. self.sign = self.get_sign() # 18、获取sign 签名
  34. #19、写成XML格式
  35. data=f'''
  36. <xml>
  37. <appid>{self.appid}</appid>
  38. <body>{ self.body}</body>
  39. <mch_id>{self.mch_id}</mch_id>
  40. <nonce_str>{self.nonce_str}</nonce_str>
  41. <notify_url>{self.notify_url}</notify_url>
  42. <openid>{self.openid}</openid>
  43. <out_trade_no>{self.out_trade_no}</out_trade_no>
  44. <spbill_create_ip>{self.spbill_create_ip}</spbill_create_ip>
  45. <total_fee>{self.total_fee}</total_fee>
  46. <trade_type>{self.trade_type}</trade_type>
  47. <sign>{self.sign}</sign>
  48. </xml>
  49. '''
  50. # 20、支付统一下单
  51. url="https://api.mch.weixin.qq.com/pay/unifiedorder"
  52. # 21、返回预付单信息
  53. # response = urllib.request.urlopen(url,data.encode("utf-8"))
  54. response = requests.post(url,data.encode("utf-8"))
  55. print("微信返回信息")
  56. # print(response.read())
  57. # 22、xml转dict
  58. res_data=self.xml_to_dict(response.text)
  59. # print(res_data)
  60. # 23、二次签名
  61. data = self.two_sign(res_data["prepay_id"])
  62. return data #24、返回
  63. #11、服务器自己获得一个随机数
  64. def get_str(self):
  65. str_all="1234567890abcdefghjklmasdwery" # 注意 开发活动功能时, 去掉1,i,0,o
  66. nonce_str="".join(random.sample(str_all,20))
  67. return nonce_str
  68. # 13、服务器生成一个订单:包括时间+随机数
  69. def get_order(self):
  70. str_all = "1234567890abcdefghjklmasdwery"
  71. nonce_str = "".join(random.sample(str_all, 10))
  72. order_id = str(time.strftime("\\\\\\\\\\\\%Y\\\\\\\\\\\\%m\\\\\\\\\\\\%d\\\\\\\\\\\\%H\\\\\\\\\\\\%M\\\\\\\\\\\\%S") + nonce_str)
  73. return order_id
  74. # 18、获取sign 签名MD5
  75. def get_sign(self):
  76. data_dic = {
  77. "nonce_str": self.nonce_str,
  78. "out_trade_no": self.out_trade_no,
  79. "spbill_create_ip": self.ip,
  80. "notify_url": self.notify_url,
  81. "openid": self.openid,
  82. "body": self.body,
  83. "trade_type": "JSAPI",
  84. "appid": self.appid,
  85. "total_fee": self.total_fee,
  86. "mch_id": self.mch_id
  87. }
  88. sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
  89. sign_str = f"{sign_str}&key={app.config['WEIXIN_APP_MCH_KEY']}"
  90. md5 = hashlib.md5()
  91. md5.update(sign_str.encode("utf-8"))
  92. return md5.hexdigest().upper()
  93. # 23、二次签名,将组合数据再次签名
  94. def two_sign(self,prepay_id):
  95. timeStamp=str(int(time.time()))
  96. nonceStr=self.get_str()
  97. data_dict={
  98. "appId":app.config["WEIXIN_APP_ID"],
  99. "timeStamp":timeStamp,
  100. "nonceStr":nonceStr,
  101. "package":f"prepay_id={prepay_id}",
  102. "signType":"MD5"
  103. }
  104. sign_str = "&".join([f"{k}={data_dict[k]}" for k in sorted(data_dict)])
  105. sign_str = f"{sign_str}&key={app.config['WEIXIN_APP_MCH_KEY']}"
  106. md5 = hashlib.md5()
  107. md5.update(sign_str.encode("utf-8"))
  108. sign=md5.hexdigest().upper()
  109. data_dict["paySign"]=sign#加入paySign
  110. data_dict.pop("appId")#去掉appId
  111. # 返回支付参数到小程序端,小程序端获取所需参数向微信服务器发送 调起支付 方法
  112. return data_dict
  113. # 22、xml转dict处理,返回预付单方法
  114. def xml_to_dict(self,data):
  115. import xml.etree.ElementTree as ET
  116. xml_dict = {}
  117. data_dic = ET.fromstring(data)
  118. for item in data_dic:
  119. xml_dict[item.tag]=item.text
  120. return xml_dict

小程序-用户确认支付-微信服务器

也就是上面小程序的代码

微信服务器-推送支付结果-商户系统+商户系统更新订单状态

这里是设置notify_url的路由是啥,这里是/payback
算是示例代码

  1. @app.route('/payback', methods=['POST'])
  2. def Payback():
  3. print("微信回调来的数据")
  4. data = request.data
  5. print(data)
  6. dict = xml_to_dict2(data)
  7. print(dict)
  8. return_code = dict['return_code']
  9. if return_code == "SUCCESS":
  10. ##
  11. #这里是判断,详细看微信文档:API列表:支付结果通知
  12. ##
  13. print("succ")
  14. data = f'''
  15. < xml >
  16. < return_code > <![CDATA[SUCCESS]] > < / return_code >
  17. < return_msg > <![CDATA[OK]] > < / return_msg >
  18. < / xml >
  19. '''
  20. return data
  21. else:
  22. print("fail")
  23. data = f'''
  24. < xml >
  25. < return_code > <![CDATA[FAIL]] > < / return_code >
  26. < return_msg > <![CDATA[OK]] > < / return_msg >
  27. < / xml >
  28. '''
  29. return data
  30. # 处理返回预付单方法
  31. def xml_to_dict2(data):
  32. import xml.etree.ElementTree as ET
  33. xml_dict = {}
  34. data_dic = ET.fromstring(data)
  35. for item in data_dic:
  36. xml_dict[item.tag]=item.text
  37. return xml_dict

1、蓝图命名
2、对比判断有无出错

微信服务器-返回、展示支付结果-小程序

小程序轮询

  1. //轮询服务器订单信息
  2. checkThePayInfo(out_trade_no) {
  3. const requestTask = wx.request({
  4. url: Config.restUrl + '/checkThePayInfo', //仅为示例,并非真实的接口地址
  5. data: {
  6. x: out_trade_no,
  7. y: ''
  8. },
  9. header: {
  10. 'content-type': 'application/json'
  11. },
  12. success(res) {
  13. console.log(res.data.info)
  14. requestTask.abort() // 取消请求任务
  15. //返回墙页和刷新
  16. wx.navigateBack({
  17. url: '../logs/logs',
  18. })
  19. }
  20. })
  21. }

小程序-商户系统

  1. #小程序轮询
  2. @app.route('/checkThePayInfo', methods=['GET'])
  3. def checkThePayInfo():
  4. return {"info":"ok"}
功能 - 微信小程序支付