from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, Text, ForeignKey, Enum as SQLEnum, JSON from sqlalchemy.orm import relationship, declarative_base from sqlalchemy.sql import func from datetime import datetime, timezone import enum import uuid Base = declarative_base() def generate_uuid(): return str(uuid.uuid4()) class OrderStatus(enum.Enum): PENDING = "pending" PROCESSING = "processing" LAYAWAY = "layaway" SHIPPED = "shipped" DELIVERED = "delivered" CANCELLED = "cancelled" REFUNDED = "refunded" ON_HOLD = "on_hold" class UserRole(enum.Enum): USER = "user" ADMIN = "admin" EMPLOYEE = "employee" ACCOUNTANT = "accountant" SALES_MANAGER = "sales_manager" class User(Base): __tablename__ = "users" id = Column(String(36), primary_key=True, default=generate_uuid) email = Column(String(255), unique=True, nullable=False, index=True) name = Column(String(255), nullable=False) password = Column(String(255), nullable=False) role = Column(SQLEnum(UserRole), default=UserRole.USER) is_active = Column(Boolean, default=True, nullable=False) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) cart_items = relationship("CartItem", back_populates="user", cascade="all, delete-orphan") orders = relationship("Order", back_populates="user") reviews = relationship("Review", back_populates="user") bookings = relationship("Booking", back_populates="user") class Category(Base): __tablename__ = "categories" id = Column(String(36), primary_key=True, default=generate_uuid) name = Column(String(100), unique=True, nullable=False) slug = Column(String(100), unique=True, nullable=False) description = Column(Text) type = Column(String(50), default="product") # product or service created_at = Column(DateTime(timezone=True), server_default=func.now()) products = relationship("Product", back_populates="category_rel") services = relationship("Service", back_populates="category_rel") class Product(Base): __tablename__ = "products" id = Column(String(36), primary_key=True, default=generate_uuid) name = Column(String(255), nullable=False) description = Column(Text) # Now supports HTML from rich text editor price = Column(Float, nullable=False) category = Column(String(100), nullable=False) category_id = Column(String(36), ForeignKey("categories.id"), nullable=True) image_url = Column(String(500)) # Deprecated - kept for backwards compatibility stock = Column(Integer, default=10) low_stock_threshold = Column(Integer, default=5) brand = Column(String(100)) specs = Column(JSON, default={}) is_active = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) category_rel = relationship("Category", back_populates="products") cart_items = relationship("CartItem", back_populates="product") order_items = relationship("OrderItem", back_populates="product") reviews = relationship("Review", back_populates="product", cascade="all, delete-orphan") inventory_logs = relationship("InventoryLog", back_populates="product", cascade="all, delete-orphan") images = relationship("ProductImage", back_populates="product", cascade="all, delete-orphan", order_by="ProductImage.display_order") class ProductImage(Base): __tablename__ = "product_images" id = Column(String(36), primary_key=True, default=generate_uuid) product_id = Column(String(36), ForeignKey("products.id"), nullable=False) image_url = Column(String(500), nullable=False) display_order = Column(Integer, default=0) is_primary = Column(Boolean, default=False) created_at = Column(DateTime(timezone=True), server_default=func.now()) product = relationship("Product", back_populates="images") class ServiceImage(Base): __tablename__ = "service_images" id = Column(String(36), primary_key=True, default=generate_uuid) service_id = Column(String(36), ForeignKey("services.id"), nullable=False) image_url = Column(String(500), nullable=False) display_order = Column(Integer, default=0) is_primary = Column(Boolean, default=False) created_at = Column(DateTime(timezone=True), server_default=func.now()) service = relationship("Service", back_populates="images") class Service(Base): __tablename__ = "services" id = Column(String(36), primary_key=True, default=generate_uuid) name = Column(String(255), nullable=False) description = Column(Text) # Now supports HTML from rich text editor price = Column(Float, nullable=False) duration = Column(String(50)) image_url = Column(String(500)) # Deprecated - kept for backwards compatibility category = Column(String(100), nullable=False) category_id = Column(String(36), ForeignKey("categories.id"), nullable=True) is_active = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) category_rel = relationship("Category", back_populates="services") bookings = relationship("Booking", back_populates="service") reviews = relationship("Review", back_populates="service", cascade="all, delete-orphan") images = relationship("ServiceImage", back_populates="service", cascade="all, delete-orphan", order_by="ServiceImage.display_order") class CartItem(Base): __tablename__ = "cart_items" id = Column(String(36), primary_key=True, default=generate_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) product_id = Column(String(36), ForeignKey("products.id"), nullable=False) quantity = Column(Integer, default=1) created_at = Column(DateTime(timezone=True), server_default=func.now()) user = relationship("User", back_populates="cart_items") product = relationship("Product", back_populates="cart_items") class Order(Base): __tablename__ = "orders" id = Column(String(36), primary_key=True, default=generate_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) status = Column(SQLEnum(OrderStatus), default=OrderStatus.PENDING) subtotal = Column(Float, default=0) tax = Column(Float, default=0) shipping = Column(Float, default=0) total = Column(Float, default=0) shipping_address = Column(JSON, default={}) notes = Column(Text) tracking_number = Column(String(100)) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) user = relationship("User", back_populates="orders") items = relationship("OrderItem", back_populates="order", cascade="all, delete-orphan") status_history = relationship("OrderStatusHistory", back_populates="order", cascade="all, delete-orphan") class OrderItem(Base): __tablename__ = "order_items" id = Column(String(36), primary_key=True, default=generate_uuid) order_id = Column(String(36), ForeignKey("orders.id"), nullable=False) product_id = Column(String(36), ForeignKey("products.id"), nullable=False) quantity = Column(Integer, default=1) price = Column(Float, nullable=False) product_name = Column(String(255)) product_image = Column(String(500)) order = relationship("Order", back_populates="items") product = relationship("Product", back_populates="order_items") class OrderStatusHistory(Base): __tablename__ = "order_status_history" id = Column(String(36), primary_key=True, default=generate_uuid) order_id = Column(String(36), ForeignKey("orders.id"), nullable=False) status = Column(SQLEnum(OrderStatus), nullable=False) notes = Column(Text) created_at = Column(DateTime(timezone=True), server_default=func.now()) created_by = Column(String(36)) order = relationship("Order", back_populates="status_history") class Review(Base): __tablename__ = "reviews" id = Column(String(36), primary_key=True, default=generate_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) product_id = Column(String(36), ForeignKey("products.id"), nullable=True) service_id = Column(String(36), ForeignKey("services.id"), nullable=True) rating = Column(Integer, nullable=False) # 1-5 title = Column(String(255)) comment = Column(Text) is_verified_purchase = Column(Boolean, default=False) is_approved = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) user = relationship("User", back_populates="reviews") product = relationship("Product", back_populates="reviews") service = relationship("Service", back_populates="reviews") class Booking(Base): __tablename__ = "bookings" id = Column(String(36), primary_key=True, default=generate_uuid) service_id = Column(String(36), ForeignKey("services.id"), nullable=False) user_id = Column(String(36), ForeignKey("users.id"), nullable=True) name = Column(String(255), nullable=False) email = Column(String(255), nullable=False) phone = Column(String(50)) preferred_date = Column(String(50)) notes = Column(Text) status = Column(String(50), default="pending") service_name = Column(String(255)) created_at = Column(DateTime(timezone=True), server_default=func.now()) service = relationship("Service", back_populates="bookings") user = relationship("User", back_populates="bookings") class Contact(Base): __tablename__ = "contacts" id = Column(String(36), primary_key=True, default=generate_uuid) name = Column(String(255), nullable=False) email = Column(String(255), nullable=False) subject = Column(String(255)) message = Column(Text, nullable=False) status = Column(String(50), default="pending") created_at = Column(DateTime(timezone=True), server_default=func.now()) class InventoryLog(Base): __tablename__ = "inventory_logs" id = Column(String(36), primary_key=True, default=generate_uuid) product_id = Column(String(36), ForeignKey("products.id"), nullable=False) action = Column(String(50), nullable=False) # add, remove, adjust, sale quantity_change = Column(Integer, nullable=False) previous_stock = Column(Integer) new_stock = Column(Integer) notes = Column(Text) created_by = Column(String(36)) created_at = Column(DateTime(timezone=True), server_default=func.now()) product = relationship("Product", back_populates="inventory_logs") class SalesReport(Base): __tablename__ = "sales_reports" id = Column(String(36), primary_key=True, default=generate_uuid) report_type = Column(String(50), nullable=False) # daily, weekly, monthly report_date = Column(DateTime(timezone=True), nullable=False) start_date = Column(DateTime(timezone=True)) end_date = Column(DateTime(timezone=True)) total_orders = Column(Integer, default=0) total_revenue = Column(Float, default=0) total_products_sold = Column(Integer, default=0) total_services_booked = Column(Integer, default=0) report_data = Column(JSON, default={}) created_at = Column(DateTime(timezone=True), server_default=func.now()) class AboutContent(Base): __tablename__ = "about_content" id = Column(String(36), primary_key=True, default=generate_uuid) section = Column(String(50), nullable=False, unique=True) # 'hero', 'story', 'stats' title = Column(String(255)) subtitle = Column(Text) content = Column(Text) # HTML content from rich text editor image_url = Column(String(500)) data = Column(JSON, default={}) # For flexible content like stats is_active = Column(Boolean, default=True) display_order = Column(Integer, default=0) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) class TeamMember(Base): __tablename__ = "team_members" id = Column(String(36), primary_key=True, default=generate_uuid) name = Column(String(255), nullable=False) role = Column(String(255), nullable=False) bio = Column(Text) # HTML content from rich text editor image_url = Column(String(500)) email = Column(String(255)) linkedin = Column(String(500)) display_order = Column(Integer, default=0) is_active = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) class CompanyValue(Base): __tablename__ = "company_values" id = Column(String(36), primary_key=True, default=generate_uuid) title = Column(String(255), nullable=False) description = Column(Text) icon = Column(String(50)) # Icon name (e.g., 'Target', 'Users', 'Award', 'Heart') display_order = Column(Integer, default=0) is_active = Column(Boolean, default=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now())