hospital-management/emr_data.py
Marwan Alwali ab2c4a36c5 update
2025-10-02 10:13:03 +03:00

2059 lines
84 KiB
Python

import os
import django
# Set up Django environment
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hospital_management.settings')
django.setup()
import random
from datetime import datetime, date, time, timedelta
from django.utils import timezone as django_timezone
from emr.models import Encounter, VitalSigns, ProblemList, CarePlan, ClinicalNote, NoteTemplate, Icd10, ClinicalRecommendation, AllergyAlert, TreatmentProtocol, ClinicalGuideline, CriticalAlert, DiagnosticSuggestion
from patients.models import PatientProfile
from accounts.models import User
from hr.models import Employee
from appointments.models import AppointmentRequest
from inpatients.models import Admission
from core.models import Tenant
import uuid
from decimal import Decimal
# Saudi-specific clinical data
SAUDI_ENCOUNTER_TYPES = [
'CONSULTATION', 'FOLLOW_UP', 'EMERGENCY', 'PROCEDURE', 'SURGERY',
'DIAGNOSTIC', 'THERAPY', 'SCREENING', 'VACCINATION', 'TELEMEDICINE'
]
SAUDI_ENCOUNTER_CLASSES = [
'OUTPATIENT', 'INPATIENT', 'EMERGENCY', 'OBSERVATION',
'DAY_SURGERY', 'TELEMEDICINE', 'HOME_VISIT'
]
SAUDI_CHIEF_COMPLAINTS = [
'Chest pain and shortness of breath',
'Abdominal pain and nausea',
'Headache and dizziness',
'Back pain and stiffness',
'Fever and cough',
'Joint pain and swelling',
'Fatigue and weakness',
'Skin rash and itching',
'Diabetes follow-up',
'Hypertension monitoring',
'Regular health checkup',
'Vaccination appointment',
'Pre-operative consultation',
'Post-operative follow-up',
'Pregnancy consultation',
'Child wellness visit',
'Mental health consultation',
'Physical therapy session',
'Diagnostic imaging',
'Laboratory test follow-up',
'Cardiac symptoms evaluation',
'Respiratory symptoms',
'Gastrointestinal complaints',
'Neurological symptoms',
'Endocrine disorders follow-up'
]
SAUDI_LOCATIONS = [
'Main Building - Floor 1',
'Main Building - Floor 2',
'Main Building - Floor 3',
'Emergency Wing',
'Outpatient Clinic - Wing A',
'Outpatient Clinic - Wing B',
'Surgical Suite - Floor 4',
'Radiology Department',
'Laboratory Building',
'Pediatric Wing',
'ICU - Floor 5',
'Cardiology Unit',
'Maternity Ward',
'Dialysis Center'
]
SAUDI_PROBLEM_TYPES = [
'DIAGNOSIS', 'SYMPTOM', 'RISK_FACTOR', 'ALLERGY',
'MEDICATION_INTOLERANCE', 'FAMILY_HISTORY', 'SOCIAL_HISTORY'
]
SAUDI_COMMON_PROBLEMS = [
('Diabetes Mellitus Type 2', 'E11.9', 'ICD10'),
('Hypertension', 'I10', 'ICD10'),
('Hyperlipidemia', 'E78.5', 'ICD10'),
('Asthma', 'J45.9', 'ICD10'),
('Chronic Kidney Disease', 'N18.9', 'ICD10'),
('Osteoarthritis', 'M19.9', 'ICD10'),
('Depression', 'F32.9', 'ICD10'),
('Anxiety Disorder', 'F41.9', 'ICD10'),
('Obesity', 'E66.9', 'ICD10'),
('Gastroesophageal Reflux', 'K21.9', 'ICD10'),
('Migraine', 'G43.9', 'ICD10'),
('Allergic Rhinitis', 'J30.9', 'ICD10'),
('Hypothyroidism', 'E03.9', 'ICD10'),
('Coronary Artery Disease', 'I25.9', 'ICD10'),
('Chronic Obstructive Pulmonary Disease', 'J44.9', 'ICD10')
]
SAUDI_CARE_PLAN_TYPES = [
'TREATMENT', 'PREVENTION', 'REHABILITATION', 'CHRONIC_CARE',
'ACUTE_CARE', 'SURGICAL', 'MEDICATION_MANAGEMENT', 'LIFESTYLE'
]
SAUDI_NOTE_TYPES = [
'CONSULTATION', 'PROGRESS', 'DISCHARGE', 'PROCEDURE',
'SURGERY', 'EMERGENCY', 'NURSING', 'THERAPY',
'DIAGNOSTIC', 'MEDICATION_REVIEW', 'FOLLOW_UP'
]
def get_providers_for_emr(tenants):
"""Get healthcare providers for EMR data creation"""
providers = []
for tenant in tenants:
tenant_providers = User.objects.filter(
tenant=tenant,
is_active=True,
employee_profile__role__in=['PHYSICIAN', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT', 'RADIOLOGIST']
)
providers.extend(list(tenant_providers))
# Create mock providers if none exist
if not providers:
providers = create_mock_providers_for_emr(tenants)
return providers
def create_mock_providers_for_emr(tenants):
"""Create mock healthcare providers for EMR data"""
providers = []
mock_providers_data = [
{'first_name': 'Ahmad', 'last_name': 'Al-Rashid', 'role': 'PHYSICIAN'},
{'first_name': 'Fatima', 'last_name': 'Al-Ghamdi', 'role': 'PHYSICIAN'},
{'first_name': 'Mohammed', 'last_name': 'Al-Otaibi', 'role': 'PHYSICIAN'},
{'first_name': 'Sarah', 'last_name': 'Al-Harbi', 'role': 'PHYSICIAN'},
{'first_name': 'Khalid', 'last_name': 'Al-Mutairi', 'role': 'SURGEON'},
{'first_name': 'Nora', 'last_name': 'Al-Zahrani', 'role': 'NURSE_PRACTITIONER'},
{'first_name': 'Omar', 'last_name': 'Al-Dawsari', 'role': 'PHYSICIAN'},
{'first_name': 'Layla', 'last_name': 'Al-Subai', 'role': 'PHYSICIAN'},
]
for tenant in tenants:
for provider_data in mock_providers_data:
try:
email = f"{provider_data['first_name'].lower()}.{provider_data['last_name'].lower().replace('-', '')}@{tenant.domain}"
existing_user = User.objects.filter(email=email).first()
if not existing_user:
user = User.objects.create_user(
email=email,
first_name=provider_data['first_name'],
last_name=provider_data['last_name'],
employee_profile__role=provider_data['role'],
tenant=tenant,
is_active=True,
password='temp_password_123'
)
providers.append(user)
else:
providers.append(existing_user)
except Exception as e:
print(f"Error creating mock provider {provider_data['first_name']} {provider_data['last_name']}: {e}")
continue
return providers
def create_note_templates(tenants):
"""Create note templates for different specialties"""
templates = []
template_configs = [
{
'name': 'General Consultation Note',
'note_type': 'CONSULTATION',
'specialty': 'FAMILY_MEDICINE',
'content': """
CHIEF COMPLAINT: [Chief Complaint]
HISTORY OF PRESENT ILLNESS:
[History details]
PAST MEDICAL HISTORY:
[Past medical history]
MEDICATIONS:
[Current medications]
ALLERGIES:
[Known allergies]
SOCIAL HISTORY:
[Social history]
PHYSICAL EXAMINATION:
General: [General appearance]
Vital Signs: [Vital signs]
HEENT: [Head, eyes, ears, nose, throat]
Cardiovascular: [Heart examination]
Respiratory: [Lung examination]
Abdomen: [Abdominal examination]
Extremities: [Extremity examination]
Neurological: [Neurological examination]
ASSESSMENT:
[Clinical impression]
PLAN:
[Treatment plan]
[Provider Name], [Title]
[Date and Time]
""",
'structured_fields': [
'chief_complaint', 'history_present_illness', 'past_medical_history',
'medications', 'allergies', 'social_history', 'physical_exam',
'assessment', 'plan'
]
},
{
'name': 'Cardiology Consultation',
'note_type': 'CONSULTATION',
'specialty': 'CARDIOLOGY',
'content': """
CHIEF COMPLAINT: [Cardiac symptoms]
HISTORY OF PRESENT ILLNESS:
[Cardiac history details]
CARDIOVASCULAR RISK FACTORS:
[Risk factors assessment]
MEDICATIONS:
[Cardiac medications]
PHYSICAL EXAMINATION:
Blood Pressure: [BP measurements]
Heart Rate: [HR and rhythm]
Cardiovascular: [Detailed cardiac exam]
Peripheral Vascular: [Peripheral circulation]
ECG: [ECG findings]
LABORATORY RESULTS:
[Cardiac markers, lipids, etc.]
IMAGING:
[Echo, stress test, etc.]
ASSESSMENT:
[Cardiac diagnosis]
PLAN:
[Cardiac management plan]
[Cardiologist Name]
[Date and Time]
""",
'structured_fields': [
'chief_complaint', 'cardiac_history', 'risk_factors',
'cardiac_medications', 'cardiac_exam', 'ecg_findings',
'lab_results', 'imaging_results', 'cardiac_assessment', 'cardiac_plan'
]
},
{
'name': 'Emergency Department Note',
'note_type': 'EMERGENCY',
'specialty': 'EMERGENCY',
'content': """
TIME OF ARRIVAL: [Arrival time]
CHIEF COMPLAINT: [Emergency complaint]
TRIAGE LEVEL: [Triage priority]
HISTORY OF PRESENT ILLNESS:
[Emergency presentation details]
PAST MEDICAL HISTORY:
[Relevant medical history]
MEDICATIONS:
[Current medications]
ALLERGIES:
[Known allergies]
PHYSICAL EXAMINATION:
General Appearance: [Patient appearance]
Vital Signs: [Emergency vital signs]
Primary Survey: [ABCDE assessment]
Secondary Survey: [Detailed examination]
EMERGENCY PROCEDURES:
[Procedures performed]
LABORATORY/IMAGING:
[Emergency testing results]
ASSESSMENT:
[Emergency diagnosis]
DISPOSITION:
[Emergency department disposition]
[Emergency Physician Name]
[Date and Time]
""",
'structured_fields': [
'arrival_time', 'chief_complaint', 'triage_level',
'emergency_history', 'emergency_exam', 'procedures_performed',
'emergency_testing', 'emergency_assessment', 'disposition'
]
},
{
'name': 'Surgical Consultation',
'note_type': 'CONSULTATION',
'specialty': 'SURGERY',
'content': """
REASON FOR CONSULTATION: [Surgical consultation reason]
HISTORY OF PRESENT ILLNESS:
[Surgical problem history]
PAST SURGICAL HISTORY:
[Previous surgeries]
MEDICATIONS:
[Current medications]
ALLERGIES:
[Known allergies]
PHYSICAL EXAMINATION:
[Surgical examination findings]
IMAGING STUDIES:
[Relevant imaging]
LABORATORY RESULTS:
[Preoperative labs]
ASSESSMENT:
[Surgical assessment]
RECOMMENDATIONS:
[Surgical recommendations]
SURGICAL PLAN:
[Proposed surgical intervention]
RISKS AND BENEFITS DISCUSSED:
[Risk discussion]
[Surgeon Name]
[Date and Time]
""",
'structured_fields': [
'consultation_reason', 'surgical_history', 'past_surgeries',
'surgical_exam', 'imaging_studies', 'preop_labs',
'surgical_assessment', 'surgical_recommendations', 'surgical_plan'
]
},
{
'name': 'Progress Note',
'note_type': 'PROGRESS',
'specialty': 'INTERNAL_MEDICINE',
'content': """
SUBJECTIVE:
[Patient's reported symptoms and concerns]
OBJECTIVE:
Vital Signs: [Current vital signs]
Physical Examination: [Current physical findings]
Laboratory Results: [Recent lab results]
Imaging Studies: [Recent imaging]
ASSESSMENT:
[Current clinical assessment]
PLAN:
[Updated treatment plan]
[Provider Name]
[Date and Time]
""",
'structured_fields': [
'subjective', 'vital_signs', 'physical_exam',
'lab_results', 'imaging', 'assessment', 'plan'
]
}
]
for tenant in tenants:
for config in template_configs:
try:
template = NoteTemplate.objects.create(
tenant=tenant,
template_id=uuid.uuid4(),
name=config['name'],
description=f"Standard {config['name'].lower()} template",
note_type=config['note_type'],
specialty=config['specialty'],
template_content=config['content'].strip(),
structured_fields=config['structured_fields'],
is_active=True,
is_default=config['name'] == 'General Consultation Note',
usage_count=random.randint(0, 100),
version=1.0,
quality_indicators=[
'completeness', 'accuracy', 'timeliness',
'clarity', 'compliance'
],
compliance_requirements=[
'documentation_complete_within_24h',
'provider_signature_required',
'patient_privacy_maintained'
],
created_at=django_timezone.now() - timedelta(days=random.randint(30, 365)),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30))
)
templates.append(template)
except Exception as e:
print(f"Error creating template {config['name']}: {e}")
continue
print(f"Created {len(templates)} note templates")
return templates
def create_encounters(tenants, days_back=30):
"""Create patient encounters"""
encounters = []
# Get patients and providers
patients = list(PatientProfile.objects.filter(tenant__in=tenants))
if not patients:
print("No patients found. Skipping encounter creation.")
return encounters
providers = get_providers_for_emr(tenants)
if not providers:
print("No providers found. Skipping encounter creation.")
return encounters
# Get existing appointments to link with encounters
appointments = list(AppointmentRequest.objects.filter(
tenant__in=tenants,
status__in=['COMPLETED', 'IN_PROGRESS']
))
# Get existing admissions
admissions = list(Admission.objects.filter(tenant__in=tenants))
start_date = django_timezone.now().date() - timedelta(days=days_back)
# Create encounters for the past days_back days
for day_offset in range(days_back):
encounter_date = start_date + timedelta(days=day_offset)
daily_encounters = random.randint(20, 50) # Variable number of encounters per day
for _ in range(daily_encounters):
patient = random.choice(patients)
provider = random.choice([p for p in providers if p.tenant == patient.tenant])
# Determine encounter type and class
encounter_type = random.choices(
SAUDI_ENCOUNTER_TYPES,
weights=[25, 20, 10, 8, 5, 12, 8, 7, 3, 2]
)[0]
if encounter_type == 'EMERGENCY':
encounter_class = 'EMERGENCY'
elif encounter_type in ['SURGERY', 'PROCEDURE']:
encounter_class = random.choice(['INPATIENT', 'DAY_SURGERY', 'OUTPATIENT'])
elif encounter_type == 'TELEMEDICINE':
encounter_class = 'TELEMEDICINE'
else:
encounter_class = random.choice(['OUTPATIENT', 'INPATIENT'])
# Generate encounter timing
start_hour = random.randint(8, 20)
start_minute = random.choice([0, 15, 30, 45])
start_datetime = django_timezone.make_aware(
datetime.combine(encounter_date, time(start_hour, start_minute))
)
duration_minutes = random.randint(15, 180)
if encounter_type == 'SURGERY':
duration_minutes = random.randint(60, 360)
elif encounter_type == 'EMERGENCY':
duration_minutes = random.randint(30, 240)
end_datetime = start_datetime + timedelta(minutes=duration_minutes)
# Determine status
if encounter_date < django_timezone.now().date():
status = random.choices(
['PLANNED','COMPLETED', 'CANCELLED'],
weights=[30,55, 15]
)[0]
elif encounter_date == django_timezone.now().date():
status = random.choices(
['IN_PROGRESS', 'COMPLETED'],
weights=[30, 70]
)[0]
else:
status = 'SCHEDULED'
# Priority and acuity
if encounter_type == 'EMERGENCY':
priority = random.choices(['EMERGENCY', 'URGENT'], weights=[60, 40])[0]
acuity_level = random.randint(2, 5)
else:
priority = random.choices(['ROUTINE', 'URGENT'], weights=[80, 20])[0]
acuity_level = random.randint(1, 3)
# Link to appointment if available
linked_appointment = None
if appointments:
suitable_appointments = [
apt for apt in appointments
if apt.patient == patient and
apt.scheduled_datetime and
apt.scheduled_datetime.date() == encounter_date
]
if suitable_appointments:
linked_appointment = random.choice(suitable_appointments)
# Link to admission if inpatient
linked_admission = None
if encounter_class == 'INPATIENT' and admissions:
suitable_admissions = [
adm for adm in admissions
if adm.patient == patient and
adm.admission_datetime <= start_datetime
]
if suitable_admissions:
linked_admission = random.choice(suitable_admissions)
# Documentation completion
documentation_complete = status == 'COMPLETED'
signed_off = documentation_complete and random.choice([True, False])
try:
encounter = Encounter.objects.create(
tenant=patient.tenant,
encounter_id=uuid.uuid4(),
patient=patient,
provider=provider,
encounter_type=encounter_type,
encounter_class=encounter_class,
start_datetime=start_datetime,
end_datetime=end_datetime if status in ['COMPLETED', 'CANCELLED'] else None,
status=status,
location=random.choice(SAUDI_LOCATIONS),
room_number=f"Room {random.randint(101, 450)}",
appointment=linked_appointment,
admission=linked_admission,
chief_complaint=random.choice(SAUDI_CHIEF_COMPLAINTS),
reason_for_visit=random.choice(SAUDI_CHIEF_COMPLAINTS),
priority=priority,
acuity_level=acuity_level,
documentation_complete=documentation_complete,
signed_off=signed_off,
signed_by=provider if signed_off else None,
signed_datetime=end_datetime if signed_off else None,
billable=random.choice([True, False]),
billing_codes=[
f"{random.randint(99200, 99499)}",
f"{random.randint(99200, 99499)}"
] if random.choice([True, False]) else [],
quality_measures={
'documentation_score': random.randint(70, 100),
'timeliness_score': random.randint(80, 100),
'completeness_score': random.randint(75, 100)
},
created_at=start_datetime - timedelta(minutes=random.randint(5, 60)),
updated_at=django_timezone.now() - timedelta(minutes=random.randint(0, 30)),
created_by=provider
)
encounters.append(encounter)
except Exception as e:
print(f"Error creating encounter for {patient.get_full_name()}: {e}")
continue
print(f"Created {len(encounters)} encounters")
return encounters
def create_vital_signs(encounters):
"""Create vital signs for encounters"""
vital_signs = []
providers = User.objects.filter(
employee_profile__role__in=['NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN', 'MEDICAL_ASSISTANT'],
is_active=True
)
if not providers:
# Use encounter providers as fallback
providers = list(set([enc.provider for enc in encounters]))
for encounter in encounters:
# Create 1-3 vital signs measurements per encounter
num_measurements = random.randint(1, 3)
for measurement_num in range(num_measurements):
# Time offset for multiple measurements
time_offset = measurement_num * random.randint(30, 120) # 30-120 minutes apart
measured_datetime = encounter.start_datetime + timedelta(minutes=time_offset)
# Generate realistic vital signs based on patient age
patient_age = (django_timezone.now().date() - encounter.patient.date_of_birth).days // 365
# Temperature (Celsius)
temperature = round(random.uniform(36.0, 39.5), 1)
if temperature > 38.5:
temperature_method = random.choice(['ORAL', 'RECTAL', 'TYMPANIC'])
else:
temperature_method = random.choice(['ORAL', 'AXILLARY', 'TYMPANIC'])
# Blood pressure
if patient_age < 18:
systolic_bp = random.randint(90, 120)
diastolic_bp = random.randint(50, 80)
elif patient_age < 65:
systolic_bp = random.randint(100, 140)
diastolic_bp = random.randint(60, 90)
else:
systolic_bp = random.randint(110, 160)
diastolic_bp = random.randint(70, 100)
bp_position = random.choice(['SITTING', 'LYING', 'STANDING'])
bp_cuff_size = 'ADULT' if patient_age >= 18 else random.choice(['PEDIATRIC', 'INFANT'])
# Heart rate
if patient_age < 1:
heart_rate = random.randint(100, 160)
elif patient_age < 12:
heart_rate = random.randint(80, 120)
else:
heart_rate = random.randint(60, 100)
heart_rhythm = random.choices(
['REGULAR', 'IRREGULAR', 'BRADYCARDIA', 'TACHYCARDIA'],
weights=[85, 10, 3, 2]
)[0]
# Respiratory rate
if patient_age < 1:
respiratory_rate = random.randint(30, 60)
elif patient_age < 12:
respiratory_rate = random.randint(18, 30)
else:
respiratory_rate = random.randint(12, 20)
# Oxygen saturation
oxygen_saturation = random.randint(95, 100)
oxygen_delivery = 'ROOM_AIR'
oxygen_flow_rate = None
if oxygen_saturation < 95:
oxygen_delivery = random.choice(['NASAL_CANNULA', 'MASK', 'NON_REBREATHER'])
oxygen_flow_rate = random.randint(2, 15)
# Pain scale
pain_scale = random.randint(0, 10)
pain_location = None
pain_quality = None
if pain_scale > 0:
pain_location = random.choice([
'Head', 'Chest', 'Abdomen', 'Back', 'Extremities',
'Generalized', 'Neck', 'Pelvis'
])
pain_quality = random.choice([
'Sharp', 'Dull', 'Burning', 'Cramping',
'Stabbing', 'Throbbing', 'Aching'
])
# Weight and height
if patient_age < 18:
weight = round(random.uniform(3.0, 70.0), 1)
height = round(random.uniform(50.0, 180.0), 1)
else:
weight = round(random.uniform(45.0, 150.0), 1)
height = round(random.uniform(150.0, 200.0), 1)
# Head circumference for pediatric patients
head_circumference = None
if patient_age < 2:
head_circumference = round(random.uniform(30.0, 50.0), 1)
# Critical values detection
critical_values = []
if temperature > 39.0 or temperature < 35.0:
critical_values.append('temperature')
if systolic_bp > 180 or systolic_bp < 90:
critical_values.append('systolic_bp')
if heart_rate > 120 or heart_rate < 50:
critical_values.append('heart_rate')
if oxygen_saturation < 90:
critical_values.append('oxygen_saturation')
alerts_generated = len(critical_values) > 0
try:
vital_sign = VitalSigns.objects.create(
encounter=encounter,
patient=encounter.patient,
measurement_id=uuid.uuid4(),
measured_datetime=measured_datetime,
temperature=Decimal(str(temperature)),
temperature_method=temperature_method,
systolic_bp=systolic_bp,
diastolic_bp=diastolic_bp,
bp_position=bp_position,
bp_cuff_size=bp_cuff_size,
heart_rate=heart_rate,
heart_rhythm=heart_rhythm,
respiratory_rate=respiratory_rate,
oxygen_saturation=oxygen_saturation,
oxygen_delivery=oxygen_delivery,
oxygen_flow_rate=oxygen_flow_rate,
pain_scale=pain_scale,
pain_location=pain_location,
pain_quality=pain_quality,
weight=Decimal(str(weight)),
height=Decimal(str(height)),
head_circumference=Decimal(str(head_circumference)) if head_circumference else None,
device_used=random.choice(['MANUAL', 'AUTOMATED', 'MONITOR']),
device_calibrated=random.choice([True, False]),
measured_by=random.choice(providers),
verified_by=random.choice(providers) if random.choice([True, False]) else None,
critical_values=critical_values,
alerts_generated=alerts_generated,
notes=f"Routine vital signs measurement #{measurement_num + 1}" if measurement_num > 0 else None,
created_at=measured_datetime,
updated_at=measured_datetime + timedelta(minutes=random.randint(1, 10))
)
vital_signs.append(vital_sign)
except Exception as e:
print(f"Error creating vital signs for encounter {encounter.encounter_id}: {e}")
continue
print(f"Created {len(vital_signs)} vital signs records")
return vital_signs
def create_problem_lists(patients, providers):
"""Create problem lists for patients"""
problems = []
for patient in patients:
# Each patient has 1-5 problems
num_problems = random.randint(1, 5)
for _ in range(num_problems):
problem_data = random.choice(SAUDI_COMMON_PROBLEMS)
problem_name, problem_code, coding_system = problem_data
problem_type = random.choices(
SAUDI_PROBLEM_TYPES,
weights=[60, 20, 10, 5, 2, 2, 1]
)[0]
# Onset date (random date in the past)
onset_date = django_timezone.now().date() - timedelta(
days=random.randint(30, 3650) # 1 month to 10 years ago
)
# Severity
severity = random.choices(
['MILD', 'MODERATE', 'SEVERE', 'CRITICAL'],
weights=[40, 35, 20, 5]
)[0]
# Priority
priority = random.choices(
['HIGH', 'MEDIUM', 'LOW'],
weights=[20, 60, 20]
)[0]
# Status
status = random.choices(
['ACTIVE', 'RESOLVED', 'INACTIVE', 'REMISSION'],
weights=[50, 20, 10, 20]
)[0]
# Resolution date for resolved problems
resolution_date = None
resolution_notes = None
if status == 'RESOLVED':
resolution_date = onset_date + timedelta(
days=random.randint(7, 365)
)
resolution_notes = f"Problem resolved after treatment. Patient improved significantly."
# Provider assignments
diagnosing_provider = random.choice([p for p in providers if p.tenant == patient.tenant])
managing_provider = diagnosing_provider if random.choice([True, False]) else random.choice(
[p for p in providers if p.tenant == patient.tenant])
# Fix timezone issue
verified_date = None
if random.choice([True, False]):
verified_date = django_timezone.now()
try:
problem = ProblemList.objects.create(
tenant=patient.tenant,
patient=patient,
problem_id=uuid.uuid4(),
problem_name=problem_name,
problem_code=problem_code,
coding_system=coding_system,
problem_type=problem_type,
onset_date=onset_date,
onset_description=f"Patient reports {problem_name.lower()} started gradually",
severity=severity,
priority=priority,
status=status,
resolution_date=resolution_date,
resolution_notes=resolution_notes,
diagnosing_provider=diagnosing_provider,
managing_provider=managing_provider,
body_site=random.choice([
'Chest', 'Abdomen', 'Head', 'Extremities', 'Back', 'Neck'
]) if random.choice([True, False]) else None,
laterality=random.choice(['LEFT', 'RIGHT', 'BILATERAL']) if random.choice([True, False]) else None,
clinical_notes=f"Patient diagnosed with {problem_name}. {severity.lower()} severity. Status: {status.lower()}.",
patient_concerns=f"Patient concerned about {problem_name.lower()} impact on daily activities",
treatment_goals=[
f"Manage {problem_name.lower()} symptoms",
"Improve quality of life",
"Prevent complications"
],
outcome_measures=[
"Symptom improvement",
"Functional status",
"Patient satisfaction"
],
verified=random.choice([True, False]),
verified_by=managing_provider if random.choice([True, False]) else None,
verified_date=verified_date, # Use timezone-aware datetime
created_at=django_timezone.make_aware(
datetime.combine(onset_date, time(random.randint(8, 17), random.randint(0, 59)))
),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)),
created_by=diagnosing_provider
)
problems.append(problem)
except Exception as e:
print(f"Error creating problem for {patient.get_full_name()}: {e}")
continue
print(f"Created {len(problems)} problem list entries")
return problems
def create_care_plans(patients, providers, problems):
"""Create care plans for patients"""
care_plans = []
for patient in patients:
# Each patient has 1-2 care plans
num_plans = random.randint(1, 2)
patient_problems = [p for p in problems if p.patient == patient]
if not patient_problems:
continue
for _ in range(num_plans):
plan_type = random.choice(SAUDI_CARE_PLAN_TYPES)
# Select related problems for this care plan
related_problems_list = random.sample(
patient_problems,
min(random.randint(1, 3), len(patient_problems))
)
# Generate care plan title and description
main_problem = related_problems_list[0].problem_name
title = f"{plan_type.replace('_', ' ').title()} Plan for {main_problem}"
description = f"Comprehensive {plan_type.lower().replace('_', ' ')} plan for managing {main_problem} and related conditions."
# Care plan category
category = random.choice([
'MEDICAL', 'SURGICAL', 'NURSING', 'REHABILITATION',
'PREVENTIVE', 'CHRONIC_DISEASE', 'ACUTE_CARE'
])
# Timeline
start_date = django_timezone.now().date()
end_date = start_date + timedelta(days=random.randint(30, 365))
target_completion_date = end_date - timedelta(days=random.randint(0, 30))
# Status
status = random.choices(
['ACTIVE', 'COMPLETED', 'ON_HOLD', 'CANCELLED'],
weights=[60, 25, 10, 5]
)[0]
# Priority
priority = random.choices(
['HIGH', 'MEDIUM', 'LOW'],
weights=[25, 50, 25]
)[0]
# Providers
primary_provider = random.choice([p for p in providers if p.tenant == patient.tenant])
care_team_list = random.sample(
[p for p in providers if p.tenant == patient.tenant],
min(random.randint(2, 4), len([p for p in providers if p.tenant == patient.tenant]))
)
# Goals and objectives
goals = [
f"Manage {main_problem} effectively",
"Improve patient quality of life",
"Prevent disease progression",
"Optimize medication therapy"
]
objectives = [
f"Reduce {main_problem.lower()} symptoms by 50%",
"Achieve target vital signs",
"Improve functional status",
"Enhance patient understanding"
]
# Interventions and activities
interventions = [
"Medication management",
"Patient education",
"Lifestyle modifications",
"Regular monitoring"
]
activities = [
"Daily medication review",
"Weekly patient assessment",
"Monthly provider consultation",
"Quarterly outcome evaluation"
]
# Completion percentage
completion_percentage = random.randint(0, 100) if status in ['ACTIVE', 'COMPLETED'] else 0
if status == 'COMPLETED':
completion_percentage = 100
# Approval
approved = random.choice([True, False])
approved_date = django_timezone.now() if approved else None
try:
care_plan = CarePlan.objects.create(
tenant=patient.tenant,
patient=patient,
care_plan_id=uuid.uuid4(),
title=title,
description=description,
plan_type=plan_type,
category=category,
start_date=start_date,
end_date=end_date,
target_completion_date=target_completion_date,
status=status,
priority=priority,
primary_provider=primary_provider,
goals=goals,
objectives=objectives,
interventions=interventions,
activities=activities,
monitoring_parameters=[
"Vital signs",
"Symptom severity",
"Functional status",
"Medication adherence"
],
evaluation_criteria=[
"Symptom improvement",
"Quality of life measures",
"Patient satisfaction",
"Clinical outcomes"
],
patient_goals=[
"Feel better",
"Return to normal activities",
"Understand my condition",
"Take medications correctly"
],
patient_preferences=[
"Prefer oral medications",
"Morning appointments preferred",
"Family involvement desired"
],
patient_barriers=[
"Transportation challenges",
"Language barriers",
"Financial constraints"
] if random.choice([True, False]) else [],
resources_needed=[
"Medication",
"Medical equipment",
"Educational materials",
"Support services"
],
support_systems=[
"Family support",
"Healthcare team",
"Community resources"
],
progress_notes=f"Patient progressing well with {plan_type.lower().replace('_', ' ')} plan.",
last_reviewed=django_timezone.now().date() - timedelta(days=random.randint(0, 30)),
next_review_date=django_timezone.now().date() + timedelta(days=random.randint(7, 90)),
outcomes_achieved=[
"Symptom reduction achieved",
"Patient education completed"
] if completion_percentage > 50 else [],
completion_percentage=completion_percentage,
approved=approved,
approved_by=primary_provider if approved else None,
approved_date=approved_date, # Use timezone-aware datetime
created_at=django_timezone.make_aware(
datetime.combine(start_date, time(random.randint(8, 17), random.randint(0, 59)))
),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 7)),
created_by=primary_provider
)
# Set many-to-many relationships after creation
care_plan.care_team.set(care_team_list)
care_plan.related_problems.set(related_problems_list)
care_plans.append(care_plan)
except Exception as e:
print(f"Error creating care plan for {patient.get_full_name()}: {e}")
continue
print(f"Created {len(care_plans)} care plans")
return care_plans
def create_clinical_notes(encounters, templates):
"""Create clinical notes for encounters"""
clinical_notes = []
for encounter in encounters:
if encounter.status not in ['COMPLETED', 'IN_PROGRESS']:
continue
# Each encounter has 1-2 clinical notes
num_notes = random.randint(1, 2)
for note_num in range(num_notes):
# Select appropriate template
suitable_templates = [
t for t in templates
if t.tenant == encounter.tenant and (
t.note_type == encounter.encounter_type or
t.specialty == 'FAMILY_MEDICINE'
)
]
template = random.choice(suitable_templates) if suitable_templates else None
# Note type based on encounter
note_type = encounter.encounter_type if encounter.encounter_type in [nt for nt in
SAUDI_NOTE_TYPES] else 'CONSULTATION'
# Generate note title
titles = {
'CONSULTATION': f"Consultation Note - {encounter.chief_complaint}",
'EMERGENCY': f"Emergency Department Note - {encounter.chief_complaint}",
'PROGRESS': f"Progress Note - Day {note_num + 1}",
'SURGERY': f"Surgical Note - {encounter.chief_complaint}",
'PROCEDURE': f"Procedure Note - {encounter.chief_complaint}",
'DISCHARGE': f"Discharge Summary - {encounter.chief_complaint}"
}
title = titles.get(note_type, f"Clinical Note - {encounter.chief_complaint}")
# Generate note content
if template:
content = template.template_content
# Replace placeholders with actual data
content = content.replace('[Chief Complaint]', encounter.chief_complaint)
content = content.replace('[Provider Name]', encounter.provider.get_full_name())
content = content.replace('[Date and Time]', encounter.start_datetime.strftime('%Y-%m-%d %H:%M'))
content = content.replace('[History details]',
f"Patient presents with {encounter.chief_complaint.lower()}.")
content = content.replace('[Clinical impression]',
f"Impression consistent with {encounter.chief_complaint.lower()}.")
content = content.replace('[Treatment plan]',
"Continue current management plan and follow up as scheduled.")
else:
content = f"""
ENCOUNTER DATE: {encounter.start_datetime.strftime('%Y-%m-%d %H:%M')}
PATIENT: {encounter.patient.get_full_name()}
PROVIDER: {encounter.provider.get_full_name()}
CHIEF COMPLAINT: {encounter.chief_complaint}
HISTORY OF PRESENT ILLNESS:
Patient presents with {encounter.chief_complaint.lower()}. Symptoms have been present for several days.
PHYSICAL EXAMINATION:
Patient appears comfortable. Vital signs stable.
ASSESSMENT:
Clinical impression consistent with {encounter.chief_complaint.lower()}.
PLAN:
Continue current management. Follow up in clinic as needed.
Electronically signed by: {encounter.provider.get_full_name()}
Date: {encounter.start_datetime.strftime('%Y-%m-%d %H:%M')}
""".strip()
# Note timing
note_datetime = encounter.start_datetime + timedelta(minutes=random.randint(15, 120))
# Status and signing
if encounter.status == 'COMPLETED':
note_status = random.choices(
['SIGNED', 'PENDING_SIGNATURE', 'DRAFT'],
weights=[70, 20, 10]
)[0]
else:
note_status = 'DRAFT'
electronically_signed = note_status == 'SIGNED'
signed_datetime = note_datetime + timedelta(
minutes=random.randint(30, 180)) if electronically_signed else None
# Co-signers list
co_signers_list = []
if random.choice([True, False]): # 50% chance of co-signer
potential_cosigners = [
p for p in User.objects.filter(
tenant=encounter.tenant,
employee_profile__role__in=['PHYSICIAN', 'NURSE_PRACTITIONER'],
is_active=True
) if p != encounter.provider
]
if potential_cosigners:
co_signers_list = [random.choice(potential_cosigners)]
# Quality and compliance
quality_score = random.randint(75, 100)
compliance_flags = []
if quality_score < 85:
compliance_flags = ['documentation_incomplete', 'signature_pending']
try:
clinical_note = ClinicalNote.objects.create(
encounter=encounter,
patient=encounter.patient,
note_id=uuid.uuid4(),
note_type=note_type,
title=title,
content=content,
template=template,
structured_data={
'chief_complaint': encounter.chief_complaint,
'encounter_type': encounter.encounter_type,
'provider': encounter.provider.get_full_name(),
'location': encounter.location
},
author=encounter.provider,
status=note_status,
electronically_signed=electronically_signed,
signed_datetime=signed_datetime,
signature_method='ELECTRONIC' if electronically_signed else None,
quality_score=quality_score,
compliance_flags=compliance_flags,
note_datetime=note_datetime,
confidential=random.choice([True, False]),
restricted_access=random.choice([True, False]) if random.random() < 0.1 else False,
access_restrictions=['PROVIDER_ONLY'] if random.choice([True, False]) else [],
created_at=note_datetime,
updated_at=note_datetime + timedelta(minutes=random.randint(5, 60))
)
# Set many-to-many relationship after creation
clinical_note.co_signers.set(co_signers_list)
clinical_notes.append(clinical_note)
except Exception as e:
print(f"Error creating clinical note for encounter {encounter.encounter_id}: {e}")
continue
print(f"Created {len(clinical_notes)} clinical notes")
return clinical_notes
def create_icd10_codes(tenants):
"""Create ICD-10 codes for clinical reference"""
icd10_codes = []
# Sample ICD-10 codes with descriptions
icd10_data = [
# Chapter 1: Certain infectious and parasitic diseases
('A00', 'Cholera', 'Certain infectious and parasitic diseases', 'Cholera and other vibrio infections'),
('A01', 'Typhoid and paratyphoid fevers', 'Certain infectious and parasitic diseases', 'Typhoid and paratyphoid fevers'),
('A02', 'Other salmonella infections', 'Certain infectious and parasitic diseases', 'Other salmonella infections'),
('A03', 'Shigellosis', 'Certain infectious and parasitic diseases', 'Shigellosis'),
('A04', 'Other bacterial intestinal infections', 'Certain infectious and parasitic diseases', 'Other bacterial intestinal infections'),
# Chapter 2: Neoplasms
('C00', 'Malignant neoplasm of lip', 'Neoplasms', 'Malignant neoplasms of lip, oral cavity and pharynx'),
('C01', 'Malignant neoplasm of base of tongue', 'Neoplasms', 'Malignant neoplasms of lip, oral cavity and pharynx'),
('C02', 'Malignant neoplasm of other and unspecified parts of tongue', 'Neoplasms', 'Malignant neoplasms of lip, oral cavity and pharynx'),
('C03', 'Malignant neoplasm of gum', 'Neoplasms', 'Malignant neoplasms of lip, oral cavity and pharynx'),
('C04', 'Malignant neoplasm of floor of mouth', 'Neoplasms', 'Malignant neoplasms of lip, oral cavity and pharynx'),
# Chapter 9: Diseases of the circulatory system
('I00', 'Rheumatic fever without mention of heart involvement', 'Diseases of the circulatory system', 'Acute rheumatic fever'),
('I01', 'Rheumatic fever with heart involvement', 'Diseases of the circulatory system', 'Acute rheumatic fever'),
('I02', 'Rheumatic chorea', 'Diseases of the circulatory system', 'Acute rheumatic fever'),
('I05', 'Rheumatic mitral valve diseases', 'Diseases of the circulatory system', 'Chronic rheumatic heart diseases'),
('I06', 'Rheumatic aortic valve diseases', 'Diseases of the circulatory system', 'Chronic rheumatic heart diseases'),
# Chapter 10: Diseases of the respiratory system
('J00', 'Acute nasopharyngitis [common cold]', 'Diseases of the respiratory system', 'Acute upper respiratory infections'),
('J01', 'Acute sinusitis', 'Diseases of the respiratory system', 'Acute upper respiratory infections'),
('J02', 'Acute pharyngitis', 'Diseases of the respiratory system', 'Acute upper respiratory infections'),
('J03', 'Acute tonsillitis', 'Diseases of the respiratory system', 'Acute upper respiratory infections'),
('J04', 'Acute laryngitis and tracheitis', 'Diseases of the respiratory system', 'Acute upper respiratory infections'),
# Chapter 11: Diseases of the digestive system
('K00', 'Disorders of tooth development and eruption', 'Diseases of the digestive system', 'Disorders of teeth and supporting structures'),
('K01', 'Embedded and impacted teeth', 'Diseases of the digestive system', 'Disorders of teeth and supporting structures'),
('K02', 'Dental caries', 'Diseases of the digestive system', 'Disorders of teeth and supporting structures'),
('K03', 'Other diseases of hard tissues of teeth', 'Diseases of the digestive system', 'Disorders of teeth and supporting structures'),
('K04', 'Diseases of pulp and periapical tissues', 'Diseases of the digestive system', 'Disorders of teeth and supporting structures'),
# Chapter 14: Diseases of the genitourinary system
('N00', 'Acute nephritic syndrome', 'Diseases of the genitourinary system', 'Glomerular diseases'),
('N01', 'Rapidly progressive nephritic syndrome', 'Diseases of the genitourinary system', 'Glomerular diseases'),
('N02', 'Recurrent and persistent hematuria', 'Diseases of the genitourinary system', 'Glomerular diseases'),
('N03', 'Chronic nephritic syndrome', 'Diseases of the genitourinary system', 'Glomerular diseases'),
('N04', 'Nephrotic syndrome', 'Diseases of the genitourinary system', 'Glomerular diseases'),
# Chapter 18: Symptoms, signs and abnormal clinical and laboratory findings
('R00', 'Abnormalities of heart beat', 'Symptoms, signs and abnormal clinical and laboratory findings', 'Symptoms and signs involving the circulatory and respiratory systems'),
('R01', 'Cardiac murmurs and other cardiac sounds', 'Symptoms, signs and abnormal clinical and laboratory findings', 'Symptoms and signs involving the circulatory and respiratory systems'),
('R02', 'Gangrene, not elsewhere classified', 'Symptoms, signs and abnormal clinical and laboratory findings', 'Symptoms and signs involving the circulatory and respiratory systems'),
('R03', 'Abnormal blood-pressure reading, without diagnosis', 'Symptoms, signs and abnormal clinical and laboratory findings', 'Symptoms and signs involving the circulatory and respiratory systems'),
('R04', 'Haemorrhage from respiratory passages', 'Symptoms, signs and abnormal clinical and laboratory findings', 'Symptoms and signs involving the circulatory and respiratory systems'),
]
for tenant in tenants:
for code_data in icd10_data:
code, description, chapter, section = code_data
# Determine if it's a header (shorter codes are typically headers)
is_header = len(code) <= 3
# Create parent relationship for sub-codes
parent = None
if len(code) > 3:
parent_code = code[:3]
try:
parent = Icd10.objects.get(code=parent_code, tenant=tenant)
except Icd10.DoesNotExist:
parent = None
try:
icd10_code = Icd10.objects.create(
code=code,
description=description,
chapter_name=chapter,
section_name=section,
parent=parent,
is_header=is_header,
created_at=django_timezone.now() - timedelta(days=random.randint(30, 365)),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30))
)
icd10_codes.append(icd10_code)
except Exception as e:
print(f"Error creating ICD-10 code {code}: {e}")
continue
print(f"Created {len(icd10_codes)} ICD-10 codes")
return icd10_codes
def create_clinical_recommendations(patients, providers, problems, encounters):
"""Create clinical recommendations for patients"""
recommendations = []
recommendation_templates = [
{
'category': 'PREVENTIVE',
'title': 'Annual Health Screening',
'description': 'Patient due for annual comprehensive health screening including blood work, imaging, and preventive counseling.',
'evidence_level': '1A',
'source': 'USPSTF Guidelines 2023',
'rationale': 'Regular screening improves early detection and prevention of chronic diseases.',
'priority': 'MEDIUM'
},
{
'category': 'DIAGNOSTIC',
'title': 'Cardiac Evaluation Recommended',
'description': 'Consider echocardiography and stress testing given patient history and risk factors.',
'evidence_level': '1B',
'source': 'ACC/AHA Guidelines 2022',
'rationale': 'Patient presents with cardiac symptoms requiring further evaluation.',
'priority': 'HIGH'
},
{
'category': 'TREATMENT',
'title': 'Optimize Diabetes Management',
'description': 'Consider adjusting diabetes regimen based on recent HbA1c and glucose readings.',
'evidence_level': '1A',
'source': 'ADA Standards of Care 2023',
'rationale': 'Current glycemic control may be suboptimal requiring treatment intensification.',
'priority': 'HIGH'
},
{
'category': 'MONITORING',
'title': 'Blood Pressure Monitoring',
'description': 'Increase frequency of blood pressure monitoring and consider 24-hour ambulatory monitoring.',
'evidence_level': '1B',
'source': 'JNC 8 Guidelines',
'rationale': 'Recent readings suggest need for closer monitoring and possible treatment adjustment.',
'priority': 'MEDIUM'
},
{
'category': 'LIFESTYLE',
'title': 'Weight Management Program',
'description': 'Recommend enrollment in structured weight management program with dietary counseling.',
'evidence_level': '1A',
'source': 'Obesity Guidelines 2023',
'rationale': 'Patient BMI indicates need for weight reduction to improve health outcomes.',
'priority': 'MEDIUM'
},
{
'category': 'MEDICATION',
'title': 'Statin Therapy Consideration',
'description': 'Consider initiating statin therapy based on cardiovascular risk assessment.',
'evidence_level': '1A',
'source': 'ACC/AHA Cholesterol Guidelines',
'rationale': 'Patient risk factors warrant preventive cardiovascular therapy.',
'priority': 'HIGH'
},
{
'category': 'FOLLOW_UP',
'title': 'Specialist Consultation',
'description': 'Refer to cardiology/endocrinology for comprehensive evaluation.',
'evidence_level': '2A',
'source': 'Clinical judgment',
'rationale': 'Complex medical condition requires specialist input.',
'priority': 'HIGH'
},
{
'category': 'EDUCATION',
'title': 'Diabetes Self-Management Education',
'description': 'Patient would benefit from structured diabetes education program.',
'evidence_level': '1A',
'source': 'ADA Standards',
'rationale': 'Education improves self-management and clinical outcomes.',
'priority': 'MEDIUM'
}
]
for patient in patients:
# Create 1-3 recommendations per patient
num_recommendations = random.randint(1, 3)
patient_problems = [p for p in problems if p.patient == patient]
patient_encounters = [e for e in encounters if e.patient == patient]
for _ in range(num_recommendations):
template = random.choice(recommendation_templates)
# Generate unique title based on patient context
if patient_problems:
main_problem = random.choice(patient_problems).problem_name
title = f"{template['title']} - {main_problem}"
else:
title = template['title']
# Status progression
status = random.choices(
['PENDING', 'ACTIVE', 'ACCEPTED', 'DEFERRED', 'COMPLETED'],
weights=[40, 30, 15, 10, 5]
)[0]
# Provider assignments
created_by_provider = random.choice([p for p in providers if p.tenant == patient.tenant])
accepted_by = None
accepted_at = None
if status in ['ACCEPTED', 'COMPLETED']:
accepted_by = random.choice([p for p in providers if p.tenant == patient.tenant])
accepted_at = django_timezone.now() - timedelta(days=random.randint(1, 30))
deferred_by = None
deferred_at = None
if status == 'DEFERRED':
deferred_by = random.choice([p for p in providers if p.tenant == patient.tenant])
deferred_at = django_timezone.now() - timedelta(days=random.randint(1, 14))
dismissed_by = None
dismissed_at = None
if status == 'DISMISSED':
dismissed_by = random.choice([p for p in providers if p.tenant == patient.tenant])
dismissed_at = django_timezone.now() - timedelta(days=random.randint(1, 7))
# Expiration
expires_at = django_timezone.now() + timedelta(days=random.randint(30, 180))
# Related data
related_problems_list = random.sample(
patient_problems,
min(random.randint(0, 2), len(patient_problems))
) if patient_problems else []
related_encounter = random.choice(patient_encounters) if patient_encounters else None
try:
recommendation = ClinicalRecommendation.objects.create(
tenant=patient.tenant,
patient=patient,
recommendation_id=uuid.uuid4(),
title=title,
description=template['description'],
category=template['category'],
priority=template['priority'],
evidence_level=template['evidence_level'],
source=template['source'],
rationale=template['rationale'],
status=status,
accepted_by=accepted_by,
accepted_at=accepted_at,
deferred_by=deferred_by,
deferred_at=deferred_at,
dismissed_by=dismissed_by,
dismissed_at=dismissed_at,
expires_at=expires_at,
related_encounter=related_encounter,
created_by=created_by_provider,
created_at=django_timezone.now() - timedelta(days=random.randint(1, 60)),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 7))
)
# Set many-to-many relationships
if related_problems_list:
recommendation.related_problems.set(related_problems_list)
recommendations.append(recommendation)
except Exception as e:
print(f"Error creating clinical recommendation for {patient.get_full_name()}: {e}")
continue
print(f"Created {len(recommendations)} clinical recommendations")
return recommendations
def create_allergy_alerts(patients, providers):
"""Create allergy alerts for patients"""
alerts = []
common_allergens = [
'Penicillin', 'Aspirin', 'Ibuprofen', 'Codeine', 'Morphine', 'Latex',
'Shellfish', 'Peanuts', 'Tree Nuts', 'Eggs', 'Milk', 'Soy',
'Wheat', 'Sulfa Drugs', 'Tetracycline', 'Erythromycin', 'Cephalosporins',
'NSAIDs', 'Contrast Dye', 'Local Anesthetics', 'Insulin', 'ACE Inhibitors'
]
reaction_types = [
'Anaphylaxis', 'Angioedema', 'Urticaria', 'Rash', 'Pruritus',
'Nausea/Vomiting', 'Diarrhea', 'Dyspnea', 'Wheezing', 'Hypotension',
'Tachycardia', 'Bronchospasm', 'Stevens-Johnson Syndrome', 'Toxic Epidermal Necrolysis'
]
severities = ['MILD', 'MODERATE', 'SEVERE', 'LIFE_THREATENING']
for patient in patients:
# 20% of patients have allergies
if random.random() > 0.2:
continue
# Each allergic patient has 1-3 allergies
num_allergies = random.randint(1, 3)
for _ in range(num_allergies):
allergen = random.choice(common_allergens)
# Ensure no duplicate allergens for same patient
existing_allergens = [alert.allergen for alert in alerts if alert.patient == patient]
while allergen in existing_allergens:
allergen = random.choice(common_allergens)
reaction_type = random.choice(reaction_types)
# Severity based on reaction type
if 'Anaphylaxis' in reaction_type or 'Stevens-Johnson' in reaction_type:
severity = random.choices(severities, weights=[0, 10, 30, 60])[0]
elif 'Angioedema' in reaction_type or 'Bronchospasm' in reaction_type:
severity = random.choices(severities, weights=[10, 30, 40, 20])[0]
else:
severity = random.choices(severities, weights=[40, 40, 15, 5])[0]
# Symptoms based on reaction type
symptoms = []
if 'Rash' in reaction_type or 'Urticaria' in reaction_type:
symptoms.extend(['Hives', 'Itching', 'Redness'])
if 'Anaphylaxis' in reaction_type:
symptoms.extend(['Difficulty breathing', 'Swelling of throat', 'Dizziness', 'Nausea'])
if 'Angioedema' in reaction_type:
symptoms.extend(['Facial swelling', 'Tongue swelling', 'Lip swelling'])
if 'Dyspnea' in reaction_type or 'Wheezing' in reaction_type:
symptoms.extend(['Shortness of breath', 'Wheezing', 'Chest tightness'])
symptoms = symptoms[:random.randint(1, 4)] if symptoms else ['Unknown symptoms']
# Onset timing
onset = random.choice([
'Immediate (< 1 hour)', 'Early (1-6 hours)', 'Delayed (6-24 hours)',
'Late (> 24 hours)', 'Unknown'
])
# Status
resolved = random.choice([True, False])
resolved_at = django_timezone.now() - timedelta(days=random.randint(1, 365)) if resolved else None
resolved_by = random.choice([p for p in providers if p.tenant == patient.tenant]) if resolved else None
try:
alert = AllergyAlert.objects.create(
tenant=patient.tenant,
patient=patient,
alert_id=uuid.uuid4(),
allergen=allergen,
reaction_type=reaction_type,
severity=severity,
symptoms=symptoms,
onset=onset,
resolved=resolved,
resolved_at=resolved_at,
resolved_by=resolved_by,
detected_at=django_timezone.now() - timedelta(days=random.randint(1, 3650)),
created_at=django_timezone.now() - timedelta(days=random.randint(1, 3650)),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30))
)
alerts.append(alert)
except Exception as e:
print(f"Error creating allergy alert for {patient.get_full_name()}: {e}")
continue
print(f"Created {len(alerts)} allergy alerts")
return alerts
def create_treatment_protocols(tenants, providers):
"""Create treatment protocols"""
protocols = []
protocol_templates = [
{
'name': 'Acute Coronary Syndrome Management',
'indication': 'Management of patients with suspected or confirmed acute coronary syndrome',
'goals': ['Rapid reperfusion', 'Pain control', 'Complication prevention'],
'interventions': ['ECG within 10 minutes', 'Cardiac enzymes', 'Antiplatelet therapy', 'Anticoagulation'],
'monitoring_parameters': ['ECG changes', 'Cardiac enzymes', 'Vital signs', 'Pain assessment'],
'success_rate': 85.0,
'average_duration': 7
},
{
'name': 'Diabetes Mellitus Type 2 Management',
'indication': 'Comprehensive management of type 2 diabetes mellitus',
'goals': ['Glycemic control (HbA1c < 7%)', 'Cardiovascular risk reduction', 'Prevention of complications'],
'interventions': ['Lifestyle modification', 'Oral hypoglycemics', 'Insulin therapy', 'Regular monitoring'],
'monitoring_parameters': ['HbA1c', 'Fasting glucose', 'Blood pressure', 'Lipid profile'],
'success_rate': 75.0,
'average_duration': 365
},
{
'name': 'Community Acquired Pneumonia Treatment',
'indication': 'Treatment of community-acquired pneumonia in adults',
'goals': ['Clinical cure', 'Prevention of complications', 'Appropriate antibiotic use'],
'interventions': ['Appropriate antibiotics', 'Supportive care', 'Vaccination assessment'],
'monitoring_parameters': ['Clinical improvement', 'Fever resolution', 'Oxygen saturation'],
'success_rate': 90.0,
'average_duration': 10
},
{
'name': 'Hypertension Management Protocol',
'indication': 'Management of essential hypertension',
'goals': ['BP control (< 130/80 mmHg)', 'Cardiovascular risk reduction', 'Organ protection'],
'interventions': ['Lifestyle modification', 'Antihypertensive therapy', 'Regular monitoring'],
'monitoring_parameters': ['Blood pressure', 'Electrolyte levels', 'Renal function'],
'success_rate': 70.0,
'average_duration': 180
},
{
'name': 'Acute Asthma Exacerbation Protocol',
'indication': 'Management of acute asthma exacerbations',
'goals': ['Rapid symptom relief', 'Prevention of respiratory failure', 'Hospitalization prevention'],
'interventions': ['Bronchodilators', 'Systemic corticosteroids', 'Oxygen therapy', 'Monitoring'],
'monitoring_parameters': ['Peak flow', 'Oxygen saturation', 'Respiratory rate', 'Clinical symptoms'],
'success_rate': 88.0,
'average_duration': 3
}
]
for tenant in tenants:
for template in protocol_templates:
try:
protocol = TreatmentProtocol.objects.create(
tenant=tenant,
protocol_id=uuid.uuid4(),
name=template['name'],
description=f"Standardized protocol for {template['name'].lower()}",
indication=template['indication'],
goals=template['goals'],
interventions=template['interventions'],
monitoring_parameters=template['monitoring_parameters'],
success_rate=Decimal(str(template['success_rate'])),
average_duration=template['average_duration'],
is_active=True,
usage_count=random.randint(10, 200),
created_at=django_timezone.now() - timedelta(days=random.randint(30, 365)),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)),
created_by=random.choice([p for p in providers if p.tenant == tenant])
)
protocols.append(protocol)
except Exception as e:
print(f"Error creating treatment protocol {template['name']}: {e}")
continue
print(f"Created {len(protocols)} treatment protocols")
return protocols
def create_clinical_guidelines(tenants):
"""Create clinical guidelines"""
guidelines = []
guideline_templates = [
{
'title': 'Management of Heart Failure',
'organization': 'American Heart Association',
'summary': 'Comprehensive guidelines for the diagnosis and management of heart failure',
'publication_date': date(2022, 4, 1),
'version': '2022',
'keywords': ['heart failure', 'cardiology', 'HFrEF', 'HFpEF'],
'specialties': ['Cardiology', 'Internal Medicine', 'Family Medicine']
},
{
'title': 'Standards of Medical Care in Diabetes',
'organization': 'American Diabetes Association',
'summary': 'Comprehensive guidelines for the diagnosis and management of diabetes mellitus',
'publication_date': date(2023, 1, 1),
'version': '2023',
'keywords': ['diabetes', 'glycemia', 'complications', 'prevention'],
'specialties': ['Endocrinology', 'Internal Medicine', 'Family Medicine']
},
{
'title': 'Guidelines for the Prevention, Detection, Evaluation, and Management of High Blood Pressure',
'organization': 'American College of Cardiology/American Heart Association',
'summary': 'Evidence-based guidelines for hypertension management',
'publication_date': date(2017, 11, 13),
'version': '2017',
'keywords': ['hypertension', 'blood pressure', 'cardiovascular', 'risk'],
'specialties': ['Cardiology', 'Internal Medicine', 'Nephrology']
},
{
'title': 'Global Initiative for Asthma (GINA) Report',
'organization': 'Global Initiative for Asthma',
'summary': 'Global strategy for asthma management and prevention',
'publication_date': date(2023, 5, 1),
'version': '2023',
'keywords': ['asthma', 'respiratory', 'inhalers', 'control'],
'specialties': ['Pulmonology', 'Allergy', 'Pediatrics']
},
{
'title': 'Prevention and Management of Osteoporosis',
'organization': 'World Health Organization',
'summary': 'Guidelines for osteoporosis prevention and treatment',
'publication_date': date(2022, 1, 1),
'version': '2022',
'keywords': ['osteoporosis', 'bone density', 'fracture', 'calcium'],
'specialties': ['Endocrinology', 'Rheumatology', 'Geriatrics']
}
]
for tenant in tenants:
for template in guideline_templates:
try:
guideline = ClinicalGuideline.objects.create(
tenant=tenant,
guideline_id=uuid.uuid4(),
title=template['title'],
organization=template['organization'],
summary=template['summary'],
url=f"https://example.com/guidelines/{template['title'].lower().replace(' ', '_')}",
publication_date=template['publication_date'],
last_updated=django_timezone.now().date() - timedelta(days=random.randint(0, 365)),
version=template['version'],
is_active=True,
keywords=template['keywords'],
specialties=template['specialties'],
created_at=django_timezone.now() - timedelta(days=random.randint(30, 365)),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30))
)
guidelines.append(guideline)
except Exception as e:
print(f"Error creating clinical guideline {template['title']}: {e}")
continue
print(f"Created {len(guidelines)} clinical guidelines")
return guidelines
def create_critical_alerts(patients, providers, encounters):
"""Create critical alerts for patients"""
alerts = []
alert_templates = [
{
'title': 'Critical Lab Value Alert',
'description': 'Potassium level critically elevated at 7.2 mEq/L',
'priority': 'CRITICAL',
'recommendation': 'Immediate treatment with calcium gluconate, insulin, and glucose. Transfer to ICU.'
},
{
'title': 'Acute Coronary Syndrome Alert',
'description': 'ST-elevation myocardial infarction detected on ECG',
'priority': 'CRITICAL',
'recommendation': 'Activate cardiac catheterization lab. Administer aspirin, heparin, and prepare for PCI.'
},
{
'title': 'Severe Hypoglycemia Alert',
'description': 'Blood glucose critically low at 35 mg/dL',
'priority': 'CRITICAL',
'recommendation': 'Administer IV dextrose immediately. Recheck glucose in 15 minutes.'
},
{
'title': 'Acute Stroke Alert',
'description': 'Suspected acute ischemic stroke with NIHSS score of 18',
'priority': 'URGENT',
'recommendation': 'Activate stroke team. Obtain CT brain immediately. Prepare for thrombolytic therapy.'
},
{
'title': 'Sepsis Alert',
'description': 'SIRS criteria met with suspected infection. Lactate elevated at 4.2 mmol/L',
'priority': 'URGENT',
'recommendation': 'Obtain blood cultures, start broad-spectrum antibiotics within 1 hour, fluid resuscitation.'
},
{
'title': 'Drug Interaction Alert',
'description': 'Critical drug interaction between warfarin and newly prescribed antibiotic',
'priority': 'HIGH',
'recommendation': 'Monitor INR closely. Consider dose adjustment or alternative antibiotic.'
},
{
'title': 'Allergy Alert - Severe Reaction',
'description': 'Patient with history of anaphylaxis to penicillin now prescribed amoxicillin',
'priority': 'HIGH',
'recommendation': 'Discontinue amoxicillin. Prescribe alternative antibiotic. Consider premedication if necessary.'
}
]
for patient in patients:
# 5% of patients have critical alerts
if random.random() > 0.05:
continue
# Each patient with alerts has 1-2 critical alerts
num_alerts = random.randint(1, 2)
patient_encounters = [e for e in encounters if e.patient == patient]
for _ in range(num_alerts):
template = random.choice(alert_templates)
# Status
acknowledged = random.choice([True, False])
acknowledged_by = random.choice([p for p in providers if p.tenant == patient.tenant]) if acknowledged else None
acknowledged_at = django_timezone.now() - timedelta(hours=random.randint(1, 24)) if acknowledged else None
# Expiration
expires_at = django_timezone.now() + timedelta(hours=random.randint(24, 168))
# Related encounter
related_encounter = random.choice(patient_encounters) if patient_encounters else None
try:
alert = CriticalAlert.objects.create(
tenant=patient.tenant,
patient=patient,
alert_id=uuid.uuid4(),
title=template['title'],
description=template['description'],
priority=template['priority'],
recommendation=template['recommendation'],
acknowledged=acknowledged,
acknowledged_by=acknowledged_by,
acknowledged_at=acknowledged_at,
expires_at=expires_at,
related_encounter=related_encounter,
created_by=random.choice([p for p in providers if p.tenant == patient.tenant]),
created_at=django_timezone.now() - timedelta(hours=random.randint(1, 48)),
updated_at=django_timezone.now() - timedelta(minutes=random.randint(0, 60))
)
alerts.append(alert)
except Exception as e:
print(f"Error creating critical alert for {patient.get_full_name()}: {e}")
continue
print(f"Created {len(alerts)} critical alerts")
return alerts
def create_diagnostic_suggestions(patients, providers, encounters):
"""Create diagnostic suggestions for patients"""
suggestions = []
suggestion_templates = [
{
'test_name': 'Echocardiogram',
'test_code': 'ECHO',
'indication': 'Evaluate cardiac function and structure',
'confidence': 85.0
},
{
'test_name': 'Coronary Angiography',
'test_code': 'CATH',
'indication': 'Assess coronary artery disease',
'confidence': 78.0
},
{
'test_name': 'MRI Brain',
'test_code': 'MRI_BRAIN',
'indication': 'Evaluate neurological symptoms',
'confidence': 72.0
},
{
'test_name': 'CT Chest',
'test_code': 'CT_CHEST',
'indication': 'Assess pulmonary pathology',
'confidence': 80.0
},
{
'test_name': 'Colonoscopy',
'test_code': 'COLON',
'indication': 'Screen for colorectal cancer',
'confidence': 88.0
},
{
'test_name': 'DEXA Scan',
'test_code': 'DEXA',
'indication': 'Assess bone mineral density',
'confidence': 90.0
},
{
'test_name': 'Thyroid Function Tests',
'test_code': 'TFT',
'indication': 'Evaluate thyroid dysfunction',
'confidence': 75.0
},
{
'test_name': 'HbA1c',
'test_code': 'HBA1C',
'indication': 'Assess long-term glycemic control',
'confidence': 95.0
}
]
for patient in patients:
# 15% of patients have diagnostic suggestions
if random.random() > 0.15:
continue
# Each patient with suggestions has 1-3 suggestions
num_suggestions = random.randint(1, 3)
patient_encounters = [e for e in encounters if e.patient == patient]
for _ in range(num_suggestions):
template = random.choice(suggestion_templates)
# Status
status = random.choices(
['PENDING', 'ORDERED', 'COMPLETED'],
weights=[50, 30, 20]
)[0]
# Provider assignments
ordered_by = None
ordered_at = None
if status in ['ORDERED', 'COMPLETED']:
ordered_by = random.choice([p for p in providers if p.tenant == patient.tenant])
ordered_at = django_timezone.now() - timedelta(days=random.randint(1, 14))
try:
suggestion = DiagnosticSuggestion.objects.create(
tenant=patient.tenant,
patient=patient,
suggestion_id=uuid.uuid4(),
test_name=template['test_name'],
test_code=template['test_code'],
indication=template['indication'],
confidence=Decimal(str(template['confidence'])),
status=status,
ordered_by=ordered_by,
ordered_at=ordered_at,
created_by=random.choice([p for p in providers if p.tenant == patient.tenant]),
created_at=django_timezone.now() - timedelta(days=random.randint(1, 30)),
updated_at=django_timezone.now() - timedelta(days=random.randint(0, 7))
)
suggestions.append(suggestion)
except Exception as e:
print(f"Error creating diagnostic suggestion for {patient.get_full_name()}: {e}")
continue
print(f"Created {len(suggestions)} diagnostic suggestions")
return suggestions
def main():
"""Main function to generate all EMR data"""
print("Starting Saudi Healthcare EMR Data Generation...")
# Get existing tenants
tenants = list(Tenant.objects.all())
if not tenants:
print("❌ No tenants found. Please run the core data generator first.")
return
# Create note templates
print("\n1. Creating Note Templates...")
templates = create_note_templates(tenants)
# Create encounters
print("\n2. Creating Patient Encounters...")
encounters = create_encounters(tenants, days_back=30)
# Create vital signs
print("\n3. Creating Vital Signs...")
vital_signs = create_vital_signs(encounters)
# Get patients and providers for remaining models
patients = list(PatientProfile.objects.filter(tenant__in=tenants))
providers = get_providers_for_emr(tenants)
# Create problem lists
print("\n4. Creating Problem Lists...")
problems = create_problem_lists(patients, providers)
# Create care plans
print("\n5. Creating Care Plans...")
care_plans = create_care_plans(patients, providers, problems)
# Create clinical notes
print("\n6. Creating Clinical Notes...")
clinical_notes = create_clinical_notes(encounters, templates)
# Create ICD-10 codes
print("\n7. Creating ICD-10 Codes...")
icd10_codes = create_icd10_codes(tenants)
# Create clinical recommendations
print("\n8. Creating Clinical Recommendations...")
clinical_recommendations = create_clinical_recommendations(patients, providers, problems, encounters)
# Create allergy alerts
print("\n9. Creating Allergy Alerts...")
allergy_alerts = create_allergy_alerts(patients, providers)
# Create treatment protocols
print("\n10. Creating Treatment Protocols...")
treatment_protocols = create_treatment_protocols(tenants, providers)
# Create clinical guidelines
print("\n11. Creating Clinical Guidelines...")
clinical_guidelines = create_clinical_guidelines(tenants)
# Create critical alerts
print("\n12. Creating Critical Alerts...")
critical_alerts = create_critical_alerts(patients, providers, encounters)
# Create diagnostic suggestions
print("\n13. Creating Diagnostic Suggestions...")
diagnostic_suggestions = create_diagnostic_suggestions(patients, providers, encounters)
print(f"\n✅ Saudi Healthcare EMR Data Generation Complete!")
print(f"📊 Summary:")
print(f" - Note Templates: {len(templates)}")
print(f" - Patient Encounters: {len(encounters)}")
print(f" - Vital Signs Records: {len(vital_signs)}")
print(f" - Problem List Entries: {len(problems)}")
print(f" - Care Plans: {len(care_plans)}")
print(f" - Clinical Notes: {len(clinical_notes)}")
print(f" - ICD-10 Codes: {len(icd10_codes)}")
print(f" - Clinical Recommendations: {len(clinical_recommendations)}")
print(f" - Allergy Alerts: {len(allergy_alerts)}")
print(f" - Treatment Protocols: {len(treatment_protocols)}")
print(f" - Clinical Guidelines: {len(clinical_guidelines)}")
print(f" - Critical Alerts: {len(critical_alerts)}")
print(f" - Diagnostic Suggestions: {len(diagnostic_suggestions)}")
# Statistics
if encounters:
encounter_type_counts = {}
for encounter in encounters:
encounter_type_counts[encounter.encounter_type] = encounter_type_counts.get(encounter.encounter_type, 0) + 1
print(f"\n📈 Encounter Type Distribution:")
for enc_type, count in sorted(encounter_type_counts.items(), key=lambda x: x[1], reverse=True)[:10]:
print(f" - {enc_type.replace('_', ' ').title()}: {count}")
if problems:
problem_status_counts = {}
for problem in problems:
problem_status_counts[problem.status] = problem_status_counts.get(problem.status, 0) + 1
print(f"\n📋 Problem Status Distribution:")
for status, count in problem_status_counts.items():
print(f" - {status.title()}: {count}")
return {
'templates': templates,
'encounters': encounters,
'vital_signs': vital_signs,
'problems': problems,
'care_plans': care_plans,
'clinical_notes': clinical_notes,
'icd10_codes': icd10_codes,
'clinical_recommendations': clinical_recommendations,
'allergy_alerts': allergy_alerts,
'treatment_protocols': treatment_protocols,
'clinical_guidelines': clinical_guidelines,
'critical_alerts': critical_alerts,
'diagnostic_suggestions': diagnostic_suggestions
}
if __name__ == "__main__":
main()