""" Django admin configuration for appointments app. """ from django.contrib import admin from django.utils.translation import gettext_lazy as _ from simple_history.admin import SimpleHistoryAdmin from .models import ( Provider, Room, Schedule, Appointment, AppointmentReminder, AppointmentConfirmation, Session, SessionParticipant, ) @admin.register(Provider) class ProviderAdmin(admin.ModelAdmin): """Admin interface for Provider model.""" list_display = ['user', 'is_available', 'max_daily_appointments', 'tenant', 'created_at'] list_filter = ['is_available', 'tenant', 'created_at'] search_fields = ['user__username', 'user__first_name', 'user__last_name', 'user__email'] readonly_fields = ['id', 'created_at', 'updated_at'] filter_horizontal = ['specialties'] fieldsets = ( (None, { 'fields': ('user', 'tenant', 'is_available') }), (_('Configuration'), { 'fields': ('specialties', 'max_daily_appointments') }), (_('Metadata'), { 'fields': ('id', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) @admin.register(Room) class RoomAdmin(admin.ModelAdmin): """Admin interface for Room model.""" list_display = ['room_number', 'name', 'clinic', 'is_available', 'tenant'] list_filter = ['is_available', 'clinic', 'tenant'] search_fields = ['name', 'room_number'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( (None, { 'fields': ('name', 'room_number', 'clinic', 'tenant', 'is_available') }), (_('Metadata'), { 'fields': ('id', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) @admin.register(Schedule) class ScheduleAdmin(admin.ModelAdmin): """Admin interface for Schedule model.""" list_display = ['provider', 'day_of_week', 'start_time', 'end_time', 'slot_duration', 'is_active'] list_filter = ['day_of_week', 'is_active', 'provider'] search_fields = ['provider__user__username', 'provider__user__first_name', 'provider__user__last_name'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( (None, { 'fields': ('provider', 'day_of_week', 'is_active') }), (_('Time Configuration'), { 'fields': ('start_time', 'end_time', 'slot_duration') }), (_('Metadata'), { 'fields': ('id', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) @admin.register(Appointment) class AppointmentAdmin(SimpleHistoryAdmin): """Admin interface for Appointment model.""" list_display = ['appointment_number', 'patient', 'provider', 'scheduled_date', 'scheduled_time', 'status', 'finance_cleared', 'consent_verified'] list_filter = ['status', 'clinic', 'scheduled_date', 'finance_cleared', 'consent_verified', 'tenant'] search_fields = ['appointment_number', 'patient__mrn', 'patient__first_name_en', 'patient__last_name_en', 'provider__user__username'] readonly_fields = ['id', 'appointment_number', 'created_at', 'updated_at', 'is_past'] date_hierarchy = 'scheduled_date' fieldsets = ( (_('Identification'), { 'fields': ('appointment_number', 'tenant') }), (_('Core Information'), { 'fields': ('patient', 'clinic', 'provider', 'room', 'service_type') }), (_('Scheduling'), { 'fields': ('scheduled_date', 'scheduled_time', 'duration') }), (_('Status'), { 'fields': ('status', 'finance_cleared', 'consent_verified') }), (_('Confirmation'), { 'fields': ('confirmation_sent_at', 'confirmation_method'), 'classes': ('collapse',) }), (_('Timestamps'), { 'fields': ('arrival_at', 'start_at', 'end_at'), 'classes': ('collapse',) }), (_('Rescheduling'), { 'fields': ('reschedule_reason', 'reschedule_count'), 'classes': ('collapse',) }), (_('Cancellation'), { 'fields': ('cancel_reason', 'cancelled_by'), 'classes': ('collapse',) }), (_('Additional Information'), { 'fields': ('notes',), 'classes': ('collapse',) }), (_('Metadata'), { 'fields': ('id', 'is_past', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) @admin.register(AppointmentReminder) class AppointmentReminderAdmin(admin.ModelAdmin): """Admin interface for AppointmentReminder model.""" list_display = ['appointment', 'reminder_type', 'scheduled_for', 'status', 'sent_at'] list_filter = ['reminder_type', 'status', 'scheduled_for'] search_fields = ['appointment__appointment_number', 'appointment__patient__mrn'] readonly_fields = ['id', 'created_at', 'updated_at'] date_hierarchy = 'scheduled_for' fieldsets = ( (None, { 'fields': ('appointment', 'reminder_type', 'status') }), (_('Scheduling'), { 'fields': ('scheduled_for', 'sent_at') }), (_('Message'), { 'fields': ('message',), 'classes': ('collapse',) }), (_('Metadata'), { 'fields': ('id', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) @admin.register(AppointmentConfirmation) class AppointmentConfirmationAdmin(admin.ModelAdmin): """Admin interface for AppointmentConfirmation model.""" list_display = ['appointment', 'status', 'confirmation_method', 'sent_at', 'confirmed_at', 'expires_at', 'is_valid'] list_filter = ['status', 'confirmation_method', 'sent_at', 'confirmed_at', 'expires_at'] search_fields = ['appointment__appointment_number', 'appointment__patient__mrn', 'token'] readonly_fields = ['id', 'token', 'is_expired', 'is_valid', 'created_at', 'updated_at'] date_hierarchy = 'created_at' fieldsets = ( (None, { 'fields': ('appointment', 'token', 'status', 'confirmation_method') }), (_('Timing'), { 'fields': ('sent_at', 'confirmed_at', 'expires_at', 'is_expired', 'is_valid') }), (_('Confirmation Details'), { 'fields': ('confirmed_by_ip', 'confirmed_by_user_agent'), 'classes': ('collapse',) }), (_('Reminders'), { 'fields': ('reminder_count', 'last_reminder_at'), 'classes': ('collapse',) }), (_('Metadata'), { 'fields': ('id', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) class SessionParticipantInline(admin.TabularInline): """Inline admin for session participants.""" model = SessionParticipant extra = 0 readonly_fields = ['appointment_number', 'created_at'] fields = ['patient', 'appointment_number', 'status', 'finance_cleared', 'consent_verified', 'arrival_at', 'attended_at'] def has_add_permission(self, request, obj=None): """Allow adding participants through the inline.""" return True @admin.register(Session) class SessionAdmin(SimpleHistoryAdmin): """Admin interface for Session model.""" list_display = ['session_number', 'session_type', 'provider', 'clinic', 'scheduled_date', 'scheduled_time', 'capacity_display', 'status', 'tenant'] list_filter = ['session_type', 'status', 'clinic', 'scheduled_date', 'tenant'] search_fields = ['session_number', 'provider__user__first_name', 'provider__user__last_name', 'service_type'] readonly_fields = ['id', 'session_number', 'current_capacity', 'available_spots', 'is_full', 'capacity_percentage', 'created_at', 'updated_at'] date_hierarchy = 'scheduled_date' inlines = [SessionParticipantInline] fieldsets = ( (_('Identification'), { 'fields': ('session_number', 'tenant', 'session_type') }), (_('Core Information'), { 'fields': ('provider', 'clinic', 'room', 'service_type') }), (_('Scheduling'), { 'fields': ('scheduled_date', 'scheduled_time', 'duration') }), (_('Capacity'), { 'fields': ('max_capacity', 'current_capacity', 'available_spots', 'is_full', 'capacity_percentage') }), (_('Status'), { 'fields': ('status', 'start_at', 'end_at') }), (_('Notes'), { 'fields': ('group_notes',), 'classes': ('collapse',) }), (_('Cancellation'), { 'fields': ('cancel_reason', 'cancelled_by'), 'classes': ('collapse',) }), (_('Metadata'), { 'fields': ('id', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) def capacity_display(self, obj): """Display capacity as current/max.""" return f"{obj.current_capacity}/{obj.max_capacity}" capacity_display.short_description = _('Capacity') def get_queryset(self, request): """Optimize queryset with related objects.""" qs = super().get_queryset(request) return qs.select_related('provider__user', 'clinic', 'room', 'tenant') @admin.register(SessionParticipant) class SessionParticipantAdmin(SimpleHistoryAdmin): """Admin interface for SessionParticipant model.""" list_display = ['appointment_number', 'patient', 'session', 'status', 'finance_cleared', 'consent_verified', 'arrival_at', 'attended_at'] list_filter = ['status', 'finance_cleared', 'consent_verified', 'session__scheduled_date', 'session__clinic'] search_fields = ['appointment_number', 'patient__mrn', 'patient__first_name_en', 'patient__last_name_en', 'session__session_number'] readonly_fields = ['id', 'appointment_number', 'can_check_in', 'created_at', 'updated_at'] date_hierarchy = 'created_at' fieldsets = ( (_('Identification'), { 'fields': ('appointment_number', 'session', 'patient') }), (_('Status'), { 'fields': ('status', 'can_check_in') }), (_('Prerequisites'), { 'fields': ('finance_cleared', 'consent_verified') }), (_('Timestamps'), { 'fields': ('confirmation_sent_at', 'arrival_at', 'attended_at'), 'classes': ('collapse',) }), (_('Notes'), { 'fields': ('individual_notes',), 'classes': ('collapse',) }), (_('Cancellation'), { 'fields': ('cancel_reason', 'cancelled_by'), 'classes': ('collapse',) }), (_('No-Show'), { 'fields': ('no_show_reason', 'no_show_notes'), 'classes': ('collapse',) }), (_('Metadata'), { 'fields': ('id', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) def get_queryset(self, request): """Optimize queryset with related objects.""" qs = super().get_queryset(request) return qs.select_related('session__provider__user', 'session__clinic', 'patient')