import enum from uuid import uuid4 from sqlalchemy import Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, Text from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.database import Base class ProductStatus(enum.Enum): DRAFT = "draft" PUBLISHED = "published" OUT_OF_STOCK = "out_of_stock" DISCONTINUED = "discontinued" class Product(Base): __tablename__ = "products" id = Column(String(36), primary_key=True, default=lambda: str(uuid4())) name = Column(String(255), nullable=False, index=True) description = Column(Text, nullable=True) price = Column(Float, nullable=False) sku = Column(String(100), unique=True, nullable=True) barcode = Column(String(100), unique=True, nullable=True) stock_quantity = Column(Integer, default=0) weight = Column(Float, nullable=True) # In kg dimensions = Column(String(100), nullable=True) # Format: LxWxH in cm status = Column(Enum(ProductStatus), default=ProductStatus.DRAFT) is_featured = Column(Boolean, default=False) is_digital = Column(Boolean, default=False) digital_download_link = Column(String(512), nullable=True) slug = Column(String(255), nullable=False, unique=True) tax_rate = Column(Float, default=0.0) # As a percentage discount_price = Column(Float, nullable=True) discount_start_date = Column(DateTime(timezone=True), nullable=True) discount_end_date = Column(DateTime(timezone=True), nullable=True) category_id = Column(String(36), ForeignKey("categories.id"), nullable=True) seller_id = Column(String(36), ForeignKey("users.id"), nullable=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # Relationships category = relationship("Category", back_populates="products") seller = relationship("User", back_populates="products") images = relationship("ProductImage", back_populates="product", cascade="all, delete-orphan") reviews = relationship("Review", back_populates="product", cascade="all, delete-orphan") order_items = relationship("OrderItem", back_populates="product") cart_items = relationship("CartItem", back_populates="product") # Tags relationship tags = relationship("Tag", secondary="product_tags") def __repr__(self): return f"" @property def average_rating(self): if not self.reviews: return None return sum(review.rating for review in self.reviews) / len(self.reviews) @property def current_price(self): """Returns the current effective price (discount or regular)""" now = func.now() if (self.discount_price and self.discount_start_date and self.discount_end_date and self.discount_start_date <= now and now <= self.discount_end_date): return self.discount_price return self.price class ProductImage(Base): __tablename__ = "product_images" id = Column(String(36), primary_key=True, default=lambda: str(uuid4())) product_id = Column(String(36), ForeignKey("products.id", ondelete="CASCADE"), nullable=False) image_url = Column(String(512), nullable=False) alt_text = Column(String(255), nullable=True) is_primary = Column(Boolean, default=False) display_order = Column(Integer, default=0) created_at = Column(DateTime(timezone=True), server_default=func.now()) # Relationship product = relationship("Product", back_populates="images") def __repr__(self): return f""