from datetime import datetime from decimal import Decimal from enum import Enum from typing import TYPE_CHECKING, List, Optional from sqlalchemy import CheckConstraint, Column from sqlalchemy import Enum as SAEnum from sqlmodel import Field, Relationship, SQLModel if TYPE_CHECKING: from app.models.mail_log import MailLog from app.models.order import Order from app.models.route import Route from app.models.wine_offering import WineOffering class PurchaseRoundStatus(str, Enum): DRAFT = "draft" OPEN = "open" CLOSED = "closed" class PurchaseRoundBase(SQLModel): name: str status: PurchaseRoundStatus = Field( default=PurchaseRoundStatus.DRAFT, sa_column=Column( SAEnum( PurchaseRoundStatus, name="purchase_round_status", native_enum=False, values_callable=lambda enum_cls: [member.value for member in enum_cls], ), nullable=False, ), ) opens_at: Optional[datetime] = Field(default=None) order_deadline_at: Optional[datetime] = Field(default=None) pickup_at: Optional[datetime] = Field(default=None) eur_dkk_rate: Optional[Decimal] = Field(default=None, max_digits=10, decimal_places=4) intro_text: Optional[str] = Field(default=None) pickup_info_text: Optional[str] = Field(default=None) class PurchaseRound(PurchaseRoundBase, table=True): __tablename__ = "purchase_round" __table_args__ = ( CheckConstraint( "status = 'draft' OR " "(opens_at IS NOT NULL AND order_deadline_at IS NOT NULL AND pickup_at IS NOT NULL)", name="ck_purchase_round_dates_required_unless_draft", ), ) id: Optional[int] = Field(default=None, primary_key=True) route_id: int = Field(foreign_key="route.id", ondelete="CASCADE") route: "Route" = Relationship(back_populates="purchase_rounds") wine_offerings: List["WineOffering"] = Relationship( back_populates="purchase_round", sa_relationship_kwargs={"cascade": "all, delete-orphan"} ) orders: List["Order"] = Relationship( back_populates="purchase_round", sa_relationship_kwargs={"cascade": "all, delete-orphan"} ) mail_logs: List["MailLog"] = Relationship( back_populates="purchase_round", sa_relationship_kwargs={"cascade": "all, delete-orphan"} ) class PurchaseRoundCreate(PurchaseRoundBase): route_id: int class PurchaseRoundUpdate(SQLModel): name: Optional[str] = None status: Optional[PurchaseRoundStatus] = None opens_at: Optional[datetime] = None order_deadline_at: Optional[datetime] = None pickup_at: Optional[datetime] = None eur_dkk_rate: Optional[Decimal] = None intro_text: Optional[str] = None pickup_info_text: Optional[str] = None class PurchaseRoundPublic(PurchaseRoundBase): id: int route_id: int