shoppe项目11---订单系统

订单系统

下订单的逻辑2

加入购物车—>点击购物车—>选中商品—>结算—>确认订单页面
前端页面的准备:将ConfirmOrder.vue & AddMyAddr.vue&icon资源分别放入Vue项目指定的目录
在这里插入图片描述

  1. 加载收货地址API
    在这里插入图片描述

  2. 点击添加新地址,实现添加新地址API(子组件给父组件传数据)
    全局事件总线
    在这里插入图片描述
    在这里插入图片描述

  3. 删除地址&选择地址
    点击地址模块右上角叉号,删除地址
    点击地址,实现框选,选择地址

表结构设计

订单信息表

#订单信息表
#order_id       user    addr  total_count  total_price  freight  pay_method  pay_status  created_time
#varchar(100)   外键    外键      int          decimal     decimal   smallint    smallint    datetime

订单商品表

#订单商品表
#id     good     count      price     comment      score     order
#int    外键      int        decimal     longtext   smallint   外键
class OrderGoods(models.Model):
    SCORES = (
        (0, "0分"),
        (1, "20分"),
        (2, "40分"),
        (3, "60分"),
        (4, "80分"),
        (5, "100分")
    )
    good = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name="商品")
    count = models.IntegerField("购买数量", default=1)
    price = models.DecimalField("价格", max_digits=7, decimal_places=2)
    comment = models.TextField("评论",default="")
    score = models.SmallIntegerField("评分", default=5, choices=SCORES)

    #若表中已有数据,迁移容易出现问题, 可以尝试修改db中的表名
    order = models.ForeignKey(Orders, on_delete=models.CASCADE, verbose_name="订单号", default=1)
    def __str__(self):
        return self.good.sku_name + " in order:" + self.order.order_id
    class Meta:
        db_table = "order_goods_table"
        verbose_name = "订单信息表"
        verbose_name_plural = verbose_name

订单模型类

from django.db import models
from users.models import User
from users.models import UserAddr
from goods.models import Goods
# Create your models here.
#订单信息表
#id user addr total_count  total_price  post_price  pay_method  pay_status  created_time
class Orders(models.Model):
    PAY_STATUS = ((1,"待支付"),(2,"待发货"),(3,"待收货"),(4,"待评论"),(5,"已完成"),(6,"已取消"))
    #订单编号--->时间戳字符串
    order_id = models.CharField("订单编号", max_length=100,primary_key=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户")
    addr = models.ForeignKey(UserAddr, on_delete=models.CASCADE, verbose_name="收货地址")
    #买的总商品数
    total_count = models.IntegerField("总商品数", default=1)
    total_price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name="总价格")
    #邮费
    post_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="运费")
    #支付方式  1为支付宝  2为银联卡
    pay_method = models.SmallIntegerField("支付方式", default=1, choices=((1,"支付宝"),(2,"银联卡")))
    #1待支付--->2待发货--->3待收货--->4待评论--->5已完成
    pay_status = models.SmallIntegerField("支付状态", default=1, choices=PAY_STATUS)
    created_time = models.DateTimeField("创建时间", auto_now_add=True)

    def __str__(self):
        return "订单编号:" + self.order_id
    class Meta:
        db_table = "order_table"
        verbose_name = "订单信息表"
        verbose_name_plural = verbose_name
#订单商品表
class OrderGoods(models.Model):
    #评分等级
    SCORE_CHOICES = (
        (0, '0分'),
        (1, '20分'),
        (2, '40分'),
        (3, '60分'),
        (4, '80分'),
        (5, '100分'),
    )
    good = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name="商品")
    count = models.IntegerField("购买数量", default=1)
    price = models.DecimalField("在售价格", max_digits=10, decimal_places=2)
    comments = models.TextField("商品评论", default="")
    score = models.SmallIntegerField("评分", default=5, choices=SCORE_CHOICES)
    #商品所属订单
    order = models.ForeignKey(Orders, on_delete=models.CASCADE, verbose_name="订单编号")
    #models.CASCADE 模型类的主表级联删除
    def __str__(self):
        return "订单%s 下的商品%s"%(self.order.order_id,self.good.sku_name)
    class Meta:
        db_table = "order_goods_table"
        verbose_name = "订单商品表"
        verbose_name_plural = verbose_name

购物车选中的商品

使用Vue的前端数据管理,也可以使用后端redis数据库查询。

创建订单

视图接口

#创建订单
class AddOrder(APIView):
    """
        创建订单
        1.接收前端数据
        { user: {"userName":"laufing"},
          products: #获取勾选的商品[{},{}],
            每个商品的数据结构{
                            'id': 'cart_1',
                            'productID': 7,
                            'productName':
                            'Redmi Note8',
                            'productImg':
                            'http://106.15.179.105:3000/public/imgs/phone/Redmi-Note8.png',
                            'price': 999,
                            'num': 3,
                            'maxNum': 20,
                            'check': True
                        }
          addr: "10", #地址id
          payMethod:"1", #支付方式,'1'支付宝 '2'银联卡
        })
        2. 查询用户对象user_obj, 查询地址对象addr_obj
        3.以原子方式开启事务,并创建事务保存点(回滚点)
        4.准备订单数据,创建订单对象,并存储订单记录
        5.遍历订单中购买的商品,判断库存;
            购买超出库存,则回滚事务,并返回响应{"code":204, "msg":"超出库存!创建订单失败!"}
            未超库存,则更新**销量**&**库存**
            good1.count += 购买的数量
            good1.stock -= 购买的数量
            good1.save()
            total_count += 购买的数量
            total_price += good1.price*购买的数量

        6.创建订单商品对象,注意再次查询good对象--->good2
            如果good2的销量&库存与good1一致,则创建订单商品对象,并保存
            否则,回滚事务,并返回响应{"code":200, "msg":"创建订单失败!"}

    """
    #接收前端数据
    #@transaction.atomic #原子方式开启事务
    def post(self, request):
        #***1.获取前端数据***
        #用户名
        username = request.data.get("user").get("userName")
        #订单中的商品,前端传入
        order_goods = request.data.get("products")
        #使用的收货地址id,字符串
        selected_addr = request.data.get("addr")
        #支付方式  '1'-支付宝  '2'-银联
        pay_method = request.data.get("payMethod")
        pay_status = "待付款"

        print("购买的商品:\n", order_goods)
        print("选择的地址:", selected_addr, "\n支付方式:", pay_method)

        #***2.查询用户对象&地址对象***
        try:
            user_obj = User.objects.get(username=username)
        except:
            #一般不会出现该异常
            return Response({"code":204, "msg":"用户不存在!"})
        try:
            addr_obj = UserAddr.objects.get(id=selected_addr)
        except:
            # 一般不会出现该异常
            return Response({"code":204, "msg":"地址不存在!"})

        #***3.以原子方式开启事务,并创建事务保存点(回滚点)***
        #创建订单 与 添加订单商品 放入一组事务中
        with transaction.atomic():
            #创建事务保存点
            point = transaction.savepoint()
            try:
                #***4.准备订单信息数据,存储订单记录***
                #生成订单编号
                order_id = str(uuid.uuid1())
                #订单中的总商品数
                total_count = 0
                #订单总价格
                total_price = 0
                #固定运费,前端固定为0
                post_price = 0
                pay_method = int(pay_method) if pay_method else 1
                #订单状态  固定为'待支付' 采用默认值1
                #创建订单对象,并存储订单信息
                order = Orders.objects.create(order_id=order_id,user=user_obj,addr=addr_obj,
                                              total_count=total_count,total_price=total_price,
                                              post_price=0,pay_method=pay_method,pay_status=1)
                # print("xxxxxxxxxx")
                #***5.遍历订单中购买的商品,判断库存***
                #order_goods
                for per_good in order_goods:
                    # ***6.创建订单商品对象,注意确认此时没有其他人改商品数据库***
                    # 如果good2的库存与good1一致,则创建订单商品对象,并保存
                    # 否则,重试;如果三次重试均失败,则抛出异常

                    #创建商品对象,每个商品对象的创建重试三次
                    for i in range(3):
                        #在db中查询该商品
                        good1 = Goods.objects.get(id=per_good.get("productID"))
                        origin_stock = good1.stock
                        #判断库存,库存过少,不可购买, 任意一个商品库存不足,订单都会创建失败!
                        if good1.stock < per_good.get("num"):
                            raise ValueError("商品库存不足!无法购买!")
                        #库存丰富,则可以正常购买,正常创建订单商品对象
                        new_stock = good1.stock - per_good.get("num")
                        new_count = good1.count + per_good.get("num")

                        #确认此时没有其他人完成购买
                        good2 = Goods.objects.filter(id=per_good.get("productID"), stock=origin_stock)
                        if good2:
                            #说明此时没有其他人完成购买,即没有修改数据库
                            #创建订单商品对象,并存储
                            # print(float(good1.selling_price))
                            selling_price = float(good1.selling_price)
                            #模型类定义的max_digits不够大,出错,已解决, 给一个float就可以
                            OrderGoods.objects.create(good=good1, count=per_good.get("num"),
                                                      price=selling_price, order=order)

                            # 更新商品的销量&库存
                            good1.stock = new_stock
                            good1.count = new_count
                            good1.save()
                            #累加订单中的商品总数
                            total_count += per_good.get("num")
                            #累加订单总价格
                            total_price += good1.selling_price * per_good.get("num")

                            break
                        else:
                            #说明在创建订单商品对象前,有其他人完成购买
                            continue
                    else:
                        #重试三次,均失败
                        raise ValueError("重试结束!创建订单失败!")
                # print("77777777")
                #***7.正常创建所有订单商品对象后,更新订单对象的总商品数和总价格***
                order.total_count = total_count
                order.total_price = float(total_price)
                order.save()

                #***8.删除redis购物车中的已经购买的商品***
                redis_conn = redis.Redis(host="localhost", port=6379, db=0)
                cart_key = "cart_%s"%user_obj.id
                cart_selected_key = "cart_selected_%s"%user_obj.id
                for per_good in order_goods:
                    good_id = per_good.get("productID")
                    #删除购物车数据
                    redis_conn.hdel(cart_key, good_id)
                    #删除购物车商品选中状态
                    redis_conn.srem(cart_selected_key, good_id)
                redis_conn.close()

                #***9.订单创建完成, 提交事务保存点***
                transaction.savepoint_commit(point)
                return Response({"code": 200, "msg":"创建订单成功!"})
            except Exception as e:
                print("创建订单异常:", e)
                #创建订单异常,直接回滚事务,防止db中产生不必要的空订单
                transaction.savepoint_rollback(point)
                #返回响应
                return Response({"code":204, "msg":"创建订单失败!"})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值