2025-03-18 08:46:50 +08:00

379 lines
22 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.db import models
from utils.models import CoreModel,BaseModel,SimpleCoreModel
from apps.address.models import Address,Area
from mysystem.models import Users
# Create your models here.
# ================================================= #
# ************** 商品分类 model ************** #
# ================================================= #
class GoodsCategory(CoreModel):
"""商品类别"""
name = models.CharField(max_length=20, verbose_name='名称')
desc = models.CharField(max_length=255, null=True, blank=True,verbose_name='描述')
# level = models.SmallIntegerField(default=1, verbose_name="分类层级(1一级 2二级)", help_text="分类层级(1一级 2二级)")
default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='默认图片') # 类别图片(单个图片)
sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序", help_text="显示顺序")
status = models.BooleanField(default=True, verbose_name="商品类别状态", help_text="商品类别状态")
is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
parent = models.ForeignKey('self', related_name='goodscategorysubs',db_constraint=False, null=True, blank=True, on_delete=models.CASCADE, verbose_name='父类别')
class Meta:
db_table = 'tb_goods_category'
verbose_name = '商品类别'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# ================================================= #
# ************** 优惠券 model ************** #
# ================================================= #
GOODSCOUPON_RECEIVE_TYPE = (
(0, ""),
(1, "手动领取"),
(2, "新人劵"),
(3, "后台发放"),
(4, "邀请劵"),
)
GOODSCOUPON_COUPONTYPE = (
(0, "通用券"),
(1, "商城类通用券"),
(2, "服务类通用券"),
)
# 通用:服务类商品+商城类商品
# 服务:仅能用于服务类商品
# 商城:仅能用于商城内商品
class GoodsCoupon(CoreModel):
"""商品优惠券(管理员创建)"""
name = models.CharField(max_length=50, verbose_name='优惠券名称')
caption = models.CharField(max_length=256, verbose_name='优惠券副标题', null=True, blank=True) # 副标题
desc = models.CharField(max_length=150, null=True, blank=True, verbose_name='描述')
sort = models.IntegerField(default=0, verbose_name="排序", help_text="显示顺序")
total_num = models.IntegerField(default=0, verbose_name="优惠券总数量", help_text="优惠券总数量")
received_num = models.IntegerField(default=0, verbose_name="优惠券已领取数量", help_text="优惠券已领取数量")
used_num = models.IntegerField(default=0, verbose_name="已被使用的数量", help_text="已被使用的数量")
is_permanent = models.BooleanField(default=True, verbose_name="是否无限张数", help_text="是否无限张数")
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='优惠券面值',default=0)
is_condition = models.BooleanField(default=False, verbose_name="有无门槛", help_text="有无门槛")#0无门槛 1有门槛
use_min_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='最低消费多少金额可用优惠券',default=0)#有无门槛,0表示无门槛
start_time = models.DateField(null=True, blank=True, help_text="优惠券领取开启时间", verbose_name="优惠券领取开启时间")
end_time = models.DateField(null=True, blank=True, help_text="优惠券领取结束时间",verbose_name="优惠券领取结束时间")
valid_begin_date = models.DateField(verbose_name="有效期开始时间", blank=True, null=True)
valid_end_date = models.DateField(verbose_name="有效结束时间", blank=True, null=True)
coupon_expiretime = models.IntegerField(default=0, verbose_name="优惠券有效期限(单位:天)", help_text="优惠券有效期限(单位:天)")#领取后几天有效,自券被领时开始算起
receive_type = models.SmallIntegerField(choices=GOODSCOUPON_RECEIVE_TYPE, default=0, verbose_name="优惠券发送方式",help_text="优惠券发送方式")
coupon_type = models.SmallIntegerField(choices=GOODSCOUPON_COUPONTYPE,default=0, verbose_name="优惠券类型2", help_text="优惠券类型2")
is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
status = models.BooleanField(default=True, verbose_name="状态", help_text="状态")#0关闭 1正常
class Meta:
db_table = 'tb_goods_coupon'
verbose_name = '商品优惠券'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class CouponRecord(CoreModel):
"""优惠券发放、消费纪录 - 面向用户(用户领取卷)"""
# 跟优惠券生成规则是一对多的关系 - 一种优惠券有30张则发放记录就有30条
coupon = models.ForeignKey("GoodsCoupon",db_constraint=False, on_delete=models.CASCADE,verbose_name="关联优惠券")
number = models.CharField(max_length=64,verbose_name="用来计数",null=True,blank=True)
# 一对多,一个用户有多张优惠券,一张优惠券只能给一个用户
user = models.ForeignKey(Users,verbose_name="拥有者", on_delete=models.CASCADE,db_constraint=False,related_name='couponuser1')
status_choices = ((0, '未领取'),(1, '未使用'), (2, '已使用'), (3, '已过期'), (4, '已撤回'))
status = models.SmallIntegerField(choices=status_choices, default=0)
used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用时间")
receive_time = models.DateTimeField(blank=True, null=True, verbose_name="领取时间")
is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
class Meta:
db_table = 'tb_goods_coupon_record'
verbose_name = '用户持券表'
verbose_name_plural = verbose_name
def __str__(self):
return '%s-%s-%s'%(self.user,self.coupon,self.get_status_display())
# ================================================= #
# ************** 商品品牌 model ************** #
# ================================================= #
class GoodsBrand(CoreModel):
""" 商品所属品牌 """
category = models.ForeignKey(GoodsCategory, on_delete=models.CASCADE,related_name="brands",db_constraint=False, verbose_name="所属分类", help_text="所属分类")
name = models.CharField(max_length=30, verbose_name="品牌名", help_text="品牌名")
desc = models.TextField(blank=True, max_length=200,default="", verbose_name="品牌描述", help_text="品牌描述")
default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='品牌logo') #(单个图片)
sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序")
class Meta:
db_table = "tb_goods_brand"
ordering = ["-sort"]
verbose_name = "商品品牌"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# ================================================= #
# ************** 商品 model ************** #
# ================================================= #
class SPU(CoreModel):
"""商品SPU"""
SPU_SPEC_TYPE = (
(0, "单规格"),
(1, "多规格")
)
name = models.CharField(max_length=60, verbose_name='标题')
sub_name = models.CharField(max_length=60, blank=True,null=True, default="", verbose_name="副标题")#副标题
category1 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat1_spu',db_constraint=False, verbose_name='一级类别')
# category2 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat2_spu',null=True, blank=True, verbose_name='二级类别')
# category3 = models.ForeignKey(GoodsCategory, on_delete=models.PROTECT, related_name='cat3_spu', null=True, blank=True, verbose_name='三级类别')
brand = models.ForeignKey(GoodsBrand, on_delete=models.PROTECT, related_name="brands",db_constraint=False, blank=True, null=True,verbose_name="品牌")
spec_type = models.PositiveIntegerField(choices=SPU_SPEC_TYPE, default=0, verbose_name="规格类型")#默认单规格
default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='商品主图') #(单个图片)
image_list = models.CharField(max_length=2000, null=True, blank=True, verbose_name='商品轮播图') # (多个图片)
price = models.DecimalField(max_digits=10, decimal_places=2,default=0, verbose_name="售价")#sku中选择一个最低的售价写入
# market_price = models.DecimalField(max_digits=10, decimal_places=2,default=0, verbose_name="市场价")
# cost_price = models.DecimalField(max_digits=10, decimal_places=2,default=0, verbose_name="成本价")
sales = models.IntegerField(default=0, verbose_name='销量')
stock = models.IntegerField(default=0, verbose_name="库存")
unit = models.CharField(max_length=30, default="", blank=True,null=True,verbose_name="商品单位")
comments = models.IntegerField(default=0, verbose_name='评论量',null=True, blank=True)
desc_detail = models.TextField(default='', verbose_name='详细介绍',null=True, blank=True)#商品详情
desc_pack = models.TextField(default='', verbose_name='包装信息',null=True, blank=True)
desc_service = models.TextField(default='', verbose_name='售后服务',null=True, blank=True)
is_launched = models.BooleanField(default=True, verbose_name='是否上架销售')
is_tuijian = models.BooleanField(default=False, verbose_name='是否推荐')#自定义字段,可删掉
sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序")
is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
class Meta:
db_table = 'tb_goods_spu'
verbose_name = '商品SPU'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class SKU(CoreModel):
"""商品SKU"""
name = models.CharField(max_length=60, verbose_name='标题',null=True, blank=True)
spu = models.ForeignKey(SPU, on_delete=models.CASCADE, verbose_name='商品SPU',db_constraint=False,related_name='skus')
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='商品单价')
shop_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="售价")
market_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="市场价")
cost_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="成本价")
stock = models.IntegerField(default=0, verbose_name='商品库存')
unite = models.CharField(max_length=20, verbose_name='商品单位',null=True, blank=True)
sales = models.IntegerField(default=0, verbose_name='商品销量',null=True, blank=True)
default_image = models.CharField(max_length=255, null=True, blank=True, verbose_name='默认图片')#商品主图(单张)
is_launched = models.BooleanField(default=True, verbose_name='是否上架销售')
is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
class Meta:
ordering = ["create_datetime"]
db_table = 'tb_goods_sku'
verbose_name = '商品SKU'
verbose_name_plural = verbose_name
def __str__(self):
return f'{self.spu.name}的SKU'
class SKUImage(CoreModel):
"""SKU图片"""
sku = models.ForeignKey(SKU, on_delete=models.CASCADE, verbose_name='商品sku',db_constraint=False,related_name='goods_imagelist')
image = models.CharField(max_length=255,verbose_name='图片')
sort = models.PositiveSmallIntegerField(default=0, verbose_name="排序")
class Meta:
ordering= ["sort"]
db_table = 'tb_goods_sku_image'
verbose_name = 'SKU图片'
verbose_name_plural = verbose_name
class SPUSpecification(CoreModel):
"""商品SPU规格名"""
spu = models.ForeignKey(SPU, on_delete=models.CASCADE, related_name='spu_specs',db_constraint=False, verbose_name='商品SPU')
name = models.CharField(max_length=20, verbose_name='规格名称')
class Meta:
ordering = ["create_datetime"]
db_table = 'tb_goods_spu_specification'
verbose_name = '商品SPU规格'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class SPUSpecificationOption(CoreModel):
"""商品SPU规格选项值"""
spec = models.ForeignKey(SPUSpecification, related_name='options', on_delete=models.CASCADE,db_constraint=False, verbose_name='规格')
value = models.CharField(max_length=20, verbose_name='选项值')
class Meta:
ordering = ["create_datetime"]
db_table = 'tb_goods_spu_specification_option'
verbose_name = '规格选项'
verbose_name_plural = verbose_name
def __str__(self):
return self.value
class SKUSpecification(CoreModel):
"""SKU具体规格"""
sku = models.ForeignKey(SKU, related_name='specs', on_delete=models.CASCADE, verbose_name='sku',db_constraint=False)
spec = models.ForeignKey(SPUSpecification, on_delete=models.CASCADE, verbose_name='规格名称',db_constraint=False)
option = models.ForeignKey(SPUSpecificationOption, on_delete=models.CASCADE, verbose_name='规格值',db_constraint=False)
class Meta:
ordering = ["create_datetime"]
db_table = 'tb_goods_sku_specification'
verbose_name = 'SKU规格'
verbose_name_plural = verbose_name
def __str__(self):
return '%s: %s - %s' % (self.sku, self.spec.name, self.option.value)
class GoodsSpecTemplate(CoreModel):
"""商品规格模板(供添加商品时选择使用)"""
spec = models.CharField(max_length=100, verbose_name='规格名称')
option = models.CharField(max_length=255, verbose_name='规格值')
class Meta:
db_table = 'tb_goods_spec_template'
verbose_name = '商品规格模板'
verbose_name_plural = verbose_name
class FreightConfigManage(SimpleCoreModel):
area = models.ManyToManyField(Area, verbose_name='关联区域', db_constraint=False, help_text="关联区域")
region_name = models.TextField(verbose_name="选择的区域名称",null=True,blank=True)#多个名称用、号分割(如省内所有市区都选择则 仅显示省名称如市内所有区都选择则 仅显示市名称)
sz = models.FloatField(default=0,verbose_name="首重kg")
yf = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='运费(元)',default=0)
xz = models.FloatField(default=0,verbose_name="续重kg")
xf = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='续费(元)',default=0)
is_default = models.BooleanField(default=False, verbose_name="是否全国默认区域")
def save(self, *args, **kwargs):
# 在保存前对浮点数进行处理,保留两位小数
self.sz = round(self.sz, 2)
self.xz = round(self.xz, 2)
super(FreightConfigManage, self).save(*args, **kwargs)
class Meta:
db_table = 'tb_freight_config'
verbose_name = "运费配置"
verbose_name_plural = verbose_name
# ================================================= #
# ************** 商品订单model ************** #
# ================================================= #
class OrderInfo(CoreModel):
"""订单信息"""
PAY_METHOD_CHOICES = (
(0, ""),
(1, "货到付款"),
(2, "微信"),
(3, "支付宝"),
)
ORDER_STATUS_CHOICES = (
(1, "待支付"),
(2, "待发货"),
(3, "待收货"),
(4, "待评价"),
(5, "已完成"),
(6, "已取消"),
)
ORDER_PAY_STATUS_CHOICES = (
(0, "待支付"),
(1, "已支付"),
(2, "退款中"),
(3, "退款失败"),
(4, "已退款"),
)
order_id = models.CharField(max_length=64, verbose_name="订单号",unique=True)#内部
trade_id = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="支付编号")#外部
user = models.ForeignKey(Users, on_delete=models.PROTECT,related_name='createorderuser1' ,db_constraint=False,verbose_name="下单用户")
address_name = models.CharField(max_length=50, null=True, blank=True, verbose_name="收货人姓名")
address_mobile = models.CharField(max_length=20, null=True, blank=True, verbose_name="收货人手机号")
address_place = models.CharField(max_length=100, null=True, blank=True, verbose_name="收货详细地址")
couponrecord_id = models.CharField(max_length=60, unique=True, null=True, blank=True, verbose_name="用户优惠券id")
couponrecord_price = models.DecimalField(max_digits=10, decimal_places=2, default=0,null=True, blank=True, verbose_name="优惠券面值")
total_count = models.IntegerField(default=1, verbose_name="商品总数")
total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="实付商品总金额",default=0)
total_amount_pay = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="订单总金额",default=0)
freight = models.DecimalField(max_digits=10, decimal_places=2,null=True, blank=True,verbose_name="运费",default=0)
logistics_id = models.CharField(max_length=100, verbose_name="物流单号",null=True, blank=True)#该商城项目特有,其他项目可去掉
send_time = models.DateTimeField(null=True, blank=True, help_text="发货时间", verbose_name="发货时间")#该商城项目特有,其他项目可去掉
logistics_company = models.CharField(max_length=90, verbose_name="物流公司", null=True, blank=True)#该商城项目特有,其他项目可去掉
pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=0, verbose_name="支付方式")
pay_time = models.CharField(max_length=64,null=True, blank=True, verbose_name="支付时间", help_text="支付时间")
remark = models.CharField(max_length=100, verbose_name="订单备注",null=True,blank=True)
cancel_reason = models.CharField(max_length=100, verbose_name="订单取消原因", null=True, blank=True)
status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")
pay_status = models.SmallIntegerField(choices=ORDER_PAY_STATUS_CHOICES, default=0, verbose_name="支付状态")
is_delete = models.BooleanField(default=False, verbose_name="是否逻辑删除", help_text="是否逻辑删除")
class Meta:
db_table = "tb_mall_order_info"
verbose_name = '订单基本信息'
verbose_name_plural = verbose_name
def __str__(self):
return self.order_id
class OrderGoods(CoreModel):
"""订单商品"""
SCORE_CHOICES = (
(0, '0分'),
(1, '20分'),
(2, '40分'),
(3, '60分'),
(4, '80分'),
(5, '100分'),
)
order = models.ForeignKey(OrderInfo, related_name='ordergoodsskus', on_delete=models.CASCADE,db_constraint=False, verbose_name="订单")
spu = models.ForeignKey(SPU, on_delete=models.PROTECT,db_constraint=False,blank=True, null=True, verbose_name="订单商品")
sku = models.ForeignKey(SKU, on_delete=models.PROTECT,db_constraint=False,blank=True, null=True, verbose_name="订单规格")
count = models.IntegerField(default=1, verbose_name="数量")
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="sku单价")
comment = models.TextField(verbose_name="评价信息",null=True,blank=True)
score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name='满意度评分')
is_anonymous = models.BooleanField(default=False, verbose_name='是否匿名评价')
is_commented = models.BooleanField(default=False, verbose_name='是否评价了')
class Meta:
db_table = "tb_mall_order_goods"
verbose_name = '订单商品'
verbose_name_plural = verbose_name
def __str__(self):
return self.spu.name
class OrderRefunds(CoreModel):
"""订单退款"""
ORDER_STATUS_CHOICES = (
(0, "待支付"),
(1, "已支付"),
(2, "退款中"),
(3, "退款失败"),
(4, "已退款"),
)
order_no= models.CharField(max_length=64, verbose_name="订单号", unique=True) # 内部
order = models.ForeignKey(OrderInfo, related_name='orderrefunds',db_constraint=False, on_delete=models.CASCADE, verbose_name="要退款的订单")
refund_id = models.CharField(max_length=64, verbose_name="退款单号", unique=True) # 外部返回
amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="退款金额")
reason = models.CharField(max_length=64, verbose_name="退款失败原因", null=True,blank=True) # 失败原因
status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=2, verbose_name="退款状态")
class Meta:
db_table = "tb_mall_order_refunds"
verbose_name = '商城订单退款'
verbose_name_plural = verbose_name