from sqlalchemy import Column, Integer, String, Boolean, Float, ForeignKey, Text from sqlalchemy.orm import relationship from database import Base class Category(Base): __tablename__ = "categories" id = Column(Integer, primary_key=True, index=True) name = Column(String, nullable=False) color = Column(String, nullable=True) sort_order = Column(Integer, default=0) products = relationship("Product", back_populates="category") class Product(Base): __tablename__ = "products" id = Column(Integer, primary_key=True, index=True) name = Column(String, nullable=False) category_id = Column(Integer, ForeignKey("categories.id"), nullable=True) base_price = Column(Float, nullable=False) is_available = Column(Boolean, default=True, nullable=False) printer_zone_id = Column(Integer, ForeignKey("printers.id"), nullable=True) image_url = Column(String, nullable=True) sort_order = Column(Integer, default=0, nullable=False) category = relationship("Category", back_populates="products") printer_zone = relationship("Printer", back_populates="products") options = relationship("ProductOption", back_populates="product", cascade="all, delete-orphan") ingredients = relationship("ProductIngredient", back_populates="product", cascade="all, delete-orphan") preference_sets = relationship("ProductPreferenceSet", back_populates="product", cascade="all, delete-orphan") order_items = relationship("OrderItem", back_populates="product") class ProductOption(Base): __tablename__ = "product_options" id = Column(Integer, primary_key=True, index=True) product_id = Column(Integer, ForeignKey("products.id"), nullable=False) name = Column(String, nullable=False) extra_cost = Column(Float, default=0.0) # JSON array [{name, extra_cost, is_default}] — sub-options shown when this option is checked sub_choices = Column(Text, nullable=True) product = relationship("Product", back_populates="options") class ProductIngredient(Base): __tablename__ = "product_ingredients" id = Column(Integer, primary_key=True, index=True) product_id = Column(Integer, ForeignKey("products.id"), nullable=False) name = Column(String, nullable=False) extra_cost = Column(Float, default=0.0) product = relationship("Product", back_populates="ingredients") class ProductPreferenceSet(Base): __tablename__ = "product_preference_sets" id = Column(Integer, primary_key=True, index=True) product_id = Column(Integer, ForeignKey("products.id"), nullable=False) name = Column(String, nullable=False) default_choice_id = Column(Integer, nullable=True) # JSON: {name, default_choice_index, choices:[{name,extra_cost,is_default}]} # Shared sub-set shown for all choices that don't have disables_subset=True shared_subset = Column(Text, nullable=True) product = relationship("Product", back_populates="preference_sets") choices = relationship("ProductPreferenceChoice", back_populates="set", cascade="all, delete-orphan") class ProductPreferenceChoice(Base): __tablename__ = "product_preference_choices" id = Column(Integer, primary_key=True, index=True) set_id = Column(Integer, ForeignKey("product_preference_sets.id"), nullable=False) name = Column(String, nullable=False) extra_cost = Column(Float, default=0.0) # JSON array of sub-choice objects: [{name, extra_cost, is_default}] # Per-choice inline sub-preference shown only when this choice is selected. sub_choices = Column(Text, nullable=True) # When True this choice hides the set-level shared_subset on the PWA. disables_subset = Column(Boolean, default=False, nullable=False) set = relationship("ProductPreferenceSet", back_populates="choices")