""" Psychology models for the Tenhal Multidisciplinary Healthcare Platform. This module handles psychological consultations, assessments, and interventions. """ 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 PsychologyConsultation(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ Psychology consultation form. Initial psychological evaluation and assessment. """ class ReferralReason(models.TextChoices): BEHAVIORAL_ISSUES = 'BEHAVIORAL', _('Behavioral Issues') EMOTIONAL_DIFFICULTIES = 'EMOTIONAL', _('Emotional Difficulties') DEVELOPMENTAL_CONCERNS = 'DEVELOPMENTAL', _('Developmental Concerns') LEARNING_DIFFICULTIES = 'LEARNING', _('Learning Difficulties') SOCIAL_SKILLS = 'SOCIAL', _('Social Skills Deficits') ANXIETY = 'ANXIETY', _('Anxiety') DEPRESSION = 'DEPRESSION', _('Depression') TRAUMA = 'TRAUMA', _('Trauma/PTSD') ADHD_ASSESSMENT = 'ADHD', _('ADHD Assessment') AUTISM_ASSESSMENT = 'AUTISM', _('Autism Spectrum Assessment') OTHER = 'OTHER', _('Other') # Core Relationships patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='psychology_consultations', verbose_name=_("Patient") ) appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='psychology_consultations', 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='psychology_consultations_provided', verbose_name=_("Provider") ) # Referral Information referral_reason = models.CharField( max_length=50, choices=ReferralReason.choices, verbose_name=_("Referral Reason") ) referral_source = models.CharField( max_length=200, blank=True, verbose_name=_("Referral Source") ) presenting_problem = models.TextField( verbose_name=_("Presenting Problem") ) # Background Information family_history = models.TextField( blank=True, verbose_name=_("Family History") ) medical_history = models.TextField( blank=True, verbose_name=_("Medical History") ) developmental_history = models.TextField( blank=True, verbose_name=_("Developmental History") ) educational_history = models.TextField( blank=True, verbose_name=_("Educational History") ) social_history = models.TextField( blank=True, verbose_name=_("Social History") ) # Mental Status Examination appearance = models.TextField( blank=True, verbose_name=_("Appearance") ) behavior = models.TextField( blank=True, verbose_name=_("Behavior") ) mood = models.CharField( max_length=200, blank=True, verbose_name=_("Mood") ) affect = models.CharField( max_length=200, blank=True, verbose_name=_("Affect") ) speech = models.TextField( blank=True, verbose_name=_("Speech") ) thought_process = models.TextField( blank=True, verbose_name=_("Thought Process") ) thought_content = models.TextField( blank=True, verbose_name=_("Thought Content") ) perception = models.TextField( blank=True, verbose_name=_("Perception") ) cognition = models.TextField( blank=True, verbose_name=_("Cognition") ) insight = models.CharField( max_length=200, blank=True, verbose_name=_("Insight") ) judgment = models.CharField( max_length=200, blank=True, verbose_name=_("Judgment") ) # Risk Assessment suicide_risk = models.CharField( max_length=50, blank=True, choices=[ ('NONE', _('None')), ('LOW', _('Low')), ('MODERATE', _('Moderate')), ('HIGH', _('High')), ], verbose_name=_("Suicide Risk") ) homicide_risk = models.CharField( max_length=50, blank=True, choices=[ ('NONE', _('None')), ('LOW', _('Low')), ('MODERATE', _('Moderate')), ('HIGH', _('High')), ], verbose_name=_("Homicide Risk") ) risk_assessment_notes = models.TextField( blank=True, verbose_name=_("Risk Assessment Notes") ) # Clinical Impressions clinical_impressions = models.TextField( blank=True, verbose_name=_("Clinical Impressions") ) provisional_diagnosis = models.TextField( blank=True, verbose_name=_("Provisional Diagnosis") ) # Treatment Plan treatment_goals = models.TextField( blank=True, verbose_name=_("Treatment Goals") ) treatment_approach = models.TextField( blank=True, verbose_name=_("Treatment Approach") ) recommendations = models.TextField( blank=True, verbose_name=_("Recommendations") ) frequency_duration = models.CharField( max_length=200, blank=True, verbose_name=_("Recommended Frequency & Duration") ) # Referrals referrals_needed = models.TextField( blank=True, verbose_name=_("Referrals Needed") ) history = HistoricalRecords() class Meta: verbose_name = _("Psychology Consultation") verbose_name_plural = _("Psychology Consultations") ordering = ['-consultation_date', '-created_at'] indexes = [ models.Index(fields=['patient', 'consultation_date']), models.Index(fields=['provider', 'consultation_date']), models.Index(fields=['referral_reason']), models.Index(fields=['tenant', 'consultation_date']), ] def __str__(self): return f"Psychology Consultation - {self.patient} - {self.consultation_date}" class PsychologyAssessment(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ Psychological assessment with standardized testing. Comprehensive evaluation using psychological tests and measures. """ class AssessmentType(models.TextChoices): COGNITIVE = 'COGNITIVE', _('Cognitive Assessment') DEVELOPMENTAL = 'DEVELOPMENTAL', _('Developmental Assessment') BEHAVIORAL = 'BEHAVIORAL', _('Behavioral Assessment') EMOTIONAL = 'EMOTIONAL', _('Emotional Assessment') PERSONALITY = 'PERSONALITY', _('Personality Assessment') NEUROPSYCHOLOGICAL = 'NEUROPSYCH', _('Neuropsychological Assessment') COMPREHENSIVE = 'COMPREHENSIVE', _('Comprehensive Assessment') # Core Relationships patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='psychology_assessments', verbose_name=_("Patient") ) appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='psychology_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='psychology_assessments_provided', verbose_name=_("Provider") ) # Assessment Details assessment_type = models.CharField( max_length=50, choices=AssessmentType.choices, verbose_name=_("Assessment Type") ) reason_for_assessment = models.TextField( verbose_name=_("Reason for Assessment") ) # Background Information relevant_history = models.TextField( blank=True, verbose_name=_("Relevant History") ) current_medications = models.TextField( blank=True, verbose_name=_("Current Medications") ) # Tests Administered (JSON for flexibility) tests_administered = models.JSONField( default=list, blank=True, help_text=_("List of tests with scores and interpretations"), verbose_name=_("Tests Administered") ) # Behavioral Observations behavioral_observations = models.TextField( blank=True, verbose_name=_("Behavioral Observations During Testing") ) test_validity = models.TextField( blank=True, verbose_name=_("Test Validity & Reliability") ) # Results Summary cognitive_functioning = models.TextField( blank=True, verbose_name=_("Cognitive Functioning") ) emotional_functioning = models.TextField( blank=True, verbose_name=_("Emotional Functioning") ) behavioral_functioning = models.TextField( blank=True, verbose_name=_("Behavioral Functioning") ) social_functioning = models.TextField( blank=True, verbose_name=_("Social Functioning") ) adaptive_functioning = models.TextField( blank=True, verbose_name=_("Adaptive Functioning") ) # Strengths & Weaknesses strengths = models.TextField( blank=True, verbose_name=_("Strengths") ) weaknesses = models.TextField( blank=True, verbose_name=_("Areas of Concern/Weakness") ) # Diagnosis diagnostic_impressions = models.TextField( blank=True, verbose_name=_("Diagnostic Impressions") ) dsm5_diagnosis = models.TextField( blank=True, verbose_name=_("DSM-5 Diagnosis") ) # Recommendations recommendations = models.TextField( blank=True, verbose_name=_("Recommendations") ) treatment_recommendations = models.TextField( blank=True, verbose_name=_("Treatment Recommendations") ) educational_recommendations = models.TextField( blank=True, verbose_name=_("Educational Recommendations") ) follow_up_recommendations = models.TextField( blank=True, verbose_name=_("Follow-up Recommendations") ) history = HistoricalRecords() class Meta: verbose_name = _("Psychology Assessment") verbose_name_plural = _("Psychology Assessments") ordering = ['-assessment_date', '-created_at'] indexes = [ models.Index(fields=['patient', 'assessment_date']), models.Index(fields=['provider', 'assessment_date']), models.Index(fields=['assessment_type']), models.Index(fields=['tenant', 'assessment_date']), ] def __str__(self): return f"Psychology Assessment ({self.get_assessment_type_display()}) - {self.patient} - {self.assessment_date}" class PsychologySession(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ Psychology therapy session notes. Individual or group therapy session documentation. """ class SessionType(models.TextChoices): INDIVIDUAL = 'INDIVIDUAL', _('Individual Therapy') GROUP = 'GROUP', _('Group Therapy') FAMILY = 'FAMILY', _('Family Therapy') PARENT_TRAINING = 'PARENT_TRAINING', _('Parent Training') CONSULTATION = 'CONSULTATION', _('Consultation') class TherapyModality(models.TextChoices): CBT = 'CBT', _('Cognitive Behavioral Therapy') DBT = 'DBT', _('Dialectical Behavior Therapy') PSYCHODYNAMIC = 'PSYCHODYNAMIC', _('Psychodynamic Therapy') HUMANISTIC = 'HUMANISTIC', _('Humanistic Therapy') PLAY_THERAPY = 'PLAY_THERAPY', _('Play Therapy') ART_THERAPY = 'ART_THERAPY', _('Art Therapy') MINDFULNESS = 'MINDFULNESS', _('Mindfulness-Based Therapy') SOLUTION_FOCUSED = 'SOLUTION_FOCUSED', _('Solution-Focused Therapy') OTHER = 'OTHER', _('Other') # Core Relationships patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='psychology_sessions', verbose_name=_("Patient") ) appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='psychology_sessions', verbose_name=_("Appointment") ) # NEW: Link to centralized session (for scheduling/capacity management) session = models.ForeignKey( 'appointments.Session', on_delete=models.CASCADE, null=True, blank=True, related_name='psychology_notes', verbose_name=_("Session"), help_text=_("Link to centralized session for scheduling") ) # NEW: Link to specific participant (for group sessions) session_participant = models.ForeignKey( 'appointments.SessionParticipant', on_delete=models.CASCADE, null=True, blank=True, related_name='psychology_notes', verbose_name=_("Session Participant"), help_text=_("For group sessions: which participant these notes are for") ) session_number = models.PositiveIntegerField( verbose_name=_("Session Number") ) session_date = models.DateField( verbose_name=_("Session Date") ) provider = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, related_name='psychology_sessions_provided', verbose_name=_("Provider") ) # Session Details session_type = models.CharField( max_length=50, choices=SessionType.choices, verbose_name=_("Session Type") ) therapy_modality = models.CharField( max_length=50, choices=TherapyModality.choices, blank=True, verbose_name=_("Therapy Modality") ) duration_minutes = models.PositiveIntegerField( null=True, blank=True, verbose_name=_("Duration (minutes)") ) # Session Content presenting_issues = models.TextField( blank=True, verbose_name=_("Presenting Issues This Session") ) interventions_used = models.TextField( blank=True, verbose_name=_("Interventions Used") ) client_response = models.TextField( blank=True, verbose_name=_("Client Response to Interventions") ) # Progress Notes progress_toward_goals = models.TextField( blank=True, verbose_name=_("Progress Toward Goals") ) behavioral_observations = models.TextField( blank=True, verbose_name=_("Behavioral Observations") ) mood_affect = models.CharField( max_length=200, blank=True, verbose_name=_("Mood & Affect") ) # Risk Assessment current_risk_level = models.CharField( max_length=50, blank=True, choices=[ ('NONE', _('None')), ('LOW', _('Low')), ('MODERATE', _('Moderate')), ('HIGH', _('High')), ], verbose_name=_("Current Risk Level") ) risk_notes = models.TextField( blank=True, verbose_name=_("Risk Assessment Notes") ) # Homework & Plan homework_assigned = models.TextField( blank=True, verbose_name=_("Homework Assigned") ) plan_for_next_session = models.TextField( blank=True, verbose_name=_("Plan for Next Session") ) # Clinical Notes clinical_notes = models.TextField( blank=True, verbose_name=_("Additional Clinical Notes") ) history = HistoricalRecords() class Meta: verbose_name = _("Psychology Session") verbose_name_plural = _("Psychology Sessions") 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"Psychology Session #{self.session_number} - {self.patient} - {self.session_date}" class PsychologyGoal(UUIDPrimaryKeyMixin, TimeStampedMixin): """ Treatment goals for psychology therapy. Tracks progress toward therapeutic objectives. """ class Status(models.TextChoices): NOT_STARTED = 'NOT_STARTED', _('Not Started') IN_PROGRESS = 'IN_PROGRESS', _('In Progress') ACHIEVED = 'ACHIEVED', _('Achieved') DISCONTINUED = 'DISCONTINUED', _('Discontinued') MODIFIED = 'MODIFIED', _('Modified') patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='psychology_goals', verbose_name=_("Patient") ) consultation = models.ForeignKey( PsychologyConsultation, on_delete=models.CASCADE, null=True, blank=True, related_name='goals', verbose_name=_("Consultation") ) goal_description = models.TextField( verbose_name=_("Goal Description") ) target_date = models.DateField( null=True, blank=True, verbose_name=_("Target Date") ) status = models.CharField( max_length=20, choices=Status.choices, default=Status.NOT_STARTED, verbose_name=_("Status") ) progress_percentage = models.PositiveSmallIntegerField( default=0, help_text=_("Progress percentage (0-100)"), verbose_name=_("Progress (%)") ) progress_notes = models.TextField( blank=True, verbose_name=_("Progress Notes") ) achieved_date = models.DateField( null=True, blank=True, verbose_name=_("Achieved Date") ) class Meta: verbose_name = _("Psychology Goal") verbose_name_plural = _("Psychology Goals") ordering = ['patient', 'target_date'] def __str__(self): return f"{self.goal_description[:50]} - {self.get_status_display()}" class PsychologyProgressReport(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin): """ Psychology progress report. Comprehensive summary of treatment progress. """ patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='psychology_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='psychology_progress_reports_provided', verbose_name=_("Provider") ) # Treatment Summary treatment_start_date = models.DateField( null=True, blank=True, verbose_name=_("Treatment Start Date") ) sessions_scheduled = models.PositiveIntegerField( default=0, verbose_name=_("Sessions Scheduled") ) sessions_attended = models.PositiveIntegerField( default=0, verbose_name=_("Sessions Attended") ) # Progress Summary presenting_problems_summary = models.TextField( blank=True, verbose_name=_("Presenting Problems Summary") ) treatment_provided = models.TextField( blank=True, verbose_name=_("Treatment Provided") ) goals_progress = models.TextField( blank=True, verbose_name=_("Progress Toward Goals") ) overall_progress = models.TextField( blank=True, verbose_name=_("Overall Progress") ) # Current Status current_functioning = models.TextField( blank=True, verbose_name=_("Current Functioning") ) current_symptoms = models.TextField( blank=True, verbose_name=_("Current Symptoms") ) # Recommendations recommendations = models.TextField( blank=True, verbose_name=_("Recommendations") ) continue_treatment = models.BooleanField( default=True, verbose_name=_("Continue Treatment") ) discharge_plan = models.TextField( blank=True, verbose_name=_("Discharge Plan") ) # Prognosis prognosis = models.TextField( blank=True, verbose_name=_("Prognosis") ) history = HistoricalRecords() class Meta: verbose_name = _("Psychology Progress Report") verbose_name_plural = _("Psychology 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"Psychology Progress Report - {self.patient} - {self.report_date}" @property def attendance_rate(self): """Calculate attendance rate percentage.""" if self.sessions_scheduled > 0: return round((self.sessions_attended / self.sessions_scheduled) * 100, 2) return 0