hospital-management/enhancements.txt
2025-10-06 15:25:37 +03:00

83 lines
4.2 KiB
Plaintext

# documentation/models.py
from django.conf import settings
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
import uuid
class NoteType(models.TextChoices):
ADMISSION = "ADMISSION", "Admission Note"
PROGRESS = "PROGRESS", "Progress Note"
DISCHARGE = "DISCHARGE", "Discharge Summary"
RADIOLOGY_REPORT = "RADIOLOGY_REPORT", "Radiology Report"
LAB_REPORT = "LAB_REPORT", "Laboratory Narrative"
PROCEDURE = "PROCEDURE", "Procedure Note"
ANESTHESIA = "ANESTHESIA", "Anesthesia Note"
OTHER = "OTHER", "Other"
class Document(models.Model):
"""
Canonical clinical document (note/report).
Stores content, metadata, provenance, and links to any domain object.
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
tenant = models.ForeignKey("core.Tenant", on_delete=models.CASCADE, related_name="documents")
patient = models.ForeignKey("core.Patient", on_delete=models.CASCADE, related_name="documents")
encounter = models.ForeignKey("core.Encounter", on_delete=models.SET_NULL, null=True, blank=True, related_name="documents")
doc_type = models.CharField(max_length=40, choices=NoteType.choices)
title = models.CharField(max_length=255)
status = models.CharField(max_length=20, default="final") # draft | amended | final | entered-in-error
authored_at = models.DateTimeField(auto_now_add=True)
authored_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, related_name="documents_authored")
signed_at = models.DateTimeField(null=True, blank=True)
signed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="documents_signed")
# Content
# Store both rich text and structured JSON to support templates, tokens, smart fields.
body_markdown = models.TextField(blank=True, default="")
body_json = models.JSONField(blank=True, null=True) # optional structured representation
# FHIR mapping hints (optional)
fhir_profile = models.CharField(max_length=120, blank=True, default="") # e.g., Composition/DiagnosticReport
code = models.CharField(max_length=64, blank=True, default="") # LOINC/SNOMED if used
# Full-text search (enable GIN index in migration)
search_vector = models.TextField(blank=True, default="") # or use a dedicated SearchVector field
# Soft flags
is_confidential = models.BooleanField(default=False)
is_amendment = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class DocumentVersion(models.Model):
document = models.ForeignKey(Document, on_delete=models.CASCADE, related_name="versions")
version = models.PositiveIntegerField()
snapshot_markdown = models.TextField(blank=True, default="")
snapshot_json = models.JSONField(blank=True, null=True)
changed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
changed_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = [("document", "version")]
ordering = ["-version"]
class DocumentLink(models.Model):
"""
Generic relation to ANY object (lab order, study, admission, procedure, etc.)
Allows many-to-many linking without embedding foreign keys in every domain app.
"""
document = models.ForeignKey(Document, on_delete=models.CASCADE, related_name="links")
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.CharField(max_length=64)
target = GenericForeignKey("content_type", "object_id")
role = models.CharField(max_length=40, blank=True, default="context") # context | source | result | followup
created_at = models.DateTimeField(auto_now_add=True)
class DocumentAttachment(models.Model):
document = models.ForeignKey(Document, on_delete=models.CASCADE, related_name="attachments")
file = models.FileField(upload_to="documents/%Y/%m/")
title = models.CharField(max_length=255, blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)