Marwan Alwali ab2c4a36c5 update
2025-10-02 10:13:03 +03:00

272 lines
9.3 KiB
Python

"""
Base data generator class for Saudi healthcare data.
Provides common functionality and patterns for all data generators.
"""
import os
import django
from datetime import datetime, timedelta
from django.utils import timezone as django_timezone
from django.db import transaction
from .constants import *
from .generators import *
from .helpers import *
class BaseDataGenerator:
"""Base class for Saudi healthcare data generators"""
def __init__(self, tenant=None):
"""Initialize the data generator"""
self.tenant = tenant
self.progress_tracker = ProgressTracker()
def setup_django(self):
"""Setup Django environment if not already done"""
if not hasattr(django, 'apps') or not django.apps.apps_ready:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hospital_management.settings')
django.setup()
def validate_dependencies(self):
"""Validate that required dependencies exist"""
return validate_dependencies()
def get_tenants(self):
"""Get tenants for data generation"""
from core.models import Tenant
if self.tenant:
return [self.tenant]
tenants = list(Tenant.objects.filter(is_active=True))
if not tenants:
raise ValueError("No active tenants found")
return tenants
def get_tenant_data(self, tenant):
"""Get common tenant data needed for generation"""
return {
'users': get_tenant_users(tenant),
'providers': get_tenant_providers(tenant),
'patients': get_tenant_patients(tenant),
'departments': get_tenant_departments(tenant)
}
def safe_bulk_create(self, Model, objects, **kwargs):
"""Safe bulk create with error handling"""
return safe_bulk_create(Model, objects, **kwargs)
def safe_create(self, Model, **kwargs):
"""Safe create with error handling"""
return safe_create(Model, **kwargs)
def print_progress(self, message=""):
"""Print current progress"""
self.progress_tracker.print_progress(message)
def increment_progress(self, count=1):
"""Increment progress counter"""
self.progress_tracker.increment(count)
def generate_summary(self, results):
"""Generate summary of generation results"""
total_created = sum(results.values()) if isinstance(results, dict) else len(results)
return {
'total_created': total_created,
'details': results,
'timestamp': django_timezone.now(),
'tenant': self.tenant.name if self.tenant else 'All Tenants'
}
def run_generation(self, **kwargs):
"""Main generation method - to be implemented by subclasses"""
raise NotImplementedError("Subclasses must implement run_generation method")
class SaudiHealthcareDataGenerator(BaseDataGenerator):
"""Base class for Saudi healthcare data generators with common Saudi-specific functionality"""
def __init__(self, tenant=None):
super().__init__(tenant)
self.setup_django()
def generate_saudi_name(self, gender=None):
"""Generate a Saudi name"""
return generate_saudi_name(gender)
def generate_saudi_address(self):
"""Generate a Saudi address"""
return generate_saudi_address()
def generate_saudi_phone(self):
"""Generate a Saudi phone number"""
return generate_saudi_phone()
def generate_saudi_mobile(self):
"""Generate a Saudi mobile number"""
return generate_saudi_mobile_e164()
def generate_birth_date(self, min_age=1, max_age=85):
"""Generate birth date within age range"""
return generate_birth_date(min_age, max_age)
def generate_hire_date(self, max_years_ago=20):
"""Generate hire date within reasonable range"""
return generate_hire_date(max_years_ago)
def generate_future_date(self, days_ahead=365):
"""Generate future date"""
return generate_future_date(days_ahead)
def generate_past_date(self, days_back=365):
"""Generate past date"""
return generate_past_date(days_back)
def generate_vital_signs(self, patient_age=None):
"""Generate realistic vital signs"""
return generate_vital_signs(patient_age)
def pick_job_title(self, department):
"""Pick appropriate job title for department"""
return pick_job_title_for_department(department)
def infer_role(self, job_title):
"""Infer role from job title"""
return infer_role_from_title(job_title)
def tenant_unique_username(self, tenant, base_username):
"""Generate tenant-unique username"""
return tenant_scoped_unique_username(tenant, base_username)
def generate_lab_values(self, test_type='QUANTITATIVE', reference_range=None):
"""Generate lab values"""
return generate_lab_values(test_type, reference_range)
class DataGenerationOrchestrator:
"""Orchestrates the execution of multiple data generators with dependency management"""
def __init__(self):
self.generators = {}
self.execution_order = [
'core', # Tenants
'accounts', # Users
'hr', # Employees/Departments
'patients', # Patients
# Clinical modules (can run in parallel)
'emr',
'lab',
'radiology',
'pharmacy',
'appointments',
'billing',
'inpatients',
'inventory',
'facility_management'
]
def register_generator(self, name, generator_class, **kwargs):
"""Register a data generator"""
self.generators[name] = {
'class': generator_class,
'kwargs': kwargs,
'instance': None
}
def get_dependencies(self, generator_name):
"""Get dependencies for a generator"""
dependencies = {
'core': [],
'accounts': ['core'],
'hr': ['core', 'accounts'],
'patients': ['core'],
'emr': ['core', 'accounts', 'hr', 'patients'],
'lab': ['core', 'accounts', 'hr', 'patients'],
'radiology': ['core', 'accounts', 'hr', 'patients'],
'pharmacy': ['core', 'accounts', 'hr', 'patients'],
'appointments': ['core', 'accounts', 'hr', 'patients'],
'billing': ['core', 'accounts', 'patients'],
'inpatients': ['core', 'accounts', 'hr', 'patients'],
'inventory': ['core'],
'facility_management': ['core']
}
return dependencies.get(generator_name, [])
def validate_dependencies(self, generator_name, completed_generators):
"""Validate that dependencies are satisfied"""
dependencies = self.get_dependencies(generator_name)
missing = [dep for dep in dependencies if dep not in completed_generators]
return len(missing) == 0, missing
def run_generator(self, name, **kwargs):
"""Run a specific generator"""
if name not in self.generators:
print(f"Generator {name} not registered")
return None
generator_config = self.generators[name]
generator_class = generator_config['class']
generator_kwargs = {**generator_config['kwargs'], **kwargs}
try:
generator = generator_class(**generator_kwargs)
results = generator.run_generation()
return results
except Exception as e:
print(f"Error running generator {name}: {e}")
return None
def run_all(self, generators_to_run=None, **kwargs):
"""Run all generators in dependency order"""
if generators_to_run is None:
generators_to_run = self.execution_order
completed = set()
results = {}
for generator_name in generators_to_run:
if generator_name not in self.generators:
print(f"Skipping {generator_name} - not registered")
continue
# Validate dependencies
valid, missing = self.validate_dependencies(generator_name, completed)
if not valid:
print(f"Skipping {generator_name} - missing dependencies: {missing}")
continue
print(f"\n🚀 Running {generator_name} generator...")
result = self.run_generator(generator_name, **kwargs)
if result is not None:
results[generator_name] = result
completed.add(generator_name)
print(f"{generator_name} completed")
else:
print(f"{generator_name} failed")
return results
def get_available_generators(self):
"""Get list of available generators"""
return list(self.generators.keys())
def get_execution_plan(self, generators_to_run=None):
"""Get execution plan with dependencies"""
if generators_to_run is None:
generators_to_run = self.execution_order
plan = []
for generator_name in generators_to_run:
if generator_name in self.generators:
dependencies = self.get_dependencies(generator_name)
plan.append({
'name': generator_name,
'dependencies': dependencies,
'class': self.generators[generator_name]['class'].__name__
})
return plan