585 lines
24 KiB
Python
585 lines
24 KiB
Python
"""
|
|
Django management command to generate Saudi-influenced Operating Theatre data
|
|
Place this file in: operating_theatre/management/commands/generate_saudi_or_data.py
|
|
"""
|
|
|
|
import random
|
|
import uuid
|
|
from datetime import datetime, timedelta, date, time
|
|
from decimal import Decimal
|
|
from django.core.management.base import BaseCommand
|
|
from django.db import transaction
|
|
from django.utils import timezone
|
|
from faker import Faker
|
|
|
|
# Import your models
|
|
from operating_theatre.models import (
|
|
OperatingRoom,
|
|
ORBlock,
|
|
SurgicalCase,
|
|
SurgicalNote,
|
|
EquipmentUsage,
|
|
SurgicalNoteTemplate
|
|
)
|
|
from core.models import Tenant
|
|
from patients.models import PatientProfile
|
|
from django.contrib.auth import get_user_model
|
|
|
|
User = get_user_model()
|
|
fake = Faker('en_US')
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Generate Saudi-influenced Operating Theatre test data'
|
|
|
|
# Saudi cultural data
|
|
SAUDI_MALE_FIRST_NAMES = [
|
|
"Mohammed", "Abdullah", "Abdulrahman", "Khalid", "Fahad",
|
|
"Sultan", "Salman", "Saud", "Faisal", "Turki", "Ahmed",
|
|
"Omar", "Youssef", "Ibrahim", "Hamad", "Nasser", "Bandar",
|
|
"Mansour", "Majed", "Waleed", "Talal", "Rakan", "Yazeed"
|
|
]
|
|
|
|
SAUDI_FEMALE_FIRST_NAMES = [
|
|
"Nora", "Fatima", "Aisha", "Mariam", "Sarah", "Reem",
|
|
"Lama", "Hind", "Mona", "Amal", "Dalal", "Jawaher",
|
|
"Latifa", "Hessa", "Nouf", "Asma", "Khadija", "Layla"
|
|
]
|
|
|
|
SAUDI_FAMILY_NAMES = [
|
|
"Al-Saud", "Al-Rasheed", "Al-Qahtani", "Al-Otaibi", "Al-Dossari",
|
|
"Al-Harbi", "Al-Zahrani", "Al-Ghamdi", "Al-Shehri", "Al-Asmari",
|
|
"Al-Mutairi", "Al-Enezi", "Al-Shamari", "Al-Maliki", "Al-Johani"
|
|
]
|
|
|
|
SAUDI_HOSPITALS = [
|
|
"King Faisal Specialist Hospital",
|
|
"King Fahad Medical City",
|
|
"King Abdulaziz University Hospital",
|
|
"Prince Sultan Military Medical City",
|
|
"King Saud Medical City"
|
|
]
|
|
|
|
SAUDI_CITIES = [
|
|
"Riyadh", "Jeddah", "Mecca", "Medina", "Dammam",
|
|
"Khobar", "Dhahran", "Taif", "Tabuk", "Buraidah"
|
|
]
|
|
|
|
SURGICAL_PROCEDURES = {
|
|
"GENERAL": [
|
|
"Laparoscopic Cholecystectomy",
|
|
"Appendectomy",
|
|
"Hernia Repair",
|
|
"Bowel Resection",
|
|
"Gastric Bypass"
|
|
],
|
|
"CARDIAC": [
|
|
"Coronary Artery Bypass Grafting",
|
|
"Valve Replacement",
|
|
"Pacemaker Insertion"
|
|
],
|
|
"ORTHOPEDIC": [
|
|
"Total Knee Replacement",
|
|
"Total Hip Replacement",
|
|
"Spinal Fusion",
|
|
"ACL Reconstruction"
|
|
],
|
|
"NEURO": [
|
|
"Craniotomy",
|
|
"Brain Tumor Resection",
|
|
"Spinal Decompression"
|
|
]
|
|
}
|
|
|
|
MEDICAL_EQUIPMENT = [
|
|
"Da Vinci Surgical Robot",
|
|
"C-Arm Fluoroscopy",
|
|
"Zeiss Surgical Microscope",
|
|
"Harmonic Scalpel",
|
|
"LigaSure Device"
|
|
]
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--tenant',
|
|
type=str,
|
|
help='Tenant ID to use for data generation'
|
|
)
|
|
parser.add_argument(
|
|
'--rooms',
|
|
type=int,
|
|
default=5,
|
|
help='Number of operating rooms to create'
|
|
)
|
|
parser.add_argument(
|
|
'--blocks',
|
|
type=int,
|
|
default=3,
|
|
help='Number of OR blocks per room'
|
|
)
|
|
parser.add_argument(
|
|
'--cases',
|
|
type=int,
|
|
default=2,
|
|
help='Number of cases per block'
|
|
)
|
|
parser.add_argument(
|
|
'--clear',
|
|
action='store_true',
|
|
help='Clear existing OR data before generating'
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
self.stdout.write(self.style.SUCCESS('Starting Saudi OR data generation...'))
|
|
|
|
# Get or create tenant
|
|
tenant = self.get_or_create_tenant(options.get('tenant'))
|
|
|
|
# Clear existing data if requested
|
|
if options['clear']:
|
|
self.clear_existing_data(tenant)
|
|
|
|
# Generate data
|
|
with transaction.atomic():
|
|
# Create users (surgeons, nurses, etc.)
|
|
users = self.create_medical_staff(tenant, 20)
|
|
|
|
# Create patients
|
|
patients = self.create_patients(tenant, 30)
|
|
|
|
# Create surgical note templates
|
|
self.create_surgical_note_templates(tenant)
|
|
|
|
# Create operating rooms
|
|
rooms = self.create_operating_rooms(tenant, options['rooms'])
|
|
|
|
# Create OR blocks and surgical cases
|
|
for room in rooms:
|
|
self.create_or_blocks_with_cases(
|
|
room,
|
|
users,
|
|
patients,
|
|
options['blocks'],
|
|
options['cases']
|
|
)
|
|
|
|
self.stdout.write(self.style.SUCCESS('Data generation complete!'))
|
|
self.print_summary(tenant)
|
|
|
|
def get_or_create_tenant(self, tenant_id=1):
|
|
"""Get existing tenant or create a new one."""
|
|
if tenant_id:
|
|
try:
|
|
return Tenant.objects.get(id=tenant_id)
|
|
except Tenant.DoesNotExist:
|
|
self.stdout.write(self.style.WARNING(f'Tenant {tenant_id} not found, creating new one'))
|
|
|
|
# Create a new tenant
|
|
hospital_name = random.choice(self.SAUDI_HOSPITALS)
|
|
tenant, created = Tenant.objects.get_or_create(
|
|
name=hospital_name,
|
|
defaults={
|
|
'domain': hospital_name.lower().replace(' ', '-') + '.sa',
|
|
'is_active': True,
|
|
'settings': {
|
|
'country': 'Saudi Arabia',
|
|
'city': random.choice(self.SAUDI_CITIES),
|
|
'timezone': 'Asia/Riyadh',
|
|
'currency': 'SAR'
|
|
}
|
|
}
|
|
)
|
|
|
|
if created:
|
|
self.stdout.write(self.style.SUCCESS(f'Created tenant: {tenant.name}'))
|
|
|
|
return tenant
|
|
|
|
def clear_existing_data(self, tenant):
|
|
"""Clear existing OR data for the tenant."""
|
|
self.stdout.write('Clearing existing data...')
|
|
|
|
OperatingRoom.objects.filter(tenant=tenant).delete()
|
|
SurgicalNoteTemplate.objects.filter(tenant=tenant).delete()
|
|
|
|
self.stdout.write(self.style.SUCCESS('Existing data cleared'))
|
|
|
|
def create_medical_staff(self, tenant, count=20):
|
|
"""Create medical staff users."""
|
|
self.stdout.write('Creating medical staff...')
|
|
users = []
|
|
|
|
for i in range(count):
|
|
is_female = i % 3 == 0 # 1/3 female staff
|
|
|
|
if is_female:
|
|
first_name = random.choice(self.SAUDI_FEMALE_FIRST_NAMES)
|
|
title = random.choice(['Dr.', 'Nurse'])
|
|
else:
|
|
first_name = random.choice(self.SAUDI_MALE_FIRST_NAMES)
|
|
title = 'Dr.'
|
|
|
|
last_name = random.choice(self.SAUDI_FAMILY_NAMES)
|
|
username = f"{first_name.lower()}.{last_name.lower().replace('-', '')}_{i}"
|
|
email = f"{username}@{tenant.domain}"
|
|
|
|
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()
|
|
|
|
users.append(user)
|
|
|
|
self.stdout.write(self.style.SUCCESS(f'Created {len(users)} medical staff'))
|
|
return users
|
|
|
|
def create_patients(self, tenant, count=30):
|
|
"""Create patient profiles."""
|
|
self.stdout.write('Creating patients...')
|
|
patients = []
|
|
|
|
for i in range(count):
|
|
is_female = random.random() > 0.6
|
|
|
|
if is_female:
|
|
first_name = random.choice(self.SAUDI_FEMALE_FIRST_NAMES)
|
|
gender = 'F'
|
|
else:
|
|
first_name = random.choice(self.SAUDI_MALE_FIRST_NAMES)
|
|
gender = 'M'
|
|
|
|
last_name = random.choice(self.SAUDI_FAMILY_NAMES)
|
|
|
|
# Create user for patient
|
|
username = f"patient_{first_name.lower()}_{i}"
|
|
user, _ = User.objects.get_or_create(
|
|
username=username,
|
|
defaults={
|
|
'email': f"{username}@example.com",
|
|
'first_name': first_name,
|
|
'last_name': last_name
|
|
}
|
|
)
|
|
|
|
# Create patient profile
|
|
patient, created = PatientProfile.objects.get_or_create(
|
|
user=user,
|
|
defaults={
|
|
'tenant': tenant,
|
|
'patient_id': f"P{datetime.now().year}{i:06d}",
|
|
'date_of_birth': fake.date_of_birth(minimum_age=18, maximum_age=80),
|
|
'gender': gender,
|
|
'blood_group': random.choice(['A+', 'A-', 'B+', 'B-', 'O+', 'O-', 'AB+', 'AB-']),
|
|
'phone': f"+966{random.randint(500000000, 599999999)}",
|
|
'email': user.email,
|
|
'address': f"{random.randint(1, 999)} {random.choice(['King Fahd Road', 'Olaya Street', 'Tahlia Street'])}, {random.choice(self.SAUDI_CITIES)}",
|
|
'emergency_contact_name': random.choice(self.SAUDI_MALE_FIRST_NAMES) + ' ' + last_name,
|
|
'emergency_contact_phone': f"+966{random.randint(500000000, 599999999)}",
|
|
'national_id': f"{random.randint(1000000000, 2999999999)}",
|
|
'insurance_provider': random.choice(['Bupa', 'Tawuniya', 'MedGulf', 'Allianz', 'AXA']),
|
|
'insurance_number': f"INS{random.randint(100000, 999999)}"
|
|
}
|
|
)
|
|
|
|
patients.append(patient)
|
|
|
|
self.stdout.write(self.style.SUCCESS(f'Created {len(patients)} patients'))
|
|
return patients
|
|
|
|
def create_surgical_note_templates(self, tenant):
|
|
"""Create surgical note templates."""
|
|
self.stdout.write('Creating surgical note templates...')
|
|
|
|
specialties = ['GENERAL', 'CARDIAC', 'NEURO', 'ORTHOPEDIC', 'OBSTETRIC']
|
|
|
|
for specialty in specialties:
|
|
for template_type in ['Standard', 'Complex', 'Emergency']:
|
|
SurgicalNoteTemplate.objects.get_or_create(
|
|
tenant=tenant,
|
|
name=f"{specialty} - {template_type} Template",
|
|
defaults={
|
|
'description': f"Standard {template_type.lower()} template for {specialty.lower()} procedures",
|
|
'specialty': specialty,
|
|
'procedure_type': random.choice(self.SURGICAL_PROCEDURES.get(specialty, ['General'])),
|
|
'preoperative_diagnosis_template': "Preoperative Diagnosis: [Enter diagnosis]",
|
|
'planned_procedure_template': "Planned Procedure: [Enter procedure]",
|
|
'indication_template': "Indication: Patient presents with [symptoms] requiring intervention",
|
|
'procedure_performed_template': "Procedure: [Describe procedure performed]",
|
|
'surgical_approach_template': "Approach: [Describe approach]",
|
|
'findings_template': "Findings: [Describe findings]",
|
|
'technique_template': "Technique: Standard surgical technique employed",
|
|
'postoperative_diagnosis_template': "Postoperative Diagnosis: [Enter diagnosis]",
|
|
'is_active': True,
|
|
'is_default': template_type == 'Standard'
|
|
}
|
|
)
|
|
|
|
self.stdout.write(self.style.SUCCESS('Created surgical note templates'))
|
|
|
|
def create_operating_rooms(self, tenant, count=5):
|
|
"""Create operating rooms."""
|
|
self.stdout.write('Creating operating rooms...')
|
|
rooms = []
|
|
|
|
room_types = ['GENERAL', 'CARDIAC', 'NEURO', 'ORTHOPEDIC', 'OBSTETRIC']
|
|
|
|
for i in range(1, count + 1):
|
|
room_type = room_types[(i-1) % len(room_types)]
|
|
|
|
room = OperatingRoom.objects.create(
|
|
tenant=tenant,
|
|
room_number=f"OR-{i:03d}",
|
|
room_name=f"{room_type.title()} Operating Room {i}",
|
|
room_type=room_type,
|
|
status='AVAILABLE',
|
|
floor_number=random.randint(1, 4),
|
|
room_size=random.uniform(40, 80),
|
|
ceiling_height=random.uniform(3.0, 4.5),
|
|
temperature_min=18.0,
|
|
temperature_max=24.0,
|
|
humidity_min=30.0,
|
|
humidity_max=60.0,
|
|
air_changes_per_hour=random.randint(20, 25),
|
|
positive_pressure=True,
|
|
equipment_list=self._get_equipment_list(room_type),
|
|
special_features=self._get_special_features(room_type),
|
|
has_c_arm=room_type in ['ORTHOPEDIC', 'NEURO'],
|
|
has_ct=room_type in ['NEURO', 'CARDIAC'] and random.random() > 0.5,
|
|
has_mri=room_type == 'NEURO' and random.random() > 0.7,
|
|
has_ultrasound=True,
|
|
has_neuromonitoring=room_type in ['NEURO', 'ORTHOPEDIC'],
|
|
supports_robotic=room_type in ['GENERAL', 'CARDIAC'] and random.random() > 0.4,
|
|
supports_laparoscopic=room_type in ['GENERAL', 'OBSTETRIC'],
|
|
supports_microscopy=room_type in ['NEURO', 'OPHTHALMOLOGY'],
|
|
max_case_duration=random.randint(240, 720),
|
|
turnover_time=random.randint(20, 45),
|
|
cleaning_time=random.randint(30, 60),
|
|
required_nurses=random.randint(2, 4),
|
|
required_techs=random.randint(1, 3),
|
|
is_active=True,
|
|
accepts_emergency=True,
|
|
building=random.choice(['Main', 'East Wing', 'West Wing']),
|
|
wing=random.choice(['North', 'South', 'Central'])
|
|
)
|
|
|
|
rooms.append(room)
|
|
|
|
self.stdout.write(self.style.SUCCESS(f'Created {len(rooms)} operating rooms'))
|
|
return rooms
|
|
|
|
def _get_equipment_list(self, room_type):
|
|
"""Get equipment list for room type."""
|
|
basic = [
|
|
"Anesthesia Machine",
|
|
"Patient Monitor",
|
|
"Surgical Lights",
|
|
"Operating Table",
|
|
"Electrocautery Unit"
|
|
]
|
|
|
|
specialized = {
|
|
'CARDIAC': ["Heart-Lung Machine", "IABP"],
|
|
'NEURO': ["Surgical Microscope", "Neuronavigation"],
|
|
'ORTHOPEDIC': ["C-Arm", "Power Tools"],
|
|
'GENERAL': ["Laparoscopic Tower", "Harmonic Scalpel"]
|
|
}
|
|
|
|
equipment = basic.copy()
|
|
if room_type in specialized:
|
|
equipment.extend(specialized[room_type])
|
|
|
|
return equipment
|
|
|
|
def _get_special_features(self, room_type):
|
|
"""Get special features for room type."""
|
|
features = ["Laminar Flow", "HEPA Filtration"]
|
|
|
|
special = {
|
|
'CARDIAC': ["Hybrid OR Capability"],
|
|
'NEURO': ["Intraoperative MRI Compatible"],
|
|
'ORTHOPEDIC': ["Class 100 Clean Room"],
|
|
'OBSTETRIC': ["Neonatal Resuscitation Area"]
|
|
}
|
|
|
|
if room_type in special:
|
|
features.extend(special[room_type])
|
|
|
|
return features
|
|
|
|
def create_or_blocks_with_cases(self, room, users, patients, num_blocks, num_cases):
|
|
"""Create OR blocks with surgical cases."""
|
|
self.stdout.write(f'Creating blocks for {room.room_number}...')
|
|
|
|
surgeons = [u for u in users if 'Dr.' in u.first_name or random.random() > 0.5]
|
|
nurses = [u for u in users if u not in surgeons]
|
|
|
|
for block_num in range(num_blocks):
|
|
# Create OR block
|
|
block_date = timezone.now().date() + timedelta(days=random.randint(1, 30))
|
|
start_hour = random.choice([7, 8, 9, 13])
|
|
duration = random.randint(2, 6)
|
|
|
|
block = ORBlock.objects.create(
|
|
operating_room=room,
|
|
date=block_date,
|
|
start_time=time(start_hour, 0),
|
|
end_time=time((start_hour + duration) % 24, 0),
|
|
block_type='SCHEDULED',
|
|
primary_surgeon=random.choice(surgeons),
|
|
service=room.room_type,
|
|
status=random.choice(['SCHEDULED', 'ACTIVE', 'COMPLETED']),
|
|
allocated_minutes=duration * 60,
|
|
used_minutes=random.randint(duration * 45, duration * 60),
|
|
special_equipment=random.sample(self.MEDICAL_EQUIPMENT, k=random.randint(0, 2)),
|
|
notes=f"Block for {room.room_type} procedures"
|
|
)
|
|
|
|
# Add assistant surgeons
|
|
if surgeons:
|
|
assistants = random.sample(surgeons, k=min(random.randint(0, 2), len(surgeons)))
|
|
block.assistant_surgeons.set(assistants)
|
|
|
|
# Create surgical cases for this block
|
|
for case_num in range(random.randint(1, num_cases)):
|
|
self.create_surgical_case(block, patients, surgeons, nurses)
|
|
|
|
def create_surgical_case(self, block, patients, surgeons, nurses):
|
|
"""Create a surgical case."""
|
|
procedure_type = block.service
|
|
procedures = self.SURGICAL_PROCEDURES.get(procedure_type, ['General Surgery'])
|
|
|
|
case_time = datetime.combine(block.date, block.start_time) + timedelta(minutes=random.randint(0, 120))
|
|
duration = random.randint(30, 240)
|
|
|
|
case = SurgicalCase.objects.create(
|
|
or_block=block,
|
|
patient=random.choice(patients),
|
|
primary_surgeon=block.primary_surgeon,
|
|
anesthesiologist=random.choice(surgeons) if surgeons else block.primary_surgeon,
|
|
circulating_nurse=random.choice(nurses) if nurses else None,
|
|
scrub_nurse=random.choice(nurses) if nurses else None,
|
|
primary_procedure=random.choice(procedures),
|
|
secondary_procedures=[],
|
|
procedure_codes=[f"CPT{random.randint(10000, 99999)}" for _ in range(random.randint(1, 3))],
|
|
case_type=random.choice(['ELECTIVE', 'URGENT', 'EMERGENCY']),
|
|
approach=random.choice(['OPEN', 'LAPAROSCOPIC', 'ROBOTIC']),
|
|
anesthesia_type=random.choice(['GENERAL', 'REGIONAL', 'SPINAL']),
|
|
scheduled_start=timezone.make_aware(case_time),
|
|
estimated_duration=duration,
|
|
status=random.choice(['SCHEDULED', 'COMPLETED', 'IN_PROGRESS']),
|
|
diagnosis=self._get_diagnosis(),
|
|
diagnosis_codes=[f"ICD10-{random.choice(['K', 'I', 'M'])}{random.randint(10, 99)}.{random.randint(0, 9)}"],
|
|
clinical_notes="Patient prepared for surgery as per protocol",
|
|
special_equipment=random.sample(self.MEDICAL_EQUIPMENT, k=random.randint(0, 2)),
|
|
patient_position=random.choice(['SUPINE', 'PRONE', 'LATERAL']),
|
|
estimated_blood_loss=random.randint(10, 500) if random.random() > 0.5 else None
|
|
)
|
|
|
|
# Add assistant surgeons
|
|
if surgeons:
|
|
assistants = random.sample(surgeons, k=min(random.randint(0, 2), len(surgeons)))
|
|
case.assistant_surgeons.set(assistants)
|
|
|
|
# Create surgical note for completed cases
|
|
if case.status == 'COMPLETED':
|
|
self.create_surgical_note(case)
|
|
|
|
# Create equipment usage
|
|
self.create_equipment_usage(case)
|
|
|
|
return case
|
|
|
|
def _get_diagnosis(self):
|
|
"""Get a random diagnosis."""
|
|
diagnoses = [
|
|
"Acute Appendicitis",
|
|
"Cholelithiasis",
|
|
"Inguinal Hernia",
|
|
"Coronary Artery Disease",
|
|
"Spinal Stenosis",
|
|
"Osteoarthritis",
|
|
"Brain Tumor",
|
|
"Breast Cancer"
|
|
]
|
|
return random.choice(diagnoses)
|
|
|
|
def create_surgical_note(self, case):
|
|
"""Create surgical note for completed case."""
|
|
SurgicalNote.objects.create(
|
|
surgical_case=case,
|
|
surgeon=case.primary_surgeon,
|
|
preoperative_diagnosis=case.diagnosis,
|
|
planned_procedure=case.primary_procedure,
|
|
indication="Symptomatic disease requiring surgical intervention",
|
|
procedure_performed=case.primary_procedure,
|
|
surgical_approach=f"{case.approach} approach utilized",
|
|
findings="As per preoperative diagnosis",
|
|
technique="Standard surgical technique employed",
|
|
postoperative_diagnosis=case.diagnosis,
|
|
condition=random.choice(['STABLE', 'GOOD', 'FAIR']),
|
|
disposition=random.choice(['RECOVERY', 'ICU', 'WARD']),
|
|
complications="None",
|
|
estimated_blood_loss=case.estimated_blood_loss or random.randint(10, 200),
|
|
specimens="Sent to pathology" if random.random() > 0.5 else None,
|
|
closure="Layered closure with absorbable sutures",
|
|
postop_instructions="Standard postoperative care protocol",
|
|
follow_up="2 weeks in surgical clinic",
|
|
status='SIGNED',
|
|
signed_datetime=timezone.now()
|
|
)
|
|
|
|
def create_equipment_usage(self, case):
|
|
"""Create equipment usage records."""
|
|
equipment_types = [
|
|
('Surgical Drape Set', 'DISPOSABLE', 1, 'SET', 150.00),
|
|
('Harmonic Scalpel', 'SURGICAL_INSTRUMENT', 1, 'EACH', 2500.00),
|
|
('Suture Pack', 'DISPOSABLE', 3, 'PACK', 75.00),
|
|
('Surgical Gloves', 'DISPOSABLE', 10, 'PAIR', 5.00)
|
|
]
|
|
|
|
for name, eq_type, qty, unit, cost in random.sample(equipment_types, k=random.randint(2, 4)):
|
|
EquipmentUsage.objects.create(
|
|
surgical_case=case,
|
|
equipment_name=name,
|
|
equipment_type=eq_type,
|
|
manufacturer=random.choice(['Medtronic', 'Johnson & Johnson', 'Stryker']),
|
|
quantity_used=qty,
|
|
unit_of_measure=unit,
|
|
unit_cost=Decimal(str(cost)),
|
|
total_cost=Decimal(str(cost * qty)),
|
|
lot_number=f"LOT{random.randint(10000, 99999)}",
|
|
expiration_date=timezone.now().date() + timedelta(days=random.randint(180, 730)),
|
|
sterilization_date=timezone.now().date() - timedelta(days=random.randint(1, 7)),
|
|
recorded_by=case.primary_surgeon
|
|
)
|
|
|
|
def print_summary(self, tenant):
|
|
"""Print summary of generated data."""
|
|
self.stdout.write("\n" + "="*60)
|
|
self.stdout.write(self.style.SUCCESS("Data Generation Summary"))
|
|
self.stdout.write("="*60)
|
|
|
|
rooms = OperatingRoom.objects.filter(tenant=tenant)
|
|
blocks = ORBlock.objects.filter(operating_room__tenant=tenant)
|
|
cases = SurgicalCase.objects.filter(or_block__operating_room__tenant=tenant)
|
|
notes = SurgicalNote.objects.filter(surgical_case__or_block__operating_room__tenant=tenant)
|
|
equipment = EquipmentUsage.objects.filter(surgical_case__or_block__operating_room__tenant=tenant)
|
|
templates = SurgicalNoteTemplate.objects.filter(tenant=tenant)
|
|
|
|
self.stdout.write(f"Tenant: {tenant.name}")
|
|
self.stdout.write(f"Operating Rooms: {rooms.count()}")
|
|
self.stdout.write(f"OR Blocks: {blocks.count()}")
|
|
self.stdout.write(f"Surgical Cases: {cases.count()}")
|
|
self.stdout.write(f"Surgical Notes: {notes.count()}")
|
|
self.stdout.write(f"Equipment Usage Records: {equipment.count()}")
|
|
self.stdout.write(f"Surgical Templates: {templates.count()}")
|
|
self.stdout.write("="*60) |