python+Django实现微信小程序支付功能

      微信支付有多种模式,刷卡支付扫码支付公众号支付APP支付小程序支付,这里我们只讨论小程序支付的实现,其他实现方式可以自行百度。

      首先我们必须先申请好商户号等信息,详情看https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_11&index=2,这里我们获取到商户号(Mch_id)和商户Key(Mch_key)两个信息,后面会用到。注意,我们需要在商户平台上绑定我们小程序的appid。

流程:

  1. 在自己的后台服务器上访问微信提供的接口,拿到预支付交易会话标识prepay_id、微信返回的随机字符串nonce_str,这两个参数是要返回给自己的小程序的,小程序在调起微信支付接口时需要这两个参数。
  2. 小程序拿到后台传递的参数,需要后台传递4个参数,后面详讲。然后在小程序上调起支付接口时传递我们拿到的参数,就可以完成支付。

第一步:

      在自己的后台服务器上访问微信提供的接口,需要携带一系列参数,这些参数的生成就是挺麻烦的事。这里先贴出微信的开发文档地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1。我们可以看到里面有些参数是必填的,有些不是,这里我们想快速完成,只要填好必填项就可以了。里面两个参数是需要我们计算的,下面逐个分析下:

生成随机字符串:

#方式一:
def getNonceStr():
    import random
    data="123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"
    nonce_str  = ''.join(random.sample(data , 30))
    return nonce_str

#方式二:
def get_nonce_str():
    import uuid

    return str(uuid.uuid4()).replace('-', '')

生成签名:

#生成签名的函数
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 getWxPayOrdrID():
    import datetime

    date=datetime.datetime.now()
    #根据当前系统时间来生成商品订单号。时间精确到微秒
    payOrdrID=date.strftime("%Y%m%d%H%M%S%f")

#方式二:
def getWxPayOrdrID():
    import time

    return str(int(time.time()))

生成paySign ,返回给小程序的参数之一:

#获取返回给小程序的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()

接下来我们写个函数来封装所有的参数信息:

#获取全部参数信息,封装成xml,传递过来的openid和客户端ip,和价格需要我们自己获取传递进来
def get_bodyData(openid,client_ip,price):
    body = 'Mytest'                    #商品描述
    notify_url = 'https:/.../'         #填写支付成功的回调地址,微信确认支付成功会访问这个接口
    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 payOrder(request,user_id):
    import time
    if request.method == 'POST':
        #获取价格
        price=request.POST.get("price")

        #获取客户端ip
        client_ip,port=request.get_host().split(":")

        #获取小程序openid
        openid=MyUser.objects.get(id=user_id).openid

        #请求微信的url
        url=configuration.order_url

        #拿到封装好的xml数据
        body_data=pay.get_bodyData(openid,client_ip,price)

        #获取时间戳
        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)

        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 HttpResponse(packaging_list(data))

        else:
            return HttpResponse("请求支付失败")
    else:
        return HttpResponse(request_code())

第二步

小程序调起接口:

// 支付按钮点击事件
  payTap: function(){
    var self = this;
    wx.request({
      url: 'https://127.0.0.1:8000/payOrder/',
      data: {
        openid: self.data.openid   // 这里正常项目不会只有openid一个参数
      },
      success: function(res){
        if(res.data.status == 100){
          var payModel = res.data;
          wx.requestPayment({
            'timeStamp': payModel.timestamp,
            'nonceStr': payModel.nonceStr,
            'package': payModel.package,
            'signType': 'MD5',
            'paySign': payModel.paySign,
            'success': function (res) {
              wx.showToast({
                title: '支付成功',
                icon: 'success',
                duration: 2000
              })
            },
            'fail': function (res) {
            }
          })
        }
      },
      fail: function(){

      }
    })
  },

github源码地址:https://github.com/xiaoyuan199/wechatPay

猜你喜欢

转载自blog.csdn.net/qq_34493908/article/details/81190057