HH/apps/analytics/models.py
2025-12-24 12:42:31 +03:00

159 lines
4.0 KiB
Python

"""
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']),
]
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}"