""" Session model for work sessions with time tracking. Tracks individual work sessions including client, project, machine used, time tracking, and session documentation. """ from datetime import date, datetime from typing import TYPE_CHECKING, Optional from sqlalchemy import Boolean, DATE, ForeignKey, Index, Integer, Numeric, String, Text, TIMESTAMP from sqlalchemy.orm import Mapped, mapped_column, relationship from .base import Base, TimestampMixin, UUIDMixin if TYPE_CHECKING: from .client import Client from .database_change import DatabaseChange from .deployment import Deployment from .infrastructure_change import InfrastructureChange from .machine import Machine from .operation_failure import OperationFailure from .project import Project from .work_item import WorkItem class Session(Base, UUIDMixin, TimestampMixin): """ Session model representing work sessions with time tracking. Tracks individual work sessions including which client, project, and machine were involved, along with timing information, billability, and session documentation. Enhanced with machine tracking to understand which machine was used for the work. Attributes: client_id: Foreign key to clients table project_id: Foreign key to projects table machine_id: Foreign key to machines table (which machine was used) session_date: Date of the session start_time: Session start timestamp end_time: Session end timestamp duration_minutes: Duration in minutes (auto-calculated or manual) status: Session status (completed, in_progress, blocked, pending) session_title: Brief title describing the session summary: Markdown summary of the session is_billable: Whether this session is billable billable_hours: Billable hours if applicable technician: Name of technician who performed the work session_log_file: Path to markdown session log file notes: Additional notes about the session client: Relationship to Client model project: Relationship to Project model machine: Relationship to Machine model """ __tablename__ = "sessions" # Foreign keys client_id: Mapped[Optional[str]] = mapped_column( String(36), ForeignKey("clients.id", ondelete="SET NULL"), doc="Foreign key to clients table" ) project_id: Mapped[Optional[str]] = mapped_column( String(36), ForeignKey("projects.id", ondelete="SET NULL"), doc="Foreign key to projects table" ) machine_id: Mapped[Optional[str]] = mapped_column( String(36), ForeignKey("machines.id", ondelete="SET NULL"), doc="Foreign key to machines table (which machine was used)" ) # Session timing session_date: Mapped[date] = mapped_column( DATE, nullable=False, doc="Date of the session" ) start_time: Mapped[Optional[datetime]] = mapped_column( TIMESTAMP, doc="Session start timestamp" ) end_time: Mapped[Optional[datetime]] = mapped_column( TIMESTAMP, doc="Session end timestamp" ) duration_minutes: Mapped[Optional[int]] = mapped_column( Integer, doc="Duration in minutes (auto-calculated or manual)" ) # Status status: Mapped[str] = mapped_column( String(50), default="completed", server_default="completed", doc="Session status: completed, in_progress, blocked, pending" ) # Session details session_title: Mapped[str] = mapped_column( String(500), nullable=False, doc="Brief title describing the session" ) summary: Mapped[Optional[str]] = mapped_column( Text, doc="Markdown summary of the session" ) # Billability is_billable: Mapped[bool] = mapped_column( Boolean, default=False, server_default="0", doc="Whether this session is billable" ) billable_hours: Mapped[Optional[float]] = mapped_column( Numeric(10, 2), doc="Billable hours if applicable" ) # Technician technician: Mapped[Optional[str]] = mapped_column( String(255), doc="Name of technician who performed the work" ) # Documentation session_log_file: Mapped[Optional[str]] = mapped_column( String(500), doc="Path to markdown session log file" ) # Notes notes: Mapped[Optional[str]] = mapped_column( Text, doc="Additional notes about the session" ) # Relationships client: Mapped[Optional["Client"]] = relationship( "Client", back_populates="sessions", doc="Relationship to Client model" ) project: Mapped[Optional["Project"]] = relationship( "Project", back_populates="sessions", doc="Relationship to Project model" ) machine: Mapped[Optional["Machine"]] = relationship( "Machine", back_populates="sessions", doc="Relationship to Machine model" ) work_items: Mapped[list["WorkItem"]] = relationship( "WorkItem", back_populates="session", cascade="all, delete-orphan", doc="Relationship to WorkItem model" ) operation_failures: Mapped[list["OperationFailure"]] = relationship( "OperationFailure", back_populates="session", cascade="all, delete-orphan", doc="Relationship to OperationFailure model" ) deployments: Mapped[list["Deployment"]] = relationship( "Deployment", back_populates="session", cascade="all, delete-orphan", doc="Relationship to Deployment model" ) database_changes: Mapped[list["DatabaseChange"]] = relationship( "DatabaseChange", back_populates="session", cascade="all, delete-orphan", doc="Relationship to DatabaseChange model" ) infrastructure_changes: Mapped[list["InfrastructureChange"]] = relationship( "InfrastructureChange", back_populates="session", cascade="all, delete-orphan", doc="Relationship to InfrastructureChange model" ) # Indexes __table_args__ = ( Index("idx_sessions_client", "client_id"), Index("idx_sessions_project", "project_id"), Index("idx_sessions_date", "session_date"), Index("idx_sessions_billable", "is_billable"), Index("idx_sessions_machine", "machine_id"), ) def __repr__(self) -> str: """String representation of the session.""" return f""