""" Speech-Language Pathology (SLP) models for the Tenhal Multidisciplinary Healthcare Platform. This module handles SLP consultations, assessments, interventions, and progress reports based on SLP-F-1, F-2, F-3, and F-4 forms. """ from django.db import models from django.utils.translation import gettext_lazy as _ from simple_history.models import HistoricalRecords from core.models import ( UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin, ) class SLPConsult(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ SLP consultation form (SLP-F-1) with variants. Initial consultation with variant-specific questionnaires. """ class ConsultVariant(models.TextChoices): ASD = 'ASD', _('Autism Spectrum Disorder') LANGUAGE_DELAY = 'LANGUAGE_DELAY', _('Language Delay') FLUENCY = 'FLUENCY', _('Fluency Disorder') class ServiceType(models.TextChoices): CONSULT = 'CONSULT', _('Consultation') EVAL = 'EVAL', _('Evaluation') INTERVENTION = 'INTERVENTION', _('Intervention') PARENT_TRAINING = 'PARENT_TRAINING', _('Parent Training') # Core Relationships patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='slp_consults', verbose_name=_("Patient") ) appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='slp_consults', verbose_name=_("Appointment") ) consultation_date = models.DateField( verbose_name=_("Consultation Date") ) provider = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, related_name='slp_consults_provided', verbose_name=_("Provider") ) # Consultation Details consult_variant = models.CharField( max_length=20, choices=ConsultVariant.choices, verbose_name=_("Consultation Variant") ) primary_concern = models.TextField( blank=True, verbose_name=_("Primary Concern") ) suspected_areas = models.TextField( blank=True, help_text=_("List of suspected problem areas"), verbose_name=_("Suspected Areas") ) type_of_service = models.CharField( max_length=20, choices=ServiceType.choices, verbose_name=_("Type of Service") ) # Communication & Environment communication_modes = models.TextField( blank=True, help_text=_("Communication modes checklist (verbal, gestures, AAC, etc.)"), verbose_name=_("Communication Modes") ) screen_time_hours = models.PositiveIntegerField( null=True, blank=True, verbose_name=_("Screen Time (hours/day)") ) # Variant-Specific Questionnaire variant_questionnaire = models.TextField( blank=True, help_text=_("Variant-specific questions and answers"), verbose_name=_("Variant Questionnaire") ) # Skills to Observe (TextField) skills_to_observe = models.TextField( blank=True, help_text=_("Skills observation matrix"), verbose_name=_("Skills to Observe") ) # Oral Motor Screening oral_motor_screening = models.TextField( blank=True, help_text=_("Oral motor screening results"), verbose_name=_("Oral Motor Screening") ) # Recommendations recommendations = models.TextField( blank=True, verbose_name=_("Recommendations") ) history = HistoricalRecords() class Meta: verbose_name = _("SLP Consultation") verbose_name_plural = _("SLP Consultations") ordering = ['-consultation_date', '-created_at'] indexes = [ models.Index(fields=['patient', 'consultation_date']), models.Index(fields=['provider', 'consultation_date']), models.Index(fields=['consult_variant']), models.Index(fields=['tenant', 'consultation_date']), ] def __str__(self): return f"SLP Consultation ({self.get_consult_variant_display()}) - {self.patient} - {self.consultation_date}" class SLPAssessment(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ SLP assessment/reassessment form (SLP-F-2). Comprehensive evaluation with standardized tests. """ # Core Relationships patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='slp_assessments', verbose_name=_("Patient") ) appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='slp_assessments', verbose_name=_("Appointment") ) assessment_date = models.DateField( verbose_name=_("Assessment Date") ) provider = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, related_name='slp_assessments_provided', verbose_name=_("Provider") ) # Diagnosis & History diagnosis_statement = models.TextField( blank=True, verbose_name=_("Diagnosis Statement") ) case_history = models.TextField( blank=True, verbose_name=_("Case History") ) # History Sections prenatal_history = models.TextField( blank=True, verbose_name=_("Prenatal History") ) perinatal_history = models.TextField( blank=True, verbose_name=_("Perinatal History") ) postnatal_history = models.TextField( blank=True, verbose_name=_("Postnatal History") ) developmental_history = models.TextField( blank=True, verbose_name=_("Developmental History") ) medical_status = models.TextField( blank=True, verbose_name=_("Medical Status") ) # Speech/Language Detail speech_language_detail = models.TextField( blank=True, help_text=_("Detailed speech and language assessment"), verbose_name=_("Speech/Language Detail") ) # Test Scores gfta3_score = models.CharField( max_length=100, blank=True, help_text=_("Goldman-Fristoe Test of Articulation-3 score"), verbose_name=_("GFTA-3 Score") ) jat_score = models.CharField( max_length=100, blank=True, help_text=_("Joliet Articulation Test score"), verbose_name=_("JAT Score") ) ssi_score = models.CharField( max_length=100, blank=True, help_text=_("Stuttering Severity Instrument score"), verbose_name=_("SSI Score") ) # Oral Mechanism oral_mechanism = models.TextField( blank=True, help_text=_("Oral mechanism examination findings"), verbose_name=_("Oral Mechanism") ) # Rossetti Domains (TextField) rossetti_domains = models.TextField( blank=True, help_text=_("Rossetti Infant-Toddler Language Scale domains and age levels"), verbose_name=_("Rossetti Domains") ) # Joint Attention Skills joint_attention_skills = models.TextField( blank=True, help_text=_("Joint attention skills assessment (present/absent)"), verbose_name=_("Joint Attention Skills") ) # Summary & Plan clinical_summary = models.TextField( blank=True, verbose_name=_("Clinical Summary") ) recommendations = models.TextField( blank=True, verbose_name=_("Recommendations") ) frequency_per_week = models.PositiveIntegerField( null=True, blank=True, help_text=_("Recommended frequency (sessions per week)"), verbose_name=_("Frequency (per week)") ) session_duration_minutes = models.PositiveIntegerField( null=True, blank=True, verbose_name=_("Session Duration (minutes)") ) # Referral Rules referral_rules = models.TextField( blank=True, help_text=_("Referral recommendations to other services"), verbose_name=_("Referral Rules") ) history = HistoricalRecords() class Meta: verbose_name = _("SLP Assessment") verbose_name_plural = _("SLP Assessments") ordering = ['-assessment_date', '-created_at'] indexes = [ models.Index(fields=['patient', 'assessment_date']), models.Index(fields=['provider', 'assessment_date']), models.Index(fields=['tenant', 'assessment_date']), ] def __str__(self): return f"SLP Assessment - {self.patient} - {self.assessment_date}" class SLPIntervention(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ SLP intervention session form (SLP-F-3). Session notes with SOAP format for targets. """ # Core Relationships patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='slp_interventions', verbose_name=_("Patient") ) appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='slp_interventions', verbose_name=_("Appointment") ) session_number = models.PositiveIntegerField( verbose_name=_("Session Number") ) session_date = models.DateField( verbose_name=_("Session Date") ) session_time = models.TimeField( verbose_name=_("Session Time") ) provider = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, related_name='slp_interventions_provided', verbose_name=_("Provider") ) # Previous Session Link previous_session = models.ForeignKey( 'self', on_delete=models.SET_NULL, null=True, blank=True, related_name='next_sessions', verbose_name=_("Previous Session") ) # Intervention Targets (JSON format - similar to OT target_skills) intervention_targets_json = models.TextField( blank=True, default='[]', help_text=_("JSON array of intervention targets with SOAP format"), verbose_name=_("Intervention Targets (JSON)") ) history = HistoricalRecords() class Meta: verbose_name = _("SLP Intervention") verbose_name_plural = _("SLP Interventions") ordering = ['-session_date', '-session_number'] indexes = [ models.Index(fields=['patient', 'session_date']), models.Index(fields=['provider', 'session_date']), models.Index(fields=['session_number']), models.Index(fields=['tenant', 'session_date']), ] def __str__(self): return f"SLP Intervention Session #{self.session_number} - {self.patient} - {self.session_date}" class SLPTarget(UUIDPrimaryKeyMixin): """ Intervention targets with SOAP format. Typically 1-2 targets per session. """ intervention = models.ForeignKey( SLPIntervention, on_delete=models.CASCADE, related_name='targets', verbose_name=_("Intervention") ) target_number = models.PositiveSmallIntegerField( help_text=_("Target number (1 or 2)"), verbose_name=_("Target Number") ) # SOAP Format subjective = models.TextField( blank=True, help_text=_("Subjective observations"), verbose_name=_("Subjective") ) objective = models.TextField( blank=True, help_text=_("Objective measurements and data"), verbose_name=_("Objective") ) assessment = models.TextField( blank=True, help_text=_("Assessment of progress"), verbose_name=_("Assessment") ) plan = models.TextField( blank=True, help_text=_("Plan for next session"), verbose_name=_("Plan") ) # Prompt Strategies prompt_strategies = models.TextField( blank=True, help_text=_("List of prompting strategies used"), verbose_name=_("Prompt Strategies") ) class Meta: verbose_name = _("SLP Target") verbose_name_plural = _("SLP Targets") ordering = ['intervention', 'target_number'] unique_together = [['intervention', 'target_number']] def __str__(self): return f"Target #{self.target_number} - Session #{self.intervention.session_number}" class SLPProgressReport(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ SLP progress report form (SLP-F-4). Comprehensive progress summary with outcomes. """ # Core Relationships patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='slp_progress_reports', verbose_name=_("Patient") ) report_date = models.DateField( verbose_name=_("Report Date") ) provider = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, related_name='slp_progress_reports_provided', verbose_name=_("Provider") ) # Session Summary sessions_scheduled = models.PositiveIntegerField( default=0, verbose_name=_("Sessions Scheduled") ) sessions_attended = models.PositiveIntegerField( default=0, verbose_name=_("Sessions Attended") ) # Diagnosis final_diagnosis = models.TextField( blank=True, verbose_name=_("Final Diagnosis") ) # Objectives & Progress (TextField) objectives_progress = models.TextField( blank=True, help_text=_("Progress on each objective with percentage accuracy"), verbose_name=_("Objectives Progress") ) # Plan Details plan_details = models.TextField( blank=True, help_text=_("Plan details (continue/add/fade prompts/generalization)"), verbose_name=_("Plan Details") ) # Progress Summary overall_progress = models.TextField( blank=True, verbose_name=_("Overall Progress") ) participation_level = models.TextField( blank=True, verbose_name=_("Participation Level") ) attendance_rate = models.DecimalField( max_digits=5, decimal_places=2, null=True, blank=True, help_text=_("Attendance rate percentage"), verbose_name=_("Attendance Rate (%)") ) carryover_level = models.TextField( blank=True, verbose_name=_("Carryover Level") ) prognosis = models.TextField( blank=True, verbose_name=_("Prognosis") ) # Recommendations recommendations = models.TextField( blank=True, verbose_name=_("Recommendations") ) package_sessions_count = models.PositiveIntegerField( null=True, blank=True, help_text=_("Recommended number of sessions in package"), verbose_name=_("Package Sessions Count") ) reassessment_needed = models.BooleanField( default=False, verbose_name=_("Reassessment Needed") ) history = HistoricalRecords() class Meta: verbose_name = _("SLP Progress Report") verbose_name_plural = _("SLP Progress Reports") ordering = ['-report_date', '-created_at'] indexes = [ models.Index(fields=['patient', 'report_date']), models.Index(fields=['provider', 'report_date']), models.Index(fields=['tenant', 'report_date']), ] def __str__(self): return f"SLP Progress Report - {self.patient} - {self.report_date}" def save(self, *args, **kwargs): # Auto-calculate attendance rate if not set if self.sessions_scheduled > 0 and not self.attendance_rate: self.attendance_rate = round( (self.sessions_attended / self.sessions_scheduled) * 100, 2 ) super().save(*args, **kwargs)