""" Communications 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 decimal import Decimal from datetime import datetime, timedelta from .models import ( Message, MessageRecipient, NotificationTemplate, AlertRule, AlertInstance, CommunicationChannel, DeliveryLog ) class MessageRecipientInline(admin.TabularInline): """ Inline admin for message recipients. """ model = MessageRecipient extra = 0 fields = [ 'recipient_type', 'user', 'email_address', 'phone_number', 'status', 'sent_at', 'delivered_at', 'read_at' ] readonly_fields = [ 'recipient_id', 'sent_at', 'delivered_at', 'read_at', 'acknowledged_at', 'delivery_attempts' ] class DeliveryLogInline(admin.TabularInline): """ Inline admin for delivery logs. """ model = DeliveryLog extra = 0 fields = [ 'channel', 'status', 'attempt_number', 'started_at', 'completed_at', 'response_code' ] readonly_fields = [ 'log_id', 'started_at', 'completed_at', 'processing_time_ms', 'payload_size_bytes' ] @admin.register(Message) class MessageAdmin(admin.ModelAdmin): """ Admin interface for messages. """ list_display = [ 'subject', 'message_type', 'priority', 'sender', 'recipient_count_display', 'status', 'created_at', 'sent_at' ] list_filter = [ 'tenant', 'message_type', 'priority', 'status', 'is_urgent', 'is_confidential', 'created_at' ] search_fields = [ 'subject', 'content', 'sender__username', 'sender__first_name', 'sender__last_name' ] readonly_fields = [ 'message_id', 'delivery_attempts', 'created_at', 'sent_at' ] fieldsets = [ ('Message Information', { 'fields': [ 'message_id', 'tenant', 'subject', 'content' ] }), ('Message Type', { 'fields': [ 'message_type', 'priority' ] }), ('Sender', { 'fields': [ 'sender' ] }), ('Message Configuration', { 'fields': [ 'is_urgent', 'requires_acknowledgment', 'is_confidential' ] }), ('Scheduling', { 'fields': [ 'scheduled_at', 'expires_at' ] }), ('Message Status', { 'fields': [ 'status' ] }), ('Delivery Settings', { 'fields': [ 'delivery_attempts', 'max_delivery_attempts' ] }), ('Threading', { 'fields': [ 'message_thread_id', 'reply_to_message' ], 'classes': ['collapse'] }), ('External References', { 'fields': [ 'external_message_id' ], 'classes': ['collapse'] }), ('Content Details', { 'fields': [ 'has_attachments', 'content_type' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'sent_at' ], 'classes': ['collapse'] }) ] inlines = [MessageRecipientInline, DeliveryLogInline] date_hierarchy = 'created_at' def recipient_count_display(self, obj): """Display recipient count.""" return obj.recipients.count() recipient_count_display.short_description = 'Recipients' 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('sender', 'reply_to_message') @admin.register(MessageRecipient) class MessageRecipientAdmin(admin.ModelAdmin): """ Admin interface for message recipients. """ list_display = [ 'message_subject', 'recipient_display', 'recipient_type', 'status', 'sent_at', 'delivered_at', 'read_at', 'delivery_attempts' ] list_filter = [ 'message__tenant', 'recipient_type', 'status', 'sent_at', 'delivered_at' ] search_fields = [ 'message__subject', 'user__username', 'user__first_name', 'user__last_name', 'email_address', 'phone_number' ] readonly_fields = [ 'recipient_id', 'sent_at', 'delivered_at', 'read_at', 'acknowledged_at', 'last_attempt_at' ] fieldsets = [ ('Recipient Information', { 'fields': [ 'recipient_id', 'message', 'recipient_type' ] }), ('Recipient Details', { 'fields': [ 'user', 'email_address', 'phone_number', 'role_name' ] }), ('Delivery Status', { 'fields': [ 'status' ] }), ('Timing', { 'fields': [ 'sent_at', 'delivered_at', 'read_at', 'acknowledged_at' ] }), ('Delivery Tracking', { 'fields': [ 'delivery_attempts', 'last_attempt_at', 'error_message' ] }), ('External Tracking', { 'fields': [ 'external_delivery_id' ], 'classes': ['collapse'] }) ] inlines = [DeliveryLogInline] def message_subject(self, obj): """Display message subject.""" return obj.message.subject message_subject.short_description = 'Message' def recipient_display(self, obj): """Display recipient information.""" if obj.user: return obj.user.get_full_name() or obj.user.username elif obj.email_address: return obj.email_address elif obj.phone_number: return obj.phone_number elif obj.role_name: return f"Role: {obj.role_name}" return obj.recipient_type recipient_display.short_description = 'Recipient' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(message__tenant=request.user.tenant) return qs.select_related('message', 'user') @admin.register(NotificationTemplate) class NotificationTemplateAdmin(admin.ModelAdmin): """ Admin interface for notification templates. """ list_display = [ 'name', 'template_type', 'category', 'usage_count', 'is_active', 'is_system_template', 'last_used_at', 'created_at' ] list_filter = [ 'tenant', 'template_type', 'category', 'is_active', 'is_system_template', 'requires_approval' ] search_fields = [ 'name', 'description', 'subject_template', 'content_template' ] readonly_fields = [ 'template_id', 'usage_count', 'last_used_at', 'created_at', 'updated_at' ] fieldsets = [ ('Template Information', { 'fields': [ 'template_id', 'tenant', 'name', 'description' ] }), ('Template Type', { 'fields': [ 'template_type', 'category' ] }), ('Template Content', { 'fields': [ 'subject_template', 'content_template' ] }), ('Template Configuration', { 'fields': [ 'variables', 'default_values', 'formatting_rules' ] }), ('Template Settings', { 'fields': [ 'is_active', 'is_system_template', 'requires_approval' ] }), ('Usage Tracking', { 'fields': [ 'usage_count', 'last_used_at' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at', 'created_by' ], 'classes': ['collapse'] }) ] 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') class AlertInstanceInline(admin.TabularInline): """ Inline admin for alert instances. """ model = AlertInstance extra = 0 fields = [ 'title', 'severity', 'status', 'triggered_at', 'acknowledged_at', 'resolved_at' ] readonly_fields = [ 'alert_id', 'triggered_at', 'acknowledged_at', 'resolved_at', 'escalation_level' ] @admin.register(AlertRule) class AlertRuleAdmin(admin.ModelAdmin): """ Admin interface for alert rules. """ list_display = [ 'name', 'trigger_type', 'severity', 'trigger_count', 'last_triggered_at', 'is_active', 'is_system_rule' ] list_filter = [ 'tenant', 'trigger_type', 'severity', 'is_active', 'is_system_rule' ] search_fields = [ 'name', 'description' ] readonly_fields = [ 'rule_id', 'trigger_count', 'last_triggered_at', 'last_evaluated_at', 'created_at', 'updated_at' ] fieldsets = [ ('Rule Information', { 'fields': [ 'rule_id', 'tenant', 'name', 'description' ] }), ('Rule Type', { 'fields': [ 'trigger_type', 'severity' ] }), ('Rule Configuration', { 'fields': [ 'trigger_conditions', 'evaluation_frequency', 'cooldown_period' ] }), ('Notification Configuration', { 'fields': [ 'notification_template', 'notification_channels', 'escalation_rules' ] }), ('Recipients', { 'fields': [ 'default_recipients', 'recipient_roles' ] }), ('Rule Status', { 'fields': [ 'is_active', 'is_system_rule' ] }), ('Tracking', { 'fields': [ 'trigger_count', 'last_triggered_at', 'last_evaluated_at' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at', 'created_by' ], 'classes': ['collapse'] }) ] inlines = [AlertInstanceInline] filter_horizontal = ['default_recipients'] 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('notification_template', 'created_by') @admin.register(AlertInstance) class AlertInstanceAdmin(admin.ModelAdmin): """ Admin interface for alert instances. """ list_display = [ 'title', 'alert_rule_name', 'severity', 'status', 'triggered_at', 'acknowledged_at', 'resolved_at', 'escalation_level' ] list_filter = [ 'alert_rule__tenant', 'severity', 'status', 'triggered_at', 'escalation_level' ] search_fields = [ 'title', 'description', 'alert_rule__name' ] readonly_fields = [ 'alert_id', 'triggered_at', 'acknowledged_at', 'resolved_at', 'escalated_at', 'notifications_sent', 'last_notification_at' ] fieldsets = [ ('Alert Information', { 'fields': [ 'alert_id', 'alert_rule', 'title', 'description' ] }), ('Alert Details', { 'fields': [ 'severity', 'trigger_data', 'context_data' ] }), ('Alert Status', { 'fields': [ 'status' ] }), ('Timing', { 'fields': [ 'triggered_at', 'acknowledged_at', 'resolved_at', 'expires_at' ] }), ('Response Tracking', { 'fields': [ 'acknowledged_by', 'resolved_by', 'resolution_notes' ] }), ('Escalation Tracking', { 'fields': [ 'escalation_level', 'escalated_at' ] }), ('Notification Tracking', { 'fields': [ 'notifications_sent', 'last_notification_at' ], 'classes': ['collapse'] }) ] date_hierarchy = 'triggered_at' def alert_rule_name(self, obj): """Display alert rule name.""" return obj.alert_rule.name alert_rule_name.short_description = 'Alert Rule' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(alert_rule__tenant=request.user.tenant) return qs.select_related('alert_rule', 'acknowledged_by', 'resolved_by') @admin.register(CommunicationChannel) class CommunicationChannelAdmin(admin.ModelAdmin): """ Admin interface for communication channels. """ list_display = [ 'name', 'channel_type', 'provider_type', 'health_status_display', 'success_rate_display', 'message_count', 'last_used_at', 'is_active' ] list_filter = [ 'tenant', 'channel_type', 'provider_type', 'is_active', 'is_healthy' ] search_fields = [ 'name', 'description' ] readonly_fields = [ 'channel_id', 'is_healthy', 'last_health_check', 'message_count', 'success_count', 'failure_count', 'last_used_at', 'created_at', 'updated_at' ] fieldsets = [ ('Channel Information', { 'fields': [ 'channel_id', 'tenant', 'name', 'description' ] }), ('Channel Type', { 'fields': [ 'channel_type', 'provider_type' ] }), ('Configuration', { 'fields': [ 'configuration', 'authentication_config', 'rate_limits' ] }), ('Channel Status', { 'fields': [ 'is_active', 'is_healthy', 'last_health_check', 'health_check_interval' ] }), ('Usage Tracking', { 'fields': [ 'message_count', 'success_count', 'failure_count', 'last_used_at' ], 'classes': ['collapse'] }), ('Metadata', { 'fields': [ 'created_at', 'updated_at', 'created_by' ], 'classes': ['collapse'] }) ] def health_status_display(self, obj): """Display health status with color coding.""" if obj.is_healthy: return format_html('✓ Healthy') return format_html('✗ Unhealthy') health_status_display.short_description = 'Health' def success_rate_display(self, obj): """Display success rate with color coding.""" rate = obj.success_rate if rate >= 95: color = 'green' elif rate >= 85: color = 'orange' else: color = 'red' return format_html( '{:.1f}%', color, rate ) success_rate_display.short_description = 'Success Rate' 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') @admin.register(DeliveryLog) class DeliveryLogAdmin(admin.ModelAdmin): """ Admin interface for delivery logs. """ list_display = [ 'message_subject', 'recipient_display', 'channel_name', 'status', 'attempt_number', 'started_at', 'duration_display', 'response_code' ] list_filter = [ 'message__tenant', 'status', 'channel__channel_type', 'started_at', 'attempt_number' ] search_fields = [ 'message__subject', 'recipient__user__username', 'recipient__email_address', 'channel__name' ] readonly_fields = [ 'log_id', 'started_at', 'completed_at', 'processing_time_ms', 'payload_size_bytes' ] fieldsets = [ ('Delivery Information', { 'fields': [ 'log_id', 'message', 'recipient', 'channel' ] }), ('Delivery Details', { 'fields': [ 'status', 'attempt_number' ] }), ('Timing', { 'fields': [ 'started_at', 'completed_at' ] }), ('Response Tracking', { 'fields': [ 'external_id', 'response_code', 'response_message', 'error_details' ] }), ('Performance Metrics', { 'fields': [ 'processing_time_ms', 'payload_size_bytes' ] }), ('Metadata', { 'fields': [ 'metadata' ], 'classes': ['collapse'] }) ] date_hierarchy = 'started_at' def message_subject(self, obj): """Display message subject.""" return obj.message.subject message_subject.short_description = 'Message' def recipient_display(self, obj): """Display recipient information.""" if obj.recipient.user: return obj.recipient.user.get_full_name() or obj.recipient.user.username elif obj.recipient.email_address: return obj.recipient.email_address elif obj.recipient.phone_number: return obj.recipient.phone_number return obj.recipient.recipient_type recipient_display.short_description = 'Recipient' def channel_name(self, obj): """Display channel name.""" return obj.channel.name channel_name.short_description = 'Channel' def duration_display(self, obj): """Display delivery duration.""" duration = obj.duration if duration: total_seconds = duration.total_seconds() if total_seconds >= 60: minutes = int(total_seconds // 60) seconds = int(total_seconds % 60) return f"{minutes}m {seconds}s" return f"{total_seconds:.1f}s" return "-" duration_display.short_description = 'Duration' def get_queryset(self, request): """Filter by user's tenant.""" qs = super().get_queryset(request) if hasattr(request.user, 'tenant'): qs = qs.filter(message__tenant=request.user.tenant) return qs.select_related('message', 'recipient', 'channel') # Customize admin site admin.site.site_header = "Hospital Management System - Communications" admin.site.site_title = "Communications Admin" admin.site.index_title = "Communications Administration"