HH/apps/standards/models.py
2026-04-08 17:13:35 +03:00

147 lines
5.5 KiB
Python

"""
Standards Section Models - Track compliance standards (CBAHI, MOH, CHI, etc.)
"""
from django.db import models
from django.core.validators import FileExtensionValidator
from apps.core.models import TimeStampedModel, UUIDModel, StatusChoices
class StandardSource(UUIDModel, TimeStampedModel):
"""Standard sources like CBAHI, MOH, CHI, JCI, etc."""
name = models.CharField(max_length=100)
name_ar = models.CharField(max_length=100, blank=True, verbose_name="Name (Arabic)")
code = models.CharField(max_length=50, unique=True)
description = models.TextField(blank=True)
website = models.URLField(blank=True)
is_active = models.BooleanField(default=True, db_index=True)
class Meta:
ordering = ["name"]
verbose_name = "Standard Source"
verbose_name_plural = "Standard Sources"
def __str__(self):
return self.name
class StandardCategory(UUIDModel, TimeStampedModel):
"""Group standards by category (Patient Safety, Quality Management, etc.)"""
name = models.CharField(max_length=100)
name_ar = models.CharField(max_length=100, blank=True, verbose_name="Name (Arabic)")
description = models.TextField(blank=True)
order = models.PositiveIntegerField(default=0, help_text="Display order")
is_active = models.BooleanField(default=True, db_index=True)
class Meta:
ordering = ["order", "name"]
verbose_name = "Standard Category"
verbose_name_plural = "Standard Categories"
def __str__(self):
return self.name
class Standard(UUIDModel, TimeStampedModel):
"""Actual standard requirements"""
class ComplianceStatus(models.TextChoices):
NOT_ASSESSED = "not_assessed", "Not Assessed"
MET = "met", "Met"
PARTIALLY_MET = "partially_met", "Partially Met"
NOT_MET = "not_met", "Not Met"
code = models.CharField(max_length=50, db_index=True, help_text="e.g., CBAHI-PS-01")
title = models.CharField(max_length=300)
title_ar = models.CharField(max_length=300, blank=True, verbose_name="Title (Arabic)")
description = models.TextField(help_text="Full description of the standard")
# Relationships
source = models.ForeignKey(StandardSource, on_delete=models.PROTECT, related_name="standards")
category = models.ForeignKey(StandardCategory, on_delete=models.PROTECT, related_name="standards")
department = models.ForeignKey(
"organizations.Department",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="standards",
help_text="Department-specific standard (null if applicable to all)",
)
# Dates
effective_date = models.DateField(null=True, blank=True, help_text="When standard becomes effective")
review_date = models.DateField(null=True, blank=True, help_text="Next review date")
is_active = models.BooleanField(default=True, db_index=True)
class Meta:
ordering = ["source", "category", "code"]
verbose_name = "Standard"
verbose_name_plural = "Standards"
def __str__(self):
return f"{self.code}: {self.title}"
class StandardCompliance(UUIDModel, TimeStampedModel):
"""Track compliance status per department"""
class ComplianceStatus(models.TextChoices):
NOT_ASSESSED = "not_assessed", "Not Assessed"
MET = "met", "Met"
PARTIALLY_MET = "partially_met", "Partially Met"
NOT_MET = "not_met", "Not Met"
department = models.ForeignKey(
"organizations.Department", on_delete=models.CASCADE, related_name="compliance_records"
)
standard = models.ForeignKey(Standard, on_delete=models.CASCADE, related_name="compliance_records")
status = models.CharField(
max_length=20, choices=ComplianceStatus.choices, default=ComplianceStatus.NOT_ASSESSED, db_index=True
)
last_assessed_date = models.DateField(null=True, blank=True, help_text="Date of last assessment")
assessor = models.ForeignKey(
"accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="assessments"
)
notes = models.TextField(blank=True, help_text="Assessment notes")
evidence_summary = models.TextField(blank=True, help_text="Summary of evidence")
class Meta:
ordering = ["-created_at"]
verbose_name = "Standard Compliance"
verbose_name_plural = "Standard Compliance"
unique_together = [["department", "standard"]]
def __str__(self):
return f"{self.department.name} - {self.standard.code} - {self.status}"
class StandardAttachment(UUIDModel, TimeStampedModel):
"""Proof of compliance - evidence documents"""
compliance = models.ForeignKey(StandardCompliance, on_delete=models.CASCADE, related_name="attachments")
file = models.FileField(
upload_to="standards/attachments/%Y/%m/",
validators=[
FileExtensionValidator(
allowed_extensions=["pdf", "doc", "docx", "xls", "xlsx", "jpg", "jpeg", "png", "zip"]
)
],
)
filename = models.CharField(max_length=255, help_text="Original filename")
description = models.TextField(blank=True, help_text="Attachment description")
uploaded_by = models.ForeignKey(
"accounts.User", on_delete=models.SET_NULL, null=True, blank=True, related_name="uploaded_standards_attachments"
)
class Meta:
ordering = ["-created_at"]
verbose_name = "Standard Attachment"
verbose_name_plural = "Standard Attachments"
def __str__(self):
return f"{self.compliance} - {self.filename}"