微信小程序——支付

小程序支付是专门被定义使用在小程序中的支付产品。目前在小程序中能且只能使用小程序支付的方式来唤起微信支付。

先判断协议字段返回,再判断业务返回,最后判断交易状态

除被扫支付场景以外,商户系统先调用统一下单接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI、APP、小程序等不同场景生成交易串调起支付
注意:
appid必须为最后拉起收银台的小程序appid;
mch_id为和appid成对绑定的支付商户号,收款资金会进入该商户号;
trade_type请填写JSAPI;
openid为appid对应的用户标识,即使用wx.login接口获得的openid


//test.wxml
<button bind:tap="pay">支付</button>
//test.js
Page({
pay:function(){
    wx.request({
      url: "http://111.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,"成功")
            },
          'fail': function (res)
          {
            console.log("支付失败",res)
           },     
        })
      }
    })
  },
})


from rest_framework.views import  APIView
from  rest_framework.response import  Response
from django.core.cache import cache
import hashlib,time
import random
from app01.wx import settings
import requests
class Pay(APIView):
    def post(self,request):
        param=request.data
        if param.get("login_key"):            #从redis中拿到小程序端login_key所对应得opendi&session_key值
            openid,session_key=cache.get(param.get("login_key")).split("&")
            self.openid=openid
            # 获取用户IP
            # 1.如果是Nginx做的负载就要HTTP_X_FORWARDED_FOR
            if request.META.get('HTTP_X_FORWARDED_FOR'):
                self.ip =request.META['HTTP_X_FORWARDED_FOR']
            else:
                # 2.如果没有用Nginx就用REMOTE_ADDR
                self.ip = request.META['REMOTE_ADDR']
            # 调用 生成商户订单 方法
            data = self.pay()
            return Response({"code":200,"msg":"ok","data":data})
        else:
            return Response({"code":200,"msg":"缺少参数"})

    def get_str(self):
        str_all="1234567890abcdefghjklmasdwery"  # 注意 开发活动功能时, 去掉1,i,0,o
        nonce_str="".join(random.sample(str_all,20))
        return nonce_str

    def get_order(self):
        order_id=str(time.strftime("%Y%m%d%H%M%S"))
        return order_id

    # 处理返回预付单方法
    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

    # 获取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",
            "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={settings.pay_apikey}"
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        return md5.hexdigest().upper()

    # 1.生成商户订单 提供 支付统一下单 所需参数
    def pay(self):
        self.appid=settings.AppId
        self.mch_id=settings.pay_mchid
        self.nonce_str=self.get_str()
        self.body="商品名"  # 商品名一般由小程序端传到后端
        self.out_trade_no=self.get_order()
        self.total_fee=1
        self.spbill_create_ip=self.ip
        self.notify_url="http://www.baidu.com"
        self.trade_type="JSAPI"
        self.sign = self.get_sign()  # 获取sign 签名
        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>
        '''
        # 2.支付统一下单
        url="https://api.mch.weixin.qq.com/pay/unifiedorder"
        # 3.返回预付单信息
        response=requests.post(url,data.encode("utf-8"),headers={"content-type":"application/xml"})
        res_data=self.xml_to_dict(response.content)
        data=self.two_sign(res_data["prepay_id"])
        return  data

    # 4.将组合数据再次签名
    def two_sign(self,prepay_id):
        timeStamp=str(int(time.time()))
        nonceStr=self.get_str()
        data_dict={
            "appId":settings.AppId,
            "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={settings.pay_apikey}"
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        sign=md5.hexdigest().upper()
        data_dict["paySign"]=sign
        data_dict.pop("appId")
        # 5.返回支付参数到小程序端,小程序端获取所需参数向微信服务器发送 调起支付 方法
        return  data_dict
项目/urls.py

猜你喜欢

转载自blog.csdn.net/wwwwrrrrwr/article/details/128151346