agdar/documents/models.py
2025-11-02 14:35:35 +03:00

130 lines
5.1 KiB
Python

from django.db import models
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from core.models import Patient
User = get_user_model()
class DocumentTemplate(models.Model):
"""
Reusable document templates for clinical notes and other documents.
"""
CATEGORY_CHOICES = [
('medical', _('Medical')),
('nursing', _('Nursing')),
('aba', _('ABA')),
('ot', _('Occupational Therapy')),
('slp', _('Speech-Language Pathology')),
('assessment', _('Assessment')),
('progress', _('Progress Report')),
('discharge', _('Discharge Summary')),
('other', _('Other')),
]
name = models.CharField(_('Template Name'), max_length=200)
category = models.CharField(_('Category'), max_length=50, choices=CATEGORY_CHOICES)
description = models.TextField(_('Description'), blank=True)
content = models.TextField(_('Template Content'), help_text=_('Use {{variable_name}} for dynamic fields'))
is_active = models.BooleanField(_('Active'), default=True)
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='created_templates')
created_at = models.DateTimeField(_('Created At'), auto_now_add=True)
updated_at = models.DateTimeField(_('Updated At'), auto_now=True)
class Meta:
verbose_name = _('Document Template')
verbose_name_plural = _('Document Templates')
ordering = ['category', 'name']
def __str__(self):
return f"{self.name} ({self.get_category_display()})"
class ClinicalNote(models.Model):
"""
Clinical notes and documentation for patient care.
"""
STATUS_CHOICES = [
('draft', _('Draft')),
('final', _('Final')),
('amended', _('Amended')),
('deleted', _('Deleted')),
]
patient = models.ForeignKey(Patient, on_delete=models.CASCADE, related_name='clinical_notes')
template = models.ForeignKey(DocumentTemplate, on_delete=models.SET_NULL, null=True, blank=True, related_name='notes')
title = models.CharField(_('Title'), max_length=200)
content = models.TextField(_('Content'))
status = models.CharField(_('Status'), max_length=20, choices=STATUS_CHOICES, default='draft')
# Metadata
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='authored_notes')
created_at = models.DateTimeField(_('Created At'), auto_now_add=True)
updated_at = models.DateTimeField(_('Updated At'), auto_now=True)
finalized_at = models.DateTimeField(_('Finalized At'), null=True, blank=True)
finalized_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='finalized_notes')
# Versioning
version = models.IntegerField(_('Version'), default=1)
parent_note = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='amendments')
class Meta:
verbose_name = _('Clinical Note')
verbose_name_plural = _('Clinical Notes')
ordering = ['-created_at']
permissions = [
('can_finalize_note', 'Can finalize clinical notes'),
('can_amend_note', 'Can amend finalized notes'),
]
def __str__(self):
return f"{self.title} - {self.patient.get_full_name()} ({self.created_at.strftime('%Y-%m-%d')})"
class NoteAddendum(models.Model):
"""
Addendums to clinical notes for corrections or additional information.
"""
note = models.ForeignKey(ClinicalNote, on_delete=models.CASCADE, related_name='addendums')
content = models.TextField(_('Addendum Content'))
reason = models.CharField(_('Reason'), max_length=200)
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
created_at = models.DateTimeField(_('Created At'), auto_now_add=True)
class Meta:
verbose_name = _('Note Addendum')
verbose_name_plural = _('Note Addendums')
ordering = ['-created_at']
def __str__(self):
return f"Addendum to {self.note.title} - {self.created_at.strftime('%Y-%m-%d %H:%M')}"
class NoteAuditLog(models.Model):
"""
Audit trail for clinical note changes.
"""
ACTION_CHOICES = [
('created', _('Created')),
('updated', _('Updated')),
('finalized', _('Finalized')),
('amended', _('Amended')),
('deleted', _('Deleted')),
('viewed', _('Viewed')),
]
note = models.ForeignKey(ClinicalNote, on_delete=models.CASCADE, related_name='audit_logs')
action = models.CharField(_('Action'), max_length=20, choices=ACTION_CHOICES)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
timestamp = models.DateTimeField(_('Timestamp'), auto_now_add=True)
ip_address = models.GenericIPAddressField(_('IP Address'), null=True, blank=True)
changes = models.JSONField(_('Changes'), null=True, blank=True)
class Meta:
verbose_name = _('Note Audit Log')
verbose_name_plural = _('Note Audit Logs')
ordering = ['-timestamp']
def __str__(self):
return f"{self.get_action_display()} - {self.note.title} by {self.user} at {self.timestamp}"