python微信小程序支付方式
Jeff的技术栈 人气:0多支付
原理
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"])
支付方式代码
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"])
加载全部内容