""" Referrals models for cross-clinic patient referrals. This module handles referrals between departments/clinics, referral tracking, and reception notifications. """ 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, ) class Referral(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin): """ Patient referrals between clinics/departments. Tracks referral workflow from initiation to appointment booking. """ class Status(models.TextChoices): PENDING = 'PENDING', _('Pending') ACKNOWLEDGED = 'ACKNOWLEDGED', _('Acknowledged') APPOINTMENT_BOOKED = 'APPOINTMENT_BOOKED', _('Appointment Booked') COMPLETED = 'COMPLETED', _('Completed') DECLINED = 'DECLINED', _('Declined') CANCELLED = 'CANCELLED', _('Cancelled') class Priority(models.TextChoices): ROUTINE = 'ROUTINE', _('Routine') URGENT = 'URGENT', _('Urgent') EMERGENCY = 'EMERGENCY', _('Emergency') class ReferralType(models.TextChoices): INITIAL_ASSESSMENT = 'INITIAL_ASSESSMENT', _('Initial Assessment') CONSULTATION = 'CONSULTATION', _('Consultation') FOLLOW_UP = 'FOLLOW_UP', _('Follow-up') SECOND_OPINION = 'SECOND_OPINION', _('Second Opinion') # Patient & Clinics patient = models.ForeignKey( 'core.Patient', on_delete=models.CASCADE, related_name='referrals', verbose_name=_("Patient") ) from_clinic = models.ForeignKey( 'core.Clinic', on_delete=models.CASCADE, related_name='outgoing_referrals', verbose_name=_("From Clinic") ) to_clinic = models.ForeignKey( 'core.Clinic', on_delete=models.CASCADE, related_name='incoming_referrals', verbose_name=_("To Clinic") ) # Referral Details referral_type = models.CharField( max_length=30, choices=ReferralType.choices, default=ReferralType.CONSULTATION, verbose_name=_("Referral Type") ) priority = models.CharField( max_length=15, choices=Priority.choices, default=Priority.ROUTINE, verbose_name=_("Priority") ) reason = models.TextField( verbose_name=_("Reason for Referral"), help_text=_("Clinical reason for referring to another department") ) clinical_notes = models.TextField( blank=True, verbose_name=_("Clinical Notes"), help_text=_("Additional clinical information for receiving clinic") ) # Workflow referred_by = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, related_name='made_referrals', verbose_name=_("Referred By") ) referred_to = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='received_referrals', verbose_name=_("Referred To"), help_text=_("Specific therapist if known") ) # Status Tracking status = models.CharField( max_length=30, choices=Status.choices, default=Status.PENDING, verbose_name=_("Status") ) acknowledged_at = models.DateTimeField( null=True, blank=True, verbose_name=_("Acknowledged At") ) acknowledged_by = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='acknowledged_referrals', verbose_name=_("Acknowledged By") ) # Appointment Linkage appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='referrals', verbose_name=_("Appointment"), help_text=_("Appointment booked for this referral") ) appointment_booked_at = models.DateTimeField( null=True, blank=True, verbose_name=_("Appointment Booked At") ) appointment_booked_by = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='booked_referral_appointments', verbose_name=_("Appointment Booked By") ) # Completion completed_at = models.DateTimeField( null=True, blank=True, verbose_name=_("Completed At") ) outcome_notes = models.TextField( blank=True, verbose_name=_("Outcome Notes"), help_text=_("Notes about the referral outcome") ) # Decline/Cancel declined_at = models.DateTimeField( null=True, blank=True, verbose_name=_("Declined At") ) declined_by = models.ForeignKey( 'core.User', on_delete=models.SET_NULL, null=True, blank=True, related_name='declined_referrals', verbose_name=_("Declined By") ) decline_reason = models.TextField( blank=True, verbose_name=_("Decline Reason") ) history = HistoricalRecords() class Meta: verbose_name = _("Referral") verbose_name_plural = _("Referrals") ordering = ['-created_at'] indexes = [ models.Index(fields=['patient', 'status']), models.Index(fields=['from_clinic', 'status']), models.Index(fields=['to_clinic', 'status']), models.Index(fields=['referred_by', 'status']), models.Index(fields=['status', 'created_at']), models.Index(fields=['tenant', 'status']), ] def __str__(self): return f"Referral: {self.patient} from {self.from_clinic.name_en} to {self.to_clinic.name_en}" def acknowledge(self, user): """Acknowledge receipt of referral.""" from django.utils import timezone self.status = self.Status.ACKNOWLEDGED self.acknowledged_at = timezone.now() self.acknowledged_by = user self.save() def book_appointment(self, appointment, user): """Link appointment to referral.""" from django.utils import timezone self.appointment = appointment self.status = self.Status.APPOINTMENT_BOOKED self.appointment_booked_at = timezone.now() self.appointment_booked_by = user self.save() def complete(self, outcome_notes=""): """Mark referral as completed.""" from django.utils import timezone self.status = self.Status.COMPLETED self.completed_at = timezone.now() self.outcome_notes = outcome_notes self.save() def decline(self, user, reason): """Decline the referral.""" from django.utils import timezone self.status = self.Status.DECLINED self.declined_at = timezone.now() self.declined_by = user self.decline_reason = reason self.save() @classmethod def get_pending_for_clinic(cls, clinic, tenant): """Get pending referrals for a clinic.""" return cls.objects.filter( to_clinic=clinic, tenant=tenant, status=cls.Status.PENDING ).select_related('patient', 'from_clinic', 'referred_by') @classmethod def get_pending_for_reception(cls, tenant): """Get referrals pending appointment booking.""" return cls.objects.filter( tenant=tenant, status__in=[cls.Status.PENDING, cls.Status.ACKNOWLEDGED], appointment__isnull=True ).select_related('patient', 'from_clinic', 'to_clinic', 'referred_by')