""" Deadline management models for legal practice deadlines and court dates """ from sqlalchemy import Column, Integer, String, DateTime, Date, Text, ForeignKey, Boolean, Enum from sqlalchemy.orm import relationship from sqlalchemy.sql import func from enum import Enum as PyEnum from app.models.base import BaseModel class DeadlineType(PyEnum): """Types of deadlines in legal practice""" COURT_FILING = "court_filing" COURT_HEARING = "court_hearing" DISCOVERY = "discovery" STATUTE_OF_LIMITATIONS = "statute_of_limitations" CONTRACT = "contract" ADMINISTRATIVE = "administrative" CLIENT_MEETING = "client_meeting" INTERNAL = "internal" OTHER = "other" class DeadlinePriority(PyEnum): """Priority levels for deadlines""" CRITICAL = "critical" # Statute of limitations, court filings HIGH = "high" # Court hearings, important discovery MEDIUM = "medium" # Client meetings, administrative LOW = "low" # Internal deadlines, optional items class DeadlineStatus(PyEnum): """Status of deadline completion""" PENDING = "pending" COMPLETED = "completed" MISSED = "missed" CANCELLED = "cancelled" EXTENDED = "extended" class NotificationFrequency(PyEnum): """How often to send deadline reminders""" NONE = "none" DAILY = "daily" WEEKLY = "weekly" MONTHLY = "monthly" CUSTOM = "custom" class Deadline(BaseModel): """ Legal deadlines and important dates Tracks court dates, filing deadlines, statute of limitations, etc. """ __tablename__ = "deadlines" id = Column(Integer, primary_key=True, autoincrement=True) # File association file_no = Column(String(45), ForeignKey("files.file_no"), nullable=True, index=True) client_id = Column(String(80), ForeignKey("rolodex.id"), nullable=True, index=True) # Deadline details title = Column(String(200), nullable=False) description = Column(Text) deadline_date = Column(Date, nullable=False, index=True) deadline_time = Column(DateTime(timezone=True), nullable=True) # For specific times # Classification deadline_type = Column(Enum(DeadlineType), nullable=False, default=DeadlineType.OTHER) priority = Column(Enum(DeadlinePriority), nullable=False, default=DeadlinePriority.MEDIUM) status = Column(Enum(DeadlineStatus), nullable=False, default=DeadlineStatus.PENDING) # Assignment and ownership assigned_to_user_id = Column(Integer, ForeignKey("users.id"), nullable=True) assigned_to_employee_id = Column(String(10), ForeignKey("employees.empl_num"), nullable=True) created_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=False) # Court/external details court_name = Column(String(200)) # Which court if applicable case_number = Column(String(100)) # Court case number judge_name = Column(String(100)) opposing_counsel = Column(String(200)) # Notification settings notification_frequency = Column(Enum(NotificationFrequency), default=NotificationFrequency.WEEKLY) advance_notice_days = Column(Integer, default=7) # Days before deadline to start notifications last_notification_sent = Column(DateTime(timezone=True)) # Completion tracking completed_date = Column(DateTime(timezone=True)) completed_by_user_id = Column(Integer, ForeignKey("users.id")) completion_notes = Column(Text) # Extension tracking original_deadline_date = Column(Date) # Track if deadline was extended extension_reason = Column(Text) extension_granted_by = Column(String(100)) # Court, opposing counsel, etc. # Metadata created_at = Column(DateTime(timezone=True), default=func.now()) updated_at = Column(DateTime(timezone=True), default=func.now(), onupdate=func.now()) # Relationships file = relationship("File", back_populates="deadlines") client = relationship("Rolodex") assigned_to_user = relationship("User", foreign_keys=[assigned_to_user_id]) assigned_to_employee = relationship("Employee") created_by = relationship("User", foreign_keys=[created_by_user_id]) completed_by = relationship("User", foreign_keys=[completed_by_user_id]) reminders = relationship("DeadlineReminder", back_populates="deadline", cascade="all, delete-orphan") def __repr__(self): return f"" @property def is_overdue(self) -> bool: """Check if deadline is overdue""" from datetime import date return self.status == DeadlineStatus.PENDING and self.deadline_date < date.today() @property def days_until_deadline(self) -> int: """Calculate days until deadline (negative if overdue)""" from datetime import date return (self.deadline_date - date.today()).days class DeadlineReminder(BaseModel): """ Automatic reminders for deadlines Tracks when notifications were sent and their status """ __tablename__ = "deadline_reminders" id = Column(Integer, primary_key=True, autoincrement=True) deadline_id = Column(Integer, ForeignKey("deadlines.id"), nullable=False, index=True) # Reminder scheduling reminder_date = Column(Date, nullable=False, index=True) reminder_time = Column(DateTime(timezone=True)) days_before_deadline = Column(Integer, nullable=False) # How many days before deadline # Notification details notification_sent = Column(Boolean, default=False) sent_at = Column(DateTime(timezone=True)) notification_method = Column(String(50), default="email") # email, sms, in_app recipient_user_id = Column(Integer, ForeignKey("users.id")) recipient_email = Column(String(255)) # Message content subject = Column(String(200)) message = Column(Text) # Status tracking delivery_status = Column(String(50), default="pending") # pending, sent, delivered, failed error_message = Column(Text) # Metadata created_at = Column(DateTime(timezone=True), default=func.now()) # Relationships deadline = relationship("Deadline", back_populates="reminders") recipient = relationship("User") def __repr__(self): return f"" class DeadlineTemplate(BaseModel): """ Templates for common deadline types Helps standardize deadline creation for common legal processes """ __tablename__ = "deadline_templates" id = Column(Integer, primary_key=True, autoincrement=True) # Template details name = Column(String(200), nullable=False, unique=True) description = Column(Text) deadline_type = Column(Enum(DeadlineType), nullable=False) priority = Column(Enum(DeadlinePriority), nullable=False, default=DeadlinePriority.MEDIUM) # Default settings default_title_template = Column(String(200)) # Template with placeholders like {file_no}, {client_name} default_description_template = Column(Text) default_advance_notice_days = Column(Integer, default=7) default_notification_frequency = Column(Enum(NotificationFrequency), default=NotificationFrequency.WEEKLY) # Timing defaults days_from_file_open = Column(Integer) # Auto-calculate deadline based on file open date days_from_event = Column(Integer) # Days from some triggering event # Status and metadata active = Column(Boolean, default=True) created_by_user_id = Column(Integer, ForeignKey("users.id")) created_at = Column(DateTime(timezone=True), default=func.now()) updated_at = Column(DateTime(timezone=True), default=func.now(), onupdate=func.now()) # Relationships created_by = relationship("User") def __repr__(self): return f"" class DeadlineHistory(BaseModel): """ History of deadline changes and updates Maintains audit trail for deadline modifications """ __tablename__ = "deadline_history" id = Column(Integer, primary_key=True, autoincrement=True) deadline_id = Column(Integer, ForeignKey("deadlines.id"), nullable=False, index=True) # Change details change_type = Column(String(50), nullable=False) # created, updated, completed, extended, cancelled field_changed = Column(String(100)) # Which field was changed old_value = Column(Text) new_value = Column(Text) # Change context change_reason = Column(Text) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) change_date = Column(DateTime(timezone=True), default=func.now()) # Relationships deadline = relationship("Deadline") user = relationship("User") def __repr__(self): return f"" class CourtCalendar(BaseModel): """ Court calendar entries and hearing schedules Specialized deadline type for court appearances """ __tablename__ = "court_calendar" id = Column(Integer, primary_key=True, autoincrement=True) deadline_id = Column(Integer, ForeignKey("deadlines.id"), nullable=False, unique=True) # Court details court_name = Column(String(200), nullable=False) courtroom = Column(String(50)) judge_name = Column(String(100)) case_number = Column(String(100)) # Hearing details hearing_type = Column(String(100)) # Motion hearing, trial, conference, etc. estimated_duration = Column(Integer) # Minutes appearance_required = Column(Boolean, default=True) # Preparation tracking preparation_deadline = Column(Date) # When prep should be completed documents_filed = Column(Boolean, default=False) client_notified = Column(Boolean, default=False) # Outcome tracking hearing_completed = Column(Boolean, default=False) outcome = Column(Text) next_hearing_date = Column(Date) # Relationships deadline = relationship("Deadline") def __repr__(self): return f""