这里写目录标题

  • 一.昨日回顾
  • 二.今日内容
    • 1.订单表设计
    • 2.立即付款接口(一堆校验,登录后)
      • 2.1视图类
      • 2.2序列化类
      • 2.3自定义异常类
      • 2.4配置文件
      • 2.5路由
    • 3.立即付款前端
    • 4.支付成功get回调用户展示
      • 4.1luffycity/ src / views / PaySucess.vue
      • 4.2luffycity/ src / router / index.js
      • 4.3get回调参数
      • 4.4后端接口
    • 5.支付成功post回调修改订单状态

一.昨日回顾

1 支付宝支付:-商户号:营业执照(登录的沙箱环境的商家)-客户:我们客户
2 生成公钥和私钥:公钥配置到支付宝网站上----》支付宝公钥-担心私钥不安全(不要把公钥私钥直接放在代码中,而是放在服务器上)-支付宝支付(官方没有sdk,只提供了api),我们用了第三方,担心有问题
3 支付流程-用户在前端提交支付--->后端要生成订单(未支付)--->生成支付宝付款链接--->返回前端--->get请求支付链接--->支付宝付款页面(扫描付款)--->支付宝收到钱--->get回调到我们网站(展示用户付款成功)--->post回调(验签)修改订单状态-用户刚打开支付链接,你服务挂了,用户付款成功了-get回调也回不来了-支付宝的post回调,你也收不到(24小时以后,支付宝会推送8次)-25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h)

二.今日内容

1.订单表设计

1 两张表-一个订单可能包含多门课程-订单表:订单号,订单生成时间,订单总价格。。。(订单跟订单详情是一对多的关系)-订单详情表:order,course,该课程的价格。。。
from django.db import modelsfrom user.models import User
from course.models import Course
# 不同app之间的表,可以建立关联关系,导入使用
#user = models.ForeignKey(User)  # 不能用引号引起来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)# 咱们生成的订单号(唯一:分布式id生成方案:雪花算法,snowflake)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="支付方式")# 支付时间(付款成功的时候,等支付宝post回调,回掉回来以后,返回数据中有支付时间)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)@propertydef 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_listclass 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__()  # 相当于没写

2.立即付款接口(一堆校验,登录后)

1 付款接口需要登录后才能使用-自己写jwt的认证类-djangorestframwork-jwt 内置有个认证类,+ djangorestframwork的权限类也可以完成认证(目前使用这种)2 记得更改lib/al_pay/pay.py
这个网址后面记得加'?'
# 支付网关
GATEWAY = 'https://openapi.alipaydev.com/gateway.do?' if DEBUG else 'https://openapi.alipay.com/gateway.do?'

2.1视图类

from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin
from .models import Order
from .serializer import PayOrderSerializer
from utils.response import APIResponse
class PayView(GenericViewSet,CreateModelMixin):queryset = Order.objects.all()serializer_class = PayOrderSerializer# 认证类,需要搭配权限类--->保证必须登录才能用# 只使用下面一个:(JSONWebTokenAuthentication)# 用户可以登录,也可以不登录,# 如果登录了后续能之间获取request.user# 如果没有登录,就获取不到authentication_classes = [JSONWebTokenAuthentication,]permission_classes = [IsAuthenticated,]# 重写create,控制返回的数据def create(self, request, *args, **kwargs):ser=self.get_serializer(data=request.data,context={'request':request})ser.is_valid(raise_exception=True)#保存self.perform_create(ser)# ser.save()  跟跟上面一样pay_url=ser.context.get('pay_url')return APIResponse(msg='订单创建成功',pay_url=pay_url)

2.2序列化类

from rest_framework import serializers
from course.models import Course
from rest_framework.exceptions import ValidationError
from utils.exception import MyException
from .models import Order,OrderDetail
import uuid
from django.conf import settings
from lib.al_pay import alipay,gateway
class PayOrderSerializer(serializers.ModelSerializer):# 用户传入的是courses:[1,2,3]==转成课程对象==》[obj1,obj2,obj3]# courses:[1,2,3]---->PrimaryKeyRelatedField--->指定queryset,会去queryset中过滤,主键为[1,2,3]的课程courses = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), many=True, write_only=True)# user=serializers.PrimaryKeyRelatedField(queryset=User.objects.all(),many=False)class Meta:model = Order# 从前端传过来(订单号后端生成)'''{'subject':'python从入门到精通',total_amount:100,pay_type:1 (支付类型,目前只有支付宝),courses:[1,2,3] 课程id号}'''fields = ['subject', 'total_amount', 'pay_type', 'courses']extra_kwargs = {'total_amount': {'required': True, }}def _check_price(self, attrs):courses = attrs.get('courses')total = 0for course in courses:total += course.priceif not total == attrs.get('total_amount'):raise MyException('钱数不合法')def _get_order_no(self):order_no=str(uuid.uuid4())return order_no.replace('-','')def _get_user(self):user=self.context.get('request').userreturn userdef _gen_pay_url(self,attrs,order_no):order_string = alipay.api_alipay_trade_page_pay(out_trade_no=order_no,total_amount=float(attrs.get('total_amount')), # 转成浮点型subject=attrs.get('subject'),# 写在配置文件中return_url=settings.RETURN_URL,notify_url=settings.NOTIFY_URL)return gateway+order_stringdef _pre_create(self,attrs,user,order_no):# 把用户,订单状态,订单号,写入attrsattrs['order_status']=0attrs['user']=userattrs['out_trade_no']=order_nodef validate(self, attrs):# 1)订单总价校验self._check_price(attrs)# 2)生成订单号order_no=self._get_order_no()# 3)支付用户:request.useruser=self._get_user()# 4)支付链接生成pay_url=self._gen_pay_url(attrs,order_no)self.context['pay_url']=pay_url# 5)入库(两个表)的信息准备(重写create方法)self._pre_create(attrs,user,order_no)return attrsdef create(self, validated_data):# 存两个表# course需要存detail表courses=validated_data.pop('courses')# 开启一个事务order=Order.objects.create(**validated_data)for course in courses:OrderDetail.objects.create(order=order,course=course,price=course.price,real_price=course.price)return order

2.3自定义异常类

'''=========>utils/exception.py'''
# 自定义异常类
from rest_framework.exceptions import  APIExceptionclass MyException(APIException):status_code = 405default_detail = '校验出错了'default_code = '错误'def __init__(self, detail=None, code=None):super().__init__(detail=None, code=None)

2.4配置文件

'''========>settings/dev.py'''
# 支付宝回调地址RETURN_URL = "http://127.0.0.1:8080/course/paysucess"
NOTIFY_URL = "http://127.0.0.1:8000/"  # 必须要用公网

2.5路由

# 使用相对导入
from . import views
# 自动生成路径
from rest_framework.routers import SimpleRouter
from .views import PayView
router = SimpleRouter()
# 127.0.0.1:8000/order/pay/
router.register('pay',PayView,'PayView')from .views import PayView
urlpatterns = [# path('pay', PayView.as_view()),
]
urlpatterns+=router.urls  # 方式二

3.立即付款前端

views/ActualCourse.vue

buy_now(course) {//没有登录,提示请先登录let token = this.$cookies.get('token')if (token) {//发送请求获取支付链接this.$axios({method: 'post',url: this.$settings.base_url + '/order/pay/',data: {subject: course.name,total_amount: course.price,pay_type: 1,courses: [course.id,]},headers: {authorization: 'jwt ' + token}}).then(item => {console.log(item.data)if (item.data.status == 0) {open(item.data.pay_url, '_self')} else {this.$message({message: item.data.msg})}})} else {this.$message({message: "请先登录"})}
}

4.支付成功get回调用户展示

4.1luffycity/ src / views / PaySucess.vue

<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=2let items = params.length ? params.split('&') : [];  // ['a=1', 'b=2']//逐个将每一项添加到args对象中for (let i = 0; i < items.length; i++) {  // 第一次循环a=1,第二次b=2let 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);if(!response.data.status==0){console.log('暂未收到您的付款,请3s钟后再刷新该页面')}}).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>

4.2luffycity/ src / router / index.js

{path: '/course/paysucess',name: 'PaySucess',component: PaySucess,}

4.3get回调参数

# get回调,携带一些参数过来,展示课程购买成功
charset=utf-8&
out_trade_no=fe2baf0893d1403a89773e1e0151b4b3&
method=alipay.trade.page.pay.return&total_amount=99.00&
sign=C%2BtM1IqF9QBB7N86m6sEkJDoe8nvGKEymOPst%2FhrOTqZvZdyRTbr37a%2BAkhjV6Co6ot64mwJDVvlraJqevYltjXvWNovcViYAXL3JNZ%2FUoOo91PIsgFMJsTgXSy2R%2FyQ7NAhRhIhxGhNs5JNzTLt2JINKcZ%2FiUxzM%2Bkz3Z1EbjgB0JaDoNgRs9Wpwqb1VT%2FwZnyOAuoxOBwhij2SeP2ZC5qZfjQ8gzglSiUzbrQplbT3ZCGu5NHE1h42Zs8r3PkyxhghoK2T8UC7suI2u7l94713L8vP5hnegxkB79fNd4DQEZ4hnTV5nWDXjXw5RP9ob%2FQthMCTGssPS9%2Flme0%2F7w%3D%3D&
trade_no=2021011522001453300501032429&
auth_app_id=2016092000554611&version=1.0&
app_id=2016092000554611&
sign_type=RSA2&seller_id=2088102176466324&
timestamp=2021-01-15%2012%3A23%3A44

4.4后端接口

'''=====>order/urls.py'''
from .views import PaySuccess
path('success', PaySuccess.as_view()),
'''=====>order/views.py'''
class PaySuccess(APIView):def get(self,request,*args,**kwargs): # 咱们前端回调的out_trade_no=request.GET.get('out_trade_no')# 去数据库查询该订单是否已经支付完成order=Order.objects.filter(out_trade_no=out_trade_no,order_status=1).first()if order: # post回调回调完了,订单状态改了return APIResponse(msg='支付成功')else:return APIResponse(status=1,msg='暂未支付成功')

5.支付成功post回调修改订单状态

# lib/al_pay/init.py
from .pay import alipay,gateway# order/views.py
from rest_framework.views import APIView
from utils.logging import get_logger
logger=get_logger('pay')class PaySuccess(APIView):def post(self,request,*args,**kwargs): # 支付宝回调# 验签,通过,修改订单状态,返回给支付宝successtry:result_data = request.data.dict()  # 一定不能忘out_trade_no = result_data.get('out_trade_no')signature = result_data.pop('sign') # 签名,必须验证签名from lib import al_payresult = al_pay.alipay.verify(result_data, signature)if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):# 完成订单修改:订单状态、流水号、支付时间Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1)# 完成日志记录logger.warning('%s订单支付成功' % out_trade_no)return Response('success')  # 必须返回给支付宝,否则支付宝会一直回调else:logger.error('%s订单支付失败' % out_trade_no)except:passreturn Response('failed')

luffy-16/订单表设计,立即付款接口/前端,支付成功get回调用户展示,支付成功post回调修改订单状态相关推荐

  1. java mysql 订单表设计

    最近由于系统日益复杂的需求系统中各种类型订单越来越多,原来的这些订单表已经不能满足当下的需求,以可扩展为目标打算对这些订单表进行重构,本文只涉及基础版的设计,对于高并发.分布式等暂不考虑. 之前的系统 ...

  2. php订单表设计,订单详情表,与,订单表 怎么做?

    detail订单详情表 字段名 数据类型 默认值 允许非空 自动递增 备注 id int(11) NO 是 id orderid int(11) NO 订单id号 goodsid int(11) NO ...

  3. dj电商-数据表的设计-购物车表与订单表设计

    购物车,商品数量 用户的购买数量不应该超过库存的数量 使用redis实现购物车的功能 原因 如果通过mysql查询数据库,浪费性能 通过redis来查,速度更快 订单 点击去结算,进入订单 >订 ...

  4. 订单表的字段类型 mysql_Mysql数据库下订单表如何设计?

    Mysql数据库下订单表如何设计 商品表和订单表 . 通过一个表来关联. 那删除了商品,相关联的订单表如何显示出这个已经删除的商品 订单表需要冗余商品名.商品编号.价格等基本信息. 不能只保存一个商品 ...

  5. 用mysql建销售订单主表_mysql订单表如何设计?

    mysql订单表如何设计? 商品表和订单表 . 通过一个表来关联. 那删除了商品,相关联的订单表如何显示出这个已经删除的商品? 订单表需要冗余商品名.商品编号.价格等基本信息. 不能只保存一个商品主键 ...

  6. java后台实现支付宝支付接口、支付宝订单查询接口 前端为APP

    最近项目APP需要接入微信.支付宝支付功能,在分配开发任务时,听说微信支付接口比支付宝支付接口要难实现,由于我开发经验不是那么丰富(现工作经验1年半)且未接触过支付接口开发,组里刚好又有支付接口的老司 ...

  7. Mysql订单表如何设计?

    mysql订单表如何设计? 商品表和订单表 . 通过一个表来关联. 那删除了商品,相关联的订单表如何显示出这个已经删除的商品? 订单表需要冗余商品名.商品编号.价格等基本信息. 不能只保存一个商品主键 ...

  8. 电子商务网站中订单号设计有什么规则和依据吗?

     https://www.zhihu.com/question/19805896#answer-31069940 你是个程序员. 隔壁老王通过你老婆找到你,说要做个"巨牛逼电商网站&qu ...

  9. 怎么创建数据表的实体类和业务类_SSM搭建二手市场交易平台(二):数据表设计...

    写在前面 从本篇开始,我们正式开始项目的搭建,首先介绍数据表的设计,具体包括:表结构,表关系,唯一索引,单索引及组合索引,时间戳这几个内容. 数据表 首先我们创建一个数据库store,然后开始创建数据 ...

最新文章

  1. topcoder srm 495 div1
  2. Leetcode 160 相交链表 (每日一题 20210802)
  3. 小波的秘密8_图像处理应用:图像降噪
  4. 18.虚拟机linux上网问题
  5. 如何估算代码量_没有量杯,没有称,如何估算碳水化合物?
  6. eclipse中如何配置tomcat
  7. html pdf文档的格式控制符,关于Unicode控制字符RLO,LRO,PDF 的坑
  8. C++读写txt文件方式以及基于opencv的Mat数据类型读写txt文件类型
  9. python2.7安装教程win7_win7下python2.7安装 pip,setuptools的正确方法
  10. matlab ones size,matlab中zeros 和 ones 这两个函数的用法以及size的用法,princomp,pcacov,pcares,barttest四大分析函数用法...
  11. [管理]ERP专业术语
  12. PHPwebshell2022免杀bypass阿里云盾等所有安全设备
  13. 2017 Python 问卷调查结果初步分析
  14. 加油站踩踏式逃亡?电网成大赢家?时代抛弃你的时候,真的一声不吭
  15. 开学季数码好物推荐,大学必备数码产品选购清单
  16. XML文件的一些操作
  17. eos安装区块链开发环境
  18. Android Send Email 发送邮件
  19. 【DFS(记忆化)】hdu 2452 Navy maneuvers
  20. 【湍流】基于matlab模拟拉盖尔高斯光束传播的光强

热门文章

  1. 知识资源整理(持续更新)
  2. python发送各类QQ邮件 —— smtplib与email模块
  3. 自然语言处理数据集-20个
  4. SpringBoot整合使用XXL-JOB
  5. 微量小程序联盟,如何实现微信小程序换量和微信小程序推广?
  6. 使用 ffmpeg 转码 视频 (使用 nvidia 硬件加速 和 h265 编码)
  7. sqlplus登录缓慢的解决
  8. PMP VS MBA:为什么我劝你别浪费钱读MBA
  9. 人工智能,机器学习,深度学习(笔记)
  10. linux下批量替换文件内容