Spaces:
Sleeping
Sleeping
File size: 4,042 Bytes
b2be963 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | from datetime import datetime, timezone
from sqlalchemy import (
Column, Integer, String, Text, Float, DateTime,
ForeignKey, Boolean, Enum as SQLEnum, JSON
)
from sqlalchemy.orm import relationship
import enum
from app.db.base import Base
class Product(Base):
__tablename__ = "products"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, autoincrement=True)
slug = Column(String(255), unique=True, index=True, nullable=True)
name_ar = Column(String(500), nullable=False)
name_en = Column(String(500), nullable=False)
description_ar = Column(Text, nullable=True)
description_en = Column(Text, nullable=True)
price = Column(Float, nullable=False)
compare_price = Column(Float, nullable=True)
stock = Column(Integer, default=0, nullable=False)
category_id = Column(Integer, ForeignKey("categories.id"), nullable=True)
rating = Column(Float, default=0.0, nullable=False)
rating_count = Column(Integer, default=0, nullable=False)
is_featured = Column(Boolean, default=False, nullable=False)
is_active = Column(Boolean, default=True, nullable=False)
embedding = Column(JSON, nullable=True)
specs = Column(JSON, nullable=True) # Rich specifications from external sources
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False)
# Soft deletion & Quality
deleted_at = Column(DateTime, nullable=True)
deleted_by = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
deletion_reason = Column(String(500), nullable=True)
quality_score = Column(Integer, default=100, nullable=False)
category = relationship("Category", back_populates="products")
images = relationship("ProductImage", back_populates="product", order_by="ProductImage.sort_order, ProductImage.id", cascade="all, delete-orphan")
audit_logs = relationship("ProductAudit", back_populates="product", cascade="all, delete-orphan")
class ProductAudit(Base):
__tablename__ = "product_audit_logs"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, autoincrement=True)
product_id = Column(Integer, ForeignKey("products.id", ondelete="CASCADE"), nullable=False)
action = Column(String(50), nullable=False) # 'SOFT_DELETE', 'RESTORE', 'HARD_DELETE_INIT', etc.
reason = Column(String(500), nullable=True)
performed_by = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
snapshot = Column(JSON, nullable=True) # Full data backup before action
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc), nullable=False)
product = relationship("Product", back_populates="audit_logs")
class ProductImage(Base):
__tablename__ = "product_images"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, autoincrement=True)
product_id = Column(Integer, ForeignKey("products.id", ondelete="CASCADE"), nullable=False)
image_url = Column(String(1000), nullable=False)
alt_text = Column(String(500), nullable=True)
sort_order = Column(Integer, default=0, nullable=False)
product = relationship("Product", back_populates="images")
class Category(Base):
__tablename__ = "categories"
__table_args__ = {'extend_existing': True}
id = Column(Integer, primary_key=True, autoincrement=True)
name_ar = Column(String(255), nullable=False)
name_en = Column(String(255), nullable=False)
icon = Column(String(50), nullable=True)
sort_order = Column(Integer, default=0, nullable=False)
parent_id = Column(Integer, ForeignKey("categories.id"), nullable=True)
parent = relationship("Category", remote_side=[id], back_populates="subcategories")
subcategories = relationship("Category", back_populates="parent", cascade="all, delete-orphan")
products = relationship("Product", back_populates="category")
|