脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - python实现微信小程序的多种支付方式

python实现微信小程序的多种支付方式

2022-11-28 10:00Jeff的技术栈 Python

这篇文章主要为大家介绍了python实现微信小程序的多种支付方式的实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪

多支付

原理

1.利用鸭子类型。规定前台传过来支付方式。pay_methon

2.再支付方式里面实现pay(名字统一)方法

3.回调函数,在支付方式里面写notify(名字统一)统一方法,返回的data统一格式。   

eg: data={"statu":'success',"order_id":notity_data['order_id'],"print":"0000"}

 这样的的牛逼之处:我们在修改、添加支付方式的时候,只需要按照鸭子类型,命名一样的函数名,写好自己的支付方式即可。不需要改其他的代码

多支付接口代码

urls.py:

?
1
2
path("order/create",order.Creat.as_view()),
path("order/notify/<paymethod>",order.Notify.as_view())
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 这里所有的支付都是走的小程序微信支付:
import importlib
class Creat(APIView):
    ...伪代码
    pay_methon = "Wxpay"  # 如果是PC端,可以前台传过来支付方式
    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":"未知支付方式"})
# 异步回调的
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数据中属性,然后修改订单
        if data["statu"] == "success":
            models.Order.objects.filter(order_id =data['order_id']).update(pay_status =1)
            return Response(data["print"])

支付方式代码

python实现微信小程序的多种支付方式

Alipay支付

?
1
2
3
4
5
6
7
8
9
10
# Alipay支付
class Alipay:
    def pay(self,order_data):
        #统一下单方法
        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支付方式

?
1
2
3
4
5
6
7
8
# YLpay支付方式
class YLpay:
    def pay(self,order_data):
        pass
    def notify(self,request_data):
        #验签
        #数据处理
        pass

Wxpay支付方式

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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 = "老男孩学费"
        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下订单

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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):
        #小程序提交给我们的数据
        '''
        {'token': '0bb2aa1102ca9c8306133b2539c3508b',
        'remark': '',
        'province': '广东省',
        'city': '广州市',
        'county': '海珠区',
        '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 出来上面的数据,有些是需要通过购买上面列表做累加才能获得到
                # 2 order_item 是通过buy_list里面的商品列表,一个键值对就是一条记入'buy_list': {'2': 1,“1”:2}
                # 3 再每一次增加一个order_item的时候,我们都需要校验库存。如果有一个商品的库存不足,我们就应该不然用户下单
                # 4 由于第三步中进行多次增加,如果再后面的的商品库存有问题,我们不让他下单,但是前面的数据已经插入。
                # 所有我们要用数据库的事务管理数据的统一。就算order_item没有问题,order_data,插入的时候,也可能出错,所以也要用事务
                # 5 由于并发问题,所有的用户都会对数据的库存进行加减,所以我们这里再校验库存的时候要用锁。
                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循环添加order_item
 
                sid = transaction.savepoint()
                for product in all_product:
                    # 将product.product_id 转字符串,为了通过product.product_id在buy_list获取商品的购买数量
                    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
                        #当前的库存的库存数量,减去购买数量,是否大于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": "创建订单失败"})
                            else:
                                continue
                        else:
                            break
                    #获取购买数量
                    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的数据
                    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去定时检查,该订单在指定时间内用没有支付,没有支付,取消订单,回滚库存
                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":"缺少参数"})
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数据中属性,然后修改订单
        if data["statu"] == "success":
            models.Order.objects.filter(order_id =data['order_id']).update(pay_status =1)
            return Response(data["print"])

以上就是python实现微信小程序的多种支付方式的详细内容,更多关于python微信支付方式的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/guyouyin123/p/12663537.html

延伸 · 阅读

精彩推荐
  • Pythonpython ChainMap的使用和说明详解

    python ChainMap的使用和说明详解

    这篇文章主要介绍了python ChainMap的使用和说明详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    茫茫碧落7952021-07-09
  • PythonDjango集成富文本编辑器summernote的实现步骤

    Django集成富文本编辑器summernote的实现步骤

    在最近的项目中小编使用了这个富文本编辑器,选择它的主要原因是配置非常简单,默认支持普通用户上传图片(不像ckeditor默认只有staff user才能上传图片。...

    大江狗6122021-11-18
  • Python浅谈python中的getattr函数 hasattr函数

    浅谈python中的getattr函数 hasattr函数

    下面小编就为大家带来一篇浅谈python中的getattr函数 hasattr函数。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    Python教程网2842020-08-27
  • PythonPython利用 matplotlib 绘制直方图

    Python利用 matplotlib 绘制直方图

    这篇文章主要介绍了Python利用 matplotlib 模块绘制直方图相关属性和方法,具有一定的参考价值,需要的朋友可以参考一下...

    盆友圈的小可爱5782022-03-11
  • Pythondjango中的setting最佳配置小结

    django中的setting最佳配置小结

    setting配置也经常将一些配置混淆今天主要是介绍django中的setting最佳配置小结,需要的朋友参考下吧...

    布吉岛丶3052020-12-19
  • Pythonpython+selenium识别验证码并登录的示例代码

    python+selenium识别验证码并登录的示例代码

    本篇文章主要介绍了python+selenium识别验证码并登录的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    ck320713012020-12-27
  • Pythonpython基于tkinter实现gif录屏功能

    python基于tkinter实现gif录屏功能

    一直在思索实现一个透明的窗体,然后可以基于这个窗体可以开发出各种好玩的应用,这一期,我们将实现有趣的GIF录屏功能...

    dhjabc_111512021-11-07
  • Pythonpython中pandas对多列进行分组统计的实现

    python中pandas对多列进行分组统计的实现

    分组统计在很多时候都需要用到,可以实现很多数据库函数的功能。本文主要介绍了python中pandas对多列进行分组统计的实现,感兴趣的可以了解一下...

    光于前裕于后10682021-12-03