304 lines
12 KiB
Python
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.")
|
|
|