test_task_crm/app/models/deal.py

92 lines
2.8 KiB
Python

"""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, Enum as SqlEnum, ForeignKey, Integer, Numeric, String, func
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)