hospital-management/inpatients_data.py
2025-10-06 15:25:37 +03:00

617 lines
28 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import django
# Setup Django (keep or remove if you convert this to a management command)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hospital_management.settings')
django.setup()
import random
import uuid
from datetime import datetime, timedelta, date, time as dt_time
from django.utils import timezone
from django.core.exceptions import ObjectDoesNotExist
from inpatients.models import Ward, Bed, Admission, Transfer, DischargeSummary
from accounts.models import User
from patients.models import PatientProfile
from core.models import Tenant
# Facility management FKs
from facility_management.models import Building, Floor, Asset
# Optional: Operating Room (if your app exists); otherwise well leave OR unset
try:
from operating_theatre.models import OperatingRoom
except Exception:
OperatingRoom = None
# ------------------------------
# Saudi-inspired constants
# ------------------------------
SAUDI_WARD_NAMES = [
'King Fahd Ward', 'King Abdulaziz Ward', 'Prince Sultan Ward', 'Princess Noura Ward',
'Al-Faisal Ward', 'Al-Rashid Ward', 'Al-Salam Ward', 'Al-Noor Ward',
'Al-Shifa Ward', 'Al-Amal Ward', 'Al-Rahma Ward', 'Al-Baraka Ward',
'Cardiac Care Unit', 'Intensive Care Unit', 'Pediatric ICU', 'Neonatal ICU',
'Medical Ward A', 'Medical Ward B', 'Surgical Ward A', 'Surgical Ward B',
'Orthopedic Ward', 'Maternity Ward', 'Pediatric Ward', 'Oncology Ward'
]
SAUDI_SPECIALTIES = [
Ward.WardSpecialty.GENERAL_MEDICINE, Ward.WardSpecialty.SURGERY,
Ward.WardSpecialty.CARDIOLOGY, Ward.WardSpecialty.NEUROLOGY,
Ward.WardSpecialty.ONCOLOGY, Ward.WardSpecialty.PEDIATRICS,
Ward.WardSpecialty.OBSTETRICS, Ward.WardSpecialty.GYNECOLOGY,
Ward.WardSpecialty.ORTHOPEDICS, Ward.WardSpecialty.PSYCHIATRY,
Ward.WardSpecialty.EMERGENCY, Ward.WardSpecialty.CRITICAL_CARE,
Ward.WardSpecialty.REHABILITATION, Ward.WardSpecialty.OTHER
]
SAUDI_WINGS = ['North Wing', 'South Wing', 'East Wing', 'West Wing', 'Central Wing', 'VIP Wing', 'Family Wing', 'Isolation Wing']
SAUDI_COMMON_DIAGNOSES = [
'Diabetes Mellitus Type 2', 'Hypertension', 'Coronary Artery Disease',
'Chronic Kidney Disease', 'Heart Failure', 'Pneumonia', 'Gastritis',
'Cholecystitis', 'Appendicitis', 'Urinary Tract Infection',
'Acute Myocardial Infarction', 'Stroke', 'Pulmonary Embolism',
'Deep Vein Thrombosis', 'Sepsis', 'Acute Renal Failure',
'Chronic Obstructive Pulmonary Disease', 'Asthma', 'Anemia'
]
SAUDI_SURGICAL_PROCEDURES = [
'Coronary Artery Bypass Graft', 'Percutaneous Coronary Intervention',
'Appendectomy', 'Cholecystectomy', 'Hernia Repair', 'Hip Replacement',
'Knee Replacement', 'Cataract Surgery', 'Thyroidectomy',
'Prostatectomy', 'Hysterectomy', 'Cesarean Section',
'Arthroscopy', 'Endoscopy', 'Colonoscopy', 'Angioplasty'
]
SAUDI_MEDICATIONS = [
'Metformin', 'Insulin', 'Lisinopril', 'Amlodipine', 'Atorvastatin',
'Aspirin', 'Warfarin', 'Furosemide', 'Omeprazole', 'Paracetamol',
'Amoxicillin', 'Ciprofloxacin', 'Prednisolone', 'Morphine', 'Tramadol'
]
# ------------------------------
# Helpers
# ------------------------------
def random_ratio_value():
# return nurse-to-patient ratio as float (e.g., 1:4 -> 0.25)
patients_per_nurse = random.choice([4, 5, 6, 8])
return round(1.0 / patients_per_nurse, 3)
def pick_tenant_users(tenant, roles=None, limit=20):
qs = User.objects.filter(tenant=tenant, is_active=True)
if roles:
qs = qs.filter(employee_profile__role__in=roles)
return list(qs[:limit])
def ensure_building_and_floors(tenant, floors_count=5):
"""
Ensure at least 1 building with a few floors exists for the tenant.
Returns (building, floors_list)
"""
bld = Building.objects.filter(tenant=tenant).first()
if not bld:
# Minimal building compatible with your facility_management.Building model
bld = Building.objects.create(
tenant=tenant,
name=f"{tenant.name} Medical Tower",
code=f"T{tenant.id}-BLD-01",
address=f"{tenant.name} Campus, KSA",
building_type=Building.BuildingType.CLINICAL
)
floors = list(Floor.objects.filter(building=bld).order_by('floor_number'))
if not floors:
for n in range(floors_count):
floors.append(Floor.objects.create(
building=bld,
floor_number=n,
name=f"Level {n}",
))
return bld, floors
def any_building_floor(tenant):
b = Building.objects.filter(tenant=tenant).order_by('?').first()
if not b:
b, _floors = ensure_building_and_floors(tenant)
f = Floor.objects.filter(building=b).order_by('?').first()
if not f:
# create one more floor
f = Floor.objects.create(building=b, floor_number=0, name="Level 0")
return b, f
def friendly_phone():
return f"+966-11-{random.randint(100, 999)}-{random.randint(1000, 9999)}"
def ward_id_for(tenant):
# unique per (tenant, ward_id)
return f"WRD-{timezone.now().strftime('%Y%m%d')}-{random.randint(1000,9999)}"
# ------------------------------
# Ward creation (FK to Building/Floor)
# ------------------------------
def create_saudi_wards(tenants, wards_per_tenant=12):
wards = []
for tenant in tenants:
# Ensure at least one building/floor exists
building, floor = any_building_floor(tenant)
nurses = pick_tenant_users(tenant, roles=['NURSE', 'NURSE_PRACTITIONER'], limit=30)
physicians = pick_tenant_users(tenant, roles=['PHYSICIAN', 'PHYSICIAN_ASSISTANT'], limit=30)
created_by = (nurses or physicians or pick_tenant_users(tenant, None, 1) or [None])[0]
for _ in range(wards_per_tenant):
name = random.choice(SAUDI_WARD_NAMES)
# Make name unique within tenant if needed
orig = name
suffix = 1
while Ward.objects.filter(tenant=tenant, name=name).exists():
name = f"{orig} {suffix}"
suffix += 1
# Choose building/floor (random per ward)
bld, flr = any_building_floor(tenant)
total_beds = random.randint(20, 60)
private_rooms = random.randint(5, 15)
semi_private_rooms = random.randint(8, 20)
shared_rooms = max(0, total_beds - private_rooms - (semi_private_rooms * 2))
ward = Ward.objects.create(
tenant=tenant,
ward_id=ward_id_for(tenant),
name=name,
description=f"Specialized ward providing comprehensive inpatient care",
ward_type=random.choice([w[0] for w in Ward.WardType.choices]),
specialty=random.choice(SAUDI_SPECIALTIES),
total_beds=total_beds,
private_rooms=private_rooms,
semi_private_rooms=semi_private_rooms,
shared_rooms=shared_rooms,
building=bld,
floor=flr,
wing=random.choice(SAUDI_WINGS),
nurse_manager=(random.choice(nurses) if nurses else None),
min_nurses_day=random.randint(8, 15),
min_nurses_night=random.randint(5, 10),
nurse_to_patient_ratio=random_ratio_value(),
equipment_list=[
'Cardiac Monitors', 'IV Pumps', 'Ventilators', 'Defibrillators',
'Oxygen Supply', 'Suction Units', 'Patient Beds', 'Wheelchairs'
],
special_features=[
'Prayer Room', 'Family Waiting Area', 'Isolation Rooms',
'Nurse Station', 'Clean Utility Room', 'Dirty Utility Room'
],
admission_criteria="Patients requiring specialized inpatient care",
age_restrictions=random.choice([
{"min_age": 0, "max_age": None},
{"min_age": 16, "max_age": None},
{"min_age": 0, "max_age": 18},
]),
gender_restrictions=random.choice([g[0] for g in Ward.GenderRestriction.choices]),
is_active=True,
is_accepting_admissions=random.choice([True, True, True, False]),
closure_reason=None,
phone_number=friendly_phone(),
extension=f"{random.randint(1000, 9999)}",
created_by=created_by
)
# Attending physicians
if physicians:
ward.attending_physicians.set(random.sample(physicians, k=min(len(physicians), random.randint(2, 5))))
wards.append(ward)
print(f"Created {wards_per_tenant} wards for {tenant.name}")
return wards
# ------------------------------
# Beds (FK to Ward) + equipment M2M to Assets in same building
# ------------------------------
def create_saudi_beds(wards):
beds = []
for ward in wards:
bed_types = [b[0] for b in Bed.BedType.choices]
room_types = [r[0] for r in Bed.RoomType.choices]
statuses = [s[0] for s in Bed.BedStatus.choices]
cleaning_levels = [c[0] for c in Bed.CleaningLevel.choices]
positions = [p[0] for p in Bed.BedPosition.choices]
# Nearby facility assets (optional)
assets_qs = Asset.objects.filter(building=ward.building)
ward_floor_num = ward.floor.floor_number if hasattr(ward.floor, "floor_number") else 0
for num in range(1, ward.total_beds + 1):
bed_number = f"{ward.name[:3].upper()}-{num:03d}"
room_type = random.choice(room_types)
status = random.choice(statuses)
# Room number: floor digit + random
room_number = f"{ward_floor_num}{random.randint(10, 99)}"
# Bed position logic based on room type
if room_type == Bed.RoomType.SHARED:
pos_choices = positions[:4] # A-D
elif room_type == Bed.RoomType.SEMI_PRIVATE:
pos_choices = positions[:2] # A-B
else:
pos_choices = [positions[0]] # A
bed_position = random.choice(pos_choices)
bed = Bed.objects.create(
ward=ward,
bed_number=bed_number,
room_number=room_number,
bed_type=random.choice(bed_types),
is_operational=True,
is_active=True,
is_out_of_service=False,
room_type=room_type,
status=status,
current_admission=None,
occupied_since=(timezone.now() - timedelta(days=random.randint(1, 30))) if status == 'OCCUPIED' else None,
reserved_until=(timezone.now() + timedelta(hours=random.randint(1, 24))) if (status == 'RESERVED' and random.choice([True, False])) else None,
features=[
'Adjustable Height', 'Side Rails', 'Trendelenburg', 'Reverse Trendelenburg',
'Patient Controls', 'LED Reading Light'
],
last_maintenance=timezone.now() - timedelta(days=random.randint(7, 90)),
next_maintenance=timezone.now() + timedelta(days=random.randint(30, 180)),
maintenance_notes="Routine maintenance completed" if random.choice([True, False]) else None,
last_cleaned=timezone.now() - timedelta(hours=random.randint(1, 24)),
cleaned_by=None,
cleaning_level=random.choice(cleaning_levels),
blocked_reason="Maintenance required" if status == 'BLOCKED' else None,
blocked_by=None,
blocked_until=(timezone.now() + timedelta(hours=random.randint(2, 48))) if status == 'BLOCKED' else None,
bed_position=bed_position,
created_by=ward.created_by
)
# Attach up to 2 assets in same building
if assets_qs.exists() and random.random() < 0.6:
bed.equipment.add(*assets_qs.order_by('?')[:random.randint(1, 2)])
beds.append(bed)
print(f"Created {len(beds)} beds across all wards")
return beds
# ------------------------------
# Admissions (uses enums + FKs) and sets bed occupancy correctly
# ------------------------------
def create_saudi_admissions(tenants, beds, admissions_per_tenant=100):
admissions = []
for tenant in tenants:
patients = list(PatientProfile.objects.filter(tenant=tenant))
physicians = pick_tenant_users(tenant, roles=['PHYSICIAN', 'PHYSICIAN_ASSISTANT'], limit=50)
nurses = pick_tenant_users(tenant, roles=['NURSE', 'NURSE_PRACTITIONER'], limit=50)
tenant_beds = [b for b in beds if b.ward.tenant_id == tenant.id]
if not patients or not physicians or not tenant_beds:
print(f"⚠️ Skipping tenant {tenant.name}: patients={len(patients)}, physicians={len(physicians)}, beds={len(tenant_beds)}")
continue
creator = (physicians or nurses or [None])[0]
for _ in range(admissions_per_tenant):
patient = random.choice(patients)
admitting_physician = random.choice(physicians)
attending_physician = random.choice(physicians)
current_bed = random.choice(tenant_beds)
current_ward = current_bed.ward
admission_dt = timezone.now() - timedelta(days=random.randint(0, 30))
status = random.choice([s[0] for s in Admission.AdmissionStatus.choices])
discharge_dt = None
discharge_disp = None
if status == Admission.AdmissionStatus.DISCHARGED:
discharge_dt = admission_dt + timedelta(days=random.randint(1, 14))
discharge_disp = random.choice([d[0] for d in Admission.DischargeDisposition.choices])
admission = Admission.objects.create(
tenant=tenant,
patient=patient,
admission_datetime=admission_dt,
admission_type=random.choice([t[0] for t in Admission.AdmissionType.choices]),
admission_source=random.choice([s[0] for s in Admission.AdmissionSource.choices]),
chief_complaint=random.choice([
'Chest pain', 'Shortness of breath', 'Abdominal pain',
'Fever and chills', 'Weakness', 'Nausea and vomiting',
'Headache', 'Dizziness', 'Joint pain', 'Back pain'
]),
admitting_diagnosis=random.choice(SAUDI_COMMON_DIAGNOSES),
secondary_diagnoses=[random.choice(SAUDI_COMMON_DIAGNOSES) for _ in range(random.randint(0, 3))],
admitting_physician=admitting_physician,
attending_physician=attending_physician,
current_ward=current_ward,
current_bed=current_bed,
status=status,
priority=random.choice([p[0] for p in Admission.AdmissionPriority.choices]),
acuity_level=random.randint(1, 5),
insurance_verified=random.choice([True, False]),
authorization_number=(f"AUTH-{random.randint(100000, 999999)}" if random.choice([True, False]) else None),
estimated_length_of_stay=random.randint(2, 14),
discharge_planning_started=random.choice([True, False]),
discharge_planner=(random.choice(nurses) if nurses and random.random() < 0.5 else None),
anticipated_discharge_date=admission_dt.date() + timedelta(days=random.randint(1, 10)),
discharge_datetime=discharge_dt,
discharge_disposition=discharge_disp,
isolation_required=random.choice([True, False, False, False]),
isolation_type=(random.choice([i[0] for i in Admission.IsolationType.choices]) if random.random() < 0.25 else None),
special_needs=(['Interpreter services', 'Dietary restrictions', 'Mobility assistance'] if random.random() < 0.3 else []),
allergies=(random.sample(['Penicillin', 'Sulfa drugs', 'Shellfish', 'Latex', 'Contrast dye'], random.randint(0, 3))),
alerts=(random.sample(['Fall risk', 'Suicide risk', 'Flight risk', 'Combative', 'Infection control', 'Allergy alert'], random.randint(0, 3))),
code_status=random.choice([c[0] for c in Admission.CodeStatus.choices]),
advance_directive=random.choice([True, False]),
healthcare_proxy=(None if random.random() < 0.7 else "Next of kin on file"),
admission_notes=f"Admitted with {random.choice(SAUDI_COMMON_DIAGNOSES).lower()} requiring inpatient management",
created_by=creator
)
# Consulting physicians
if physicians:
admission.consulting_physicians.set(random.sample(physicians, random.randint(0, min(3, len(physicians)))))
# Update bed status according to admission status
if status in [Admission.AdmissionStatus.ADMITTED, Admission.AdmissionStatus.TRANSFERRED]:
current_bed.status = Bed.BedStatus.OCCUPIED
current_bed.current_admission = admission
current_bed.occupied_since = admission_dt
current_bed.reserved_until = None
current_bed.save()
elif status == Admission.AdmissionStatus.PENDING:
# reserve a pending bed sometimes
if random.random() < 0.5:
current_bed.status = Bed.BedStatus.RESERVED
current_bed.reserved_until = admission_dt + timedelta(hours=random.randint(2, 12))
current_bed.save()
admissions.append(admission)
print(f"Created {admissions_per_tenant} admissions for {tenant.name}")
return admissions
# ------------------------------
# Transfers (matches enums, timestamps; requested_datetime is auto_now_add)
# ------------------------------
def create_saudi_transfers(admissions):
transfers = []
for admission in random.sample(admissions, int(len(admissions) * 0.3) or 0):
# Find an available bed in a different ward of same tenant
available_beds = Bed.objects.filter(
ward__tenant=admission.tenant,
status=Bed.BedStatus.AVAILABLE
).exclude(ward=admission.current_ward)
if not available_beds.exists():
continue
to_bed = available_beds.order_by('?').first()
to_ward = to_bed.ward
# Requesting user (prefer clinical roles)
requesters = pick_tenant_users(admission.tenant,
roles=['PHYSICIAN', 'NURSE', 'NURSE_PRACTITIONER', 'PHYSICIAN_ASSISTANT'],
limit=50) or pick_tenant_users(admission.tenant, None, 5)
if not requesters:
continue
requested_by = random.choice(requesters)
status = random.choice([s[0] for s in Transfer.TransferStatus.choices])
scheduled_datetime = timezone.now() + timedelta(hours=random.randint(1, 12)) if status in ['APPROVED', 'SCHEDULED', 'IN_PROGRESS', 'COMPLETED'] else None
actual_datetime = scheduled_datetime + timedelta(minutes=random.randint(5, 60)) if status in ['IN_PROGRESS', 'COMPLETED'] else None
transfer = Transfer.objects.create(
admission=admission,
patient=admission.patient,
transfer_type=random.choice([t[0] for t in Transfer.TransferType.choices]),
from_ward=admission.current_ward,
from_bed=admission.current_bed,
to_ward=to_ward,
to_bed=to_bed,
scheduled_datetime=scheduled_datetime,
actual_datetime=actual_datetime,
status=status,
reason=random.choice([
'Clinical deterioration', 'Need for higher level of care',
'Bed availability', 'Specialist consultation required',
'Patient preference', 'Isolation requirements'
]),
priority=random.choice([p[0] for p in Transfer.TransferPriority.choices]),
requested_by=requested_by,
approved_by=None,
completed_by=None,
transport_method=random.choice([m[0] for m in Transfer.TransportMethod.choices]),
equipment_needed=(['IV pole', 'Oxygen tank', 'Monitor'] if random.random() < 0.4 else []),
supplies_needed=(['Medications', 'Patient chart', 'Personal items'] if random.random() < 0.4 else []),
patient_condition=random.choice([pc[0] for pc in Transfer.TransferPatientCondition.choices]),
vital_signs={
'blood_pressure': f"{random.randint(90, 180)}/{random.randint(60, 100)}",
'heart_rate': random.randint(60, 120),
'respiratory_rate': random.randint(12, 24),
'temperature': round(random.uniform(36.0, 39.0), 1),
'oxygen_saturation': random.randint(92, 100)
},
handoff_report=f"Handoff given to receiving nurse; patient for {random.choice(['specialized care', 'higher acuity monitoring', 'isolation'])}",
medications_transferred=random.sample(SAUDI_MEDICATIONS, random.randint(0, 4)),
delay_reason=("Bed not ready" if status in ['APPROVED', 'SCHEDULED'] and random.random() < 0.3 else None),
complications=("None noted" if status == 'COMPLETED' else None),
notes=(f"Transfer completed successfully" if status == 'COMPLETED' else None)
)
# Transport team
nurses = pick_tenant_users(admission.tenant, roles=['NURSE', 'NURSE_PRACTITIONER'], limit=20)
if nurses:
transfer.transport_team.set(random.sample(nurses, k=min(len(nurses), random.randint(1, 3))))
# If completed, update bed occupancy and admission location
if status == 'COMPLETED':
# free from_bed
if transfer.from_bed:
transfer.from_bed.status = Bed.BedStatus.AVAILABLE
transfer.from_bed.current_admission = None
transfer.from_bed.occupied_since = None
transfer.from_bed.save()
# occupy to_bed
to_bed.status = Bed.BedStatus.OCCUPIED
to_bed.current_admission = admission
to_bed.occupied_since = actual_datetime or timezone.now()
to_bed.save()
# update admission location
admission.current_ward = to_ward
admission.current_bed = to_bed
admission.save(update_fields=['current_ward', 'current_bed'])
transfers.append(transfer)
print(f"Created {len(transfers)} transfers")
return transfers
# ------------------------------
# Discharge Summaries (match choices/fields)
# ------------------------------
def create_saudi_discharge_summaries(admissions):
summaries = []
discharged = [a for a in admissions if a.status == Admission.AdmissionStatus.DISCHARGED and a.discharge_datetime]
for admission in discharged:
los = (admission.discharge_datetime.date() - admission.admission_datetime.date()).days
discharging_physician = admission.attending_physician
summary = DischargeSummary.objects.create(
admission=admission,
discharge_date=admission.discharge_datetime.date(),
discharge_time=admission.discharge_datetime.time(),
length_of_stay=max(los, 0),
admission_diagnosis=admission.admitting_diagnosis,
final_diagnosis=random.choice(SAUDI_COMMON_DIAGNOSES),
secondary_diagnoses=admission.secondary_diagnoses or [],
procedures_performed=random.sample(SAUDI_SURGICAL_PROCEDURES, random.randint(0, 3)),
hospital_course=f"Admitted with {admission.admitting_diagnosis.lower()} and responded well to treatment.",
complications=(None if random.random() < 0.7 else "Minor wound infection, resolved with antibiotics"),
discharge_medications=random.sample(SAUDI_MEDICATIONS, random.randint(3, 8)),
medication_changes=(None if random.random() < 0.5 else "Adjusted antihypertensives and insulin dosing."),
activity_restrictions=random.choice([
None, "No lifting >10 kg for 2 weeks", "Bedrest x 24 hours", "Activity as tolerated"
]),
diet_instructions=random.choice([
None, "Diabetic diet", "Low sodium diet", "Cardiac diet", "Regular diet"
]),
wound_care=(None if random.random() < 0.6 else "Keep incision clean and dry. Change dressing daily."),
special_instructions=(None if random.random() < 0.5 else "Monitor blood pressure and blood sugar at home."),
follow_up_appointments=[
{"provider": "Primary Care Physician", "date": (admission.discharge_datetime.date() + timedelta(days=7)).isoformat(), "time": "10:00"},
{"provider": "Cardiologist", "date": (admission.discharge_datetime.date() + timedelta(days=14)).isoformat(), "time": "14:00"}
],
follow_up_instructions="Follow up with PCP in 1 week and specialist in 2 weeks.",
warning_signs="Fever >38.5°C, chest pain, worsening shortness of breath.",
when_to_call="Call physician or return to ED if any warning signs occur.",
discharge_disposition=(admission.discharge_disposition or 'HOME'),
discharge_location=("Home" if (admission.discharge_disposition or 'HOME') == 'HOME' else "Rehabilitation facility"),
transportation_arranged=random.choice([True, False]),
transportation_method=random.choice([t[0] for t in DischargeSummary.TransportationMethod.choices]),
durable_medical_equipment=(random.sample(['Walker', 'Hospital bed', 'Oxygen concentrator'], random.randint(0, 2))),
supplies_provided=(random.sample(['Wound care supplies', 'Medications', 'Educational materials'], random.randint(0, 3))),
education_provided=['Disease management', 'Medication administration', 'Signs and symptoms to report'],
education_materials=['Discharge instructions', 'Medication list', 'Educational brochures'],
patient_understanding=random.choice([p[0] for p in DischargeSummary.PatientUnderstanding.choices]),
discharge_planner=(admission.discharge_planner or None),
social_worker_involved=random.choice([True, False]),
case_manager_involved=random.choice([True, False]),
readmission_risk=random.choice([r[0] for r in DischargeSummary.ReadmissionRisk.choices]),
patient_satisfaction=random.randint(6, 10), # 110 scale
discharging_physician=discharging_physician,
primary_nurse=None,
summary_completed=True,
summary_signed=True,
patient_copy_provided=True,
created_by=discharging_physician
)
summaries.append(summary)
print(f"Created {len(summaries)} discharge summaries")
return summaries
# ------------------------------
# Main
# ------------------------------
def main():
print("Starting Saudi Inpatients Data Generation (refactored for updated models)…")
tenants = list(Tenant.objects.all())
if not tenants:
print("❌ No tenants found. Seed core/tenants first.")
return
# 1) Wards
print("\n1. Creating Wards …")
wards = create_saudi_wards(tenants, wards_per_tenant=10)
# 2) Beds
print("\n2. Creating Beds …")
beds = create_saudi_beds(wards)
# 3) Admissions
print("\n3. Creating Admissions …")
admissions = create_saudi_admissions(tenants, beds, admissions_per_tenant=80)
# 4) Transfers
print("\n4. Creating Transfers …")
transfers = create_saudi_transfers(admissions)
# 5) Discharge Summaries
print("\n5. Creating Discharge Summaries …")
summaries = create_saudi_discharge_summaries(admissions)
print("\n✅ Done.")
print(f"📊 Summary:")
print(f" - Wards: {len(wards)}")
print(f" - Beds: {len(beds)}")
print(f" - Admissions: {len(admissions)}")
print(f" - Transfers: {len(transfers)}")
print(f" - Discharge Summaries: {len(summaries)}")
# Status distribution (nice labels)
from collections import Counter
st = Counter([a.status for a in admissions])
print("\n🏥 Admission Status Distribution:")
for k, v in st.items():
print(f" - {k}: {v}")
# Nurse-to-patient ratios used
print("\n👩‍⚕️ Nurse-to-Patient Ratios Used:")
seen = set()
for w in wards:
if w.nurse_to_patient_ratio and w.nurse_to_patient_ratio > 0:
p = int(round(1 / w.nurse_to_patient_ratio))
seen.add(f"1:{p}")
for r in sorted(seen):
print(f" - {r}")
return {
'wards': wards,
'beds': beds,
'admissions': admissions,
'transfers': transfers,
'summaries': summaries
}
if __name__ == "__main__":
main()