changes
This commit is contained in:
272
app/models/deadlines.py
Normal file
272
app/models/deadlines.py
Normal file
@@ -0,0 +1,272 @@
|
||||
"""
|
||||
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"<Deadline(id={self.id}, title='{self.title}', date='{self.deadline_date}', status='{self.status.value}')>"
|
||||
|
||||
@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"<DeadlineReminder(id={self.id}, deadline_id={self.deadline_id}, date='{self.reminder_date}', sent={self.notification_sent})>"
|
||||
|
||||
|
||||
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"<DeadlineTemplate(id={self.id}, name='{self.name}', type='{self.deadline_type.value}')>"
|
||||
|
||||
|
||||
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"<DeadlineHistory(id={self.id}, deadline_id={self.deadline_id}, change='{self.change_type}')>"
|
||||
|
||||
|
||||
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"<CourtCalendar(id={self.id}, court='{self.court_name}', hearing='{self.hearing_type}')>"
|
||||
Reference in New Issue
Block a user