网络编程
位置:首页>> 网络编程>> Python编程>> python实现微信小程序的多种支付方式

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

作者:Jeff的技术栈  发布时间:2021-03-26 21:38:58 

标签:python,微信小程序,支付方式

多支付

原理

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

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

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

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

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

多支付接口代码

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}")  # 调用对应的支付方式
       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支付

# 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支付方式

# YLpay支付方式
class YLpay:
   def pay(self,order_data):
       pass
   def notify(self,request_data):
       #验签
       #数据处理
       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 = "老男孩学费"
       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):
       #小程序提交给我们的数据
       '''
       {'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"])

来源:https://www.cnblogs.com/guyouyin123/p/12663537.html

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com