1414 lines
54 KiB
Python
1414 lines
54 KiB
Python
# Generated by Django 5.2.6 on 2025-09-19 10:58
|
|
|
|
import django.core.validators
|
|
import django.db.models.deletion
|
|
import django.utils.timezone
|
|
import uuid
|
|
from django.conf import settings
|
|
from django.db import migrations, models
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
initial = True
|
|
|
|
dependencies = [
|
|
("core", "0001_initial"),
|
|
("patients", "0001_initial"),
|
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name="Encounter",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"encounter_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique encounter identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"encounter_type",
|
|
models.CharField(
|
|
choices=[
|
|
("INPATIENT", "Inpatient"),
|
|
("OUTPATIENT", "Outpatient"),
|
|
("EMERGENCY", "Emergency"),
|
|
("URGENT_CARE", "Urgent Care"),
|
|
("OBSERVATION", "Observation"),
|
|
("TELEMEDICINE", "Telemedicine"),
|
|
("HOME_VISIT", "Home Visit"),
|
|
("CONSULTATION", "Consultation"),
|
|
("FOLLOW_UP", "Follow-up"),
|
|
("PROCEDURE", "Procedure"),
|
|
("SURGERY", "Surgery"),
|
|
("DIAGNOSTIC", "Diagnostic"),
|
|
("PREVENTIVE", "Preventive Care"),
|
|
],
|
|
help_text="Type of encounter",
|
|
max_length=30,
|
|
),
|
|
),
|
|
(
|
|
"encounter_class",
|
|
models.CharField(
|
|
choices=[
|
|
("AMB", "Ambulatory"),
|
|
("EMER", "Emergency"),
|
|
("FLD", "Field"),
|
|
("HH", "Home Health"),
|
|
("IMP", "Inpatient"),
|
|
("ACUTE", "Inpatient Acute"),
|
|
("NONAC", "Inpatient Non-Acute"),
|
|
("OBSENC", "Observation Encounter"),
|
|
("PRENC", "Pre-Admission"),
|
|
("SS", "Short Stay"),
|
|
("VR", "Virtual"),
|
|
],
|
|
help_text="Encounter class (HL7 standard)",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"start_datetime",
|
|
models.DateTimeField(help_text="Encounter start date and time"),
|
|
),
|
|
(
|
|
"end_datetime",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Encounter end date and time", null=True
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("PLANNED", "Planned"),
|
|
("ARRIVED", "Arrived"),
|
|
("TRIAGED", "Triaged"),
|
|
("IN_PROGRESS", "In Progress"),
|
|
("ON_HOLD", "On Hold"),
|
|
("FINISHED", "Finished"),
|
|
("CANCELLED", "Cancelled"),
|
|
("ENTERED_IN_ERROR", "Entered in Error"),
|
|
("UNKNOWN", "Unknown"),
|
|
],
|
|
default="PLANNED",
|
|
help_text="Current encounter status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"location",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Encounter location",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"room_number",
|
|
models.CharField(
|
|
blank=True, help_text="Room number", max_length=20, null=True
|
|
),
|
|
),
|
|
(
|
|
"chief_complaint",
|
|
models.TextField(
|
|
blank=True, help_text="Chief complaint", null=True
|
|
),
|
|
),
|
|
(
|
|
"reason_for_visit",
|
|
models.TextField(
|
|
blank=True, help_text="Reason for visit", null=True
|
|
),
|
|
),
|
|
(
|
|
"priority",
|
|
models.CharField(
|
|
choices=[
|
|
("ROUTINE", "Routine"),
|
|
("URGENT", "Urgent"),
|
|
("STAT", "STAT"),
|
|
("EMERGENCY", "Emergency"),
|
|
],
|
|
default="ROUTINE",
|
|
help_text="Encounter priority",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"acuity_level",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Patient acuity level (1-5, 5 being highest)",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(1),
|
|
django.core.validators.MaxValueValidator(5),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"documentation_complete",
|
|
models.BooleanField(
|
|
default=False, help_text="Documentation is complete"
|
|
),
|
|
),
|
|
(
|
|
"signed_off",
|
|
models.BooleanField(
|
|
default=False, help_text="Encounter has been signed off"
|
|
),
|
|
),
|
|
(
|
|
"signed_datetime",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Date and time of sign-off", null=True
|
|
),
|
|
),
|
|
(
|
|
"billable",
|
|
models.BooleanField(
|
|
default=True, help_text="Encounter is billable"
|
|
),
|
|
),
|
|
(
|
|
"billing_codes",
|
|
models.JSONField(
|
|
blank=True, default=list, help_text="Associated billing codes"
|
|
),
|
|
),
|
|
(
|
|
"quality_measures",
|
|
models.JSONField(
|
|
blank=True, default=dict, help_text="Quality measure data"
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Encounter",
|
|
"verbose_name_plural": "Encounters",
|
|
"db_table": "emr_encounter",
|
|
"ordering": ["-start_datetime"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="Icd10",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
("code", models.CharField(db_index=True, max_length=10, unique=True)),
|
|
("description", models.TextField(blank=True, null=True)),
|
|
(
|
|
"chapter_name",
|
|
models.CharField(blank=True, max_length=255, null=True),
|
|
),
|
|
(
|
|
"section_name",
|
|
models.CharField(blank=True, max_length=255, null=True),
|
|
),
|
|
("is_header", models.BooleanField(default=False)),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "ICD-10 Code",
|
|
"verbose_name_plural": "ICD-10 Codes",
|
|
"db_table": "emr_icd10",
|
|
"ordering": ["code"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="NoteTemplate",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"template_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique template identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
("name", models.CharField(help_text="Template name", max_length=200)),
|
|
(
|
|
"description",
|
|
models.TextField(
|
|
blank=True, help_text="Template description", null=True
|
|
),
|
|
),
|
|
(
|
|
"note_type",
|
|
models.CharField(
|
|
choices=[
|
|
("PROGRESS", "Progress Note"),
|
|
("ADMISSION", "Admission Note"),
|
|
("DISCHARGE", "Discharge Note"),
|
|
("CONSULTATION", "Consultation Note"),
|
|
("PROCEDURE", "Procedure Note"),
|
|
("OPERATIVE", "Operative Note"),
|
|
("NURSING", "Nursing Note"),
|
|
("THERAPY", "Therapy Note"),
|
|
("SOCIAL_WORK", "Social Work Note"),
|
|
("PSYCHOLOGY", "Psychology Note"),
|
|
("NUTRITION", "Nutrition Note"),
|
|
("PHARMACY", "Pharmacy Note"),
|
|
("CASE_MANAGEMENT", "Case Management Note"),
|
|
("EDUCATION", "Patient Education Note"),
|
|
("TELEPHONE", "Telephone Note"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Type of note this template is for",
|
|
max_length=30,
|
|
),
|
|
),
|
|
(
|
|
"specialty",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("GENERAL_MEDICINE", "General Medicine"),
|
|
("SURGERY", "Surgery"),
|
|
("CARDIOLOGY", "Cardiology"),
|
|
("NEUROLOGY", "Neurology"),
|
|
("ONCOLOGY", "Oncology"),
|
|
("PEDIATRICS", "Pediatrics"),
|
|
("OBSTETRICS", "Obstetrics"),
|
|
("GYNECOLOGY", "Gynecology"),
|
|
("ORTHOPEDICS", "Orthopedics"),
|
|
("PSYCHIATRY", "Psychiatry"),
|
|
("EMERGENCY", "Emergency Medicine"),
|
|
("CRITICAL_CARE", "Critical Care"),
|
|
("REHABILITATION", "Rehabilitation"),
|
|
("NURSING", "Nursing"),
|
|
("THERAPY", "Therapy"),
|
|
("SOCIAL_WORK", "Social Work"),
|
|
("NUTRITION", "Nutrition"),
|
|
("PHARMACY", "Pharmacy"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Medical specialty",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"template_content",
|
|
models.TextField(help_text="Template content with placeholders"),
|
|
),
|
|
(
|
|
"structured_fields",
|
|
models.JSONField(
|
|
default=list, help_text="Structured fields definition"
|
|
),
|
|
),
|
|
(
|
|
"is_active",
|
|
models.BooleanField(
|
|
default=True,
|
|
help_text="Template is active and available for use",
|
|
),
|
|
),
|
|
(
|
|
"is_default",
|
|
models.BooleanField(
|
|
default=False, help_text="Default template for this note type"
|
|
),
|
|
),
|
|
(
|
|
"usage_count",
|
|
models.PositiveIntegerField(
|
|
default=0, help_text="Number of times template has been used"
|
|
),
|
|
),
|
|
(
|
|
"version",
|
|
models.CharField(
|
|
default="1.0", help_text="Template version", max_length=20
|
|
),
|
|
),
|
|
(
|
|
"quality_indicators",
|
|
models.JSONField(
|
|
default=list, help_text="Quality indicators to track"
|
|
),
|
|
),
|
|
(
|
|
"compliance_requirements",
|
|
models.JSONField(default=list, help_text="Compliance requirements"),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Note Template",
|
|
"verbose_name_plural": "Note Templates",
|
|
"db_table": "emr_note_template",
|
|
"ordering": ["note_type", "name"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="ProblemList",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"problem_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique problem identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"problem_name",
|
|
models.CharField(
|
|
help_text="Problem name or description", max_length=200
|
|
),
|
|
),
|
|
(
|
|
"problem_code",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="ICD-10 or SNOMED code",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"coding_system",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("ICD10", "ICD-10"),
|
|
("ICD9", "ICD-9"),
|
|
("SNOMED", "SNOMED CT"),
|
|
("CPT", "CPT"),
|
|
("LOINC", "LOINC"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Coding system used",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"problem_type",
|
|
models.CharField(
|
|
choices=[
|
|
("DIAGNOSIS", "Diagnosis"),
|
|
("SYMPTOM", "Symptom"),
|
|
("FINDING", "Finding"),
|
|
("COMPLAINT", "Complaint"),
|
|
("CONDITION", "Condition"),
|
|
("DISORDER", "Disorder"),
|
|
("SYNDROME", "Syndrome"),
|
|
("INJURY", "Injury"),
|
|
("ALLERGY", "Allergy"),
|
|
("INTOLERANCE", "Intolerance"),
|
|
("RISK_FACTOR", "Risk Factor"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Type of problem",
|
|
max_length=30,
|
|
),
|
|
),
|
|
(
|
|
"onset_date",
|
|
models.DateField(blank=True, help_text="Date of onset", null=True),
|
|
),
|
|
(
|
|
"onset_description",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Description of onset",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"severity",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("MILD", "Mild"),
|
|
("MODERATE", "Moderate"),
|
|
("SEVERE", "Severe"),
|
|
("CRITICAL", "Critical"),
|
|
("UNKNOWN", "Unknown"),
|
|
],
|
|
help_text="Problem severity",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"priority",
|
|
models.CharField(
|
|
choices=[
|
|
("LOW", "Low"),
|
|
("MEDIUM", "Medium"),
|
|
("HIGH", "High"),
|
|
("URGENT", "Urgent"),
|
|
],
|
|
default="MEDIUM",
|
|
help_text="Problem priority",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("ACTIVE", "Active"),
|
|
("INACTIVE", "Inactive"),
|
|
("RESOLVED", "Resolved"),
|
|
("REMISSION", "In Remission"),
|
|
("RECURRENCE", "Recurrence"),
|
|
("RELAPSE", "Relapse"),
|
|
("UNKNOWN", "Unknown"),
|
|
("OTHER", "Other"),
|
|
],
|
|
default="ACTIVE",
|
|
help_text="Current problem status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"resolution_date",
|
|
models.DateField(
|
|
blank=True, help_text="Date problem was resolved", null=True
|
|
),
|
|
),
|
|
(
|
|
"resolution_notes",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Notes about problem resolution",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"body_site",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Body site affected",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"laterality",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("LEFT", "Left"),
|
|
("RIGHT", "Right"),
|
|
("BILATERAL", "Bilateral"),
|
|
("UNILATERAL", "Unilateral"),
|
|
("NOT_APPLICABLE", "Not Applicable"),
|
|
],
|
|
help_text="Laterality",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"clinical_notes",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Clinical notes about the problem",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"patient_concerns",
|
|
models.TextField(
|
|
blank=True, help_text="Patient concerns and comments", null=True
|
|
),
|
|
),
|
|
(
|
|
"treatment_goals",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Treatment goals for this problem",
|
|
),
|
|
),
|
|
(
|
|
"outcome_measures",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Outcome measures being tracked",
|
|
),
|
|
),
|
|
(
|
|
"verified",
|
|
models.BooleanField(
|
|
default=False, help_text="Problem has been verified"
|
|
),
|
|
),
|
|
(
|
|
"verified_date",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Date problem was verified", null=True
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Problem",
|
|
"verbose_name_plural": "Problem List",
|
|
"db_table": "emr_problem_list",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="VitalSigns",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"measurement_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique measurement identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"measured_datetime",
|
|
models.DateTimeField(
|
|
default=django.utils.timezone.now,
|
|
help_text="Date and time of measurement",
|
|
),
|
|
),
|
|
(
|
|
"temperature",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=1,
|
|
help_text="Temperature in Celsius",
|
|
max_digits=4,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"temperature_method",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("ORAL", "Oral"),
|
|
("RECTAL", "Rectal"),
|
|
("AXILLARY", "Axillary"),
|
|
("TYMPANIC", "Tympanic"),
|
|
("TEMPORAL", "Temporal"),
|
|
("CORE", "Core"),
|
|
],
|
|
help_text="Temperature measurement method",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"systolic_bp",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Systolic blood pressure (mmHg)",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(50),
|
|
django.core.validators.MaxValueValidator(300),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"diastolic_bp",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Diastolic blood pressure (mmHg)",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(30),
|
|
django.core.validators.MaxValueValidator(200),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"bp_position",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("SITTING", "Sitting"),
|
|
("STANDING", "Standing"),
|
|
("LYING", "Lying"),
|
|
("SUPINE", "Supine"),
|
|
],
|
|
help_text="Patient position during BP measurement",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"bp_cuff_size",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("SMALL", "Small"),
|
|
("REGULAR", "Regular"),
|
|
("LARGE", "Large"),
|
|
("EXTRA_LARGE", "Extra Large"),
|
|
("PEDIATRIC", "Pediatric"),
|
|
],
|
|
help_text="Blood pressure cuff size",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"heart_rate",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Heart rate (beats per minute)",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(20),
|
|
django.core.validators.MaxValueValidator(300),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"heart_rhythm",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("REGULAR", "Regular"),
|
|
("REGULARLY_IRREGULAR", "Regularly irregular"),
|
|
("IRREGULARLY_IRREGULAR", "Irregularly irregular"),
|
|
("IRREGULAR_UNSPECIFIED", "Irregular (unspecified)"),
|
|
],
|
|
help_text="Heart rhythm",
|
|
max_length=25,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"respiratory_rate",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Respiratory rate (breaths per minute)",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(5),
|
|
django.core.validators.MaxValueValidator(60),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"oxygen_saturation",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Oxygen saturation (%)",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(50),
|
|
django.core.validators.MaxValueValidator(100),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"oxygen_delivery",
|
|
models.CharField(
|
|
choices=[
|
|
("ROOM_AIR", "Room Air"),
|
|
("NASAL_CANNULA", "Nasal Cannula"),
|
|
("SIMPLE_MASK", "Simple Mask"),
|
|
("NON_REBREATHER", "Non-Rebreather Mask"),
|
|
("VENTURI_MASK", "Venturi Mask"),
|
|
("CPAP", "CPAP"),
|
|
("BIPAP", "BiPAP"),
|
|
("MECHANICAL_VENTILATION", "Mechanical Ventilation"),
|
|
("OTHER", "Other"),
|
|
],
|
|
default="ROOM_AIR",
|
|
help_text="Oxygen delivery method",
|
|
max_length=30,
|
|
),
|
|
),
|
|
(
|
|
"oxygen_flow_rate",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=1,
|
|
help_text="Oxygen flow rate (L/min)",
|
|
max_digits=4,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"pain_scale",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Pain scale (0-10)",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(0),
|
|
django.core.validators.MaxValueValidator(10),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"pain_location",
|
|
models.CharField(
|
|
blank=True, help_text="Pain location", max_length=100, null=True
|
|
),
|
|
),
|
|
(
|
|
"pain_quality",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Pain quality description",
|
|
max_length=50,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"weight",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=1,
|
|
help_text="Weight in pounds",
|
|
max_digits=5,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"height",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=1,
|
|
help_text="Height in inches",
|
|
max_digits=5,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"bmi",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=1,
|
|
help_text="Body Mass Index",
|
|
max_digits=4,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"head_circumference",
|
|
models.DecimalField(
|
|
blank=True,
|
|
decimal_places=1,
|
|
help_text="Head circumference in cm (pediatric)",
|
|
max_digits=4,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"device_used",
|
|
models.CharField(
|
|
blank=True,
|
|
help_text="Device used for measurements",
|
|
max_length=100,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"device_calibrated",
|
|
models.BooleanField(
|
|
default=True, help_text="Device was calibrated"
|
|
),
|
|
),
|
|
(
|
|
"critical_values",
|
|
models.JSONField(
|
|
blank=True, default=list, help_text="Critical values identified"
|
|
),
|
|
),
|
|
(
|
|
"alerts_generated",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Alerts generated from measurements",
|
|
),
|
|
),
|
|
(
|
|
"notes",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Additional notes about measurements",
|
|
null=True,
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
],
|
|
options={
|
|
"verbose_name": "Vital Signs",
|
|
"verbose_name_plural": "Vital Signs",
|
|
"db_table": "emr_vital_signs",
|
|
"ordering": ["-measured_datetime"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="CarePlan",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"care_plan_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique care plan identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"title",
|
|
models.CharField(help_text="Care plan title", max_length=200),
|
|
),
|
|
("description", models.TextField(help_text="Care plan description")),
|
|
(
|
|
"plan_type",
|
|
models.CharField(
|
|
choices=[
|
|
("COMPREHENSIVE", "Comprehensive Care Plan"),
|
|
("DISEASE_SPECIFIC", "Disease-Specific Plan"),
|
|
("PREVENTIVE", "Preventive Care Plan"),
|
|
("CHRONIC_CARE", "Chronic Care Management"),
|
|
("ACUTE_CARE", "Acute Care Plan"),
|
|
("DISCHARGE", "Discharge Planning"),
|
|
("REHABILITATION", "Rehabilitation Plan"),
|
|
("PALLIATIVE", "Palliative Care Plan"),
|
|
("MENTAL_HEALTH", "Mental Health Plan"),
|
|
("MEDICATION", "Medication Management"),
|
|
("NUTRITION", "Nutrition Plan"),
|
|
("EXERCISE", "Exercise Plan"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Type of care plan",
|
|
max_length=30,
|
|
),
|
|
),
|
|
(
|
|
"category",
|
|
models.CharField(
|
|
choices=[
|
|
("ASSESSMENT", "Assessment and Monitoring"),
|
|
("TREATMENT", "Treatment"),
|
|
("EDUCATION", "Patient Education"),
|
|
("COORDINATION", "Care Coordination"),
|
|
("PREVENTION", "Prevention"),
|
|
("LIFESTYLE", "Lifestyle Modification"),
|
|
("MEDICATION", "Medication Management"),
|
|
("FOLLOW_UP", "Follow-up Care"),
|
|
("EMERGENCY", "Emergency Planning"),
|
|
("SUPPORT", "Support Services"),
|
|
],
|
|
help_text="Care plan category",
|
|
max_length=50,
|
|
),
|
|
),
|
|
("start_date", models.DateField(help_text="Care plan start date")),
|
|
(
|
|
"end_date",
|
|
models.DateField(
|
|
blank=True, help_text="Care plan end date", null=True
|
|
),
|
|
),
|
|
(
|
|
"target_completion_date",
|
|
models.DateField(
|
|
blank=True, help_text="Target completion date", null=True
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("DRAFT", "Draft"),
|
|
("ACTIVE", "Active"),
|
|
("ON_HOLD", "On Hold"),
|
|
("COMPLETED", "Completed"),
|
|
("CANCELLED", "Cancelled"),
|
|
("ENTERED_IN_ERROR", "Entered in Error"),
|
|
("UNKNOWN", "Unknown"),
|
|
],
|
|
default="DRAFT",
|
|
help_text="Care plan status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"priority",
|
|
models.CharField(
|
|
choices=[
|
|
("LOW", "Low"),
|
|
("ROUTINE", "Routine"),
|
|
("URGENT", "Urgent"),
|
|
("STAT", "STAT"),
|
|
],
|
|
default="ROUTINE",
|
|
help_text="Care plan priority",
|
|
max_length=20,
|
|
),
|
|
),
|
|
("goals", models.JSONField(default=list, help_text="Care plan goals")),
|
|
(
|
|
"objectives",
|
|
models.JSONField(
|
|
default=list, help_text="Specific objectives and targets"
|
|
),
|
|
),
|
|
(
|
|
"interventions",
|
|
models.JSONField(default=list, help_text="Planned interventions"),
|
|
),
|
|
(
|
|
"activities",
|
|
models.JSONField(
|
|
default=list, help_text="Specific activities and tasks"
|
|
),
|
|
),
|
|
(
|
|
"monitoring_parameters",
|
|
models.JSONField(default=list, help_text="Parameters to monitor"),
|
|
),
|
|
(
|
|
"evaluation_criteria",
|
|
models.JSONField(
|
|
default=list, help_text="Criteria for evaluating progress"
|
|
),
|
|
),
|
|
(
|
|
"patient_goals",
|
|
models.TextField(
|
|
blank=True, help_text="Patient-identified goals", null=True
|
|
),
|
|
),
|
|
(
|
|
"patient_preferences",
|
|
models.TextField(
|
|
blank=True,
|
|
help_text="Patient preferences and concerns",
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"patient_barriers",
|
|
models.TextField(
|
|
blank=True, help_text="Identified barriers to care", null=True
|
|
),
|
|
),
|
|
(
|
|
"resources_needed",
|
|
models.JSONField(
|
|
default=list,
|
|
help_text="Resources needed for plan implementation",
|
|
),
|
|
),
|
|
(
|
|
"support_systems",
|
|
models.JSONField(
|
|
default=list, help_text="Available support systems"
|
|
),
|
|
),
|
|
(
|
|
"progress_notes",
|
|
models.TextField(blank=True, help_text="Progress notes", null=True),
|
|
),
|
|
(
|
|
"last_reviewed",
|
|
models.DateField(
|
|
blank=True, help_text="Date of last review", null=True
|
|
),
|
|
),
|
|
(
|
|
"next_review_date",
|
|
models.DateField(
|
|
blank=True, help_text="Next scheduled review date", null=True
|
|
),
|
|
),
|
|
(
|
|
"outcomes_achieved",
|
|
models.JSONField(default=list, help_text="Outcomes achieved"),
|
|
),
|
|
(
|
|
"completion_percentage",
|
|
models.PositiveIntegerField(
|
|
default=0,
|
|
help_text="Completion percentage",
|
|
validators=[
|
|
django.core.validators.MinValueValidator(0),
|
|
django.core.validators.MaxValueValidator(100),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"approved",
|
|
models.BooleanField(
|
|
default=False, help_text="Care plan has been approved"
|
|
),
|
|
),
|
|
(
|
|
"approved_date",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Date of approval", null=True
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"approved_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="Provider who approved the plan",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="approved_care_plans",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"care_team",
|
|
models.ManyToManyField(
|
|
blank=True,
|
|
help_text="Care team members",
|
|
related_name="care_team_plans",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"created_by",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="User who created the care plan",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="created_care_plans",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"patient",
|
|
models.ForeignKey(
|
|
help_text="Patient",
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="care_plans",
|
|
to="patients.patientprofile",
|
|
),
|
|
),
|
|
(
|
|
"primary_provider",
|
|
models.ForeignKey(
|
|
help_text="Primary provider responsible for care plan",
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="primary_care_plans",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"tenant",
|
|
models.ForeignKey(
|
|
help_text="Organization tenant",
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="care_plans",
|
|
to="core.tenant",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Care Plan",
|
|
"verbose_name_plural": "Care Plans",
|
|
"db_table": "emr_care_plan",
|
|
"ordering": ["-created_at"],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name="ClinicalNote",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"note_id",
|
|
models.UUIDField(
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
help_text="Unique note identifier",
|
|
unique=True,
|
|
),
|
|
),
|
|
(
|
|
"note_type",
|
|
models.CharField(
|
|
choices=[
|
|
("PROGRESS", "Progress"),
|
|
("ADMISSION", "Admission Note"),
|
|
("DISCHARGE", "Discharge Note"),
|
|
("CONSULTATION", "Consultation Note"),
|
|
("PROCEDURE", "Procedure Note"),
|
|
("OPERATIVE", "Operative Note"),
|
|
("NURSING", "Nursing Note"),
|
|
("THERAPY", "Therapy Note"),
|
|
("SOCIAL_WORK", "Social Work Note"),
|
|
("PSYCHOLOGY", "Psychology Note"),
|
|
("NUTRITION", "Nutrition Note"),
|
|
("PHARMACY", "Pharmacy Note"),
|
|
("CASE_MANAGEMENT", "Case Management Note"),
|
|
("EDUCATION", "Patient Education Note"),
|
|
("TELEPHONE", "Telephone Note"),
|
|
("ADDENDUM", "Addendum"),
|
|
("CORRECTION", "Correction"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Type of clinical note",
|
|
max_length=30,
|
|
),
|
|
),
|
|
("title", models.CharField(help_text="Note title", max_length=200)),
|
|
("content", models.TextField(help_text="Note content")),
|
|
(
|
|
"structured_data",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=dict,
|
|
help_text="Structured data from template",
|
|
),
|
|
),
|
|
(
|
|
"status",
|
|
models.CharField(
|
|
choices=[
|
|
("DRAFT", "Draft"),
|
|
("IN_PROGRESS", "In Progress"),
|
|
("COMPLETED", "Completed"),
|
|
("SIGNED", "Signed"),
|
|
("AMENDED", "Amended"),
|
|
("CORRECTED", "Corrected"),
|
|
("CANCELLED", "Cancelled"),
|
|
("ERROR", "Entered in Error"),
|
|
("UNKNOWN", "Unknown"),
|
|
],
|
|
default="DRAFT",
|
|
help_text="Note status",
|
|
max_length=20,
|
|
),
|
|
),
|
|
(
|
|
"electronically_signed",
|
|
models.BooleanField(
|
|
default=False, help_text="Note has been electronically signed"
|
|
),
|
|
),
|
|
(
|
|
"signed_datetime",
|
|
models.DateTimeField(
|
|
blank=True, help_text="Date and time of signature", null=True
|
|
),
|
|
),
|
|
(
|
|
"signature_method",
|
|
models.CharField(
|
|
blank=True,
|
|
choices=[
|
|
("ELECTRONIC", "Electronic"),
|
|
("DIGITAL", "Digital Signature"),
|
|
("BIOMETRIC", "Biometric Signature"),
|
|
("PASSWORD", "Password"),
|
|
("TOKEN", "Token Authentication"),
|
|
("OTHER", "Other"),
|
|
],
|
|
help_text="Method of signature",
|
|
max_length=20,
|
|
null=True,
|
|
),
|
|
),
|
|
(
|
|
"amendment_reason",
|
|
models.TextField(
|
|
blank=True, help_text="Reason for amendment", null=True
|
|
),
|
|
),
|
|
(
|
|
"quality_score",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
help_text="Documentation quality score",
|
|
null=True,
|
|
validators=[
|
|
django.core.validators.MinValueValidator(0),
|
|
django.core.validators.MaxValueValidator(100),
|
|
],
|
|
),
|
|
),
|
|
(
|
|
"compliance_flags",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Compliance flags and issues",
|
|
),
|
|
),
|
|
(
|
|
"note_datetime",
|
|
models.DateTimeField(
|
|
default=django.utils.timezone.now,
|
|
help_text="Date and time note was written",
|
|
),
|
|
),
|
|
(
|
|
"confidential",
|
|
models.BooleanField(
|
|
default=False,
|
|
help_text="Note contains confidential information",
|
|
),
|
|
),
|
|
(
|
|
"restricted_access",
|
|
models.BooleanField(
|
|
default=False, help_text="Access to note is restricted"
|
|
),
|
|
),
|
|
(
|
|
"access_restrictions",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=list,
|
|
help_text="Specific access restrictions",
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"amended_note",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
help_text="Original note if this is an amendment",
|
|
null=True,
|
|
on_delete=django.db.models.deletion.SET_NULL,
|
|
related_name="amendments",
|
|
to="emr.clinicalnote",
|
|
),
|
|
),
|
|
(
|
|
"author",
|
|
models.ForeignKey(
|
|
help_text="Note author",
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="authored_notes",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"co_signers",
|
|
models.ManyToManyField(
|
|
blank=True,
|
|
help_text="Co-signers for this note",
|
|
related_name="co_signed_notes",
|
|
to=settings.AUTH_USER_MODEL,
|
|
),
|
|
),
|
|
(
|
|
"patient",
|
|
models.ForeignKey(
|
|
help_text="Patient",
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="clinical_notes",
|
|
to="patients.patientprofile",
|
|
),
|
|
),
|
|
(
|
|
"related_care_plans",
|
|
models.ManyToManyField(
|
|
blank=True,
|
|
help_text="Related care plans",
|
|
related_name="clinical_notes",
|
|
to="emr.careplan",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Clinical Note",
|
|
"verbose_name_plural": "Clinical Notes",
|
|
"db_table": "emr_clinical_note",
|
|
"ordering": ["-note_datetime"],
|
|
},
|
|
),
|
|
]
|