支付限额了怎么才能使用(支付宝支付)
导读:支付宝支付流程 在python中封装alipay 安装...
支付宝支付流程
在python中封装alipay
安装 >: pip install python-alipay-sdk --upgrade # 如果抛ssl相关错误 ,代表缺失该包 >: pip install pyopenssl 结构 libs ├── AliPay # aliapy二次封装包 │ ├── __init__.py # 包文件 │ ├── pem # 公钥私钥文件夹 │ │ ├── alipay_public_key.pem # 支付宝公钥文件 │ │ ├── app_private_key.pem # 应用私钥文件 │ ├── pay.py # 支付文件 └── └── settings.py # 应用配置 alipay_public_key.pemhttps://openhome.alipay.com/develop/sandbox/account
前往支付宝开放平台 ,注册沙箱环境获取支付宝公钥和应用私钥 ,进行测试 。 -----BEGIN PUBLIC KEY----- 拿应用公钥跟支付宝换来的支付宝公钥 -----END PUBLIC KEY----- app_private_key.pem -----BEGIN RSA PRIVATE KEY----- 通过支付宝公钥私钥签发软件签发的应用私钥 -----END RSA PRIVATE KEY----- setting.py import os # 应用私钥 APP_PRIVATE_KEY_STRING = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), pem, app_private_key.pem)).read() # 支付宝公钥 ALIPAY_PUBLIC_KEY_STRING = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), pem, alipay_public_key.pem)).read() # 应用ID APP_ID = 2016093000631831 # 加密方式 SIGN = RSA2 # 是否是支付宝测试环境(沙箱环境) ,如果采用真是支付宝环境 ,配置False DEBUG = True # 支付网关 GATEWAY = https://openapi.alipaydev.com/gateway.do? if DEBUG else https://openapi.alipay.com/gateway.do? pay.py from alipay import AliPay from . import settings # 支付对象 alipay = AliPay( appid=settings.APP_ID, app_notify_url=None, app_private_key_string=settings.APP_PRIVATE_KEY_STRING, alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY_STRING, sign_type=settings.SIGN, debug=settings.DEBUG ) # 支付网关 gateway = settings.GATEWAY init.py # 包对外提供的变量 from .pay import gateway, alipay支付相关模型表的设计
""" class Order(models.Model): # 主键 、总金额 、订单名 、订单号 、订单状态 、创建时间 、支付时间 、流水号 、支付方式 、支付人(外键) - 优惠劵(外键 ,可为空) pass class OrderDetail(models.Model): # 订单号(外键) 、商品(外键) 、实价 、成交价 - 商品数量 pass """ from django.db import models from user.models import User from course.models import Course class Order(models.Model): """订单模型""" status_choices = ( (0, 未支付), (1, 已支付), (2, 已取消), (3, 超时取消), ) pay_choices = ( (1, 支付宝), (2, 微信支付), ) subject = models.CharField(max_length=150, verbose_name="订单标题") total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="订单总价", default=0) out_trade_no = models.CharField(max_length=64, verbose_name="订单号", unique=True) trade_no = models.CharField(max_length=64, null=True, verbose_name="流水号") order_status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="订单状态") pay_type = models.SmallIntegerField(choices=pay_choices, default=1, verbose_name="支付方式") pay_time = models.DateTimeField(null=True, verbose_name="支付时间") user = models.ForeignKey(User, related_name=order_user, on_delete=models.DO_NOTHING, db_constraint=False, verbose_name="下单用户") created_time = models.DateTimeField(auto_now_add=True, verbose_name=创建时间) class Meta: db_table = "luffy_order" verbose_name = "订单记录" verbose_name_plural = "订单记录" def __str__(self): return "%s - ¥%s" % (self.subject, self.total_amount) @property def courses(self): data_list = [] for item in self.order_courses.all(): data_list.append({ "id": item.id, "course_name": item.course.name, "real_price": item.real_price, }) return data_list class OrderDetail(models.Model): """订单详情""" order = models.ForeignKey(Order, related_name=order_courses, on_delete=models.CASCADE, db_constraint=False, verbose_name="订单") course = models.ForeignKey(Course, related_name=course_orders, on_delete=models.CASCADE, db_constraint=False, verbose_name="课程") price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程原价") real_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程实价") class Meta: db_table = "luffy_order_detail" verbose_name = "订单详情" verbose_name_plural = "订单详情" def __str__(self): try: return "%s的订单:%s" % (self.course.name, self.order.out_trade_no) except: return super().__str__()订单模块接口的设计分析
1.点击购买 ,产生支付接口(生成支付订单(往order和订单详情表插入数据) ,生成支付链接 ,返回支付链接)
2.支付宝异步回调的post接口(验证签名、修改订单状态)
3.当支付宝get回调给前端页面(告诉前端支付成功了),此时vue组件一创建 ,我们在写一个get请求询问后端是否支付成功 。支付接口
serializes.py
from rest_framework import serializers from . import models from rest_framework.exceptions import ValidationError from course.models import Course from django.conf import settings class OrderSerializer(serializers.ModelSerializer): # 要支持单购物和群购物(购物车) ,前台要提交 课程主键(们) # PrimaryKeyRelatedField方法的作用就是把课程id的列表对象 ,转换为课程对象的列表对象 course = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), write_only=True, many=True) class Meta: model = models.Order fields = [subject,total_amount,pay_type,course] # 这些字段是需要前端传给我们进行反序列化的 def _check_price(self,attrs): total_amount = attrs.get(total_amount) course_list = attrs.get(course) total_price = 0 for course in course_list: total_price += course.price if total_amount != total_price: raise ValidationError(价格不正确) return total_amount def _gen_order(self): import uuid return str(uuid.uuid4()).replace(-,) def _get_user(self): request = self.context.get(request) return request.user def _get_pay_url(self,out_trade_no,total_amount,subject): from luffyapi.libs.al_pay import alipay,gateway order_string = alipay.api_alipay_trade_page_pay ( out_trade_no=out_trade_no, total_amount=total_amount, subject=subject, return_url=settings.RETURN_URL, notify_url=settings.NOTIFY_URL ) return gateway+order_string def _before_create(self,attrs,user,pay_url,out_trade_no): attrs[user] = user attrs[out_trade_no] = out_trade_no self.context[pay_url]=pay_url def validate(self, attrs): """ #1)订单总价校验 # 2)生成订单号 # 3)支付用户:request.user # 4)支付链接生成 # 5)入库(两个表)的信息准备 :param attrs: :return: """ # 1)订单总价校验 total_amount = self._check_price(attrs) # 2)生成订单号 out_trade_no = self._gen_order() # 3)支付用户:request.user user = self._get_user() # 4)支付链接生成 pay_url = self._get_pay_url(out_trade_no,total_amount,attrs.get(subject)) # 5)入库(两个表)的信息准备 self._before_create(attrs,user,pay_url,out_trade_no) return attrs # 重写create方法 def create(self, validated_data): course_list = validated_data.pop(course) order = models.Order.objects.create(**validated_data) for course in course_list: models.OrderDetail.objects.create(order=order,course=course,price=course.price,real_price=course.price) return orderviews.py
from django.shortcuts import render from rest_framework.viewsets import ViewSet,GenericViewSet from rest_framework.mixins import CreateModelMixin from rest_framework.decorators import action from luffyapi.utils.response import APIResponse from . import models from . import serializers from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response class PayView(GenericViewSet,CreateModelMixin): queryset = models.Order.objects.all() serializer_class = serializers.OrderSerializer # 下面这两句话是为了给立即购买接口增加认证和权限:只有登录用户才能点击购买 authentication_classes = [JSONWebTokenAuthentication,] permission_classes = [IsAuthenticated,] # 重写CreateModelMixin里的create方法,返回自定义的response和添加context def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data,context={request:request}) serializer.is_valid(raise_exception=True) self.perform_create(serializer) return Response(serializer.context.get(pay_url))前端在立即购买按钮下定义一个方法
// 点击立即购买时 ,定义一个方法并把课程信息传入 buy_now(course) { // 先获取一个token ,获取不到则提示需要先登录 let token = this.$cookies.get(token) if (!token) { this.$message({ message: "请先登录!", }) return false } // 有token,则想后端发送post请求 ,拿到支付链接 this.$axios( { method: post, url: this.$settings.base_url + /order/pay/, data: { "subject": course.name, "total_amount":course.price, "pay_type": 1, "course": [ course.id, ] }, headers: {Authorization: jwt + token}, } ) .then(response => { // 成功拿到支付链接之后 ,采用open方法 ,指定页面跳转支付页面 let pay_url = response.data // _self指定当前页面直接跳,而不是在新窗口跳转 open(pay_url,_self) }).catch(error => { }) },支付成功前端页面
<template> <div class="pay-success"> <!--如果是单独的页面 ,就没必要展示导航栏(带有登录的用户)--> <Header/> <div class="main"> <div class="title"> <div class="success-tips"> <p class="tips">您已成功购买 1 门课程!</p> </div> </div> <div class="order-info"> <p class="info"><b>订单号:</b><span>{{ result.out_trade_no }}</span></p> <p class="info"><b>交易号:</b><span>{{ result.trade_no }}</span></p> <p class="info"><b>付款时间:</b><span><span>{{ result.timestamp }}</span></span></p> </div> <div class="study"> <span>立即学习</span> </div> </div> </div> </template> <script> import Header from "@/components/Header" export default { name: "Success", data() { return { result: {}, }; }, created() { // url后拼接的参数:?及后面的所有参数 => ?a=1&b=2 // console.log(location.search); // 解析支付宝回调的url参数 let params = location.search.substring(1); // 去除? => a=1&b=2 let items = params.length ? params.split(&) : []; // [a=1, b=2] //逐个将每一项添加到args对象中 for (let i = 0; i < items.length; i++) { // 第一次循环a=1 ,第二次b=2 let k_v = items[i].split(=); // [a, 1] //解码操作 ,因为查询字符串经过编码的 if (k_v.length >= 2) { // url编码反解 let k = decodeURIComponent(k_v[0]); this.result[k] = decodeURIComponent(k_v[1]); // 没有url编码反解 // this.result[k_v[0]] = k_v[1]; } } // 解析后的结果 // console.log(this.result); // 把地址栏上面的支付结果 ,再get请求转发给后端 this.$axios({ url: this.$settings.base_url + /order/success/ + location.search, method: get, }).then(response => { console.log(response.data); }).catch(() => { console.log(支付结果同步失败); }) }, components: { Header, } } </script> <style scoped> .main { padding: 60px 0; margin: 0 auto; width: 1200px; background: #fff; } .main .title { display: flex; -ms-flex-align: center; align-items: center; padding: 25px 40px; border-bottom: 1px solid #f2f2f2; } .main .title .success-tips { box-sizing: border-box; } .title img { vertical-align: middle; width: 60px; height: 60px; margin-right: 40px; } .title .success-tips { box-sizing: border-box; } .title .tips { font-size: 26px; color: #000; } .info span { color: #ec6730; } .order-info { padding: 25px 48px; padding-bottom: 15px; border-bottom: 1px solid #f2f2f2; } .order-info p { display: -ms-flexbox; display: flex; margin-bottom: 10px; font-size: 16px; } .order-info p b { font-weight: 400; color: #9d9d9d; white-space: nowrap; } .study { padding: 25px 40px; } .study span { display: block; width: 140px; height: 42px; text-align: center; line-height: 42px; cursor: pointer; background: #ffc210; border-radius: 6px; font-size: 16px; color: #fff; } </style> { path: /pay/success/, name: PaySuccess, component: PaySuccess },支付宝同步异步回调
支付成功之后 ,支付宝会给前端发送一个post回调 ,我们也需要在用户支付成功之后 ,在前端添加一个同步的get回调 ,以此来反馈给前端 ,用户是否支付成功!!
path(success/,views.SuccessView.as_view()), class SuccessView(APIView): def get(self,request,*args,**kwargs): out_trade_no=request.query_params.get(out_trade_no) order=models.Order.objects.filter(out_trade_no=out_trade_no).first() if order.order_status==1: return Response(True) else: return Response(False) def post(self,request,*args,**kwargs): 支付宝回调接口 from luffyapi.libs.al_pay import alipay from luffyapi.utils.logger import log data = request.data out_trade_no=data.get(out_trade_no,None) gmt_payment=data.get(gmt_payment,None) signature = data.pop("sign") # 验证签名 success = alipay.verify(data, signature) if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"): models.Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1,pay_time=gmt_payment) log.info(%s订单支付成功%out_trade_no) return Response(success) # 这里必须按支付宝规范返回一个success else: log.error(%s订单有问题 % out_trade_no) return Response(error)创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!