593 lines
21 KiB
Python
593 lines
21 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
Seed script for Standards App - Creates fake data for testing
|
|
Usage: python manage.py shell < seed_standards_data.py
|
|
Or: python seed_standards_data.py
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import django
|
|
from datetime import date, timedelta
|
|
import random
|
|
|
|
# Setup Django
|
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.dev')
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
django.setup()
|
|
|
|
from apps.organizations.models import Hospital, Department, Staff, Patient
|
|
from apps.standards.models import (
|
|
StandardSource, StandardCategory, Standard,
|
|
StandardCompliance, StandardAttachment
|
|
)
|
|
from apps.accounts.models import User, Group
|
|
|
|
# Fake data generators
|
|
ARABIC_NAMES_FIRST = [
|
|
"محمد", "أحمد", "عبدالله", "سعيد", "فهد",
|
|
"محمد", "عبدالرحمن", "خالد", "سعود",
|
|
"ناصر", "سلطان", "نايف", "بندر"
|
|
]
|
|
|
|
ARABIC_NAMES_LAST = [
|
|
"العمري", "القحطاني", "الدوسري", "السبيعي",
|
|
"الشعلان", "العتيبي", "الفريح", "الزهراني",
|
|
"الراشد", "العمير", "الحربي", "الشمري"
|
|
]
|
|
|
|
ENGLISH_NAMES_FIRST = [
|
|
"Ahmed", "Mohammed", "Abdullah", "Saud", "Khalid",
|
|
"Fahad", "Nasser", "Sultan", "Naif", "Bandar",
|
|
"Sarah", "Fatima", "Aisha", "Hana", "Layla"
|
|
]
|
|
|
|
ENGLISH_NAMES_LAST = [
|
|
"Al-Omri", "Al-Qahtani", "Al-Dossari", "Al-Subaie",
|
|
"Al-Shaalan", "Al-Otaibi", "Al-Furaih", "Al-Zahrani",
|
|
"Al-Rashed", "Al-Ameer", "Al-Harbi", "Al-Shamrari"
|
|
]
|
|
|
|
HOSPITAL_NAMES = [
|
|
{
|
|
"name": "King Faisal Specialist Hospital",
|
|
"name_ar": "مستشفى الملك فيصل التخصصي",
|
|
"code": "KFSH",
|
|
"city": "Riyadh"
|
|
},
|
|
{
|
|
"name": "King Fahad Medical City",
|
|
"name_ar": "مدينة الملك فهد الطبية",
|
|
"code": "KFMC",
|
|
"city": "Riyadh"
|
|
},
|
|
{
|
|
"name": "Prince Sultan Military Medical City",
|
|
"name_ar": "مدينة الأمير سلطان الطبية العسكرية",
|
|
"code": "PSMMC",
|
|
"city": "Riyadh"
|
|
}
|
|
]
|
|
|
|
DEPARTMENTS = [
|
|
{"name": "Emergency Department", "name_ar": "قسم الطوارئ", "code": "ED"},
|
|
{"name": "Intensive Care Unit", "name_ar": "وحدة العناية المركزة", "code": "ICU"},
|
|
{"name": "Cardiology Department", "name_ar": "قسم أمراض القلب", "code": "CARDIO"},
|
|
{"name": "Surgery Department", "name_ar": "قسم الجراحة", "code": "SURG"},
|
|
{"name": "Pediatrics Department", "name_ar": "قسم طب الأطفال", "code": "PED"},
|
|
{"name": "Radiology Department", "name_ar": "قسم الأشعة", "code": "RADIO"},
|
|
{"name": "Laboratory Department", "name_ar": "قسم المختبر", "code": "LAB"},
|
|
{"name": "Pharmacy Department", "name_ar": "قسم الصيدلية", "code": "PHARM"},
|
|
]
|
|
|
|
STANDARD_SOURCES = [
|
|
{
|
|
"name": "CBAHI",
|
|
"name_ar": "المجلس المركزي لاعتماد المؤسسات الصحية",
|
|
"code": "CBAHI",
|
|
"description": "Central Board for Accreditation of Healthcare Institutions",
|
|
"website": "https://www.cbahi.gov.sa"
|
|
},
|
|
{
|
|
"name": "MOH",
|
|
"name_ar": "وزارة الصحة",
|
|
"code": "MOH",
|
|
"description": "Ministry of Health Saudi Arabia",
|
|
"website": "https://www.moh.gov.sa"
|
|
},
|
|
{
|
|
"name": "CHI",
|
|
"name_ar": "مجلس الضمان الصحي",
|
|
"code": "CHI",
|
|
"description": "Council of Health Insurance",
|
|
"website": "https://www.chi.gov.sa"
|
|
},
|
|
{
|
|
"name": "JCI",
|
|
"name_ar": "المفوضية المشتركة",
|
|
"code": "JCI",
|
|
"description": "Joint Commission International",
|
|
"website": "https://www.jointcommissioninternational.org"
|
|
}
|
|
]
|
|
|
|
STANDARD_CATEGORIES = [
|
|
{
|
|
"name": "Patient Safety",
|
|
"name_ar": "سلامة المرضى",
|
|
"description": "Standards related to patient safety and risk management",
|
|
"order": 1
|
|
},
|
|
{
|
|
"name": "Quality Management",
|
|
"name_ar": "إدارة الجودة",
|
|
"description": "Standards for quality improvement and management",
|
|
"order": 2
|
|
},
|
|
{
|
|
"name": "Infection Control",
|
|
"name_ar": "مكافحة العدوى",
|
|
"description": "Infection prevention and control standards",
|
|
"order": 3
|
|
},
|
|
{
|
|
"name": "Emergency Management",
|
|
"name_ar": "إدارة الطوارئ",
|
|
"description": "Emergency preparedness and response standards",
|
|
"order": 4
|
|
},
|
|
{
|
|
"name": "Medication Management",
|
|
"name_ar": "إدارة الأدوية",
|
|
"description": "Safe medication use and management standards",
|
|
"order": 5
|
|
},
|
|
{
|
|
"name": "Patient Rights",
|
|
"name_ar": "حقوق المرضى",
|
|
"description": "Patient rights and education standards",
|
|
"order": 6
|
|
}
|
|
]
|
|
|
|
STANDARD_TEMPLATES = [
|
|
{
|
|
"code": "CBAHI-PS-01",
|
|
"title": "Patient Identification",
|
|
"title_ar": "تحديد هوية المريض",
|
|
"description": "The hospital identifies patients accurately and consistently across all care settings using at least two patient identifiers."
|
|
},
|
|
{
|
|
"code": "CBAHI-PS-02",
|
|
"title": "Communication of Critical Test Results",
|
|
"title_ar": "التواصل بشأن نتائج الفحوصات الحرجة",
|
|
"description": "The hospital has a process for reporting critical test results to the responsible licensed caregiver."
|
|
},
|
|
{
|
|
"code": "CBAHI-PS-03",
|
|
"title": "Medication Safety",
|
|
"title_ar": "سلامة الأدوية",
|
|
"description": "The hospital safely manages high-alert medications and looks-alike/sound-alike medications."
|
|
},
|
|
{
|
|
"code": "CBAHI-PS-04",
|
|
"title": "Prevention of Healthcare-Associated Infections",
|
|
"title_ar": "منع العدوى المرتبطة بالرعاية الصحية",
|
|
"description": "The hospital implements a comprehensive program to prevent healthcare-associated infections."
|
|
},
|
|
{
|
|
"code": "CBAHI-PS-05",
|
|
"title": "Prevention of Patient Falls",
|
|
"title_ar": "منع سقوط المرضى",
|
|
"description": "The hospital assesses patients for fall risk and implements interventions to prevent falls."
|
|
},
|
|
{
|
|
"code": "CBAHI-QM-01",
|
|
"title": "Quality Improvement Program",
|
|
"title_ar": "برنامج تحسين الجودة",
|
|
"description": "The hospital has a comprehensive quality improvement program that is integrated into daily operations."
|
|
},
|
|
{
|
|
"code": "CBAHI-QM-02",
|
|
"title": "Performance Measurement",
|
|
"title_ar": "قياس الأداء",
|
|
"description": "The hospital measures and monitors performance for key processes and outcomes."
|
|
},
|
|
{
|
|
"code": "CBAHI-IC-01",
|
|
"title": "Hand Hygiene",
|
|
"title_ar": "نظافة اليدين",
|
|
"description": "The hospital implements an effective hand hygiene program to reduce infection transmission."
|
|
},
|
|
{
|
|
"code": "CBAHI-IC-02",
|
|
"title": "Isolation Precautions",
|
|
"title_ar": "احتياطات العزل",
|
|
"description": "The hospital follows standard and transmission-based precautions to prevent spread of infections."
|
|
},
|
|
{
|
|
"code": "CBAHI-EM-01",
|
|
"title": "Emergency Preparedness Plan",
|
|
"title_ar": "خطة الاستعداد للطوارئ",
|
|
"description": "The hospital has a comprehensive emergency preparedness plan that is tested regularly."
|
|
},
|
|
{
|
|
"code": "CBAHI-MM-01",
|
|
"title": "Medication Storage",
|
|
"title_ar": "تخزين الأدوية",
|
|
"description": "The hospital stores medications securely according to manufacturer and regulatory requirements."
|
|
},
|
|
{
|
|
"code": "CBAHI-PR-01",
|
|
"title": "Patient Rights and Responsibilities",
|
|
"title_ar": "حقوق وواجبات المرضى",
|
|
"description": "The hospital informs patients about their rights and responsibilities."
|
|
},
|
|
{
|
|
"code": "CBAHI-PR-02",
|
|
"title": "Patient Education",
|
|
"title_ar": "تثقيف المرضى",
|
|
"description": "The hospital provides patient education appropriate to patient needs and understanding."
|
|
}
|
|
]
|
|
|
|
|
|
def get_or_create_hospital():
|
|
"""Get or create the first hospital for testing"""
|
|
hospital = Hospital.objects.first()
|
|
if hospital:
|
|
print(f"✓ Using existing hospital: {hospital.name}")
|
|
return hospital
|
|
|
|
# Create first hospital
|
|
hospital_data = HOSPITAL_NAMES[0]
|
|
hospital = Hospital.objects.create(
|
|
name=hospital_data["name"],
|
|
name_ar=hospital_data["name_ar"],
|
|
code=hospital_data["code"],
|
|
city=hospital_data["city"],
|
|
address=f"{hospital_data['city']}, Saudi Arabia",
|
|
phone="+966110000000",
|
|
email=f"info@{hospital_data['code'].lower()}.sa",
|
|
license_number=f"LICENSE-{hospital_data['code']}",
|
|
capacity=500,
|
|
status="active"
|
|
)
|
|
print(f"✓ Created hospital: {hospital.name}")
|
|
return hospital
|
|
|
|
|
|
def create_departments(hospital):
|
|
"""Create departments for the hospital"""
|
|
print("\n--- Creating Departments ---")
|
|
for dept_data in DEPARTMENTS:
|
|
dept, created = Department.objects.get_or_create(
|
|
hospital=hospital,
|
|
code=dept_data["code"],
|
|
defaults={
|
|
"name": dept_data["name"],
|
|
"name_ar": dept_data["name_ar"],
|
|
"location": f"Building 1, Floor {random.randint(1, 5)}",
|
|
"phone": f"+96611{random.randint(100000, 999999)}",
|
|
"email": f"{dept_data['code'].lower()}@{hospital.code.lower()}.sa",
|
|
"status": "active"
|
|
}
|
|
)
|
|
if created:
|
|
print(f" ✓ Created department: {dept.name}")
|
|
else:
|
|
print(f" - Department already exists: {dept.name}")
|
|
|
|
return Department.objects.filter(hospital=hospital, status="active")
|
|
|
|
|
|
def create_users(hospital, num_users=5):
|
|
"""Create test users"""
|
|
print("\n--- Creating Users ---")
|
|
users = []
|
|
|
|
for i in range(num_users):
|
|
first_name = ENGLISH_NAMES_FIRST[random.randint(0, len(ENGLISH_NAMES_FIRST) - 1)]
|
|
last_name = ENGLISH_NAMES_LAST[random.randint(0, len(ENGLISH_NAMES_LAST) - 1)]
|
|
username = f"{first_name.lower()}.{last_name.lower()}{i+1}"
|
|
email = f"{username}@hospital.test"
|
|
|
|
user, created = User.objects.get_or_create(
|
|
username=username,
|
|
defaults={
|
|
"email": email,
|
|
"first_name": first_name,
|
|
"last_name": last_name,
|
|
"is_active": True
|
|
}
|
|
)
|
|
|
|
if created:
|
|
user.set_password("password123")
|
|
user.save()
|
|
print(f" ✓ Created user: {user.get_full_name()} ({username})")
|
|
|
|
# Create Group and assign to user for role
|
|
role_name = "PX Admin" if i == 0 else "Staff"
|
|
group, _ = Group.objects.get_or_create(name=role_name)
|
|
user.groups.add(group)
|
|
|
|
# Assign hospital to user
|
|
user.hospital = hospital
|
|
user.save()
|
|
else:
|
|
print(f" - User already exists: {user.get_full_name()}")
|
|
|
|
users.append(user)
|
|
|
|
return users
|
|
|
|
|
|
def create_staff(hospital, departments, users):
|
|
"""Create staff members"""
|
|
print("\n--- Creating Staff ---")
|
|
staff_types = ["physician", "nurse", "admin"]
|
|
specializations = ["Cardiology", "General Surgery", "Internal Medicine", "Pediatrics", "Emergency Medicine"]
|
|
|
|
for i, user in enumerate(users):
|
|
dept = random.choice(departments)
|
|
staff_type = staff_types[random.randint(0, len(staff_types) - 1)]
|
|
|
|
staff, created = Staff.objects.get_or_create(
|
|
user=user,
|
|
defaults={
|
|
"first_name": user.first_name,
|
|
"last_name": user.last_name,
|
|
"first_name_ar": ARABIC_NAMES_FIRST[random.randint(0, len(ARABIC_NAMES_FIRST) - 1)],
|
|
"last_name_ar": ARABIC_NAMES_LAST[random.randint(0, len(ARABIC_NAMES_LAST) - 1)],
|
|
"staff_type": staff_type,
|
|
"job_title": f"{staff_type.title()} - {dept.name}",
|
|
"license_number": f"LIC-{random.randint(100000, 999999)}",
|
|
"specialization": specializations[random.randint(0, len(specializations) - 1)] if staff_type == "physician" else "",
|
|
"email": user.email,
|
|
"employee_id": f"EMP-{random.randint(10000, 99999)}",
|
|
"hospital": hospital,
|
|
"department": dept,
|
|
"status": "active"
|
|
}
|
|
)
|
|
|
|
if created:
|
|
print(f" ✓ Created staff: {staff} ({staff_type})")
|
|
else:
|
|
print(f" - Staff already exists: {staff}")
|
|
|
|
|
|
def create_patients(hospital, num_patients=10):
|
|
"""Create test patients"""
|
|
print("\n--- Creating Patients ---")
|
|
patients = []
|
|
|
|
for i in range(num_patients):
|
|
first_name = ENGLISH_NAMES_FIRST[random.randint(0, len(ENGLISH_NAMES_FIRST) - 1)]
|
|
last_name = ENGLISH_NAMES_LAST[random.randint(0, len(ENGLISH_NAMES_LAST) - 1)]
|
|
|
|
patient = Patient.objects.create(
|
|
mrn=Patient.generate_mrn(),
|
|
national_id=f"{''.join([str(random.randint(0, 9)) for _ in range(10)])}",
|
|
first_name=first_name,
|
|
last_name=last_name,
|
|
first_name_ar=ARABIC_NAMES_FIRST[random.randint(0, len(ARABIC_NAMES_FIRST) - 1)],
|
|
last_name_ar=ARABIC_NAMES_LAST[random.randint(0, len(ARABIC_NAMES_LAST) - 1)],
|
|
date_of_birth=date.today() - timedelta(days=random.randint(18*365, 80*365)),
|
|
gender=random.choice(["male", "female"]),
|
|
phone=f"+96650{random.randint(1000000, 9999999)}",
|
|
email=f"patient{i+1}@test.com",
|
|
city=random.choice(["Riyadh", "Jeddah", "Dammam", "Makkah", "Madinah"]),
|
|
primary_hospital=hospital,
|
|
status="active"
|
|
)
|
|
|
|
patients.append(patient)
|
|
print(f" ✓ Created patient: {patient}")
|
|
|
|
return patients
|
|
|
|
|
|
def create_standard_sources():
|
|
"""Create standard sources"""
|
|
print("\n--- Creating Standard Sources ---")
|
|
sources = []
|
|
|
|
for source_data in STANDARD_SOURCES:
|
|
source, created = StandardSource.objects.get_or_create(
|
|
code=source_data["code"],
|
|
defaults={
|
|
"name": source_data["name"],
|
|
"name_ar": source_data["name_ar"],
|
|
"description": source_data["description"],
|
|
"website": source_data["website"],
|
|
"is_active": True
|
|
}
|
|
)
|
|
|
|
if created:
|
|
print(f" ✓ Created source: {source.name}")
|
|
else:
|
|
print(f" - Source already exists: {source.name}")
|
|
|
|
sources.append(source)
|
|
|
|
return sources
|
|
|
|
|
|
def create_standard_categories():
|
|
"""Create standard categories"""
|
|
print("\n--- Creating Standard Categories ---")
|
|
categories = []
|
|
|
|
for cat_data in STANDARD_CATEGORIES:
|
|
category, created = StandardCategory.objects.get_or_create(
|
|
name=cat_data["name"],
|
|
defaults={
|
|
"name_ar": cat_data["name_ar"],
|
|
"description": cat_data["description"],
|
|
"order": cat_data["order"],
|
|
"is_active": True
|
|
}
|
|
)
|
|
|
|
if created:
|
|
print(f" ✓ Created category: {category.name}")
|
|
else:
|
|
print(f" - Category already exists: {category.name}")
|
|
|
|
categories.append(category)
|
|
|
|
return categories
|
|
|
|
|
|
def create_standards(sources, categories, departments):
|
|
"""Create standards"""
|
|
print("\n--- Creating Standards ---")
|
|
standards = []
|
|
|
|
for std_data in STANDARD_TEMPLATES:
|
|
# Random source and category
|
|
source = sources[random.randint(0, len(sources) - 1)]
|
|
category = categories[random.randint(0, len(categories) - 1)]
|
|
|
|
# Randomly assign to a department (40% chance) or leave null
|
|
department = None
|
|
if random.random() < 0.4:
|
|
department = departments[random.randint(0, len(departments) - 1)]
|
|
|
|
standard, created = Standard.objects.get_or_create(
|
|
code=std_data["code"],
|
|
defaults={
|
|
"title": std_data["title"],
|
|
"title_ar": std_data["title_ar"],
|
|
"description": std_data["description"],
|
|
"source": source,
|
|
"category": category,
|
|
"department": department,
|
|
"effective_date": date.today() - timedelta(days=random.randint(30, 365)),
|
|
"review_date": date.today() + timedelta(days=random.randint(30, 365)),
|
|
"is_active": True
|
|
}
|
|
)
|
|
|
|
if created:
|
|
print(f" ✓ Created standard: {standard.code} - {standard.title}")
|
|
else:
|
|
print(f" - Standard already exists: {standard.code}")
|
|
|
|
standards.append(standard)
|
|
|
|
return standards
|
|
|
|
|
|
def create_compliance_records(departments, standards, users):
|
|
"""Create compliance records for all department-standard combinations"""
|
|
print("\n--- Creating Compliance Records ---")
|
|
status_choices = ["met", "partially_met", "not_met", "not_assessed"]
|
|
|
|
for dept in departments:
|
|
# Get all standards applicable to this department (department-specific or general)
|
|
applicable_standards = Standard.objects.filter(
|
|
models.Q(department=dept) | models.Q(department__isnull=True)
|
|
).filter(is_active=True)
|
|
|
|
for standard in applicable_standards:
|
|
# Check if compliance already exists
|
|
if StandardCompliance.objects.filter(department=dept, standard=standard).exists():
|
|
print(f" - Compliance exists: {dept.name} - {standard.code}")
|
|
continue
|
|
|
|
# Random status (bias towards met and partially_met)
|
|
weights = [0.35, 0.25, 0.15, 0.25] # 35% met, 25% partially_met, 15% not_met, 25% not_assessed
|
|
status = random.choices(status_choices, weights=weights, k=1)[0]
|
|
|
|
# Only add assessor and dates if assessed
|
|
assessor = None
|
|
last_assessed = None
|
|
|
|
if status != "not_assessed":
|
|
assessor = random.choice(users)
|
|
last_assessed = date.today() - timedelta(days=random.randint(1, 90))
|
|
|
|
compliance = StandardCompliance.objects.create(
|
|
department=dept,
|
|
standard=standard,
|
|
status=status,
|
|
last_assessed_date=last_assessed,
|
|
assessor=assessor,
|
|
notes=f"Assessment completed for {standard.title}" if status != "not_assessed" else "",
|
|
evidence_summary=f"Evidence documentation available" if status == "met" else ""
|
|
)
|
|
|
|
status_symbol = "✓" if status != "not_assessed" else "○"
|
|
print(f" {status_symbol} Created compliance: {dept.name} - {standard.code} ({status})")
|
|
|
|
|
|
def main():
|
|
"""Main function to seed all data"""
|
|
print("=" * 70)
|
|
print("STANDARDS APP DATA SEEDING SCRIPT")
|
|
print("=" * 70)
|
|
|
|
try:
|
|
# Get or create hospital
|
|
hospital = get_or_create_hospital()
|
|
|
|
# Create departments
|
|
departments = list(create_departments(hospital))
|
|
|
|
# Create users
|
|
users = create_users(hospital, num_users=5)
|
|
|
|
# Create staff
|
|
create_staff(hospital, departments, users)
|
|
|
|
# Create patients
|
|
patients = create_patients(hospital, num_patients=10)
|
|
|
|
# Create standard sources
|
|
sources = create_standard_sources()
|
|
|
|
# Create standard categories
|
|
categories = create_standard_categories()
|
|
|
|
# Create standards
|
|
standards = create_standards(sources, categories, departments)
|
|
|
|
# Create compliance records
|
|
create_compliance_records(departments, standards, users)
|
|
|
|
# Print summary
|
|
print("\n" + "=" * 70)
|
|
print("SEEDING COMPLETE!")
|
|
print("=" * 70)
|
|
print(f"\nSummary:")
|
|
print(f" Hospital: {hospital.name}")
|
|
print(f" Departments: {len(departments)}")
|
|
print(f" Users: {len(users)}")
|
|
print(f" Patients: {len(patients)}")
|
|
print(f" Standard Sources: {StandardSource.objects.count()}")
|
|
print(f" Standard Categories: {StandardCategory.objects.count()}")
|
|
print(f" Standards: {Standard.objects.count()}")
|
|
print(f" Compliance Records: {StandardCompliance.objects.count()}")
|
|
print(f"\nLogin Credentials:")
|
|
for user in users:
|
|
print(f" - Username: {user.username}, Password: password123")
|
|
print("\n" + "=" * 70)
|
|
|
|
except Exception as e:
|
|
print(f"\n❌ Error during seeding: {str(e)}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Import models for the query
|
|
from django.db import models as django_models
|
|
models = django_models
|
|
|
|
main()
|