""" Client model for all client organizations. Master table for MSP clients, internal projects, and client organizations. """ from typing import TYPE_CHECKING, Optional from sqlalchemy import Boolean, Index, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from .base import Base, TimestampMixin, UUIDMixin if TYPE_CHECKING: from .pending_task import PendingTask from .project import Project from .session import Session class Client(Base, UUIDMixin, TimestampMixin): """ Client model representing client organizations. Master table for all client organizations including MSP clients, internal projects, and project-based clients. Stores client identification, network information, and Microsoft 365 tenant details. Attributes: name: Client name (unique) type: Client type (msp_client, internal, project) network_subnet: Client network subnet (e.g., "192.168.0.0/24") domain_name: Active Directory domain or primary domain m365_tenant_id: Microsoft 365 tenant ID primary_contact: Primary contact person notes: Additional notes about the client is_active: Whether client is currently active """ __tablename__ = "clients" # Client identification name: Mapped[str] = mapped_column( String(255), nullable=False, unique=True, doc="Client name (unique)" ) type: Mapped[str] = mapped_column( String(50), nullable=False, doc="Client type: msp_client, internal, project" ) # Network information network_subnet: Mapped[Optional[str]] = mapped_column( String(100), doc="Client network subnet (e.g., '192.168.0.0/24')" ) domain_name: Mapped[Optional[str]] = mapped_column( String(255), doc="Active Directory domain or primary domain" ) # Microsoft 365 m365_tenant_id: Mapped[Optional[str]] = mapped_column( String(36), doc="Microsoft 365 tenant ID (UUID format)" ) # Contact information primary_contact: Mapped[Optional[str]] = mapped_column( String(255), doc="Primary contact person" ) # Notes notes: Mapped[Optional[str]] = mapped_column( Text, doc="Additional notes about the client" ) # Status is_active: Mapped[bool] = mapped_column( Boolean, default=True, server_default="1", doc="Whether client is currently active" ) # Relationships projects: Mapped[list["Project"]] = relationship( "Project", back_populates="client", cascade="all, delete-orphan", doc="Projects associated with this client" ) sessions: Mapped[list["Session"]] = relationship( "Session", back_populates="client", doc="Sessions associated with this client" ) pending_tasks: Mapped[list["PendingTask"]] = relationship( "PendingTask", back_populates="client", doc="Pending tasks associated with this client" ) # Indexes __table_args__ = ( Index("idx_clients_type", "type"), Index("idx_clients_name", "name"), ) def __repr__(self) -> str: """String representation of the client.""" return f""