""" Analytics models - KPIs, metrics, and dashboards This module implements analytics capabilities: - KPI definitions and tracking - Metric aggregation - Dashboard data - Trend analysis """ from django.db import models from apps.core.models import TimeStampedModel, UUIDModel class KPI(UUIDModel, TimeStampedModel): """ KPI (Key Performance Indicator) definition. Defines metrics to track across the system. """ name = models.CharField(max_length=200, unique=True) name_ar = models.CharField(max_length=200, blank=True) description = models.TextField(blank=True) # Category category = models.CharField( max_length=100, choices=[ ("patient_satisfaction", "Patient Satisfaction"), ("complaint_management", "Complaint Management"), ("action_management", "Action Management"), ("sla_compliance", "SLA Compliance"), ("survey_response", "Survey Response"), ("operational", "Operational"), ], db_index=True, ) # Measurement unit = models.CharField(max_length=50, help_text="Unit of measurement (%, count, hours, etc.)") calculation_method = models.TextField(help_text="Description of how this KPI is calculated") # Thresholds target_value = models.DecimalField( max_digits=10, decimal_places=2, null=True, blank=True, help_text="Target value for this KPI" ) warning_threshold = models.DecimalField( max_digits=10, decimal_places=2, null=True, blank=True, help_text="Warning threshold" ) critical_threshold = models.DecimalField( max_digits=10, decimal_places=2, null=True, blank=True, help_text="Critical threshold" ) # Configuration is_active = models.BooleanField(default=True) class Meta: ordering = ["category", "name"] verbose_name = "KPI" verbose_name_plural = "KPIs" def __str__(self): return self.name class KPIValue(UUIDModel, TimeStampedModel): """ KPI value - actual measurement at a point in time. """ kpi = models.ForeignKey(KPI, on_delete=models.CASCADE, related_name="values") # Scope hospital = models.ForeignKey( "organizations.Hospital", on_delete=models.CASCADE, null=True, blank=True, related_name="kpi_values" ) department = models.ForeignKey( "organizations.Department", on_delete=models.CASCADE, null=True, blank=True, related_name="kpi_values" ) # Value value = models.DecimalField(max_digits=10, decimal_places=2) # Time period period_start = models.DateTimeField(db_index=True) period_end = models.DateTimeField(db_index=True) period_type = models.CharField( max_length=20, choices=[ ("hourly", "Hourly"), ("daily", "Daily"), ("weekly", "Weekly"), ("monthly", "Monthly"), ("quarterly", "Quarterly"), ("yearly", "Yearly"), ], default="daily", ) # Status status = models.CharField( max_length=20, choices=[ ("on_target", "On Target"), ("warning", "Warning"), ("critical", "Critical"), ], db_index=True, ) # Metadata metadata = models.JSONField(default=dict, blank=True, help_text="Additional calculation details") class Meta: ordering = ["-period_end"] indexes = [ models.Index(fields=["kpi", "-period_end"]), models.Index(fields=["hospital", "kpi", "-period_end"]), models.Index(fields=["hospital", "department", "-period_end"]), ] def __str__(self): scope = self.hospital.name if self.hospital else "Global" return f"{self.kpi.name} - {scope} - {self.period_end.strftime('%Y-%m-%d')}: {self.value}"