ifixkart-backend/Backend/app/models/ProductModel.py

100 lines
4.9 KiB
Python

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")