""" Projects models - Quality Improvement (QI) projects tracking This module implements QI project management: - Project tracking - Task management - PDCA cycle phases - Milestone tracking - Outcome measurement """ from django.db import models from django.utils.translation import gettext_lazy as _ from apps.core.models import StatusChoices, TimeStampedModel, UUIDModel class PDCAPhaseChoices(models.TextChoices): PLAN = "plan", _("Plan") DO = "do", _("Do") CHECK = "check", _("Check") ACT = "act", _("Act") class QIProject(UUIDModel, TimeStampedModel): """ Quality Improvement Project. Tracks improvement initiatives driven by PX feedback. Can also serve as a template for creating new projects. """ name = models.CharField(max_length=200) name_ar = models.CharField(max_length=200, blank=True) description = models.TextField() # Template flag - if True, this is a template not an active project is_template = models.BooleanField( default=False, db_index=True, help_text="If True, this is a reusable template, not an active project" ) # Organization hospital = models.ForeignKey( "organizations.Hospital", on_delete=models.CASCADE, related_name="qi_projects", null=True, blank=True, help_text="Null for global templates available to all hospitals", ) department = models.ForeignKey( "organizations.Department", on_delete=models.SET_NULL, null=True, blank=True, related_name="qi_projects" ) # Project lead project_lead = models.ForeignKey("accounts.User", on_delete=models.SET_NULL, null=True, related_name="led_projects") # Creator created_by = models.ForeignKey( "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="created_qi_projects" ) # Team members team_members = models.ManyToManyField("accounts.User", blank=True, related_name="qi_projects") # Status status = models.CharField( max_length=20, choices=StatusChoices.choices, default=StatusChoices.PENDING, db_index=True ) # Dates start_date = models.DateField(null=True, blank=True) target_completion_date = models.DateField(null=True, blank=True, db_index=True) actual_completion_date = models.DateField(null=True, blank=True) # Linked to PX Actions (optional) related_actions = models.ManyToManyField("px_action_center.PXAction", blank=True, related_name="qi_projects") # Outcomes outcome_description = models.TextField(blank=True) success_metrics = models.JSONField(default=dict, blank=True, help_text="Success metrics and results") # Metadata metadata = models.JSONField(default=dict, blank=True) class Meta: ordering = ["-created_at"] indexes = [ models.Index(fields=["hospital", "status", "-created_at"]), models.Index(fields=["is_template", "hospital"]), models.Index(fields=["project_lead", "status"]), models.Index(fields=["status", "target_completion_date"]), ] def __str__(self): if self.is_template: return f"[Template] {self.name}" return f"{self.name} ({self.status})" class QIProjectTask(UUIDModel, TimeStampedModel): """ Task within a QI project. """ project = models.ForeignKey(QIProject, on_delete=models.CASCADE, related_name="tasks") pdca_phase = models.ForeignKey( "PDCAPhase", on_delete=models.CASCADE, null=True, blank=True, related_name="tasks", ) title = models.CharField(max_length=500) description = models.TextField(blank=True) # Assignment assigned_to = models.ForeignKey( "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="qi_tasks" ) # Status status = models.CharField(max_length=20, choices=StatusChoices.choices, default=StatusChoices.PENDING) # Dates due_date = models.DateField(null=True, blank=True) completed_date = models.DateField(null=True, blank=True) # Order order = models.IntegerField(default=0) class Meta: ordering = ["project", "order"] def __str__(self): return f"{self.project.name} - {self.title}" class PDCAPhase(UUIDModel, TimeStampedModel): """ PDCA (Plan-Do-Check-Act) phase within a QI project. Each project can have up to 4 phases, one per PDCA stage. """ project = models.ForeignKey(QIProject, on_delete=models.CASCADE, related_name="pdca_phases") phase = models.CharField(max_length=10, choices=PDCAPhaseChoices.choices) title = models.CharField(max_length=300, blank=True) description = models.TextField(blank=True) owner = models.ForeignKey( "accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="owned_pdca_phases", ) status = models.CharField(max_length=20, choices=StatusChoices.choices, default=StatusChoices.PENDING) start_date = models.DateField(null=True, blank=True) due_date = models.DateField(null=True, blank=True) completed_date = models.DateField(null=True, blank=True) findings = models.TextField(blank=True) order = models.IntegerField(default=0) class Meta: unique_together = [("project", "phase")] ordering = ["project", "order"] def __str__(self): return f"{self.project.name} - {self.get_phase_display()}"