diff --git a/app/models/account.py b/app/models/account.py new file mode 100644 index 0000000..0e3315c --- /dev/null +++ b/app/models/account.py @@ -0,0 +1,86 @@ +"""Account model: companies/organizations that the CRM tracks.""" + +from __future__ import annotations + +from enum import Enum +from typing import TYPE_CHECKING, Any, Optional + +from sqlalchemy import JSON, ForeignKey, String +from sqlalchemy.orm import Mapped, mapped_column, relationship + +from app.models.base import Base, OrgScopedMixin, SoftDeleteMixin, TimestampMixin + +if TYPE_CHECKING: + from app.models.user import User + from app.models.contact import Contact + from app.models.deal import Deal + from app.models.activity import Activity + from app.models.note import Note + from app.models.tag_link import TagLink + + +class Industry(str, Enum): + """Industry classification for accounts.""" + + startup = "startup" + sme = "sme" + midmarket = "midmarket" + enterprise = "enterprise" + other = "other" + + +class AccountSize(str, Enum): + """Company size category.""" + + startup = "startup" + sme = "sme" + midmarket = "midmarket" + enterprise = "enterprise" + + +class Account(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin): + __tablename__ = "accounts" + + id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) + name: Mapped[str] = mapped_column(String(255), nullable=False, index=True) + website: Mapped[Optional[str]] = mapped_column(String(512), nullable=True) + industry: Mapped[Optional[Industry]] = mapped_column( + String(32), nullable=True, index=True + ) + size: Mapped[Optional[AccountSize]] = mapped_column(String(32), nullable=True) + address: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON, nullable=True) + owner_id: Mapped[int] = mapped_column( + ForeignKey("users.id"), nullable=False, index=True + ) + + # Relationships + owner: Mapped["User"] = relationship( + "User", foreign_keys=[owner_id], lazy="joined" + ) + contacts: Mapped[list["Contact"]] = relationship( + "Contact", back_populates="account", lazy="selectin" + ) + deals: Mapped[list["Deal"]] = relationship( + "Deal", back_populates="account", lazy="selectin" + ) + activities: Mapped[list["Activity"]] = relationship( + "Activity", back_populates="account", lazy="selectin" + ) + notes: Mapped[list["Note"]] = relationship( + "Note", + primaryjoin="and_(Account.id==foreign(Note.parent_id), Note.parent_type=='account')", + viewonly=True, + lazy="selectin", + ) + tags: Mapped[list["TagLink"]] = relationship( + "TagLink", + primaryjoin="and_(Account.id==foreign(TagLink.parent_id), TagLink.parent_type=='account')", + viewonly=True, + lazy="selectin", + ) + + def __repr__(self) -> str: + return f"" + + +__all__ = ["Account", "AccountSize", "Industry"]