""" API serializers for appointments app. """ from rest_framework import serializers from django.contrib.auth import get_user_model from ..models import ( AppointmentRequest, SlotAvailability, WaitingQueue, QueueEntry, TelemedicineSession, AppointmentTemplate ) User = get_user_model() class AppointmentRequestListSerializer(serializers.ModelSerializer): """ Serializer for appointment request list view. """ patient_name = serializers.CharField(source='patient.get_full_name', read_only=True) patient_mrn = serializers.CharField(source='patient.mrn', read_only=True) provider_name = serializers.CharField(source='provider.get_full_name', read_only=True) appointment_type_display = serializers.CharField(source='get_appointment_type_display', read_only=True) specialty_display = serializers.CharField(source='get_specialty_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) priority_display = serializers.CharField(source='get_priority_display', read_only=True) class Meta: model = AppointmentRequest fields = [ 'id', 'request_id', 'patient_name', 'patient_mrn', 'provider_name', 'appointment_type', 'appointment_type_display', 'specialty', 'specialty_display', 'scheduled_datetime', 'scheduled_end_datetime', 'duration_minutes', 'status', 'status_display', 'priority', 'priority_display', 'urgency_score', 'is_telemedicine', 'location', 'room_number', 'created_at', 'updated_at' ] class AppointmentRequestDetailSerializer(serializers.ModelSerializer): """ Serializer for appointment request detail view. """ patient = serializers.StringRelatedField(read_only=True) provider = serializers.StringRelatedField(read_only=True) created_by = serializers.StringRelatedField(read_only=True) checked_in_by = serializers.StringRelatedField(read_only=True) cancelled_by = serializers.StringRelatedField(read_only=True) class Meta: model = AppointmentRequest fields = '__all__' class AppointmentRequestCreateSerializer(serializers.ModelSerializer): """ Serializer for creating appointment requests. """ class Meta: model = AppointmentRequest fields = [ 'patient', 'provider', 'appointment_type', 'specialty', 'preferred_date', 'preferred_time', 'duration_minutes', 'flexible_scheduling', 'earliest_acceptable_date', 'latest_acceptable_date', 'priority', 'urgency_score', 'chief_complaint', 'clinical_notes', 'referring_provider', 'insurance_verified', 'authorization_required', 'authorization_number', 'is_telemedicine', 'telemedicine_platform', 'special_requirements', 'interpreter_needed', 'interpreter_language' ] def validate(self, data): """ Validate appointment request data. """ # Validate telemedicine requirements if data.get('is_telemedicine') and not data.get('telemedicine_platform'): raise serializers.ValidationError( "Telemedicine platform is required for telemedicine appointments." ) # Validate date preferences if data.get('earliest_acceptable_date') and data.get('latest_acceptable_date'): if data['earliest_acceptable_date'] > data['latest_acceptable_date']: raise serializers.ValidationError( "Earliest acceptable date cannot be after latest acceptable date." ) return data class SlotAvailabilitySerializer(serializers.ModelSerializer): """ Serializer for slot availability. """ provider_name = serializers.CharField(source='provider.get_full_name', read_only=True) specialty_display = serializers.CharField(source='get_specialty_display', read_only=True) availability_type_display = serializers.CharField(source='get_availability_type_display', read_only=True) class Meta: model = SlotAvailability fields = [ 'id', 'slot_id', 'provider', 'provider_name', 'date', 'start_time', 'end_time', 'duration_minutes', 'availability_type', 'availability_type_display', 'max_appointments', 'booked_appointments', 'available_capacity', 'location', 'room_number', 'specialty', 'specialty_display', 'supports_telemedicine', 'telemedicine_only', 'is_active', 'is_blocked' ] class WaitingQueueSerializer(serializers.ModelSerializer): """ Serializer for waiting queues. """ queue_type_display = serializers.CharField(source='get_queue_type_display', read_only=True) current_queue_size = serializers.IntegerField(read_only=True) estimated_wait_time_minutes = serializers.IntegerField(read_only=True) class Meta: model = WaitingQueue fields = [ 'id', 'queue_id', 'name', 'description', 'queue_type', 'queue_type_display', 'specialty', 'location', 'max_queue_size', 'average_service_time_minutes', 'current_queue_size', 'estimated_wait_time_minutes', 'is_active', 'is_accepting_patients', 'created_at', 'updated_at' ] class QueueEntrySerializer(serializers.ModelSerializer): """ Serializer for queue entries. """ patient_name = serializers.CharField(source='patient.get_full_name', read_only=True) patient_mrn = serializers.CharField(source='patient.mrn', read_only=True) queue_name = serializers.CharField(source='queue.name', read_only=True) assigned_provider_name = serializers.CharField(source='assigned_provider.get_full_name', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) wait_time_minutes = serializers.IntegerField(read_only=True) class Meta: model = QueueEntry fields = [ 'id', 'entry_id', 'queue', 'queue_name', 'patient', 'patient_name', 'patient_mrn', 'appointment', 'queue_position', 'priority_score', 'status', 'status_display', 'assigned_provider', 'assigned_provider_name', 'joined_at', 'estimated_service_time', 'called_at', 'served_at', 'wait_time_minutes', 'notification_sent', 'notes' ] class TelemedicineSessionSerializer(serializers.ModelSerializer): """ Serializer for telemedicine sessions. """ appointment_details = AppointmentRequestListSerializer(source='appointment', read_only=True) platform_display = serializers.CharField(source='get_platform_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) duration_minutes = serializers.IntegerField(read_only=True) class Meta: model = TelemedicineSession fields = [ 'id', 'session_id', 'appointment', 'appointment_details', 'platform', 'platform_display', 'meeting_url', 'meeting_id', 'waiting_room_enabled', 'recording_enabled', 'recording_consent', 'encryption_enabled', 'password_required', 'status', 'status_display', 'scheduled_start', 'scheduled_end', 'actual_start', 'actual_end', 'duration_minutes', 'provider_joined_at', 'patient_joined_at', 'connection_quality', 'technical_issues', 'session_notes', 'created_at', 'updated_at' ] class TelemedicineSessionCreateSerializer(serializers.ModelSerializer): """ Serializer for creating telemedicine sessions. """ class Meta: model = TelemedicineSession fields = [ 'appointment', 'platform', 'meeting_url', 'meeting_id', 'meeting_password', 'waiting_room_enabled', 'recording_enabled', 'recording_consent', 'encryption_enabled', 'password_required', 'scheduled_start', 'scheduled_end' ] def validate(self, data): """ Validate telemedicine session data. """ # Ensure appointment is telemedicine appointment = data.get('appointment') if appointment and not appointment.is_telemedicine: raise serializers.ValidationError( "Cannot create telemedicine session for non-telemedicine appointment." ) # Validate scheduled times if data.get('scheduled_start') and data.get('scheduled_end'): if data['scheduled_start'] >= data['scheduled_end']: raise serializers.ValidationError( "Scheduled start time must be before end time." ) return data class AppointmentTemplateSerializer(serializers.ModelSerializer): """ Serializer for appointment templates. """ appointment_type_display = serializers.CharField(source='get_appointment_type_display', read_only=True) specialty_display = serializers.CharField(source='get_specialty_display', read_only=True) class Meta: model = AppointmentTemplate fields = [ 'id', 'name', 'description', 'appointment_type', 'appointment_type_display', 'specialty', 'specialty_display', 'duration_minutes', 'advance_booking_days', 'minimum_notice_hours', 'insurance_verification_required', 'authorization_required', 'pre_appointment_instructions', 'post_appointment_instructions', 'required_forms', 'is_active', 'created_at', 'updated_at' ] class AppointmentStatsSerializer(serializers.Serializer): """ Serializer for appointment statistics. """ total_appointments = serializers.IntegerField() todays_appointments = serializers.IntegerField() pending_appointments = serializers.IntegerField() completed_today = serializers.IntegerField() total_in_queue = serializers.IntegerField() telemedicine_today = serializers.IntegerField() average_wait_time = serializers.FloatField() provider_utilization = serializers.ListField() appointment_types = serializers.DictField() status_breakdown = serializers.DictField() class AvailableSlotSerializer(serializers.Serializer): """ Serializer for available appointment slots. """ slot_id = serializers.UUIDField() provider_id = serializers.IntegerField() provider_name = serializers.CharField() date = serializers.DateField() start_time = serializers.TimeField() end_time = serializers.TimeField() duration_minutes = serializers.IntegerField() location = serializers.CharField() room_number = serializers.CharField() specialty = serializers.CharField() available_capacity = serializers.IntegerField() supports_telemedicine = serializers.BooleanField() class ScheduleAppointmentSerializer(serializers.Serializer): """ Serializer for scheduling appointments. """ patient_id = serializers.IntegerField() slot_id = serializers.UUIDField() appointment_type = serializers.CharField() chief_complaint = serializers.CharField() clinical_notes = serializers.CharField(required=False, allow_blank=True) special_requirements = serializers.CharField(required=False, allow_blank=True) interpreter_needed = serializers.BooleanField(default=False) interpreter_language = serializers.CharField(required=False, allow_blank=True) def validate_slot_id(self, value): """ Validate that the slot exists and is available. """ try: slot = SlotAvailability.objects.get(slot_id=value) if not slot.is_available: raise serializers.ValidationError("Selected slot is not available.") return value except SlotAvailability.DoesNotExist: raise serializers.ValidationError("Invalid slot ID.") class CheckInSerializer(serializers.Serializer): """ Serializer for patient check-in. """ appointment_id = serializers.IntegerField() notes = serializers.CharField(required=False, allow_blank=True) def validate_appointment_id(self, value): """ Validate that the appointment exists and can be checked in. """ try: appointment = AppointmentRequest.objects.get(id=value) if appointment.status not in ['SCHEDULED', 'CONFIRMED']: raise serializers.ValidationError( "Appointment cannot be checked in with current status." ) return value except AppointmentRequest.DoesNotExist: raise serializers.ValidationError("Invalid appointment ID.")