Marwan Alwali 263292f6be update
2025-11-04 00:50:06 +03:00

10 KiB

Appointments, Queuing, and waiting list

  1. Detailed Feature Specifications

1.1. Appointment Management System

1.1.1 Core Scheduling Logic

# appointments/models.py (simplified)
class Appointment(models.Model):
    APPOINTMENT_STATUS = (
        ('scheduled', 'Scheduled'),
        ('confirmed', 'Confirmed'),
        ('checked_in', 'Checked In'),
        ('in_progress', 'In Progress'),
        ('completed', 'Completed'),
        ('cancelled', 'Cancelled'),
        ('no_show', 'No Show'),
    )
    
    patient = models.ForeignKey('accounts.Patient', on_delete=models.CASCADE)
    provider = models.ForeignKey('accounts.HealthcareProvider', on_delete=models.CASCADE)
    appointment_type = models.ForeignKey('AppointmentType', on_delete=models.PROTECT)
    scheduled_time = models.DateTimeField()
    duration = models.DurationField(default=timedelta(minutes=30))
    status = models.CharField(max_length=20, choices=APPOINTMENT_STATUS, default='scheduled')
    reason_for_visit = models.TextField()
    
    # Smart scheduling fields
    priority_score = models.IntegerField(default=0)  # For triage logic
    is_waitlist_conversion = models.BooleanField(default=False)

1.1.2 Scheduling Algorithms

# appointments/logic/scheduling.py
class SmartScheduler:
    def find_optimal_slot(self, patient, provider, appointment_type, preferred_dates):
        """Implements multi-factor slot finding"""
        
        # Factor 1: Provider availability with buffer time
        base_slots = self.get_available_slots(provider, preferred_dates)
        
        # Factor 2: Patient priority (urgent cases get priority)
        prioritized_slots = self.apply_priority_routing(base_slots, patient)
        
        # Factor 3: Historical no-show prediction
        optimized_slots = self.apply_no_show_mitigation(prioritized_slots, patient)
        
        # Factor 4: Travel time consideration for follow-ups
        final_slots = self.apply_geographic_optimization(optimized_slots, patient)
        
        return final_slots
    
    def apply_priority_routing(self, slots, patient):
        """Route high-priority patients to sooner available slots"""
        if self.is_high_priority(patient):
            return sorted(slots, key=lambda x: x['datetime'])
        return slots

1.2 Intelligent Queue Management

1.2.1 Real-time Queue System

# queue/models.py
class PatientQueue(models.Model):
    clinic = models.ForeignKey('accounts.Clinic', on_delete=models.CASCADE)
    name = models.CharField(max_length=100)  # e.g., "Triage", "Consultation"
    capacity = models.IntegerField(default=10)
    current_wait_time = models.DurationField(null=True, blank=True)
    is_active = models.BooleanField(default=True)

class QueueEntry(models.Model):
    queue = models.ForeignKey(PatientQueue, on_delete=models.CASCADE)
    patient = models.ForeignKey('accounts.Patient', on_delete=models.CASCADE)
    appointment = models.OneToOneField('appointments.Appointment', on_delete=models.CASCADE)
    position = models.IntegerField()
    check_in_time = models.DateTimeField(auto_now_add=True)
    estimated_wait_time = models.DurationField()
    actual_wait_time = models.DurationField(null=True, blank=True)
    status = models.CharField(max_length=20, choices=QUEUE_STATUS)
    
    class Meta:
        ordering = ['position']

1.2.2 Queue Logic Engine

# queue/logic/queue_engine.py
class QueueEngine:
    def add_to_queue(self, appointment, queue_name="Main"):
        """Add patient to queue with intelligent positioning"""
        queue = PatientQueue.objects.get(name=queue_name, clinic=appointment.clinic)
        
        # Calculate position based on multiple factors
        position = self.calculate_queue_position(appointment, queue)
        
        # Estimate wait time based on historical data
        wait_time = self.calculate_estimated_wait(queue, position)
        
        queue_entry = QueueEntry.objects.create(
            queue=queue,
            patient=appointment.patient,
            appointment=appointment,
            position=position,
            estimated_wait_time=wait_time
        )
        
        # Real-time update via WebSocket
        self.broadcast_queue_update(queue)
        
        return queue_entry
    
    def calculate_estimated_wait(self, queue, position):
        """Dynamic wait time calculation"""
        avg_appointment_time = timedelta(minutes=20)
        current_load = queue.queueentry_set.filter(status='waiting').count()
        
        # Factor in provider availability and current load
        base_wait = avg_appointment_time * position
        
        # Adjust based on real-time factors
        adjustment_factor = self.calculate_load_factor(current_load)
        
        return base_wait * adjustment_factor

1.3 Smart Waitlist Management

1.3.1 Waitlist Logic

# waitlist/models.py
class WaitlistEntry(models.Model):
    patient = models.ForeignKey('accounts.Patient', on_delete=models.CASCADE)
    preferred_provider = models.ForeignKey('accounts.HealthcareProvider', null=True, blank=True)
    appointment_type = models.ForeignKey('AppointmentType', on_delete=models.PROTECT)
    desired_date_range_start = models.DateField()
    desired_date_range_end = models.DateField()
    flexibility_score = models.IntegerField(default=0)  # How flexible is patient on timing
    priority = models.IntegerField(default=0)  # Clinical priority
    created_at = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)
    
    # Notification preferences
    notify_by_sms = models.BooleanField(default=True)
    notify_by_email = models.BooleanField(default=False)
    notify_by_phone = models.BooleanField(default=False)

class SlotCancellation(models.Model):
    """Track cancelled slots for waitlist fulfillment"""
    provider = models.ForeignKey('accounts.HealthcareProvider', on_delete=models.CASCADE)
    original_appointment = models.ForeignKey('appointments.Appointment', on_delete=models.SET_NULL, null=True)
    cancelled_slot_start = models.DateTimeField()
    cancelled_slot_end = models.DateTimeField()
    cancellation_time = models.DateTimeField(auto_now_add=True)
    filled_by_waitlist = models.BooleanField(default=False)

1.3.2 Automated Waitlist Fulfillment

# waitlist/logic/waitlist_engine.py
class WaitlistEngine:
    def check_and_fulfill_waitlist(self, cancellation):
        """Automatically fill cancelled slots from waitlist"""
        suitable_waitlist_entries = self.find_matching_waitlist_entries(cancellation)
        
        for waitlist_entry in suitable_waitlist_entries:
            if self.attempt_waitlist_fulfillment(waitlist_entry, cancellation):
                break  # Stop after first successful fulfillment
    
    def find_matching_waitlist_entries(self, cancellation):
        """Find the best waitlist matches for a cancelled slot"""
        return WaitlistEntry.objects.filter(
            is_active=True,
            appointment_type__in=cancellation.provider.supported_appointment_types,
            desired_date_range_start__lte=cancellation.cancelled_slot_start.date(),
            desired_date_range_end__gte=cancellation.cancelled_slot_start.date()
        ).order_by('-priority', 'created_at')

1.4 Multi-channel Notification System

1.4.1 Notification Engine

# notifications/engine.py
class NotificationEngine:
    CHANNELS = ['sms', 'email', 'push', 'voice']
    
    def send_appointment_reminder(self, appointment):
        """Send smart reminders based on patient preference"""
        patient_prefs = appointment.patient.notification_preferences
        
        # Base reminder (48 hours before)
        self._send_reminder(appointment, hours_before=48)
        
        # Same-day confirmation (4 hours before)
        self._send_reminder(appointment, hours_before=4)
    
    def send_waitlist_opportunity(self, waitlist_entry, available_slot):
        """Notify patient of waitlist opportunity"""
        context = {
            'patient': waitlist_entry.patient,
            'available_slot': available_slot,
            'expiration_minutes': 30  # Quick response required
        }
        
        # Use preferred notification channel
        if waitlist_entry.notify_by_sms:
            self.send_sms(waitlist_entry.patient.phone, 'waitlist_opportunity', context)
  1. User Workflows

2.1 Patient Self-Scheduling Workflow

1. Patient accesses portal → Authenticates (OAuth2/OIDC)
2. Selects appointment type and preferred provider/dates
3. System shows available slots with intelligent recommendations
4. Patient selects slot → System checks insurance eligibility
5. Patient completes booking → Automated reminders scheduled
6. System suggests waitlist option if no preferred slots available

2.2 Clinic Queue Management Workflow

1. Patient checks in at kiosk/mobile → Appointment status updates
2. System automatically places patient in appropriate queue
3. Real-time wait time estimates calculated and displayed
4. Staff dashboard shows queue status with patient priorities
5. Provider marks patient as "in progress" → Next patient alerted
6. Completion triggers automated follow-up tasks

2.3 Waitlist Automation Workflow

1. Cancellation occurs → System immediately scans waitlist
2. Matching algorithm finds suitable waitlist patients
3. Automated notifications sent via preferred channels
4. First patient to respond gets the slot
5. System updates all related records automatically
6. Unfilled slots trigger secondary notification rounds
  1. Integration Specifications

3.1 EHR Integration Layer

# integrations/ehr/base.py
class EHRIntegrationBase:
    def sync_patient_data(self, patient_id):
        """Two-way sync with EHR system"""
        pass
    
    def push_appointment_to_ehr(self, appointment):
        """Ensure EHR system has latest appointment data"""
        pass
    
    def pull_schedule_changes(self, provider, date_range):
        """Sync schedule changes from EHR"""
        pass

3.2 Insurance Verification Integration

# integrations/insurance/verification.py
class InsuranceVerification:
    def verify_eligibility(self, patient, appointment_type):
        """Real-time insurance eligibility check"""
        # Integration with insurance clearinghouses
        pass
    
    def estimate_co-pay(self, patient, services):
        """Provide cost estimates to patients"""
        pass