106 lines
5.3 KiB
Python
106 lines
5.3 KiB
Python
from sqlalchemy import Column, String, Boolean, DateTime, Integer, Numeric, ForeignKey, Index, JSON, Text
|
|
from sqlalchemy.sql import func
|
|
from sqlalchemy.orm import relationship
|
|
from app.core.database.db_session import Base
|
|
from app.models.TagModel import product_tags
|
|
from app.models.CollectionModel import product_collections
|
|
from app.models.DeviceCatalogModel import DeviceSeries, DeviceModel
|
|
|
|
class AttributeType(Base):
|
|
__tablename__ = "attribute_types"
|
|
|
|
attribute_id = Column(String(26), primary_key=True)
|
|
name = Column(String(100), nullable=False)
|
|
code = Column(String(100), unique=True, nullable=False) # e.g., "color", "screen_type", "storage"
|
|
status = Column(String(20), default="active") # active, inactive
|
|
preset_values = Column(JSON, nullable=True)
|
|
|
|
class Product(Base):
|
|
__tablename__ = "products"
|
|
|
|
product_id = Column(String(26), primary_key=True)
|
|
category_id = Column(String(26), ForeignKey("categories.category_id", ondelete="SET NULL"), nullable=True, index=True)
|
|
brand_id = Column(String(26), ForeignKey("brands.brand_id", ondelete="SET NULL"), nullable=True, index=True)
|
|
device_series_id = Column(String(26), ForeignKey("device_series.series_id", ondelete="SET NULL"), nullable=True)
|
|
device_model_id = Column(String(26), ForeignKey("device_models.model_id", ondelete="SET NULL"), nullable=True)
|
|
device_type = Column(String(50), nullable=True) # laptop, tablet, mobile
|
|
name = Column(String(255), nullable=False)
|
|
slug = Column(String(255), unique=True, nullable=False)
|
|
full_path = Column(String(500), nullable=False)
|
|
description = Column(Text, nullable=True)
|
|
warranty_type = Column(String(100), nullable=True)
|
|
warranty_summary = Column(String(500), nullable=True)
|
|
seo_title = Column(Text, nullable=True)
|
|
seo_description = Column(Text, nullable=True)
|
|
meta_keywords = Column(Text, nullable=True)
|
|
show_specifications = Column(Boolean, default=True, server_default="1", nullable=False)
|
|
status = Column(String(20), default="draft", index=True) # draft, active, archived
|
|
created_at = Column(DateTime, server_default=func.now(), index=True)
|
|
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
|
|
|
__table_args__ = (
|
|
Index('idx_products_parent_hierarchy', 'category_id', 'brand_id', 'device_series_id', 'device_model_id'),
|
|
)
|
|
|
|
# Relations
|
|
category = relationship("Category")
|
|
brand = relationship("Brand")
|
|
device_series = relationship("DeviceSeries")
|
|
device_model = relationship("DeviceModel")
|
|
images = relationship("ProductImage", back_populates="product", cascade="all, delete-orphan")
|
|
variants = relationship("ProductVariant", back_populates="product", cascade="all, delete-orphan")
|
|
tags = relationship("Tag", secondary=product_tags, backref="products")
|
|
collections = relationship("Collection", secondary=product_collections, backref="products")
|
|
|
|
class ProductImage(Base):
|
|
__tablename__ = "product_images"
|
|
|
|
image_id = Column(String(26), primary_key=True)
|
|
product_id = Column(String(26), ForeignKey("products.product_id", ondelete="CASCADE"), nullable=False)
|
|
image_url = Column(String(500), nullable=False)
|
|
alt_text = Column(String(255), nullable=True)
|
|
sort_order = Column(Integer, default=0)
|
|
is_banner = Column(Boolean, default=False)
|
|
|
|
product = relationship("Product", back_populates="images")
|
|
|
|
class ProductVariant(Base):
|
|
__tablename__ = "product_variants"
|
|
|
|
variant_id = Column(String(26), primary_key=True)
|
|
product_id = Column(String(26), ForeignKey("products.product_id", ondelete="CASCADE"), nullable=False)
|
|
sku = Column(String(100), unique=True, nullable=False)
|
|
barcode = Column(String(100), unique=True, nullable=True)
|
|
price = Column(Numeric(10, 2), nullable=False, index=True)
|
|
compare_price = Column(Numeric(10, 2), nullable=True)
|
|
cost_price = Column(Numeric(10, 2), nullable=False)
|
|
low_stock_threshold = Column(Integer, default=5)
|
|
status = Column(String(20), default="active", index=True) # active, inactive
|
|
created_at = Column(DateTime, server_default=func.now())
|
|
|
|
|
|
product = relationship("Product", back_populates="variants")
|
|
attributes = relationship("VariantAttribute", back_populates="variant", cascade="all, delete-orphan")
|
|
images = relationship("VariantImage", back_populates="variant", cascade="all, delete-orphan")
|
|
|
|
class VariantAttribute(Base):
|
|
__tablename__ = "variant_attributes"
|
|
|
|
id = Column(String(26), primary_key=True)
|
|
variant_id = Column(String(26), ForeignKey("product_variants.variant_id", ondelete="CASCADE"), nullable=False)
|
|
attribute_id = Column(String(26), ForeignKey("attribute_types.attribute_id", ondelete="RESTRICT"), nullable=False)
|
|
attribute_value = Column(String(255), nullable=False)
|
|
|
|
variant = relationship("ProductVariant", back_populates="attributes")
|
|
attribute_type = relationship("AttributeType")
|
|
|
|
class VariantImage(Base):
|
|
__tablename__ = "variant_images"
|
|
|
|
image_id = Column(String(26), primary_key=True)
|
|
variant_id = Column(String(26), ForeignKey("product_variants.variant_id", ondelete="CASCADE"), nullable=False)
|
|
image_url = Column(String(500), nullable=False)
|
|
sort_order = Column(Integer, default=0)
|
|
is_primary = Column(Boolean, default=False)
|
|
|
|
variant = relationship("ProductVariant", back_populates="images")
|