2025-07-04 19:07:35 +08:00

266 lines
9.4 KiB
Python

"""
商品相关模型
"""
from datetime import datetime
from config.database import db
import json
class Category(db.Model):
"""商品分类模型"""
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
parent_id = db.Column(db.Integer, default=0)
level = db.Column(db.Integer, default=1)
sort_order = db.Column(db.Integer, default=0)
icon_url = db.Column(db.String(255))
is_active = db.Column(db.Integer, default=1)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'parent_id': self.parent_id,
'level': self.level,
'sort_order': self.sort_order,
'icon_url': self.icon_url,
'is_active': self.is_active,
'created_at': self.created_at.isoformat() if self.created_at else None
}
def __repr__(self):
return f'<Category {self.name}>'
class SpecName(db.Model):
"""规格名称模型"""
__tablename__ = 'spec_names'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
sort_order = db.Column(db.Integer, default=0)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'sort_order': self.sort_order
}
def __repr__(self):
return f'<SpecName {self.name}>'
class SpecValue(db.Model):
"""规格值模型"""
__tablename__ = 'spec_values'
id = db.Column(db.Integer, primary_key=True)
spec_name_id = db.Column(db.Integer, db.ForeignKey('spec_names.id'), nullable=False)
value = db.Column(db.String(100), nullable=False)
sort_order = db.Column(db.Integer, default=0)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
spec_name = db.relationship('SpecName', backref='values')
def to_dict(self):
return {
'id': self.id,
'spec_name_id': self.spec_name_id,
'value': self.value,
'sort_order': self.sort_order
}
def __repr__(self):
return f'<SpecValue {self.value}>'
class Product(db.Model):
"""商品模型"""
__tablename__ = 'products'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
brand = db.Column(db.String(100))
price = db.Column(db.Numeric(10, 2), nullable=False)
original_price = db.Column(db.Numeric(10, 2))
description = db.Column(db.Text)
main_image = db.Column(db.String(255))
status = db.Column(db.Integer, default=1) # 0-下架 1-上架
has_specs = db.Column(db.Integer, default=0) # 0-无规格 1-有规格
sales_count = db.Column(db.Integer, default=0)
view_count = db.Column(db.Integer, default=0)
weight = db.Column(db.Numeric(8, 2))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
category = db.relationship('Category', backref='products')
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'category_id': self.category_id,
'category_name': self.category.name if self.category else '',
'brand': self.brand,
'price': float(self.price) if self.price else 0,
'original_price': float(self.original_price) if self.original_price else None,
'description': self.description,
'main_image': self.main_image,
'status': self.status,
'has_specs': self.has_specs,
'sales_count': self.sales_count,
'view_count': self.view_count,
'weight': float(self.weight) if self.weight else None,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
def __repr__(self):
return f'<Product {self.name}>'
class ProductImage(db.Model):
"""商品图片模型"""
__tablename__ = 'product_images'
id = db.Column(db.Integer, primary_key=True)
product_id = db.Column(db.Integer, db.ForeignKey('products.id'), nullable=False)
image_url = db.Column(db.String(255), nullable=False)
sort_order = db.Column(db.Integer, default=0)
is_main = db.Column(db.Integer, default=0) # 0-否 1-是
created_at = db.Column(db.DateTime, default=datetime.utcnow)
product = db.relationship('Product', backref='images')
def to_dict(self):
return {
'id': self.id,
'product_id': self.product_id,
'image_url': self.image_url,
'sort_order': self.sort_order,
'is_main': self.is_main,
'created_at': self.created_at.isoformat() if self.created_at else None
}
def __repr__(self):
return f'<ProductImage {self.id}>'
class ProductSpecRelation(db.Model):
"""商品规格关联模型"""
__tablename__ = 'product_spec_relations'
id = db.Column(db.Integer, primary_key=True)
product_id = db.Column(db.Integer, db.ForeignKey('products.id'), nullable=False)
spec_name_id = db.Column(db.Integer, db.ForeignKey('spec_names.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
product = db.relationship('Product', backref='spec_relations')
spec_name = db.relationship('SpecName')
def __repr__(self):
return f'<ProductSpecRelation {self.product_id}-{self.spec_name_id}>'
class ProductInventory(db.Model):
"""商品库存模型(SKU)"""
__tablename__ = 'product_inventory'
id = db.Column(db.Integer, primary_key=True)
product_id = db.Column(db.Integer, db.ForeignKey('products.id'), nullable=False)
sku_code = db.Column(db.String(100), unique=True, nullable=False)
spec_combination = db.Column(db.JSON)
price_adjustment = db.Column(db.Numeric(10, 2), default=0)
stock = db.Column(db.Integer, nullable=False, default=0)
warning_stock = db.Column(db.Integer, default=10)
is_default = db.Column(db.Integer, default=0)
status = db.Column(db.Integer, default=1)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
product = db.relationship('Product', backref='inventory')
def get_final_price(self):
"""获取最终价格"""
base_price = float(self.product.price) if self.product and self.product.price else 0
adjustment = float(self.price_adjustment) if self.price_adjustment else 0
return base_price + adjustment
def to_dict(self):
return {
'id': self.id,
'product_id': self.product_id,
'sku_code': self.sku_code,
'spec_combination': self.spec_combination,
'price_adjustment': float(self.price_adjustment) if self.price_adjustment else 0,
'final_price': self.get_final_price(),
'stock': self.stock,
'warning_stock': self.warning_stock,
'is_default': self.is_default,
'status': self.status,
'created_at': self.created_at.isoformat() if self.created_at else None
}
def __repr__(self):
return f'<ProductInventory {self.sku_code}>'
class InventoryLog(db.Model):
"""库存变更日志模型"""
__tablename__ = 'inventory_logs'
id = db.Column(db.Integer, primary_key=True)
product_id = db.Column(db.Integer, db.ForeignKey('products.id'), nullable=False)
sku_code = db.Column(db.String(100), nullable=False)
change_type = db.Column(db.Integer, nullable=False) # 1-入库 2-出库 3-调整
change_quantity = db.Column(db.Integer, nullable=False)
before_stock = db.Column(db.Integer, nullable=False)
after_stock = db.Column(db.Integer, nullable=False)
related_order_id = db.Column(db.Integer)
remark = db.Column(db.String(255))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
product = db.relationship('Product')
@classmethod
def create_log(cls, product_id, sku_code, change_type, change_quantity,
before_stock, after_stock, related_order_id=None, remark=None):
"""创建库存变更日志"""
log = cls(
product_id=product_id,
sku_code=sku_code,
change_type=change_type,
change_quantity=change_quantity,
before_stock=before_stock,
after_stock=after_stock,
related_order_id=related_order_id,
remark=remark
)
db.session.add(log)
db.session.commit()
return log
def to_dict(self):
return {
'id': self.id,
'product_id': self.product_id,
'sku_code': self.sku_code,
'change_type': self.change_type,
'change_quantity': self.change_quantity,
'before_stock': self.before_stock,
'after_stock': self.after_stock,
'related_order_id': self.related_order_id,
'remark': self.remark,
'created_at': self.created_at.isoformat() if self.created_at else None
}
def __repr__(self):
return f'<InventoryLog {self.sku_code}>'