"""Deal ORM model and schemas.""" from __future__ import annotations from datetime import datetime from decimal import Decimal from enum import StrEnum from pydantic import BaseModel, ConfigDict from sqlalchemy import DateTime, ForeignKey, Integer, Numeric, String, func from sqlalchemy import Enum as SqlEnum from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import Base, enum_values class DealStatus(StrEnum): NEW = "new" IN_PROGRESS = "in_progress" WON = "won" LOST = "lost" class DealStage(StrEnum): QUALIFICATION = "qualification" PROPOSAL = "proposal" NEGOTIATION = "negotiation" CLOSED = "closed" class Deal(Base): """Represents a sales opportunity/deal.""" __tablename__ = "deals" id: Mapped[int] = mapped_column(Integer, primary_key=True) organization_id: Mapped[int] = mapped_column(ForeignKey("organizations.id", ondelete="CASCADE")) contact_id: Mapped[int] = mapped_column(ForeignKey("contacts.id", ondelete="RESTRICT")) owner_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="RESTRICT")) title: Mapped[str] = mapped_column(String(255), nullable=False) amount: Mapped[Decimal | None] = mapped_column(Numeric(12, 2), nullable=True) currency: Mapped[str | None] = mapped_column(String(8), nullable=True) status: Mapped[DealStatus] = mapped_column( SqlEnum(DealStatus, name="deal_status", values_callable=enum_values), nullable=False, default=DealStatus.NEW, ) stage: Mapped[DealStage] = mapped_column( SqlEnum(DealStage, name="deal_stage", values_callable=enum_values), nullable=False, default=DealStage.QUALIFICATION, ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) organization = relationship("Organization", back_populates="deals") contact = relationship("Contact", back_populates="deals") owner = relationship("User", back_populates="owned_deals") tasks = relationship("Task", back_populates="deal", cascade="all, delete-orphan") activities = relationship("Activity", back_populates="deal", cascade="all, delete-orphan") class DealBase(BaseModel): organization_id: int contact_id: int owner_id: int title: str amount: Decimal | None = None currency: str | None = None status: DealStatus = DealStatus.NEW stage: DealStage = DealStage.QUALIFICATION class DealCreate(DealBase): pass class DealRead(DealBase): id: int created_at: datetime updated_at: datetime model_config = ConfigDict(from_attributes=True)