小程序支付功能

详细流程步骤请看官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3

xcx.wxml

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

xcx.js

const app=getApp()
pay: function () {
    wx.request({
      url: app.globalData.URL + 'pay/',
      data: {
        token: wx.getStorageSync("token")
      },
      header: {
        "content-type": "application/json"
      },
      method: "POST",
      success: function (e) {
        console.log("pay_data", e)
        wx.requestPayment(
          {
            'timeStamp': e.data.data.timeStamp,
            'nonceStr': e.data.data.nonceStr,
            'package': e.data.data.package,
            'signType': 'MD5',
            'paySign': e.data.data.paySign,
            'success': function (res) {
              console.log("支付成功", res)
            },
            'fail': function (res) {
              console.log("支付失败", res)
            }
          })
      }
    })
  }

app.js

globalData: {
    userInfo: null,
    URL:"http://127.0.0.1:8000/",
  }

后台业务(重点)

urls.py

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    #path('admin/', admin.site.urls),
    #path('login/', views.LoginAPIView.as_view()),
    #path('userinfo/', views.UserInfo.as_view()),
    path('pay/', views.Pay.as_view()),
]

app01/wx/settings.py

# 小程序 appid
AppId="wx10658d6b326fd700"

# 小程序 appsecret
AppSecret="43cae8cf58c13b2323afef1f8d3c054b"

# 调用的微信后端接口
code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"

# 商户号
pay_mchid ='1415981402'
pay_apikey = 'xi34nu5jn7x2uujd8u4jiijd2u5d6j8e'

views.py---(由于商户号(mch_id)及pay_apikey需要申请或公司提供,所有本段代码无法本地运行验证)

class Pay(APIView):
    def post(self, request):
        # print(111111)
        param = request.data
        # 获取前台传入的token
        if param.get("token"):
            # 检验token 拿到缓存数据库中的 session_key与openid做绑定得到的 val
            cache_data = cache.get(param.get("token"))
            if cache_data:
                # 获取客户端ip,如果是负载均衡,就用HTTP_X_FORWARDED_FOR,如果不是就用下面的		
                # 通过 requests.META接口 向微信后端 获取参数 ip
                if request.META.get('HTTP_X_FORWARDED_FOR'):
                    self.ip = request.META['HTTP_X_FORWARDED_FOR']
                else:
                    self.ip = request.META['REMOTE_ADDR']
                session_key, self.openid = cache_data.split("&")
                # 获取所有返回参数 重点就是(prepay_id)
                data = self.get_pay_data()
                return Response({"code": 200, "msg": "suc", "data": data})
            else:
                return Response({"code": 202, "msg": "token无效"})
	# 获取参数nonce_str 随机字符串
    def get_nonce_str(self, num=30):
        # strs = ""
        # for i in range(30):
        #     strs += str(random.randint(0,9))  产生结果是一个列表
        all_str = "0123456789abcdefghijklmnopqrstuvwxyz"
        # 将列表内的所有字符串以''拼接得到一个字符串
        strs = "".join(random.sample(all_str, num)) 
        return strs
	# 获取参数out_trade_no
    def get_out_trade_no(self):
        import time
        strs = str(int(time.time())) + self.get_nonce_str(5)
        return strs
	# 获取参数 签名 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",
            "sign_type": "MD5",
            "appid": self.appid,
            "total_fee": self.total_fee,
            "mch_id": self.mch_id
        }
        # 对数据进行排序(sorted)并拼接成需求格式
        # sorted 是对 字典中的 key排序 key1, key2, key3, ...
        str_a = "&".join([f"{i}={data_dic[i]}" for i in sorted(data_dic)])
        str_b = f"{str_a}&key={settings.pay_apikey}"
        md5 = hashlib.md5()
        md5.update(str_b.encode("utf8"))
        return md5.hexdigest().upper()
	# 将 xml 数据转换成 字典
    def xml_to_dic(self, xml_data):
        # 导入 xml 
        import xml.etree.ElementTree as ET
        xml_data = ET.fromstring(xml_data)
        dic = {}
        for child in xml_data:
            dic[child.tag] = child.text
        return dic
	# 获取 prepay_id
    def get_prepay_data(self):
        url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
        response = requests.post(url=url, data=self.body_data.encode("utf8"),
        headers={"content-type": "application/xml"})
        xml_data = response.content
        dic_data = self.xml_to_dic(xml_data)
        return dic_data
	# 二次签名 
    def get_second_sign(self):
        self.second_nonceStr = self.get_nonce_str()
        self.timeStamp = str(int(time.time()))
        data_dic = {
            "appId": settings.AppId,
            "timeStamp": self.timeStamp,
            "nonceStr": self.second_nonceStr,
            "package": f"prepay_id={self.prepay_data.get('prepay_id')}",
            "signType": "MD5"
        }
        print(data_dic)
        str_a = "&".join([f"{i}={data_dic[i]}" for i in sorted(data_dic)])
        str_b = f"{str_a}&key={settings.pay_apikey}"
        md5 = hashlib.md5()
        md5.update(str_b.encode("utf8"))
        return md5.hexdigest().upper()
	# 支付功能 ,返回数据 data
    def get_pay_data(self):
        self.appid = settings.AppId
        self.mch_id = settings.pay_mchid
        self.nonce_str = self.get_nonce_str()
        self.sign_type = "MD5"
        self.body = "py11最难一届"
        self.out_trade_no = self.get_out_trade_no()
        self.total_fee = 1
        self.spbill_create_ip = self.ip
        self.notify_url = "http://www.weixin.qq.com/wxpay/pay.php"
        self.trade_type = "JSAPI"
        self.sign = self.get_sign()
        self.body_data = f"""
                <xml>
                <appid>{self.appid}</appid>
                <mch_id>{self.mch_id}</mch_id>
                <nonce_str>{self.nonce_str}</nonce_str>
                <sign>{self.sign}</sign>
                <body>{self.body}</body>
                <out_trade_no>{self.out_trade_no}</out_trade_no>
                <total_fee>1</total_fee>
                <sign_type>MD5</sign_type>
                <spbill_create_ip>{ self.spbill_create_ip}</spbill_create_ip>
                <notify_url>{self.notify_url}</notify_url>
                <openid>{self.openid}</openid>
                <trade_type>JSAPI</trade_type> 
                </xml>"""
        self.prepay_data = self.get_prepay_data()

        second_sign = self.get_second_sign()
        data = {
            "timeStamp": self.timeStamp,
            "nonceStr": self.second_nonceStr,
            "package": f"prepay_id={self.prepay_data.get('prepay_id')}",
            "paySign": second_sign
        }
        return data