2025-08-12 13:33:25 +03:00

304 lines
12 KiB
Python

"""
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.")