2026-04-19 10:53:12 +03:00

351 lines
13 KiB
Python

"""
Executive Summary models - AI-powered executive dashboards and reports
This module implements:
- Executive metrics (KPI snapshots for trending)
- Executive reports (AI-generated weekly/monthly summaries)
- Predictive insights (AI-detected patterns and risks)
- AI recommendations (suggested actions)
"""
from django.db import models
from django.utils.translation import gettext_lazy as _
from apps.core.models import TimeStampedModel, UUIDModel
class ExecutiveMetric(UUIDModel, TimeStampedModel):
"""
Executive Metric - Daily KPI snapshots for trending and analysis.
Stores aggregated metrics across all hospitals for executive overview.
Used for trend analysis and dashboard display.
"""
METRIC_TYPES = [
("complaints_total", _("Total Complaints")),
("complaints_critical", _("Critical Complaints")),
("complaints_overdue", _("Overdue Complaints")),
("complaints_resolution_time", _("Avg Resolution Time (hours)")),
("surveys_total", _("Total Surveys")),
("surveys_satisfaction", _("Satisfaction Rate %")),
("surveys_nps", _("NPS Score")),
("surveys_response_rate", _("Response Rate %")),
("actions_total", _("Total Actions")),
("actions_open", _("Open Actions")),
("actions_overdue", _("Overdue Actions")),
("actions_closed", _("Closed Actions")),
("observations_total", _("Total Observations")),
("observations_critical", _("Critical Observations")),
("inquiries_total", _("Total Inquiries")),
("inquiries_resolved", _("Resolved Inquiries")),
("call_center_total", _("Call Center Interactions")),
("call_center_satisfaction", _("Call Center Satisfaction %")),
("physician_avg_rating", _("Avg Physician Rating")),
]
# Date for this metric snapshot
metric_date = models.DateField(db_index=True, help_text="Date of this metric snapshot")
# Metric type
metric_type = models.CharField(max_length=50, choices=METRIC_TYPES, db_index=True)
# Metric value
metric_value = models.DecimalField(max_digits=10, decimal_places=2)
# Variance from previous period
variance = models.DecimalField(
max_digits=10, decimal_places=2, null=True, blank=True, help_text="Variance from previous period"
)
# Variance direction
variance_direction = models.CharField(
max_length=10,
choices=[("up", "Up"), ("down", "Down"), ("neutral", "Neutral")],
default="neutral",
help_text="Direction of variance",
)
# Hospital (null = system-wide aggregate)
hospital = models.ForeignKey(
"organizations.Hospital", on_delete=models.CASCADE, null=True, blank=True, related_name="executive_metrics"
)
# Metadata
metadata = models.JSONField(default=dict, blank=True)
class Meta:
ordering = ["-metric_date", "metric_type"]
indexes = [
models.Index(fields=["metric_date", "metric_type"]),
models.Index(fields=["hospital", "metric_date"]),
]
verbose_name = _("Executive Metric")
verbose_name_plural = _("Executive Metrics")
def __str__(self):
hospital_name = f" - {self.hospital.name}" if self.hospital else " (All)"
return f"{self.get_metric_type_display()}: {self.metric_value}{hospital_name} ({self.metric_date})"
class ExecutiveReport(UUIDModel, TimeStampedModel):
"""
Executive Report - AI-generated weekly/monthly narrative summaries.
Contains natural language summaries generated by AI analyzing
performance data across all hospitals.
"""
REPORT_TYPES = [
("weekly", _("Weekly Summary")),
("monthly", _("Monthly Summary")),
("quarterly", _("Quarterly Summary")),
("custom", _("Custom Report")),
]
STATUS_CHOICES = [
("pending", _("Pending")),
("generating", _("Generating")),
("completed", _("Completed")),
("failed", _("Failed")),
]
# Report metadata
report_type = models.CharField(max_length=20, choices=REPORT_TYPES, db_index=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending", db_index=True)
# Date range
start_date = models.DateField()
end_date = models.DateField()
# AI-generated narratives (bilingual)
narrative_en = models.TextField(blank=True, help_text="English narrative summary")
narrative_ar = models.TextField(blank=True, help_text="Arabic narrative summary")
# Key highlights
highlights_en = models.JSONField(default=list, blank=True, help_text="Key highlights (English)")
highlights_ar = models.JSONField(default=list, blank=True, help_text="Key highlights (Arabic)")
# Key concerns
concerns_en = models.JSONField(default=list, blank=True, help_text="Key concerns (English)")
concerns_ar = models.JSONField(default=list, blank=True, help_text="Key concerns (Arabic)")
# Summary metrics snapshot
metrics_snapshot = models.JSONField(default=dict, blank=True, help_text="Key metrics at report time")
# AI metadata
ai_model = models.CharField(max_length=100, blank=True, help_text="AI model used for generation")
generation_time_ms = models.IntegerField(null=True, blank=True, help_text="Generation time in milliseconds")
# PDF report file (if generated)
pdf_file = models.FileField(
upload_to="executive_reports/pdfs/%Y/%m/", null=True, blank=True, help_text="Generated PDF report"
)
# Error message if failed
error_message = models.TextField(blank=True, help_text="Error message if generation failed")
class Meta:
ordering = ["-created_at"]
indexes = [
models.Index(fields=["report_type", "-created_at"]),
models.Index(fields=["status", "-created_at"]),
]
verbose_name = _("Executive Report")
verbose_name_plural = _("Executive Reports")
def __str__(self):
return f"{self.get_report_type_display()} ({self.start_date} to {self.end_date}) - {self.get_status_display()}"
class PredictiveInsight(UUIDModel, TimeStampedModel):
"""
Predictive Insight - AI-detected patterns, anomalies, and early warnings.
Automatically generated insights identifying:
- Emerging complaint patterns
- Declining satisfaction trends
- SLA breach risks
- Performance anomalies
- Resource bottlenecks
"""
INSIGHT_TYPES = [
("trend_change", _("Trend Change")),
("anomaly", _("Anomaly Detected")),
("risk_warning", _("Risk Warning")),
("sla_breach_risk", _("SLA Breach Risk")),
("performance_drop", _("Performance Drop")),
("volume_spike", _("Volume Spike")),
("satisfaction_decline", _("Satisfaction Decline")),
("positive_trend", _("Positive Trend")),
]
SEVERITY_LEVELS = [
("low", _("Low")),
("medium", _("Medium")),
("high", _("High")),
("critical", _("Critical")),
]
STATUS_CHOICES = [
("new", _("New")),
("acknowledged", _("Acknowledged")),
("resolved", _("Resolved")),
("dismissed", _("Dismissed")),
]
# Insight details
insight_type = models.CharField(max_length=30, choices=INSIGHT_TYPES, db_index=True)
severity = models.CharField(max_length=10, choices=SEVERITY_LEVELS, default="medium", db_index=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="new", db_index=True)
# Title and description (bilingual)
title_en = models.CharField(max_length=300)
title_ar = models.CharField(max_length=300, blank=True)
description_en = models.TextField()
description_ar = models.TextField(blank=True)
# AI-generated recommendation
recommendation_en = models.TextField(blank=True)
recommendation_ar = models.TextField(blank=True)
# Affected entities
hospital = models.ForeignKey(
"organizations.Hospital", on_delete=models.SET_NULL, null=True, blank=True, related_name="predictive_insights"
)
department = models.ForeignKey(
"organizations.Department", on_delete=models.SET_NULL, null=True, blank=True, related_name="predictive_insights"
)
# Metric affected
metric_type = models.CharField(max_length=50, blank=True, help_text="Related metric type")
# Related entity (for SLA breach predictions, etc.)
entity_type = models.CharField(
max_length=50, blank=True, help_text="Type of related entity (e.g., complaint, px_action)"
)
entity_id = models.CharField(max_length=100, blank=True, help_text="ID of related entity")
# Predicted values
current_value = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
predicted_value = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
confidence_score = models.DecimalField(
max_digits=5, decimal_places=2, null=True, blank=True, help_text="AI confidence score (0-100)"
)
# Time-related
predicted_date = models.DateField(null=True, blank=True, help_text="When this is expected to occur")
# Acknowledgement
acknowledged_by = models.ForeignKey(
"accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="acknowledged_insights"
)
acknowledged_at = models.DateTimeField(null=True, blank=True)
# AI metadata
ai_model = models.CharField(max_length=100, blank=True)
detection_metadata = models.JSONField(default=dict, blank=True)
class Meta:
ordering = ["-severity", "-created_at"]
indexes = [
models.Index(fields=["status", "severity", "-created_at"]),
models.Index(fields=["hospital", "status"]),
]
verbose_name = _("Predictive Insight")
verbose_name_plural = _("Predictive Insights")
def __str__(self):
return f"[{self.get_severity_display()}] {self.title_en}"
class AIRecommendation(UUIDModel, TimeStampedModel):
"""
AI Recommendation - Suggested actions based on data analysis.
AI-generated recommendations for:
- Process improvements
- Resource allocation
- Training needs
- Policy changes
- Preventive measures
"""
CATEGORY_CHOICES = [
("process_improvement", _("Process Improvement")),
("resource_allocation", _("Resource Allocation")),
("training", _("Training")),
("policy_change", _("Policy Change")),
("preventive_action", _("Preventive Action")),
("performance_optimization", _("Performance Optimization")),
("communication", _("Communication")),
("quality_assurance", _("Quality Assurance")),
]
PRIORITY_LEVELS = [
("low", _("Low")),
("medium", _("Medium")),
("high", _("High")),
("urgent", _("Urgent")),
]
STATUS_CHOICES = [
("new", _("New")),
("under_review", _("Under Review")),
("approved", _("Approved")),
("implemented", _("Implemented")),
("rejected", _("Rejected")),
]
# Recommendation details
category = models.CharField(max_length=30, choices=CATEGORY_CHOICES, db_index=True)
priority = models.CharField(max_length=10, choices=PRIORITY_LEVELS, default="medium", db_index=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="new", db_index=True)
# Title and description (bilingual)
title_en = models.CharField(max_length=300)
title_ar = models.CharField(max_length=300, blank=True)
description_en = models.TextField()
description_ar = models.TextField(blank=True)
# Expected impact
expected_impact_en = models.TextField(blank=True, help_text="Expected impact if implemented (English)")
expected_impact_ar = models.TextField(blank=True, help_text="Expected impact if implemented (Arabic)")
# Related data
hospital = models.ForeignKey(
"organizations.Hospital", on_delete=models.SET_NULL, null=True, blank=True, related_name="ai_recommend"
)
department = models.ForeignKey(
"organizations.Department", on_delete=models.SET_NULL, null=True, blank=True, related_name="ai_recommend"
)
# Related insight (if generated from one)
related_insight = models.ForeignKey(
PredictiveInsight, on_delete=models.SET_NULL, null=True, blank=True, related_name="recommendations"
)
# Implementation tracking
implemented_by = models.ForeignKey(
"accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="implemented_recommendations"
)
implemented_at = models.DateTimeField(null=True, blank=True)
# AI metadata
confidence_score = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
ai_model = models.CharField(max_length=100, blank=True)
generation_metadata = models.JSONField(default=dict, blank=True)
class Meta:
ordering = ["-priority", "-created_at"]
indexes = [
models.Index(fields=["status", "priority", "-created_at"]),
models.Index(fields=["hospital", "status"]),
]
verbose_name = _("AI Recommendation")
verbose_name_plural = _("AI Recommendations")
def __str__(self):
return f"[{self.get_priority_display()}] {self.title_en}"