""" Observations admin configuration. """ from django.contrib import admin from django.utils.html import format_html, mark_safe from .models import ( Observation, ObservationAttachment, ObservationCategory, ObservationNote, ObservationStatusLog, ) @admin.register(ObservationCategory) class ObservationCategoryAdmin(admin.ModelAdmin): """Admin for ObservationCategory model.""" list_display = ["name_en", "name_ar", "is_active", "sort_order", "observation_count", "created_at"] list_filter = ["is_active", "created_at"] search_fields = ["name_en", "name_ar", "description"] ordering = ["sort_order", "name_en"] fieldsets = ( (None, {"fields": ("name_en", "name_ar", "description")}), ("Settings", {"fields": ("icon", "sort_order", "is_active")}), ) def observation_count(self, obj): return obj.observations.count() observation_count.short_description = "Observations" class ObservationAttachmentInline(admin.TabularInline): """Inline admin for ObservationAttachment.""" model = ObservationAttachment extra = 0 readonly_fields = ["filename", "file_type", "file_size", "created_at"] fields = ["file", "filename", "file_type", "file_size", "description", "created_at"] class ObservationNoteInline(admin.TabularInline): """Inline admin for ObservationNote.""" model = ObservationNote extra = 0 readonly_fields = ["created_by", "created_at"] fields = ["note", "is_internal", "created_by", "created_at"] class ObservationStatusLogInline(admin.TabularInline): """Inline admin for ObservationStatusLog.""" model = ObservationStatusLog extra = 0 readonly_fields = ["from_status", "to_status", "changed_by", "comment", "created_at"] fields = ["from_status", "to_status", "changed_by", "comment", "created_at"] can_delete = False def has_add_permission(self, request, obj=None): return False @admin.register(Observation) class ObservationAdmin(admin.ModelAdmin): """Admin for Observation model.""" list_display = [ "tracking_code", "title_display", "category", "severity_badge", "status_badge", "reporter_display", "assigned_department", "assigned_to", "created_at", ] list_filter = ["status", "severity", "category", "assigned_department", "created_at", "triaged_at", "resolved_at"] search_fields = ["tracking_code", "title", "description", "reporter_name", "reporter_staff_id", "location_text"] readonly_fields = [ "tracking_code", "created_at", "updated_at", "triaged_at", "resolved_at", "closed_at", "client_ip", "user_agent", ] ordering = ["-created_at"] date_hierarchy = "created_at" fieldsets = ( ("Tracking", {"fields": ("tracking_code", "status")}), ("Content", {"fields": ("category", "title", "description", "severity")}), ("Location & Time", {"fields": ("location_text", "incident_datetime")}), ( "Reporter Information", { "fields": ("reporter_staff_id", "reporter_name", "reporter_phone", "reporter_email"), "classes": ("collapse",), }, ), ("Assignment", {"fields": ("assigned_department", "assigned_to")}), ("Triage", {"fields": ("triaged_by", "triaged_at"), "classes": ("collapse",)}), ("Resolution", {"fields": ("resolved_by", "resolved_at", "resolution_notes"), "classes": ("collapse",)}), ("Closure", {"fields": ("closed_by", "closed_at"), "classes": ("collapse",)}), ("Action Center", {"fields": ("action_id",), "classes": ("collapse",)}), ( "Metadata", {"fields": ("client_ip", "user_agent", "metadata", "created_at", "updated_at"), "classes": ("collapse",)}, ), ) inlines = [ObservationAttachmentInline, ObservationNoteInline, ObservationStatusLogInline] def title_display(self, obj): if obj.title: return obj.title[:50] + "..." if len(obj.title) > 50 else obj.title return obj.description[:50] + "..." if len(obj.description) > 50 else obj.description title_display.short_description = "Title/Description" def severity_badge(self, obj): colors = { "low": "#28a745", "medium": "#ffc107", "high": "#dc3545", "critical": "#343a40", } color = colors.get(obj.severity, "#6c757d") return format_html( '{}', color, obj.get_severity_display(), ) severity_badge.short_description = "Severity" def status_badge(self, obj): colors = { "new": "#007bff", "triaged": "#17a2b8", "assigned": "#17a2b8", "in_progress": "#ffc107", "resolved": "#28a745", "closed": "#6c757d", "rejected": "#dc3545", "duplicate": "#6c757d", } color = colors.get(obj.status, "#6c757d") return format_html( '{}', color, obj.get_status_display(), ) status_badge.short_description = "Status" def reporter_display(self, obj): if obj.is_anonymous: return mark_safe('Anonymous') return obj.reporter_display reporter_display.short_description = "Reporter" @admin.register(ObservationAttachment) class ObservationAttachmentAdmin(admin.ModelAdmin): """Admin for ObservationAttachment model.""" list_display = ["observation", "filename", "file_type", "file_size_display", "created_at"] list_filter = ["file_type", "created_at"] search_fields = ["observation__tracking_code", "filename", "description"] readonly_fields = ["file_size", "created_at"] def file_size_display(self, obj): if obj.file_size < 1024: return f"{obj.file_size} B" elif obj.file_size < 1024 * 1024: return f"{obj.file_size / 1024:.1f} KB" else: return f"{obj.file_size / (1024 * 1024):.1f} MB" file_size_display.short_description = "Size" @admin.register(ObservationNote) class ObservationNoteAdmin(admin.ModelAdmin): """Admin for ObservationNote model.""" list_display = ["observation", "note_preview", "created_by", "is_internal", "created_at"] list_filter = ["is_internal", "created_at"] search_fields = ["observation__tracking_code", "note", "created_by__email"] readonly_fields = ["created_at"] def note_preview(self, obj): return obj.note[:100] + "..." if len(obj.note) > 100 else obj.note note_preview.short_description = "Note" @admin.register(ObservationStatusLog) class ObservationStatusLogAdmin(admin.ModelAdmin): """Admin for ObservationStatusLog model.""" list_display = ["observation", "from_status", "to_status", "changed_by", "created_at"] list_filter = ["from_status", "to_status", "created_at"] search_fields = ["observation__tracking_code", "comment", "changed_by__email"] readonly_fields = ["observation", "from_status", "to_status", "changed_by", "comment", "created_at"] def has_add_permission(self, request): return False def has_change_permission(self, request, obj=None): return False