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 ( QualityIndicator, QualityMeasurement, IncidentReport, RiskAssessment, AuditPlan, AuditFinding, ImprovementProject ) class QualityMeasurementInline(admin.TabularInline): """Inline for quality measurements""" model = QualityMeasurement extra = 0 fields = ['measurement_date', 'value', 'numerator', 'denominator', 'status', 'verified_by'] readonly_fields = ['created_by', 'created_at'] def get_queryset(self, request): return super().get_queryset(request).select_related('verified_by', 'created_by') @admin.register(QualityIndicator) class QualityIndicatorAdmin(admin.ModelAdmin): """Admin for quality indicators""" list_display = [ 'name', 'category', 'type', 'frequency', 'target_value', 'current_status_display', 'responsible_department', 'is_active' ] list_filter = [ 'category', 'type', 'frequency', 'is_active', 'regulatory_requirement', 'responsible_department' ] search_fields = ['name', 'description', 'data_source'] readonly_fields = ['created_at', 'updated_at'] fieldsets = [ ('Basic Information', { 'fields': ['name', 'description', 'category', 'type'] }), ('Measurement Details', { 'fields': ['measurement_unit', 'target_value', 'threshold_warning', 'threshold_critical'] }), ('Calculation', { 'fields': ['calculation_method', 'data_source', 'frequency'] }), ('Responsibility', { 'fields': ['responsible_department', 'responsible_user'] }), ('Settings', { 'fields': ['is_active', 'regulatory_requirement'] }), ('Timestamps', { 'fields': ['created_at', 'updated_at'], 'classes': ['collapse'] }) ] inlines = [QualityMeasurementInline] def current_status_display(self, obj): """Display current status with color coding""" status = obj.current_status colors = { 'within_target': 'green', 'warning': 'orange', 'critical': 'red', 'improving': 'blue', 'declining': 'purple', 'no_data': 'gray' } return format_html( '{}', colors.get(status, 'black'), status.replace('_', ' ').title() ) current_status_display.short_description = 'Current Status' def get_queryset(self, request): return super().get_queryset(request).select_related( 'responsible_department', 'responsible_user' ).prefetch_related('measurements') @admin.register(QualityMeasurement) class QualityMeasurementAdmin(admin.ModelAdmin): """Admin for quality measurements""" list_display = [ 'indicator', 'measurement_date', 'value', 'status_display', 'verified_by', 'created_by' ] list_filter = [ 'status', 'measurement_date', 'verified_by', 'indicator__category', 'indicator__type' ] search_fields = ['indicator__name', 'notes', 'data_source_reference'] readonly_fields = ['created_at', 'updated_at'] date_hierarchy = 'measurement_date' fieldsets = [ ('Measurement', { 'fields': ['indicator', 'measurement_date', 'value'] }), ('Rate Calculation', { 'fields': ['numerator', 'denominator'], 'classes': ['collapse'] }), ('Status and Notes', { 'fields': ['status', 'notes', 'data_source_reference'] }), ('Verification', { 'fields': ['verified_by', 'verified_at'] }), ('Audit', { 'fields': ['created_by', 'created_at', 'updated_at'], 'classes': ['collapse'] }) ] def status_display(self, obj): """Display status with color coding""" colors = { 'within_target': 'green', 'warning': 'orange', 'critical': 'red', 'improving': 'blue', 'declining': 'purple' } return format_html( '{}', colors.get(obj.status, 'black'), obj.get_status_display() ) status_display.short_description = 'Status' def get_queryset(self, request): return super().get_queryset(request).select_related( 'indicator', 'verified_by', 'created_by' ) class RiskAssessmentInline(admin.TabularInline): """Inline for risk assessments""" model = RiskAssessment extra = 0 fields = ['title', 'risk_category', 'risk_level', 'status', 'responsible_person'] readonly_fields = ['risk_score', ] @admin.register(IncidentReport) class IncidentReportAdmin(admin.ModelAdmin): """Admin for incident reports""" list_display = [ 'incident_number', 'title', 'incident_type', 'severity_display', 'status', 'assigned_to', 'incident_date' ] list_filter = [ 'incident_type', 'severity', 'category', 'status', 'priority', 'incident_date', 'is_confidential', 'regulatory_notification' ] search_fields = ['incident_number', 'title', 'description', 'location'] readonly_fields = ['incident_number', 'created_at', 'updated_at'] date_hierarchy = 'incident_date' fieldsets = [ ('Incident Details', { 'fields': ['incident_number', 'title', 'description'] }), ('Classification', { 'fields': ['incident_type', 'severity', 'category', 'location'] }), ('Timeline', { 'fields': ['incident_date', 'discovered_date'] }), ('People Involved', { 'fields': ['patient', 'reported_by'] }), ('Investigation', { 'fields': ['status', 'priority', 'assigned_to', 'due_date'] }), ('Analysis', { 'fields': ['root_cause', 'contributing_factors'], 'classes': ['collapse'] }), ('Actions', { 'fields': ['corrective_actions', 'preventive_actions'], 'classes': ['collapse'] }), ('Settings', { 'fields': ['is_confidential', 'regulatory_notification'] }), ('Closure', { 'fields': ['closed_date'], 'classes': ['collapse'] }), ('Audit', { 'fields': ['created_at', 'updated_at'], 'classes': ['collapse'] }) ] inlines = [RiskAssessmentInline] def severity_display(self, obj): """Display severity with color coding""" colors = { 'no_harm': 'green', 'minor_harm': 'yellow', 'moderate_harm': 'orange', 'severe_harm': 'red', 'death': 'darkred' } return format_html( '{}', colors.get(obj.severity, 'black'), obj.get_severity_display() ) severity_display.short_description = 'Severity' def get_queryset(self, request): return super().get_queryset(request).select_related( 'patient', 'reported_by', 'assigned_to' ) @admin.register(RiskAssessment) class RiskAssessmentAdmin(admin.ModelAdmin): """Admin for risk assessments""" list_display = [ 'title', 'risk_category', 'risk_level_display', 'status', 'responsible_person', 'review_date' ] list_filter = [ 'risk_category', 'risk_type', 'risk_level', 'status', 'control_effectiveness', 'review_date' ] search_fields = ['title', 'description', 'current_controls', 'mitigation_plan'] readonly_fields = ['risk_score', 'risk_level', 'created_at', 'updated_at'] date_hierarchy = 'review_date' fieldsets = [ ('Risk Information', { 'fields': ['title', 'description', 'risk_category', 'risk_type'] }), ('Initial Risk Assessment', { 'fields': ['likelihood', 'impact', 'risk_score', 'risk_level'] }), ('Current Controls', { 'fields': ['current_controls', 'control_effectiveness'] }), ('Residual Risk', { 'fields': ['residual_likelihood', 'residual_impact', 'residual_risk_score', 'residual_risk_level'] }), ('Mitigation', { 'fields': ['mitigation_plan', 'responsible_person', 'review_date'] }), ('Status', { 'fields': ['status', 'incident_report'] }), ('Audit', { 'fields': ['created_by', 'created_at', 'updated_at'], 'classes': ['collapse'] }) ] def risk_level_display(self, obj): """Display risk level with color coding""" colors = { 'low': 'green', 'medium': 'yellow', 'high': 'orange', 'critical': 'red' } return format_html( '{}', colors.get(obj.risk_level, 'black'), obj.get_risk_level_display() ) risk_level_display.short_description = 'Risk Level' def residual_risk_level_display(self, obj): """Display residual risk level with color coding""" colors = { 'low': 'green', 'medium': 'yellow', 'high': 'orange', 'critical': 'red' } return format_html( '{}', colors.get(obj.residual_risk_level, 'black'), obj.get_residual_risk_level_display() ) residual_risk_level_display.short_description = 'Residual Risk Level' def get_queryset(self, request): return super().get_queryset(request).select_related( 'responsible_person', 'incident_report', 'created_by' ) class AuditFindingInline(admin.TabularInline): """Inline for audit findings""" model = AuditFinding extra = 0 fields = ['finding_number', 'title', 'finding_type', 'severity', 'status', 'responsible_person'] readonly_fields = ['finding_number'] @admin.register(AuditPlan) class AuditPlanAdmin(admin.ModelAdmin): """Admin for audit plans""" list_display = [ 'title', 'audit_type', 'department', 'auditor', 'planned_start_date', 'status', 'findings_count_display' ] list_filter = [ 'audit_type', 'status', 'priority', 'regulatory_requirement', 'planned_start_date', 'department' ] search_fields = ['title', 'description', 'scope', 'criteria', 'accreditation_body'] readonly_fields = ['created_at', 'updated_at'] date_hierarchy = 'planned_start_date' filter_horizontal = ['audit_team'] fieldsets = [ ('Audit Information', { 'fields': ['title', 'description', 'audit_type'] }), ('Scope and Criteria', { 'fields': ['scope', 'criteria', 'department'] }), ('Team', { 'fields': ['auditor', 'audit_team'] }), ('Schedule', { 'fields': ['planned_start_date', 'planned_end_date', 'actual_start_date', 'actual_end_date'] }), ('Status', { 'fields': ['status', 'priority'] }), ('Regulatory', { 'fields': ['regulatory_requirement', 'accreditation_body'], 'classes': ['collapse'] }), ('Audit', { 'fields': ['created_by', 'created_at', 'updated_at'], 'classes': ['collapse'] }) ] inlines = [AuditFindingInline] def findings_count_display(self, obj): """Display findings count with link""" count = obj.findings_count if count > 0: url = reverse('admin:quality_auditfinding_changelist') + f'?audit_plan__id__exact={obj.id}' return format_html('{} findings', url, count) return '0 findings' findings_count_display.short_description = 'Findings' def get_queryset(self, request): return super().get_queryset(request).select_related( 'department', 'auditor', 'created_by' ).prefetch_related('audit_team', 'findings') @admin.register(AuditFinding) class AuditFindingAdmin(admin.ModelAdmin): """Admin for audit findings""" list_display = [ 'finding_number', 'title', 'audit_plan', 'finding_type', 'severity_display', 'status', 'responsible_person', 'target_completion_date' ] list_filter = [ 'finding_type', 'severity', 'category', 'status', 'corrective_action_required', 'target_completion_date', 'audit_plan__audit_type' ] search_fields = ['finding_number', 'title', 'description', 'evidence', 'criteria_reference'] readonly_fields = ['finding_number', 'created_at', 'updated_at'] date_hierarchy = 'target_completion_date' fieldsets = [ ('Finding Information', { 'fields': ['audit_plan', 'finding_number', 'title', 'description'] }), ('Classification', { 'fields': ['finding_type', 'severity', 'category', 'criteria_reference'] }), ('Evidence and Analysis', { 'fields': ['evidence', 'root_cause'] }), ('Corrective Action', { 'fields': ['corrective_action_required', 'corrective_action_plan', 'responsible_person'] }), ('Timeline', { 'fields': ['target_completion_date', 'actual_completion_date'] }), ('Status and Verification', { 'fields': ['status', 'verification_method', 'verified_by', 'verified_date'] }), ('Audit', { 'fields': ['created_by', 'created_at', 'updated_at'], 'classes': ['collapse'] }) ] def severity_display(self, obj): """Display severity with color coding""" colors = { 'minor': 'green', 'major': 'orange', 'critical': 'red' } return format_html( '{}', colors.get(obj.severity, 'black'), obj.get_severity_display() ) severity_display.short_description = 'Severity' def get_queryset(self, request): return super().get_queryset(request).select_related( 'audit_plan', 'responsible_person', 'verified_by', 'created_by' ) @admin.register(ImprovementProject) class ImprovementProjectAdmin(admin.ModelAdmin): """Admin for improvement projects""" list_display = [ 'project_number', 'title', 'project_type', 'status', 'project_manager', 'planned_start_date', 'phase' ] list_filter = [ 'project_type', 'methodology', 'status', 'phase', 'planned_start_date', 'department' ] search_fields = ['project_number', 'title', 'description', 'problem_statement', 'goal_statement'] readonly_fields = ['project_number', 'duration_planned', 'duration_actual', 'created_at', 'updated_at'] date_hierarchy = 'planned_start_date' filter_horizontal = ['project_team'] fieldsets = [ ('Project Information', { 'fields': ['project_number', 'title', 'description', 'project_type', 'methodology'] }), ('Problem and Goals', { 'fields': ['problem_statement', 'goal_statement', 'scope'] }), ('Metrics', { 'fields': ['success_metrics', 'baseline_data', 'target_metrics'] }), ('Team', { 'fields': ['project_manager', 'project_team', 'sponsor', 'department'] }), ('Timeline', { 'fields': ['planned_start_date', 'planned_end_date', 'actual_start_date', 'actual_end_date', 'duration_planned', 'duration_actual'] }), ('Status', { 'fields': ['status', 'phase'] }), ('Budget and ROI', { 'fields': ['budget', 'actual_cost', 'roi_expected', 'roi_actual'], 'classes': ['collapse'] }), ('Outcomes', { 'fields': ['lessons_learned', 'sustainability_plan'], 'classes': ['collapse'] }), ('Audit', { 'fields': ['created_by', 'created_at', 'updated_at'], 'classes': ['collapse'] }) ] def get_queryset(self, request): return super().get_queryset(request).select_related( 'project_manager', 'sponsor', 'department', 'created_by' ).prefetch_related('project_team') # Register models with custom admin classes admin.site.site_header = "Hospital Management System - Quality Administration" admin.site.site_title = "Quality Admin" admin.site.index_title = "Quality Management Administration"