""" Operating Theatre app admin configuration. """ from django.contrib import admin from django.utils.html import format_html from django.urls import reverse from django.utils.safestring import mark_safe from .models import ( OperatingRoom, ORBlock, SurgicalCase, SurgicalNote, EquipmentUsage, SurgicalNoteTemplate ) class ORBlockInline(admin.TabularInline): """ Inline admin for OR blocks. """ model = ORBlock extra = 0 fields = [ 'date', 'start_time', 'end_time', 'block_type', 'primary_surgeon', 'service', 'status' ] readonly_fields = [] class SurgicalCaseInline(admin.TabularInline): """ Inline admin for surgical cases. """ model = SurgicalCase extra = 0 fields = [ 'case_number', 'patient', 'primary_procedure', 'scheduled_start', 'estimated_duration', 'status' ] readonly_fields = ['case_number'] class EquipmentUsageInline(admin.TabularInline): """ Inline admin for equipment usage. """ model = EquipmentUsage extra = 0 fields = [ 'equipment_name', 'equipment_type', 'quantity_used', 'unit_cost', 'total_cost' ] readonly_fields = ['total_cost'] @admin.register(OperatingRoom) class OperatingRoomAdmin(admin.ModelAdmin): """ Admin interface for operating rooms. """ list_display = [ 'room_number', 'room_name', 'room_type', 'status', 'floor_number', 'is_active', 'accepts_emergency', 'utilization_today' ] list_filter = [ 'tenant', 'room_type', 'status', 'floor_number', 'is_active', 'accepts_emergency', 'supports_robotic', 'supports_laparoscopic' ] search_fields = [ 'room_number', 'room_name', 'building', 'wing' ] readonly_fields = [ 'room_id', 'created_at', 'updated_at' ] fieldsets = [ ('Room Information', { 'fields': [ 'room_id', 'room_number', 'room_name', 'tenant' ] }), ('Room Type and Status', { 'fields': [ 'room_type', 'status', 'is_active', 'accepts_emergency' ] }), ('Physical Characteristics', { 'fields': [ 'floor_number', 'room_size', 'ceiling_height', 'building', 'wing' ] }), ('Environmental Controls', { 'fields': [ 'temperature_min', 'temperature_max', 'humidity_min', 'humidity_max', 'air_changes_per_hour', 'positive_pressure' ], 'classes': ['collapse'] }), ('Imaging Capabilities', { 'fields': [ 'has_c_arm', 'has_ct', 'has_mri', 'has_ultrasound', 'has_neuromonitoring' ], 'classes': ['collapse'] }), ('Surgical Capabilities', { 'fields': [ 'supports_robotic', 'supports_laparoscopic', 'supports_microscopy', 'supports_laser' ], 'classes': ['collapse'] }), ('Capacity and Scheduling', { 'fields': [ 'max_case_duration', 'turnover_time', 'cleaning_time' ], 'classes': ['collapse'] }), ('Staffing Requirements', { 'fields': [ 'required_nurses', 'required_techs' ], 'classes': ['collapse'] }), ('Equipment and Features', { 'fields': [ 'equipment_list', 'special_features' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at', 'created_by' ], 'classes': ['collapse'] }) ] inlines = [ORBlockInline] def utilization_today(self, obj): """Display today's utilization.""" # This would calculate actual utilization return "75%" # Placeholder utilization_today.short_description = 'Today Utilization' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(tenant=request.user.tenant) return qs @admin.register(ORBlock) class ORBlockAdmin(admin.ModelAdmin): """ Admin interface for OR blocks. """ list_display = [ 'operating_room_number', 'date', 'start_time', 'end_time', 'primary_surgeon_name', 'service', 'status', 'utilization_percentage', 'case_count' ] list_filter = [ 'operating_room__tenant', 'date', 'block_type', 'service', 'status', 'operating_room__room_type' ] search_fields = [ 'operating_room__room_number', 'primary_surgeon__first_name', 'primary_surgeon__last_name', 'service' ] readonly_fields = [ 'block_id', 'allocated_minutes', 'utilization_percentage', 'created_at', 'updated_at' ] fieldsets = [ ('Block Information', { 'fields': [ 'block_id', 'operating_room' ] }), ('Block Timing', { 'fields': [ 'date', 'start_time', 'end_time', 'allocated_minutes' ] }), ('Block Assignment', { 'fields': [ 'block_type', 'primary_surgeon', 'assistant_surgeons', 'service' ] }), ('Block Status', { 'fields': [ 'status' ] }), ('Utilization', { 'fields': [ 'used_minutes', 'utilization_percentage' ] }), ('Special Requirements', { 'fields': [ 'special_equipment', 'special_setup' ], 'classes': ['collapse'] }), ('Notes', { 'fields': [ 'notes' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at', 'created_by' ], 'classes': ['collapse'] }) ] inlines = [SurgicalCaseInline] date_hierarchy = 'date' def operating_room_number(self, obj): """Display operating room number.""" return obj.operating_room.room_number operating_room_number.short_description = 'OR' def primary_surgeon_name(self, obj): """Display primary surgeon name.""" return obj.primary_surgeon.get_full_name() primary_surgeon_name.short_description = 'Primary Surgeon' def case_count(self, obj): """Display number of cases in block.""" return obj.surgical_cases.count() case_count.short_description = 'Cases' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(operating_room__tenant=request.user.tenant) return qs.select_related('operating_room', 'primary_surgeon') @admin.register(SurgicalCase) class SurgicalCaseAdmin(admin.ModelAdmin): """ Admin interface for surgical cases. """ list_display = [ 'case_number', 'patient_name', 'primary_procedure', 'primary_surgeon_name', 'scheduled_start', 'estimated_duration', 'case_type', 'status', 'operating_room_number' ] list_filter = [ 'or_block__operating_room__tenant', 'case_type', 'status', 'approach', 'anesthesia_type', 'scheduled_start' ] search_fields = [ 'case_number', 'patient__first_name', 'patient__last_name', 'patient__mrn', 'primary_procedure', 'diagnosis' ] readonly_fields = [ 'case_id', 'case_number', 'actual_duration', 'created_at', 'updated_at' ] fieldsets = [ ('Case Information', { 'fields': [ 'case_id', 'case_number', 'or_block' ] }), ('Patient and Team', { 'fields': [ 'patient', 'primary_surgeon', 'assistant_surgeons', 'anesthesiologist', 'circulating_nurse', 'scrub_nurse' ] }), ('Procedure Information', { 'fields': [ 'primary_procedure', 'secondary_procedures', 'procedure_codes' ] }), ('Case Classification', { 'fields': [ 'case_type', 'approach', 'anesthesia_type' ] }), ('Timing', { 'fields': [ 'scheduled_start', 'estimated_duration', 'actual_start', 'actual_end', 'actual_duration' ] }), ('Case Status', { 'fields': [ 'status' ] }), ('Clinical Information', { 'fields': [ 'diagnosis', 'diagnosis_codes', 'clinical_notes' ] }), ('Special Requirements', { 'fields': [ 'special_equipment', 'blood_products', 'implants' ], 'classes': ['collapse'] }), ('Patient Positioning', { 'fields': [ 'patient_position' ], 'classes': ['collapse'] }), ('Complications and Outcomes', { 'fields': [ 'complications', 'estimated_blood_loss' ], 'classes': ['collapse'] }), ('Related Information', { 'fields': [ 'encounter', 'admission' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at', 'created_by' ], 'classes': ['collapse'] }) ] inlines = [EquipmentUsageInline] date_hierarchy = 'scheduled_start' def patient_name(self, obj): """Display patient name.""" return obj.patient.get_full_name() patient_name.short_description = 'Patient' def primary_surgeon_name(self, obj): """Display primary surgeon name.""" return obj.primary_surgeon.get_full_name() primary_surgeon_name.short_description = 'Primary Surgeon' def operating_room_number(self, obj): """Display operating room number.""" return obj.or_block.operating_room.room_number operating_room_number.short_description = 'OR' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(or_block__operating_room__tenant=request.user.tenant) return qs.select_related('patient', 'primary_surgeon', 'or_block__operating_room') @admin.register(SurgicalNote) class SurgicalNoteAdmin(admin.ModelAdmin): """ Admin interface for surgical notes. """ list_display = [ 'case_number', 'patient_name', 'surgeon_name', 'procedure_performed_short', 'status', 'signed_datetime' ] list_filter = [ 'surgical_case__or_block__operating_room__tenant', 'status', 'condition', 'disposition', 'signed_datetime' ] search_fields = [ 'surgical_case__case_number', 'surgical_case__patient__first_name', 'surgical_case__patient__last_name', 'surgeon__first_name', 'surgeon__last_name', 'procedure_performed', 'findings' ] readonly_fields = [ 'note_id', 'created_at', 'updated_at' ] fieldsets = [ ('Note Information', { 'fields': [ 'note_id', 'surgical_case', 'template_used' ] }), ('Surgeon Information', { 'fields': [ 'surgeon' ] }), ('Preoperative Information', { 'fields': [ 'preoperative_diagnosis', 'planned_procedure', 'indication' ] }), ('Intraoperative Information', { 'fields': [ 'procedure_performed', 'surgical_approach', 'findings', 'technique' ] }), ('Postoperative Information', { 'fields': [ 'postoperative_diagnosis', 'condition', 'disposition' ] }), ('Complications and Blood Loss', { 'fields': [ 'complications', 'estimated_blood_loss', 'blood_transfusion' ], 'classes': ['collapse'] }), ('Specimens and Pathology', { 'fields': [ 'specimens' ], 'classes': ['collapse'] }), ('Implants and Devices', { 'fields': [ 'implants' ], 'classes': ['collapse'] }), ('Drains and Tubes', { 'fields': [ 'drains' ], 'classes': ['collapse'] }), ('Closure', { 'fields': [ 'closure' ], 'classes': ['collapse'] }), ('Postoperative Instructions', { 'fields': [ 'postop_instructions', 'follow_up' ], 'classes': ['collapse'] }), ('Note Status', { 'fields': [ 'status', 'signed_datetime' ] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at' ], 'classes': ['collapse'] }) ] def case_number(self, obj): """Display case number.""" return obj.surgical_case.case_number case_number.short_description = 'Case' def patient_name(self, obj): """Display patient name.""" return obj.surgical_case.patient.get_full_name() patient_name.short_description = 'Patient' def surgeon_name(self, obj): """Display surgeon name.""" return obj.surgeon.get_full_name() surgeon_name.short_description = 'Surgeon' def procedure_performed_short(self, obj): """Display shortened procedure performed.""" if obj.procedure_performed: return obj.procedure_performed[:50] + "..." if len(obj.procedure_performed) > 50 else obj.procedure_performed return "-" procedure_performed_short.short_description = 'Procedure' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(surgical_case__or_block__operating_room__tenant=request.user.tenant) return qs.select_related('surgical_case__patient', 'surgeon') @admin.register(EquipmentUsage) class EquipmentUsageAdmin(admin.ModelAdmin): """ Admin interface for equipment usage. """ list_display = [ 'equipment_name', 'equipment_type', 'case_number', 'quantity_used', 'unit_cost', 'total_cost', 'recorded_by_name' ] list_filter = [ 'surgical_case__or_block__operating_room__tenant', 'equipment_type', 'unit_of_measure', 'created_at' ] search_fields = [ 'equipment_name', 'manufacturer', 'model', 'serial_number', 'surgical_case__case_number' ] readonly_fields = [ 'usage_id', 'total_cost', 'duration_minutes', 'created_at', 'updated_at' ] fieldsets = [ ('Usage Information', { 'fields': [ 'usage_id', 'surgical_case' ] }), ('Equipment Information', { 'fields': [ 'equipment_name', 'equipment_type', 'manufacturer', 'model', 'serial_number' ] }), ('Usage Details', { 'fields': [ 'quantity_used', 'unit_of_measure' ] }), ('Timing', { 'fields': [ 'start_time', 'end_time', 'duration_minutes' ] }), ('Cost Information', { 'fields': [ 'unit_cost', 'total_cost' ] }), ('Quality and Safety', { 'fields': [ 'lot_number', 'expiration_date', 'sterilization_date' ], 'classes': ['collapse'] }), ('Usage Notes', { 'fields': [ 'notes' ], 'classes': ['collapse'] }), ('Staff Information', { 'fields': [ 'recorded_by' ] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at' ], 'classes': ['collapse'] }) ] def case_number(self, obj): """Display case number.""" return obj.surgical_case.case_number case_number.short_description = 'Case' def recorded_by_name(self, obj): """Display recorded by name.""" return obj.recorded_by.get_full_name() if obj.recorded_by else "-" recorded_by_name.short_description = 'Recorded By' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(surgical_case__or_block__operating_room__tenant=request.user.tenant) return qs.select_related('surgical_case', 'recorded_by') @admin.register(SurgicalNoteTemplate) class SurgicalNoteTemplateAdmin(admin.ModelAdmin): """ Admin interface for surgical note templates. """ list_display = [ 'name', 'specialty', 'procedure_type', 'is_active', 'is_default', 'usage_count', 'created_by_name' ] list_filter = [ 'tenant', 'specialty', 'is_active', 'is_default' ] search_fields = [ 'name', 'description', 'procedure_type' ] readonly_fields = [ 'template_id', 'usage_count', 'created_at', 'updated_at' ] fieldsets = [ ('Template Information', { 'fields': [ 'template_id', 'name', 'description', 'tenant' ] }), ('Template Scope', { 'fields': [ 'procedure_type', 'specialty' ] }), ('Preoperative Templates', { 'fields': [ 'preoperative_diagnosis_template', 'planned_procedure_template', 'indication_template' ], 'classes': ['collapse'] }), ('Intraoperative Templates', { 'fields': [ 'procedure_performed_template', 'surgical_approach_template', 'findings_template', 'technique_template' ], 'classes': ['collapse'] }), ('Postoperative Templates', { 'fields': [ 'postoperative_diagnosis_template', 'complications_template' ], 'classes': ['collapse'] }), ('Additional Templates', { 'fields': [ 'specimens_template', 'implants_template', 'closure_template', 'postop_instructions_template' ], 'classes': ['collapse'] }), ('Template Status', { 'fields': [ 'is_active', 'is_default' ] }), ('Usage Statistics', { 'fields': [ 'usage_count' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at', 'created_by' ], 'classes': ['collapse'] }) ] def created_by_name(self, obj): """Display created by name.""" return obj.created_by.get_full_name() if obj.created_by else "-" created_by_name.short_description = 'Created By' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(tenant=request.user.tenant) return qs.select_related('created_by') # Customize admin site admin.site.site_header = "Hospital Management System - Operating Theatre" admin.site.site_title = "Operating Theatre Admin" admin.site.index_title = "Operating Theatre Administration"