import os import django # Set up Django environment os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hospital_management.settings') django.setup() import random from datetime import datetime, date, time, timedelta from django.utils import timezone as django_timezone from django.contrib.auth import get_user_model from appointments.models import ( AppointmentRequest, SlotAvailability, WaitingQueue, QueueEntry, TelemedicineSession, AppointmentTemplate ) from patients.models import PatientProfile from core.models import Tenant from hr.models import Employee, Department import uuid User = get_user_model() # Saudi-specific healthcare data SAUDI_SPECIALTIES = [ 'FAMILY_MEDICINE', 'INTERNAL_MEDICINE', 'PEDIATRICS', 'CARDIOLOGY', 'DERMATOLOGY', 'ENDOCRINOLOGY', 'GASTROENTEROLOGY', 'NEUROLOGY', 'ONCOLOGY', 'ORTHOPEDICS', 'PSYCHIATRY', 'RADIOLOGY', 'SURGERY', 'UROLOGY', 'GYNECOLOGY', 'OPHTHALMOLOGY', 'ENT', 'EMERGENCY' ] APPOINTMENT_TYPES = [ 'CONSULTATION', 'FOLLOW_UP', 'PROCEDURE', 'SURGERY', 'DIAGNOSTIC', 'THERAPY', 'VACCINATION', 'SCREENING', 'EMERGENCY', 'TELEMEDICINE' ] SAUDI_CHIEF_COMPLAINTS = [ 'Chest pain and shortness of breath', 'Abdominal pain and nausea', 'Headache and dizziness', 'Back pain and stiffness', 'Fever and cough', 'Joint pain and swelling', 'Fatigue and weakness', 'Skin rash and itching', 'Diabetes follow-up', 'Hypertension monitoring', 'Regular health checkup', 'Vaccination appointment', 'Pre-operative consultation', 'Post-operative follow-up', 'Pregnancy consultation', 'Child wellness visit', 'Mental health consultation', 'Physical therapy session', 'Diagnostic imaging', 'Laboratory test follow-up' ] SAUDI_LOCATIONS = [ 'Main Building - Floor 1', 'Main Building - Floor 2', 'Main Building - Floor 3', 'Emergency Wing', 'Outpatient Clinic - Wing A', 'Outpatient Clinic - Wing B', 'Surgical Suite - Floor 4', 'Radiology Department', 'Laboratory Building', 'Pediatric Wing' ] TELEMEDICINE_PLATFORMS = ['ZOOM', 'TEAMS', 'WEBEX', 'DOXY', 'CUSTOM'] def create_mock_providers(tenants): """Create mock healthcare providers for demonstration""" providers = [] mock_providers_data = [ {'first_name': 'Ahmad', 'last_name': 'Al-Rashid', 'role': 'PHYSICIAN', 'specialty': 'CARDIOLOGY'}, {'first_name': 'Fatima', 'last_name': 'Al-Ghamdi', 'role': 'PHYSICIAN', 'specialty': 'PEDIATRICS'}, {'first_name': 'Mohammed', 'last_name': 'Al-Otaibi', 'role': 'PHYSICIAN', 'specialty': 'FAMILY_MEDICINE'}, {'first_name': 'Sarah', 'last_name': 'Al-Harbi', 'role': 'PHYSICIAN', 'specialty': 'INTERNAL_MEDICINE'}, {'first_name': 'Khalid', 'last_name': 'Al-Mutairi', 'role': 'SURGEON', 'specialty': 'SURGERY'}, {'first_name': 'Nora', 'last_name': 'Al-Zahrani', 'role': 'PHYSICIAN', 'specialty': 'RADIOLOGY'}, {'first_name': 'Omar', 'last_name': 'Al-Dawsari', 'role': 'PHYSICIAN', 'specialty': 'EMERGENCY'}, {'first_name': 'Layla', 'last_name': 'Al-Subai', 'role': 'PHYSICIAN', 'specialty': 'GYNECOLOGY'}, ] for tenant in tenants: for provider_data in mock_providers_data: try: # Check if user already exists email = f"{provider_data['first_name'].lower()}.{provider_data['last_name'].lower().replace('-', '')}@{tenant.domain}" existing_user = User.objects.filter(email=email).first() if not existing_user: user = User.objects.create_user( email=email, first_name=provider_data['first_name'], last_name=provider_data['last_name'], role=provider_data['role'], tenant=tenant, is_active=True, password='temp_password_123' # Should be changed in production ) providers.append(user) print(f"Created mock provider: {user.get_full_name()}") else: providers.append(existing_user) except Exception as e: print(f"Error creating mock provider {provider_data['first_name']} {provider_data['last_name']}: {e}") continue return providers def get_providers_for_tenant(tenants): """Get healthcare providers using multiple fallback strategies""" providers = [] # First try: Look for users with clinical employee profiles for tenant in tenants: tenant_providers = User.objects.filter( employee_profile__tenant=tenant, employee_profile__department__department_type='CLINICAL', employee_profile__employment_status='ACTIVE' ).select_related('employee_profile__department') providers.extend(list(tenant_providers)) # Second try: If no clinical providers found, look for any employees with medical roles if not providers: for tenant in tenants: tenant_providers = User.objects.filter( employee_profile__tenant=tenant, role__in=['PHYSICIAN', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT', 'RADIOLOGIST', 'SURGEON'] ).select_related('employee_profile') providers.extend(list(tenant_providers)) # Third try: If still no providers, look for any active users with medical-sounding roles if not providers: for tenant in tenants: tenant_providers = User.objects.filter( tenant=tenant, is_active=True, role__icontains='PHYSICIAN' ) providers.extend(list(tenant_providers)) # Fourth try: Create some mock providers if none exist if not providers: print("No existing providers found. Creating mock providers...") providers = create_mock_providers(tenants) return providers def create_appointment_templates(tenants): """Create appointment templates for common appointment types""" templates = [] template_configs = [ { 'name': 'Family Medicine Consultation', 'appointment_type': 'CONSULTATION', 'specialty': 'FAMILY_MEDICINE', 'duration_minutes': 30, 'advance_booking_days': 30, 'minimum_notice_hours': 24, 'pre_instructions': 'Please bring your medical history and current medications list.', }, { 'name': 'Cardiology Follow-up', 'appointment_type': 'FOLLOW_UP', 'specialty': 'CARDIOLOGY', 'duration_minutes': 45, 'advance_booking_days': 60, 'minimum_notice_hours': 48, 'authorization_required': True, 'pre_instructions': 'Please bring your latest ECG and cardiac test results.', }, { 'name': 'Pediatric Wellness Visit', 'appointment_type': 'SCREENING', 'specialty': 'PEDIATRICS', 'duration_minutes': 45, 'advance_booking_days': 90, 'minimum_notice_hours': 24, 'pre_instructions': 'Please bring your child\'s vaccination record.', }, { 'name': 'Surgical Consultation', 'appointment_type': 'CONSULTATION', 'specialty': 'SURGERY', 'duration_minutes': 60, 'advance_booking_days': 45, 'minimum_notice_hours': 72, 'authorization_required': True, 'pre_instructions': 'Please bring all relevant imaging studies and lab results.', }, { 'name': 'Telemedicine Consultation', 'appointment_type': 'TELEMEDICINE', 'specialty': 'FAMILY_MEDICINE', 'duration_minutes': 20, 'advance_booking_days': 14, 'minimum_notice_hours': 4, 'pre_instructions': 'Please ensure you have a stable internet connection and privacy.', }, { 'name': 'Emergency Consultation', 'appointment_type': 'EMERGENCY', 'specialty': 'EMERGENCY', 'duration_minutes': 60, 'advance_booking_days': 1, 'minimum_notice_hours': 1, 'pre_instructions': 'Please come immediately if experiencing emergency symptoms.', }, { 'name': 'Diagnostic Imaging', 'appointment_type': 'DIAGNOSTIC', 'specialty': 'RADIOLOGY', 'duration_minutes': 30, 'advance_booking_days': 21, 'minimum_notice_hours': 24, 'pre_instructions': 'Please follow preparation instructions provided.', }, { 'name': 'Physical Therapy Session', 'appointment_type': 'THERAPY', 'specialty': 'ORTHOPEDICS', 'duration_minutes': 60, 'advance_booking_days': 30, 'minimum_notice_hours': 24, 'pre_instructions': 'Please wear comfortable clothing suitable for exercise.', }, ] for tenant in tenants: for config in template_configs: try: template = AppointmentTemplate.objects.create( tenant=tenant, name=config['name'], description=f"Standard {config['name'].lower()} appointment template", appointment_type=config['appointment_type'], specialty=config['specialty'], duration_minutes=config['duration_minutes'], advance_booking_days=config['advance_booking_days'], minimum_notice_hours=config['minimum_notice_hours'], insurance_verification_required=config.get('insurance_verification_required', False), authorization_required=config.get('authorization_required', False), pre_appointment_instructions=config['pre_instructions'], post_appointment_instructions="Please follow up as instructed by your healthcare provider.", required_forms=[ "Patient Registration Form", "Medical History Form", "Insurance Information Form" ], is_active=True, created_at=django_timezone.now() - timedelta(days=random.randint(30, 180)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)) ) templates.append(template) except Exception as e: print(f"Error creating template {config['name']} for {tenant.name}: {e}") continue print(f"Created {len(templates)} appointment templates") return templates def create_waiting_queues(tenants): """Create waiting queues for different departments and specialties""" queues = [] queue_configs = [ { 'name': 'Emergency Department Queue', 'queue_type': 'EMERGENCY', 'specialty': 'EMERGENCY', 'location': 'Emergency Wing', 'max_queue_size': 100, 'average_service_time': 45, 'priority_weights': {'EMERGENCY': 10, 'STAT': 8, 'URGENT': 5, 'ROUTINE': 1} }, { 'name': 'Family Medicine Queue', 'queue_type': 'SPECIALTY', 'specialty': 'FAMILY_MEDICINE', 'location': 'Outpatient Clinic - Wing A', 'max_queue_size': 50, 'average_service_time': 30, 'priority_weights': {'STAT': 8, 'URGENT': 5, 'ROUTINE': 1} }, { 'name': 'Cardiology Queue', 'queue_type': 'SPECIALTY', 'specialty': 'CARDIOLOGY', 'location': 'Main Building - Floor 2', 'max_queue_size': 30, 'average_service_time': 45, 'priority_weights': {'STAT': 8, 'URGENT': 5, 'ROUTINE': 1} }, { 'name': 'Pediatrics Queue', 'queue_type': 'SPECIALTY', 'specialty': 'PEDIATRICS', 'location': 'Pediatric Wing', 'max_queue_size': 40, 'average_service_time': 35, 'priority_weights': {'STAT': 8, 'URGENT': 5, 'ROUTINE': 1} }, { 'name': 'Surgery Consultation Queue', 'queue_type': 'SPECIALTY', 'specialty': 'SURGERY', 'location': 'Main Building - Floor 3', 'max_queue_size': 25, 'average_service_time': 60, 'priority_weights': {'STAT': 8, 'URGENT': 5, 'ROUTINE': 1} }, { 'name': 'Radiology Queue', 'queue_type': 'PROCEDURE', 'specialty': 'RADIOLOGY', 'location': 'Radiology Department', 'max_queue_size': 35, 'average_service_time': 25, 'priority_weights': {'STAT': 8, 'URGENT': 5, 'ROUTINE': 1} } ] # Operating hours for queues (Saudi working hours) operating_hours = { 'sunday': {'start': '08:00', 'end': '20:00'}, 'monday': {'start': '08:00', 'end': '20:00'}, 'tuesday': {'start': '08:00', 'end': '20:00'}, 'wednesday': {'start': '08:00', 'end': '20:00'}, 'thursday': {'start': '08:00', 'end': '20:00'}, 'friday': {'start': '14:00', 'end': '20:00'}, # After Friday prayers 'saturday': {'start': '08:00', 'end': '16:00'} # Half day } for tenant in tenants: for config in queue_configs: try: queue = WaitingQueue.objects.create( tenant=tenant, name=config['name'], description=f"Patient waiting queue for {config['specialty'].replace('_', ' ').title()}", queue_type=config['queue_type'], specialty=config['specialty'], location=config['location'], max_queue_size=config['max_queue_size'], average_service_time_minutes=config['average_service_time'], priority_weights=config['priority_weights'], is_active=True, is_accepting_patients=True, operating_hours=operating_hours, created_at=django_timezone.now() - timedelta(days=random.randint(30, 180)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)) ) queues.append(queue) except Exception as e: print(f"Error creating queue {config['name']} for {tenant.name}: {e}") continue print(f"Created {len(queues)} waiting queues") return queues def create_slot_availability(tenants, days_ahead=30): """Create provider availability slots""" slots = [] # Get healthcare providers using the improved strategy providers = get_providers_for_tenant(tenants) if not providers: print("No clinical providers found. Skipping slot creation.") return slots print(f"Found {len(providers)} providers for slot creation") # Time slots configuration time_slots = { 'MORNING': [ (time(8, 0), time(8, 30)), (time(8, 30), time(9, 0)), (time(9, 0), time(9, 30)), (time(9, 30), time(10, 0)), (time(10, 0), time(10, 30)), (time(10, 30), time(11, 0)), (time(11, 0), time(11, 30)), (time(11, 30), time(12, 0)), ], 'AFTERNOON': [ (time(14, 0), time(14, 30)), (time(14, 30), time(15, 0)), (time(15, 0), time(15, 30)), (time(15, 30), time(16, 0)), (time(16, 0), time(16, 30)), (time(16, 30), time(17, 0)), (time(17, 0), time(17, 30)), (time(17, 30), time(18, 0)), ], 'EVENING': [ (time(19, 0), time(19, 30)), (time(19, 30), time(20, 0)), ] } start_date = django_timezone.now().date() for provider in providers: tenant = provider.tenant # Get department if available, otherwise use a default department = None if hasattr(provider, 'employee_profile') and provider.employee_profile: department = provider.employee_profile.department # Determine specialty based on role or department specialty_mapping = { 'CARDIOLOGY': 'CARDIOLOGY', 'PEDIATRICS': 'PEDIATRICS', 'SURGERY': 'SURGERY', 'RADIOLOGY': 'RADIOLOGY', 'EMERGENCY': 'EMERGENCY', 'OBSTETRICS': 'GYNECOLOGY', 'ORTHOPEDICS': 'ORTHOPEDICS' } if department and hasattr(department, 'department_code'): specialty = specialty_mapping.get(department.department_code, 'FAMILY_MEDICINE') elif hasattr(provider, 'role') and provider.role: if 'SURGEON' in provider.role: specialty = 'SURGERY' elif 'RADIOLOGY' in provider.role: specialty = 'RADIOLOGY' else: specialty = 'FAMILY_MEDICINE' else: specialty = 'FAMILY_MEDICINE' # Create slots for the next days_ahead days for day_offset in range(days_ahead): slot_date = start_date + timedelta(days=day_offset) weekday = slot_date.weekday() # Skip Fridays for most providers (except emergency) if weekday == 4 and specialty != 'EMERGENCY': continue # Determine working periods for the day working_periods = ['MORNING'] if weekday != 5: # Not Saturday (half day) working_periods.append('AFTERNOON') if specialty == 'EMERGENCY': working_periods.append('EVENING') # Random availability (not all providers work every day) if random.random() < 0.8: # 80% chance provider is available for period in working_periods: # Select some slots from the period available_slots = random.sample( time_slots[period], random.randint(2, min(6, len(time_slots[period]))) ) for start_time, end_time in available_slots: duration = int((datetime.combine(date.today(), end_time) - datetime.combine(date.today(), start_time)).total_seconds() / 60) # Determine slot configuration max_appointments = 1 if specialty in ['FAMILY_MEDICINE', 'PEDIATRICS']: max_appointments = random.choice([1, 2]) availability_type = 'REGULAR' if period == 'EVENING': availability_type = 'EXTENDED' if specialty == 'EMERGENCY': availability_type = 'EMERGENCY' supports_telemedicine = random.choice([True, False]) if specialty != 'SURGERY' else False # Get location from department or use default location = 'Main Building - Floor 1' if department and hasattr(department, 'location') and department.location: location = department.location else: location = random.choice(SAUDI_LOCATIONS) try: slot = SlotAvailability.objects.create( tenant=tenant, provider=provider, date=slot_date, start_time=start_time, end_time=end_time, duration_minutes=duration, availability_type=availability_type, max_appointments=max_appointments, booked_appointments=0, location=location, room_number=f"Room {random.randint(101, 350)}", specialty=specialty, appointment_types=random.sample(APPOINTMENT_TYPES, random.randint(3, 6)), supports_telemedicine=supports_telemedicine, telemedicine_only=False, is_active=True, is_blocked=False, created_at=django_timezone.now() - timedelta(days=random.randint(1, 30)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 7)) ) slots.append(slot) except Exception as e: print(f"Error creating slot for {provider.get_full_name()}: {e}") continue print(f"Created {len(slots)} availability slots") return slots def create_appointment_requests(tenants, slots, days_back=14, appointments_per_day=50): """Create appointment requests with various statuses""" appointments = [] # Get patients patients = list(PatientProfile.objects.filter(tenant__in=tenants)) if not patients: print("No patients found. Skipping appointment creation.") return appointments # Get providers using the same improved logic providers = get_providers_for_tenant(tenants) if not providers: print("No providers found. Skipping appointment creation.") return appointments print(f"Found {len(providers)} providers for appointment creation") start_date = django_timezone.now().date() - timedelta(days=days_back) for day_offset in range(days_back + 30): # Past and future appointments appointment_date = start_date + timedelta(days=day_offset) # Create appointments for this day daily_appointments = random.randint(int(appointments_per_day * 0.7), int(appointments_per_day * 1.3)) for _ in range(daily_appointments): patient = random.choice(patients) provider = random.choice([p for p in providers if p.tenant == patient.tenant]) # Select appointment type and specialty appointment_type = random.choices( APPOINTMENT_TYPES, weights=[20, 25, 10, 5, 15, 8, 5, 10, 3, 4] # Weighted by frequency )[0] specialty = random.choice(SAUDI_SPECIALTIES) # Set priority based on appointment type if appointment_type == 'EMERGENCY': priority = 'EMERGENCY' urgency_score = random.randint(8, 10) elif appointment_type in ['SURGERY', 'PROCEDURE']: priority = random.choices(['URGENT', 'STAT'], weights=[70, 30])[0] urgency_score = random.randint(5, 8) else: priority = random.choices(['ROUTINE', 'URGENT'], weights=[85, 15])[0] urgency_score = random.randint(1, 5) # Determine status based on appointment date if appointment_date < django_timezone.now().date(): # Past appointments status = random.choices( ['COMPLETED', 'NO_SHOW', 'CANCELLED'], weights=[75, 15, 10] )[0] elif appointment_date == django_timezone.now().date(): # Today's appointments status = random.choices( ['CONFIRMED', 'CHECKED_IN', 'IN_PROGRESS', 'COMPLETED'], weights=[40, 30, 20, 10] )[0] else: # Future appointments status = random.choices( ['SCHEDULED', 'CONFIRMED'], weights=[40, 60] )[0] # Generate appointment time preferred_time = time( random.randint(8, 17), random.choice([0, 15, 30, 45]) ) duration = 30 if appointment_type in ['SURGERY', 'PROCEDURE']: duration = random.randint(60, 180) elif appointment_type == 'CONSULTATION': duration = random.randint(30, 60) # Schedule datetime scheduled_datetime = None scheduled_end_datetime = None if status != 'PENDING': scheduled_datetime = django_timezone.make_aware( datetime.combine(appointment_date, preferred_time) ) scheduled_end_datetime = scheduled_datetime + timedelta(minutes=duration) # Telemedicine configuration is_telemedicine = appointment_type == 'TELEMEDICINE' or ( appointment_type in ['CONSULTATION', 'FOLLOW_UP'] and random.random() < 0.2 ) telemedicine_platform = None meeting_url = None meeting_id = None if is_telemedicine: telemedicine_platform = random.choice(TELEMEDICINE_PLATFORMS) meeting_url = f"https://{telemedicine_platform.lower()}.com/j/{random.randint(100000000, 999999999)}" meeting_id = str(random.randint(100000000, 999999999)) # Check-in and completion times for completed appointments checked_in_at = None completed_at = None actual_duration = None if status in ['CHECKED_IN', 'IN_PROGRESS', 'COMPLETED'] and scheduled_datetime: # Random check-in time (usually 10-30 minutes before appointment) checkin_offset = random.randint(-30, 5) # Can be late too checked_in_at = scheduled_datetime + timedelta(minutes=checkin_offset) if status == 'COMPLETED': # Random completion time actual_duration = random.randint(int(duration * 0.8), int(duration * 1.2)) completed_at = scheduled_datetime + timedelta(minutes=actual_duration) # Cancellation information cancelled_at = None cancellation_reason = None if status == 'CANCELLED': cancelled_at = scheduled_datetime - timedelta( hours=random.randint(1, 72)) if scheduled_datetime else django_timezone.now() cancellation_reason = random.choice([ 'Patient requested cancellation', 'Provider unavailable', 'Emergency situation', 'Insurance issues', 'Patient illness' ]) try: appointment = AppointmentRequest.objects.create( tenant=patient.tenant, patient=patient, provider=provider, appointment_type=appointment_type, specialty=specialty, preferred_date=appointment_date, preferred_time=preferred_time, duration_minutes=duration, flexible_scheduling=random.choice([True, False]), earliest_acceptable_date=appointment_date - timedelta(days=random.randint(0, 3)), latest_acceptable_date=appointment_date + timedelta(days=random.randint(0, 7)), acceptable_times=['morning', 'afternoon'] if random.choice([True, False]) else [], priority=priority, urgency_score=urgency_score, chief_complaint=random.choice(SAUDI_CHIEF_COMPLAINTS), clinical_notes=f"Patient presenting with {random.choice(SAUDI_CHIEF_COMPLAINTS).lower()}", referring_provider=f"Dr. {random.choice(['Ahmed', 'Fatima', 'Mohammed', 'Sara'])} Al-{random.choice(['Rashid', 'Ghamdi', 'Otaibi'])}" if random.choice( [True, False]) else None, insurance_verified=random.choice([True, False]), authorization_required=appointment_type in ['SURGERY', 'PROCEDURE'], authorization_number=f"AUTH-{random.randint(100000, 999999)}" if appointment_type in ['SURGERY', 'PROCEDURE'] else None, status=status, scheduled_datetime=scheduled_datetime, scheduled_end_datetime=scheduled_end_datetime, location=random.choice(SAUDI_LOCATIONS), room_number=f"Room {random.randint(101, 350)}", is_telemedicine=is_telemedicine, telemedicine_platform=telemedicine_platform, meeting_url=meeting_url, meeting_id=meeting_id, meeting_password=f"pwd{random.randint(1000, 9999)}" if is_telemedicine else None, checked_in_at=checked_in_at, completed_at=completed_at, actual_duration_minutes=actual_duration, cancelled_at=cancelled_at, cancellation_reason=cancellation_reason, reminder_preferences={ 'sms': True, 'email': random.choice([True, False]), 'phone': False }, special_requirements=random.choice([ None, None, None, # Most appointments don't have special requirements 'Wheelchair accessible', 'Interpreter needed', 'Elderly patient assistance', 'Child-friendly environment' ]), interpreter_needed=random.choice([True, False]) if random.random() < 0.1 else False, interpreter_language=random.choice( ['Urdu', 'Hindi', 'Bengali', 'English']) if random.random() < 0.1 else None, created_at=django_timezone.now() - timedelta(days=random.randint(1, 30)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 7)) ) appointments.append(appointment) except Exception as e: print(f"Error creating appointment for {patient.get_full_name()}: {e}") continue print(f"Created {len(appointments)} appointment requests") return appointments def create_telemedicine_sessions(appointments): """Create telemedicine sessions for telemedicine appointments""" sessions = [] telemedicine_appointments = [apt for apt in appointments if apt.is_telemedicine and apt.scheduled_datetime] for appointment in telemedicine_appointments: # Determine session status if appointment.status == 'COMPLETED': session_status = 'COMPLETED' elif appointment.status in ['IN_PROGRESS']: session_status = 'IN_PROGRESS' elif appointment.status in ['CONFIRMED', 'CHECKED_IN']: session_status = 'READY' elif appointment.status == 'CANCELLED': session_status = 'CANCELLED' else: session_status = 'SCHEDULED' # Generate session timing actual_start = None actual_end = None provider_joined_at = None patient_joined_at = None if session_status in ['COMPLETED', 'IN_PROGRESS']: # Provider usually joins first provider_joined_at = appointment.scheduled_datetime + timedelta(minutes=random.randint(-5, 2)) patient_joined_at = provider_joined_at + timedelta(minutes=random.randint(1, 8)) actual_start = max(provider_joined_at, patient_joined_at) if session_status == 'COMPLETED': duration = appointment.actual_duration_minutes or appointment.duration_minutes actual_end = actual_start + timedelta(minutes=duration) # Connection quality and technical issues connection_quality = random.choices( ['EXCELLENT', 'GOOD', 'FAIR', 'POOR'], weights=[40, 35, 20, 5] )[0] technical_issues = None if connection_quality in ['FAIR', 'POOR']: technical_issues = random.choice([ 'Intermittent audio issues', 'Video quality degradation', 'Connection drops', 'Echo and feedback problems', 'Bandwidth limitations' ]) # Recording information recording_enabled = random.choice([True, False]) if random.random() < 0.3 else False recording_consent = recording_enabled recording_url = f"https://recordings.{appointment.telemedicine_platform.lower()}.com/{uuid.uuid4()}" if recording_enabled and session_status == 'COMPLETED' else None recording_duration = appointment.actual_duration_minutes if recording_enabled and session_status == 'COMPLETED' else None try: session = TelemedicineSession.objects.create( appointment=appointment, platform=appointment.telemedicine_platform, meeting_url=appointment.meeting_url, meeting_id=appointment.meeting_id, meeting_password=appointment.meeting_password, waiting_room_enabled=True, recording_enabled=recording_enabled, recording_consent=recording_consent, encryption_enabled=True, password_required=appointment.meeting_password is not None, status=session_status, scheduled_start=appointment.scheduled_datetime, scheduled_end=appointment.scheduled_end_datetime, actual_start=actual_start, actual_end=actual_end, provider_joined_at=provider_joined_at, patient_joined_at=patient_joined_at, connection_quality=connection_quality, technical_issues=technical_issues, recording_url=recording_url, recording_duration_minutes=recording_duration, session_notes=f"Telemedicine session for {appointment.chief_complaint}" if session_status == 'COMPLETED' else None, created_at=django_timezone.now() - timedelta(days=random.randint(0, 7)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 3)) ) sessions.append(session) except Exception as e: print(f"Error creating telemedicine session for appointment {appointment.request_id}: {e}") continue print(f"Created {len(sessions)} telemedicine sessions") return sessions def create_queue_entries(queues, appointments): """Create queue entries for appointments""" entries = [] # Get appointments that should have queue entries (checked in, in progress, or recently completed) relevant_appointments = [ apt for apt in appointments if apt.status in ['CHECKED_IN', 'IN_PROGRESS', 'COMPLETED'] and apt.scheduled_datetime and apt.scheduled_datetime >= django_timezone.now() - timedelta(days=1) ] for appointment in relevant_appointments: # Find appropriate queue for this appointment suitable_queues = [ q for q in queues if q.tenant == appointment.tenant and ( q.specialty == appointment.specialty or ( q.queue_type == 'EMERGENCY' and appointment.priority == 'EMERGENCY')) ] if not suitable_queues: continue queue = random.choice(suitable_queues) # Determine queue entry status if appointment.status == 'CHECKED_IN': entry_status = 'WAITING' elif appointment.status == 'IN_PROGRESS': entry_status = 'IN_SERVICE' else: # COMPLETED entry_status = 'COMPLETED' # Calculate priority score priority_weights = queue.priority_weights base_score = priority_weights.get(appointment.priority, 1) urgency_bonus = appointment.urgency_score * 0.1 priority_score = base_score + urgency_bonus # Queue position (random for now) queue_position = random.randint(1, min(10, queue.max_queue_size)) # Timing information joined_at = appointment.checked_in_at or appointment.scheduled_datetime estimated_service_time = joined_at + timedelta(minutes=queue.average_service_time_minutes) called_at = None served_at = None if entry_status in ['IN_SERVICE', 'COMPLETED']: # Patient was called before being served call_delay = random.randint(5, 30) # 5-30 minutes wait called_at = joined_at + timedelta(minutes=call_delay) if entry_status == 'COMPLETED': serve_delay = random.randint(1, 10) # 1-10 minutes after being called served_at = called_at + timedelta(minutes=serve_delay) # Notification information notification_sent = entry_status != 'WAITING' notification_method = random.choice(['SMS', 'APP', 'PAGER']) if notification_sent else None try: entry = QueueEntry.objects.create( queue=queue, patient=appointment.patient, appointment=appointment, queue_position=queue_position, priority_score=priority_score, joined_at=joined_at, estimated_service_time=estimated_service_time, called_at=called_at, served_at=served_at, status=entry_status, assigned_provider=appointment.provider, notification_sent=notification_sent, notification_method=notification_method, notes=f"Queue entry for {appointment.appointment_type.lower()} appointment", updated_at=django_timezone.now() - timedelta(minutes=random.randint(0, 60)) ) entries.append(entry) except Exception as e: print(f"Error creating queue entry for appointment {appointment.request_id}: {e}") continue print(f"Created {len(entries)} queue entries") return entries def main(): """Main function to generate all appointments data""" print("Starting Saudi Healthcare Appointments Data Generation...") # Get existing tenants tenants = list(Tenant.objects.all()) if not tenants: print("āŒ No tenants found. Please run the core data generator first.") return # Create appointment templates print("\n1. Creating Appointment Templates...") templates = create_appointment_templates(tenants) # Create waiting queues print("\n2. Creating Waiting Queues...") queues = create_waiting_queues(tenants) # Create slot availability print("\n3. Creating Provider Availability Slots...") slots = create_slot_availability(tenants, 30) # Create appointment requests print("\n4. Creating Appointment Requests...") appointments = create_appointment_requests(tenants, slots, 14, 50) # Create telemedicine sessions print("\n5. Creating Telemedicine Sessions...") sessions = create_telemedicine_sessions(appointments) # Create queue entries print("\n6. Creating Queue Entries...") entries = create_queue_entries(queues, appointments) print(f"\nāœ… Saudi Healthcare Appointments Data Generation Complete!") print(f" Summary:") print(f" - Appointment Templates: {len(templates)}") print(f" - Waiting Queues: {len(queues)}") print(f" - Availability Slots: {len(slots)}") print(f" - Appointment Requests: {len(appointments)}") print(f" - Telemedicine Sessions: {len(sessions)}") print(f" - Queue Entries: {len(entries)}") # Only show distributions if appointments exist if appointments: # Appointment status distribution status_counts = {} for appointment in appointments: status_counts[appointment.status] = status_counts.get(appointment.status, 0) + 1 print(f"\nšŸ“Š Appointment Status Distribution:") for status, count in status_counts.items(): print(f" - {status.title()}: {count}") # Appointment type distribution type_counts = {} for appointment in appointments: type_counts[appointment.appointment_type] = type_counts.get(appointment.appointment_type, 0) + 1 print(f"\nšŸ“Š Appointment Type Distribution:") for apt_type, count in sorted(type_counts.items(), key=lambda x: x[1], reverse=True)[:10]: print(f" - {apt_type.replace('_', ' ').title()}: {count}") # Telemedicine statistics telemedicine_count = len([apt for apt in appointments if apt.is_telemedicine]) print( f"\nšŸ’» Telemedicine Appointments: {telemedicine_count} ({telemedicine_count / len(appointments) * 100:.1f}%)") else: print(f"\nāš ļø No appointments were created. Check provider and patient data.") return { 'templates': templates, 'queues': queues, 'slots': slots, 'appointments': appointments, 'sessions': sessions, 'entries': entries } if __name__ == "__main__": main()