溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python怎么實現(xiàn)微信小程序的多種支付方式

發(fā)布時間:2022-04-13 10:36:43 來源:億速云 閱讀:139 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“python怎么實現(xiàn)微信小程序的多種支付方式”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“python怎么實現(xiàn)微信小程序的多種支付方式”吧!

多支付

原理

1.利用鴨子類型。規(guī)定前臺傳過來支付方式。pay_methon
2.再支付方式里面實現(xiàn)pay(名字統(tǒng)一)方法
3.回調(diào)函數(shù),在支付方式里面寫notify(名字統(tǒng)一)統(tǒng)一方法,返回的data統(tǒng)一格式。
		eg: data={"statu":'success',"order_id":notity_data['order_id'],"print":"0000"}

        
   這樣的的牛逼之處:我們在修改、添加支付方式的時候,只需要按照鴨子類型,命名一樣的函數(shù)名,寫好自己的支付方式即可。不需要改其他的代碼

多支付接口代碼

urls.py:

path("order/create",order.Creat.as_view()),

path("order/notify/<paymethod>",order.Notify.as_view())
# 這里所有的支付都是走的小程序微信支付:

import importlib

class Creat(APIView):
    ...偽代碼
    
    pay_methon = "Wxpay"  # 如果是PC端,可以前臺傳過來支付方式
    try:
        #pay_file是對象
        pay_file = importlib.import_module(f"app01.Pay.{pay_methon}")  # 調(diào)用對應(yīng)的支付方式
        pay_class = getattr(pay_file, pay_methon)  # 反射機制
        order_data['open_id'] = openid # 傳的參數(shù)
        order_data['ip'] = host_ip  # 傳的參數(shù)
        data = pay_class().pay(order_data)  # 調(diào)用支付
    except:
        return  Response({"code":201,"msg":"未知支付方式"})



# 異步回調(diào)的
class Notify(APIView):
    def post(self,request,paymethod):
        pay_file = importlib.import_module(f"app01.Pay.{paymethod}")
        pay_class = getattr(pay_file,paymethod)
        data = pay_class().notify(request.data)  # 調(diào)用異步回調(diào)

        # 判斷data數(shù)據(jù)中屬性,然后修改訂單
        if data["statu"] == "success":
            models.Order.objects.filter(order_id =data['order_id']).update(pay_status =1)
            return Response(data["print"])

支付方式代碼

python怎么實現(xiàn)微信小程序的多種支付方式

Alipay支付

# Alipay支付
class Alipay:
    def pay(self,order_data):
        #統(tǒng)一下單方法
        pass


    def notify(self,notity_data):
        if notity_data['success'] :
            #notity_data['order_id']表示商城訂單號
            data={"statu":'success',"order_id":notity_data['order_id'],"print":"0000"}
            return   data

YLpay支付方式

# YLpay支付方式

class YLpay:
    def pay(self,order_data):
        pass


    def notify(self,request_data):
        #驗簽
        #數(shù)據(jù)處理
        pass

Wxpay支付方式

import time
from app01.wx import settings


class Wxpay:
    def pay(self,order_data):
        self.order_id = order_data["order_id"]
        self.open_id = order_data['open_id']
        self.ip = order_data['ip']
        data_body = self.get_body_data()
        import requests
        url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
        response = requests.post(url, data_body.encode("utf-8"), headers={'content-type': "application/xml"})
        res_dict = self.xml_to_dic(response.content)
        timeStamp = str(int(time.time()))
        paySign = self.get_pay_sign(res_dict, timeStamp)

        data_dic = {
            'timeStamp': timeStamp,
            'nonceStr': res_dict['nonce_str'],
            'package': f"prepay_id={res_dict['prepay_id']}",
            'signType': 'MD5',
            "paySign": paySign,
        }

        return data_dic

    def get_pay_sign(self, res_dict, timeStamp):
        data_dic = {
            'appId': res_dict['appid'],
            'timeStamp': timeStamp,
            'nonceStr': res_dict['nonce_str'],
            'package': f"prepay_id={res_dict['prepay_id']}",
            "signType": "MD5"
        }
        sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
        sign_str = f"{sign_str}&key={settings.pay_apikey}"
        import hashlib
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        sign = md5.hexdigest()
        return sign.upper()

    def xml_to_dic(self, xml_data):
        import xml.etree.ElementTree as ET
        '''
        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 get_random(self):
        import random
        data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"
        nonce_str = "".join(random.sample(data, 30))
        return nonce_str



    def get_sign(self):
        data_dic = {
            "nonce_str": self.nonce_str,
            "out_trade_no": self.out_trade_no,
            "spbill_create_ip": self.spbill_create_ip,
            "notify_url": self.notify_url,
            "openid": self.open_id,
            "body": self.body,
            "trade_type": "JSAPI",
            "appid": self.appid,
            "total_fee": "1",
            "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}"
        import hashlib
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        sign = md5.hexdigest()
        return sign.upper()

    def get_body_data(self):
        self.appid = settings.AppId
        # openid=self.open_id
        self.mch_id = str(settings.pay_mchid)
        self.nonce_str = self.get_random()
        self.out_trade_no = self.order_id
        self.spbill_create_ip = self.ip
        self.notify_url = "https://www.test.com"
        self.body = "老男孩學(xué)費"
        self.sign = self.get_sign()
        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>
               <spbill_create_ip>{ self.spbill_create_ip}</spbill_create_ip>
               <notify_url>{self.notify_url}</notify_url>
               <openid>{self.open_id}</openid>
               <trade_type>JSAPI</trade_type> 
           </xml>"""
        return body_data

Creat下訂單

from  rest_framework.views import  APIView
from rest_framework.response import  Response
from app01.wx import wx_login
import hashlib ,time
from app01 import models
from django.core.cache import cache
from django.db import transaction
from app01.func import function_tool
import importlib

class Creat(APIView):
    @transaction.atomic
    def post(self,request):
        #小程序提交給我們的數(shù)據(jù)
        '''
        {'token': '0bb2aa1102ca9c8306133b2539c3508b',
        'remark': '',
        'province': '廣東省',
        'city': '廣州市',
        'county': '海珠區(qū)',
        'address':
        '新港中路397號',
        'phone': '020-81167888',
        'name': '張三',
        'buy_list': {'2': 1}}
        '''
        param = request.data
        if param.get("token") and param.get("buy_list"):
            user_cache = cache.get(param["token"])
            if user_cache:
                # 獲取ip
                if request.META.get("HTTP_X_FORWARDED_FOR"):
                    host_ip = request.META["HTTP_X_FROWARDED_FOR"]
                else:
                    host_ip = request.META["REMOTE_ADDR"]
                openid = user_cache.split("&")[0]  #data['openid']+"&"+data["session_key"]
                user_data = models.Wxuser.objects.filter(openid=openid).first()
                order_data = {
                    "consignee_mobile": param['phone'],
                    'consignee_name': param['name'],
                    'wxuser_id': user_data.id,
                    "memo": param['remark'],
                    "consignee_area": f"{param['province']},{param['city']},{param['county']}",
                    "consignee_address": param['address'],
                    "order_id": function_tool.get_order_id(),
                    "order_total": 0
                }
                # 1 上面的order_data 出來上面的數(shù)據(jù),有些是需要通過購買上面列表做累加才能獲得到
                # 2 order_item 是通過buy_list里面的商品列表,一個鍵值對就是一條記入'buy_list': {'2': 1,“1”:2}
                # 3 再每一次增加一個order_item的時候,我們都需要校驗庫存。如果有一個商品的庫存不足,我們就應(yīng)該不然用戶下單
                # 4 由于第三步中進行多次增加,如果再后面的的商品庫存有問題,我們不讓他下單,但是前面的數(shù)據(jù)已經(jīng)插入。
                # 所有我們要用數(shù)據(jù)庫的事務(wù)管理數(shù)據(jù)的統(tǒng)一。就算order_item沒有問題,order_data,插入的時候,也可能出錯,所以也要用事務(wù)
                # 5 由于并發(fā)問題,所有的用戶都會對數(shù)據(jù)的庫存進行加減,所以我們這里再校驗庫存的時候要用鎖。
                buy_list = param.get("buy_list")
                # 獲取到buy_list是沒有商品信息只有有id,我們先把buy_list中的所有商品查出來
                goods_key = list(buy_list.keys())
                all_product = models.Product.objects.filter(product_id__in = goods_key)
                #用for循環(huán)添加order_item

                sid = transaction.savepoint()
                for product in all_product:
                    # 將product.product_id 轉(zhuǎn)字符串,為了通過product.product_id在buy_list獲取商品的購買數(shù)量
                    product.product_id = str(product.product_id)
                    # 獲取訂單總金額
                    order_data['order_total'] += product.price* buy_list[product.product_id]

                    for i in range(3):
                        #先查庫存,重新查庫的
                        stock = product.stock.quantity

                        #當(dāng)前的庫存的庫存數(shù)量,減去購買數(shù)量,是否大于0
                        new_stock = stock-buy_list[product.product_id]
                        if new_stock < 0 :
                            #庫存不足,回滾
                            transaction.savepoint_rollback(sid)
                            return Response({"code":201,"msg": f"{product.name}庫存不足"})
                        #樂觀鎖
                        res = models.Stock.objects.filter(quantity= stock,stock_id =product.stock.stock_id).update(quantity = new_stock)
                        if not res:
                            if i == 2:
                                transaction.savepoint_rollback(sid)
                                return  Response({"code":201,"msg": "創(chuàng)建訂單失敗"})
                            else:
                                continue
                        else:
                            break
                    #獲取購買數(shù)量
                    new_buy_cout = product.buy_count + buy_list[product.product_id]
                    models.Product.objects.filter(product_id=product.product_id).update(buy_count =new_buy_cout)
                    #組織order_item的數(shù)據(jù)
                    order_item_data = {
                         'order_id': order_data['order_id'],
                         'product_id': product.product_id,
                         "name": product.name,
                         "image": product.image,
                         "price": product.price,
                          "nums": buy_list[product.product_id],
                          "brief": product.brief
                     }
                    models.Order_items.objects.create(**order_item_data)

                models.Order.objects.create(**order_data)
                transaction.savepoint_commit(sid)

                #所有的支付都是走的小程序微信支付:
                pay_methon = "Wxpay"
                try:
                    #pay_file是對象
                    pay_file = importlib.import_module(f"app01.Pay.{pay_methon}")
                    pay_class = getattr(pay_file, pay_methon)
                    order_data['open_id'] = openid
                    order_data['ip'] = host_ip
                    data = pay_class().pay(order_data)
                except:
                    return  Response({"code":201,"msg":"未知支付方式"})

                # 1對接小程序支付
                # 2 我們要用celery去定時檢查,該訂單在指定時間內(nèi)用沒有支付,沒有支付,取消訂單,回滾庫存
                function_tool.pay_status(order_data['order_id'])
                return  Response({"code":200,"msg":"ok","data":data})

            else:
                return Response({"code": 201, "msg": "無效的token"})

        else:
            return Response({"code":202,"msg":"缺少參數(shù)"})


class Notify(APIView):
    def post(self,request,paymethod):
        pay_file = importlib.import_module(f"app01.Pay.{paymethod}")
        pay_class = getattr(pay_file,paymethod)
        data = pay_class().notify(request.data)

        # 判斷data數(shù)據(jù)中屬性,然后修改訂單
        if data["statu"] == "success":
            models.Order.objects.filter(order_id =data['order_id']).update(pay_status =1)
            return Response(data["print"])

到此,相信大家對“python怎么實現(xiàn)微信小程序的多種支付方式”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI