from __future__ import annotations from datetime import datetime from typing import Optional, List from sqlalchemy import Integer, String, DateTime, ForeignKey, Numeric, func, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from shared.db.base import Base class Order(Base): __tablename__ = "orders" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) user_id: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) session_id: Mapped[Optional[str]] = mapped_column(String(64), index=True, nullable=True) page_config_id: Mapped[Optional[int]] = mapped_column( Integer, nullable=True, index=True, ) status: Mapped[str] = mapped_column( String(32), nullable=False, default="pending", server_default="pending", ) currency: Mapped[str] = mapped_column(String(16), nullable=False, default="GBP") total_amount: Mapped[float] = mapped_column(Numeric(12, 2), nullable=False) # free-form description for the order description: Mapped[Optional[str]] = mapped_column(Text, nullable=True, index=True) # SumUp reference string (what we send as checkout_reference) sumup_reference: Mapped[Optional[str]] = mapped_column( String(255), nullable=True, index=True, ) # SumUp integration fields sumup_checkout_id: Mapped[Optional[str]] = mapped_column( String(128), nullable=True, index=True, ) sumup_status: Mapped[Optional[str]] = mapped_column(String(32), nullable=True) sumup_hosted_url: Mapped[Optional[str]] = mapped_column(Text, nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now(), ) items: Mapped[List["OrderItem"]] = relationship( "OrderItem", back_populates="order", cascade="all, delete-orphan", lazy="selectin", ) # Cross-domain relationship — explicit join, viewonly (no FK constraint) page_config: Mapped[Optional["PageConfig"]] = relationship( "PageConfig", primaryjoin="Order.page_config_id == PageConfig.id", foreign_keys="[Order.page_config_id]", viewonly=True, lazy="selectin", ) class OrderItem(Base): __tablename__ = "order_items" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) order_id: Mapped[int] = mapped_column( ForeignKey("orders.id", ondelete="CASCADE"), nullable=False, ) product_id: Mapped[int] = mapped_column( Integer, nullable=False, ) product_title: Mapped[Optional[str]] = mapped_column(String(512), nullable=True) quantity: Mapped[int] = mapped_column(Integer, nullable=False, default=1) unit_price: Mapped[float] = mapped_column(Numeric(12, 2), nullable=False) currency: Mapped[str] = mapped_column(String(16), nullable=False, default="GBP") created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), ) order: Mapped["Order"] = relationship( "Order", back_populates="items", ) # Cross-domain relationship — explicit join, viewonly (no FK constraint) product: Mapped["Product"] = relationship( "Product", primaryjoin="OrderItem.product_id == Product.id", foreign_keys="[OrderItem.product_id]", viewonly=True, lazy="selectin", )