from sqlalchemy import Column, String, Boolean, DateTime, Integer, Numeric, ForeignKey, Index, JSON 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(String(1000), nullable=True) 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")