86 lines
2.7 KiB
Python
86 lines
2.7 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)
|