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, timedelta, date, time from django.utils import timezone as django_timezone from hr.models import Employee, Department, Schedule, ScheduleAssignment, TimeEntry, PerformanceReview, TrainingRecord from accounts.models import User from core.models import Tenant from decimal import Decimal import uuid # Saudi-specific data constants SAUDI_FIRST_NAMES_MALE = [ 'Mohammed', 'Ahmed', 'Abdullah', 'Khalid', 'Omar', 'Ali', 'Hassan', 'Ibrahim', 'Yousef', 'Fahd', 'Faisal', 'Saud', 'Nasser', 'Abdulaziz', 'Abdulrahman', 'Majid', 'Saeed', 'Waleed', 'Tariq', 'Mansour', 'Sultan', 'Bandar', 'Turki', 'Nawaf', 'Rayan', 'Ziad', 'Adel', 'Salman', 'Fares', 'Amjad' ] SAUDI_FIRST_NAMES_FEMALE = [ 'Fatima', 'Aisha', 'Khadija', 'Maryam', 'Zahra', 'Noor', 'Layla', 'Sara', 'Hala', 'Noura', 'Reem', 'Lina', 'Dina', 'Rana', 'Jana', 'Maya', 'Amal', 'Hanan', 'Widad', 'Nada', 'Rawan', 'Ghada', 'Samar', 'Hind', 'Munira', 'Rahma', 'Najla', 'Dalal', 'Abeer', 'Manal' ] SAUDI_LAST_NAMES = [ 'Al-Rashid', 'Al-Otaibi', 'Al-Dosari', 'Al-Harbi', 'Al-Zahrani', 'Al-Ghamdi', 'Al-Qahtani', 'Al-Maliki', 'Al-Shammari', 'Al-Mutairi', 'Al-Subai', 'Al-Shamsi', 'Al-Faisal', 'Al-Saud', 'Al-Thani', 'Al-Fahd', 'Al-Sultan', 'Al-Nasser', 'Al-Mansour', 'Al-Khalil', 'Al-Ibrahim', 'Al-Hassan', 'Al-Ali', 'Al-Omar', 'Al-Ahmed', 'Al-Mohammed', 'Bin Laden', 'Bin Rashid', 'Bin Abdullah', 'Bin Sultan' ] SAUDI_CITIES = [ 'Riyadh', 'Jeddah', 'Mecca', 'Medina', 'Dammam', 'Khobar', 'Dhahran', 'Taif', 'Tabuk', 'Buraidah', 'Khamis Mushait', 'Hail', 'Hofuf', 'Najran', 'Jazan', 'Yanbu', 'Abha', 'Arar', 'Sakaka', 'Qatif' ] SAUDI_DEPARTMENTS = [ ('EMERGENCY', 'Emergency Department', 'Emergency medical services'), ('ICU', 'Intensive Care Unit', 'Critical care services'), ('CARDIOLOGY', 'Cardiology Department', 'Heart and cardiovascular care'), ('SURGERY', 'General Surgery', 'Surgical services'), ('ORTHOPEDICS', 'Orthopedics Department', 'Bone and joint care'), ('PEDIATRICS', 'Pediatrics Department', 'Children healthcare'), ('OBSTETRICS', 'Obstetrics & Gynecology', 'Women and maternity care'), ('RADIOLOGY', 'Radiology Department', 'Medical imaging services'), ('LABORATORY', 'Laboratory Services', 'Diagnostic testing'), ('PHARMACY', 'Pharmacy Department', 'Medication services'), ('NURSING', 'Nursing Services', 'Patient care services'), ('ADMINISTRATION', 'Administration', 'Hospital administration'), ('FINANCE', 'Finance Department', 'Financial management'), ('HR', 'Human Resources', 'Staff management'), ('IT', 'Information Technology', 'Technology services'), ('MAINTENANCE', 'Maintenance Services', 'Facility maintenance'), ('SECURITY', 'Security Department', 'Hospital security'), ('HOUSEKEEPING', 'Housekeeping Services', 'Cleaning services'), ('FOOD_SERVICE', 'Food Services', 'Dietary services'), ('SOCIAL_WORK', 'Social Work', 'Patient social services') ] SAUDI_JOB_TITLES = { 'CLINICAL': [ 'Chief Medical Officer', 'Medical Director', 'Department Head', 'Consultant Physician', 'Senior Physician', 'Physician', 'Resident Physician', 'Intern', 'Chief Nurse', 'Nurse Manager', 'Senior Nurse', 'Staff Nurse', 'Nurse Practitioner', 'Clinical Nurse Specialist', 'Charge Nurse', 'Pharmacist', 'Clinical Pharmacist', 'Pharmacy Technician', 'Radiologist', 'Radiology Technician', 'Medical Technologist', 'Laboratory Technician', 'Physical Therapist', 'Respiratory Therapist' ], 'ADMINISTRATIVE': [ 'Chief Executive Officer', 'Chief Operating Officer', 'Administrator', 'Assistant Administrator', 'Department Manager', 'Supervisor', 'Administrative Assistant', 'Secretary', 'Clerk', 'Coordinator' ], 'SUPPORT': [ 'Security Officer', 'Security Guard', 'Maintenance Technician', 'Housekeeping Supervisor', 'Housekeeper', 'Food Service Manager', 'Cook', 'Kitchen Assistant', 'Transport Aide', 'Receptionist' ] } SAUDI_TRAINING_PROGRAMS = [ 'Basic Life Support (BLS)', 'Advanced Cardiac Life Support (ACLS)', 'Pediatric Advanced Life Support (PALS)', 'Infection Control', 'Patient Safety', 'Fire Safety', 'Emergency Procedures', 'HIPAA Compliance', 'Cultural Sensitivity', 'Arabic Language', 'Islamic Healthcare Ethics', 'Medication Administration', 'Wound Care Management', 'Electronic Health Records', 'Quality Improvement', 'Customer Service Excellence' ] def create_saudi_departments(tenants): """Create Saudi hospital departments""" departments = [] for tenant in tenants: # Check for existing departments to avoid duplicates existing_dept_codes = set( Department.objects.filter(tenant=tenant).values_list('department_code', flat=True) ) for dept_code, dept_name, dept_desc in SAUDI_DEPARTMENTS: # Skip if department already exists for this tenant if dept_code in existing_dept_codes: print(f"Department {dept_code} already exists for {tenant.name}, skipping...") continue # Determine department type if dept_code in ['EMERGENCY', 'ICU', 'CARDIOLOGY', 'SURGERY', 'ORTHOPEDICS', 'PEDIATRICS', 'OBSTETRICS', 'RADIOLOGY', 'LABORATORY', 'PHARMACY', 'NURSING']: dept_type = 'CLINICAL' elif dept_code in ['ADMINISTRATION', 'FINANCE', 'HR', 'IT']: dept_type = 'ADMINISTRATIVE' elif dept_code in ['MAINTENANCE', 'SECURITY', 'HOUSEKEEPING', 'FOOD_SERVICE']: dept_type = 'SUPPORT' else: dept_type = 'ANCILLARY' try: department = Department.objects.create( tenant=tenant, department_code=dept_code, name=dept_name, description=dept_desc, department_type=dept_type, annual_budget=Decimal(str(random.randint(500000, 5000000))), cost_center=f"CC-{dept_code}", location=f"{random.choice(['Building A', 'Building B', 'Main Building'])}, Floor {random.randint(1, 5)}", is_active=True, notes=f"Primary {dept_name.lower()} for {tenant.name}", created_at=django_timezone.now() - timedelta(days=random.randint(30, 365)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)) ) departments.append(department) except Exception as e: print(f"Error creating department {dept_code} for {tenant.name}: {e}") continue created_count = len([d for d in departments if d.tenant == tenant]) print(f"Created {created_count} new departments for {tenant.name}") return departments def create_saudi_employees(tenants, departments, employees_per_tenant=150): """Create Saudi hospital employees""" employees = [] for tenant in tenants: tenant_departments = [dept for dept in departments if dept.tenant == tenant] if not tenant_departments: print(f"No departments found for {tenant.name}, skipping employee creation...") continue # Check existing employee numbers to avoid duplicates existing_emp_numbers = set( Employee.objects.filter(tenant=tenant).values_list('employee_number', flat=True) ) created_count = 0 for i in range(employees_per_tenant): # Generate unique employee number emp_number = f"EMP-{i + 1:04d}" counter = 1 original_emp_number = emp_number while emp_number in existing_emp_numbers: emp_number = f"{original_emp_number}-{counter}" counter += 1 # Generate employee details gender = random.choice(['MALE', 'FEMALE']) first_name = random.choice(SAUDI_FIRST_NAMES_MALE if gender == 'MALE' else SAUDI_FIRST_NAMES_FEMALE) last_name = random.choice(SAUDI_LAST_NAMES) middle_name = random.choice(SAUDI_FIRST_NAMES_MALE + SAUDI_FIRST_NAMES_FEMALE) if random.choice( [True, False]) else None # Select department and job title department = random.choice(tenant_departments) if department.department_type == 'CLINICAL': job_titles = SAUDI_JOB_TITLES['CLINICAL'] elif department.department_type == 'ADMINISTRATIVE': job_titles = SAUDI_JOB_TITLES['ADMINISTRATIVE'] else: job_titles = SAUDI_JOB_TITLES['SUPPORT'] job_title = random.choice(job_titles) # Determine employment type and status employment_type = random.choices( ['FULL_TIME', 'PART_TIME', 'CONTRACT', 'CONTRACT'], weights=[70, 15, 10, 5] )[0] employment_status = random.choices( ['ACTIVE', 'INACTIVE', 'LEAVE'], weights=[85, 10, 5] )[0] # Generate dates hire_date = django_timezone.now().date() - timedelta(days=random.randint(30, 2000)) date_of_birth = hire_date - timedelta(days=random.randint(8000, 15000)) # 22-41 years old at hire # Generate salary information if 'Chief' in job_title or 'Director' in job_title: annual_salary = Decimal(str(random.randint(300000, 600000))) hourly_rate = None elif 'Manager' in job_title or 'Head' in job_title: annual_salary = Decimal(str(random.randint(180000, 350000))) hourly_rate = None elif 'Senior' in job_title or 'Consultant' in job_title: annual_salary = Decimal(str(random.randint(120000, 250000))) hourly_rate = None else: annual_salary = None hourly_rate = Decimal(str(random.randint(50, 150))) # FTE and hours if employment_type == 'FULL_TIME': fte_percentage = Decimal('100.00') standard_hours = Decimal('40.00') elif employment_type == 'PART_TIME': fte_percentage = Decimal(str(random.choice([50, 60, 75]))) standard_hours = Decimal(str(fte_percentage / 100 * 40)) else: fte_percentage = Decimal('100.00') standard_hours = Decimal('40.00') # Contact information city = random.choice(SAUDI_CITIES) phone = f"+966-{random.randint(11, 13)}-{random.randint(100, 999)}-{random.randint(1000, 9999)}" mobile = f"+966-5{random.randint(0, 9)}-{random.randint(100, 999)}-{random.randint(1000, 9999)}" try: # Create employee employee = Employee.objects.create( tenant=tenant, employee_number=emp_number, first_name=first_name, last_name=last_name, middle_name=middle_name, preferred_name=first_name if random.choice([True, False]) else None, email=f"{first_name.lower()}.{last_name.lower().replace('-', '').replace(' ', '')}@{tenant.name.lower().replace(' ', '')}.sa", phone=phone, mobile_phone=mobile, address_line_1=f"{random.randint(1, 999)} {random.choice(['King Fahd Road', 'Prince Sultan Street', 'Al-Malik Road', 'Olaya Street'])}", address_line_2=f"Apt {random.randint(1, 50)}" if random.choice([True, False]) else None, city=city, state=random.choice(['Riyadh Province', 'Makkah Province', 'Eastern Province', 'Asir Province']), postal_code=f"{random.randint(10000, 99999)}", country='Saudi Arabia', date_of_birth=date_of_birth, gender=gender, marital_status=random.choice(['SINGLE', 'MARRIED', 'DIVORCED', 'WIDOWED']), department=department, job_title=job_title, employment_type=employment_type, employment_status=employment_status, hire_date=hire_date, termination_date=None if employment_status != 'TERMINATED' else hire_date + timedelta( days=random.randint(30, 1000)), standard_hours_per_week=standard_hours, fte_percentage=fte_percentage, hourly_rate=hourly_rate, annual_salary=annual_salary, license_number=f"LIC-{random.randint(100000, 999999)}" if 'Physician' in job_title or 'Nurse' in job_title else None, license_expiry_date=django_timezone.now().date() + timedelta( days=random.randint(30, 730)) if 'Physician' in job_title or 'Nurse' in job_title else None, certifications=[ {'name': 'BLS Certification', 'number': f"BLS-{random.randint(10000, 99999)}", 'expiry': (django_timezone.now().date() + timedelta(days=365)).isoformat()}, {'name': 'ACLS Certification', 'number': f"ACLS-{random.randint(10000, 99999)}", 'expiry': (django_timezone.now().date() + timedelta(days=730)).isoformat()} ] if 'Physician' in job_title or 'Nurse' in job_title else [], emergency_contact_name=f"{random.choice(SAUDI_FIRST_NAMES_MALE + SAUDI_FIRST_NAMES_FEMALE)} {random.choice(SAUDI_LAST_NAMES)}", emergency_contact_relationship=random.choice(['Spouse', 'Parent', 'Sibling', 'Child']), emergency_contact_phone=f"+966-5{random.randint(0, 9)}-{random.randint(100, 999)}-{random.randint(1000, 9999)}", notes=f"Employee hired for {department.name} department", created_at=django_timezone.now() - timedelta(days=random.randint(1, 100)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)) ) employees.append(employee) existing_emp_numbers.add(emp_number) created_count += 1 except Exception as e: print(f"Error creating employee {emp_number} for {tenant.name}: {e}") continue print(f"Created {created_count} employees for {tenant.name}") return employees def assign_department_heads(departments, employees): """Assign department heads from senior employees""" for department in departments: # Skip if department already has a head if department.department_head: continue # Find senior employees in this department dept_employees = [emp for emp in employees if emp.department == department and emp.employment_status == 'ACTIVE'] senior_employees = [emp for emp in dept_employees if any(title in emp.job_title for title in ['Chief', 'Director', 'Head', 'Manager'])] if senior_employees: department.department_head = random.choice(senior_employees) department.save() print("Assigned department heads") def assign_supervisors(employees): """Assign supervisors to employees based on hierarchy""" for employee in employees: if employee.employment_status != 'ACTIVE' or employee.supervisor: continue # Don't assign supervisors to top-level positions if any(title in employee.job_title for title in ['Chief', 'Director']): continue # Find potential supervisors in the same department potential_supervisors = [ emp for emp in employees if emp.department == employee.department and emp.employment_status == 'ACTIVE' and emp != employee and any(title in emp.job_title for title in ['Chief', 'Director', 'Head', 'Manager', 'Senior']) ] if potential_supervisors: employee.supervisor = random.choice(potential_supervisors) employee.save() print("Assigned employee supervisors") def create_saudi_schedules(employees, schedules_per_employee=2): """Create work schedules for Saudi employees""" schedules = [] schedule_patterns = { 'DAY_SHIFT': { 'sunday': {'start': '07:00', 'end': '19:00'}, 'monday': {'start': '07:00', 'end': '19:00'}, 'tuesday': {'start': '07:00', 'end': '19:00'}, 'wednesday': {'start': '07:00', 'end': '19:00'}, 'thursday': {'start': '07:00', 'end': '19:00'}, 'friday': {'start': '07:00', 'end': '19:00'}, 'saturday': {'start': '07:00', 'end': '19:00'}, }, # 'EVENING_SHIFT': { # 'monday': {'start': '15:00', 'end': '23:00'}, # 'tuesday': {'start': '15:00', 'end': '23:00'}, # 'wednesday': {'start': '15:00', 'end': '23:00'}, # 'thursday': {'start': '15:00', 'end': '23:00'}, # 'friday': {'start': '13:00', 'end': '21:00'}, # 'saturday': {'start': '15:00', 'end': '23:00'}, # 'sunday': 'off' # }, 'NIGHT_SHIFT': { 'sunday': {'start': '19:00', 'end': '07:00'}, 'monday': {'start': '19:00', 'end': '07:00'}, 'tuesday': {'start': '19:00', 'end': '07:00'}, 'wednesday': {'start': '19:00', 'end': '07:00'}, 'thursday': {'start': '19:00', 'end': '07:00'}, 'friday': {'start': '19:00', 'end': '07:00'}, 'saturday': {'start': '19:00', 'end': '07:00'}, }, 'ADMIN_HOURS': { 'sunday': {'start': '08:00', 'end': '17:00'}, 'monday': {'start': '08:00', 'end': '17:00'}, 'tuesday': {'start': '08:00', 'end': '17:00'}, 'wednesday': {'start': '08:00', 'end': '17:00'}, 'thursday': {'start': '08:00', 'end': '16:00'}, 'friday': 'off', 'saturday': 'off', } } clinical_employees = [emp for emp in employees if emp.department and emp.department.department_type == 'CLINICAL' and emp.employment_status == 'ACTIVE'] admin_employees = [emp for emp in employees if emp.department and emp.department.department_type in ['ADMINISTRATIVE', 'SUPPORT'] and emp.employment_status == 'ACTIVE'] # Create schedules for clinical staff (rotating shifts) for employee in clinical_employees: for i in range(schedules_per_employee): schedule_type = random.choice(['REGULAR', 'ROTATING']) pattern_name = random.choice(['DAY_SHIFT', 'EVENING_SHIFT', 'NIGHT_SHIFT']) effective_date = django_timezone.now().date() - timedelta(days=random.randint(0, 180)) end_date = effective_date + timedelta(days=random.randint(90, 365)) if random.choice( [True, False]) else None try: schedule = Schedule.objects.create( employee=employee, name=f"{employee.get_full_name()} - {pattern_name.replace('_', ' ').title()}", description=f"{pattern_name.replace('_', ' ').title()} schedule for {employee.job_title}", schedule_type=schedule_type, effective_date=effective_date, end_date=end_date, schedule_pattern=schedule_patterns[pattern_name], is_active=i == 0, # Only first schedule is active notes=f"Standard {pattern_name.replace('_', ' ').lower()} for clinical staff", created_at=django_timezone.now() - timedelta(days=random.randint(1, 90)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)) ) schedules.append(schedule) except Exception as e: print(f"Error creating schedule for {employee.get_full_name()}: {e}") continue # Create schedules for administrative staff (regular hours) for employee in admin_employees: schedule_type = 'REGULAR' pattern_name = 'ADMIN_HOURS' effective_date = django_timezone.now().date() - timedelta(days=random.randint(0, 180)) try: schedule = Schedule.objects.create( employee=employee, name=f"{employee.get_full_name()} - Administrative Hours", description="Standard administrative working hours", schedule_type=schedule_type, effective_date=effective_date, end_date=None, schedule_pattern=schedule_patterns[pattern_name], is_active=True, notes="Standard administrative schedule", created_at=django_timezone.now() - timedelta(days=random.randint(1, 90)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)) ) schedules.append(schedule) except Exception as e: print(f"Error creating schedule for {employee.get_full_name()}: {e}") continue print(f"Created {len(schedules)} employee schedules") return schedules def create_schedule_assignments(schedules, days_back=30): """Create specific schedule assignments""" assignments = [] shift_types = { 'DAY_SHIFT': 'DAY', # 'EVENING_SHIFT': 'EVENING', 'NIGHT_SHIFT': 'NIGHT', 'ADMIN_HOURS': 'DAY' } for schedule in schedules: if not schedule.is_active: continue # Create assignments for the last 30 days start_date = django_timezone.now().date() - timedelta(days=days_back) for day_offset in range(days_back): assignment_date = start_date + timedelta(days=day_offset) weekday = assignment_date.strftime('%A').lower() # Skip if no work scheduled for this day if weekday not in schedule.schedule_pattern or schedule.schedule_pattern[weekday] == 'off': continue day_schedule = schedule.schedule_pattern[weekday] start_time = datetime.strptime(day_schedule['start'], '%H:%M').time() end_time = datetime.strptime(day_schedule['end'], '%H:%M').time() # Determine shift type based on schedule pattern pattern_key = None for pattern_name, pattern_data in [ ('DAY_SHIFT', schedule.schedule_pattern), # ('EVENING_SHIFT', schedule.schedule_pattern), ('NIGHT_SHIFT', schedule.schedule_pattern), ('ADMIN_HOURS', schedule.schedule_pattern) ]: if pattern_data == schedule.schedule_pattern: pattern_key = pattern_name break shift_type = shift_types.get(pattern_key, 'DAY') # Random status (mostly completed for past dates) if assignment_date < django_timezone.now().date(): status = random.choices( ['COMPLETED', 'NO_SHOW', 'CANCELLED'], weights=[90, 5, 5] )[0] else: status = random.choices( ['SCHEDULED', 'CONFIRMED'], weights=[70, 30] )[0] try: assignment = ScheduleAssignment.objects.create( schedule=schedule, assignment_date=assignment_date, start_time=start_time, end_time=end_time, shift_type=shift_type, department=schedule.employee.department, location=schedule.employee.department.location if schedule.employee.department else None, status=status, break_minutes=15 if shift_type in ['DAY', 'EVENING'] else 30, lunch_minutes=30 if shift_type in ['DAY', 'EVENING'] else 0, notes=f"{shift_type.title()} shift assignment", created_at=django_timezone.now() - timedelta(days=random.randint(0, 7)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 3)) ) assignments.append(assignment) except Exception as e: print(f"Error creating assignment for {schedule.employee.get_full_name()}: {e}") continue print(f"Created {len(assignments)} schedule assignments") return assignments def create_time_entries(employees, days_back=30): """Create time entries for employees""" entries = [] active_employees = [emp for emp in employees if emp.employment_status == 'ACTIVE'] for employee in active_employees: # Create time entries for working days start_date = django_timezone.now().date() - timedelta(days=days_back) for day_offset in range(days_back): work_date = start_date + timedelta(days=day_offset) # Skip weekends for administrative staff if (employee.department and employee.department.department_type == 'ADMINISTRATIVE' and work_date.weekday() in [4, 5]): # Friday, Saturday continue # Random chance of working (85% for clinical, 90% for admin) work_probability = 0.85 if employee.department and employee.department.department_type == 'CLINICAL' else 0.90 if random.random() > work_probability: continue # Generate work times based on typical schedules if employee.department and employee.department.department_type == 'CLINICAL': # Clinical staff - various shifts shift_options = [ (time(7, 0), time(15, 0)), # Day shift (time(15, 0), time(23, 0)), # Evening shift (time(23, 0), time(7, 0)), # Night shift (next day) ] start_time, end_time = random.choice(shift_options) else: # Administrative staff - regular hours start_time = time(8, 0) end_time = time(17, 0) if work_date.weekday() != 4 else time(12, 0) # Half day Friday # Add some variance to clock in/out times clock_in_variance = random.randint(-15, 15) # ±15 minutes clock_out_variance = random.randint(-15, 15) clock_in = datetime.combine(work_date, start_time) + timedelta(minutes=clock_in_variance) clock_out = datetime.combine(work_date, end_time) + timedelta(minutes=clock_out_variance) # Handle overnight shifts if end_time < start_time: clock_out += timedelta(days=1) # Break and lunch times break_start = clock_in + timedelta(hours=2, minutes=random.randint(0, 60)) break_end = break_start + timedelta(minutes=15) lunch_start = clock_in + timedelta(hours=4, minutes=random.randint(0, 60)) lunch_end = lunch_start + timedelta(minutes=30) entry_type = random.choices( ['REGULAR', 'OVERTIME', 'HOLIDAY'], weights=[85, 10, 5] )[0] status = random.choices( ['APPROVED', 'SUBMITTED', 'DRAFT'], weights=[70, 20, 10] )[0] try: entry = TimeEntry.objects.create( employee=employee, work_date=work_date, clock_in_time=clock_in, clock_out_time=clock_out, break_start_time=break_start, break_end_time=break_end, lunch_start_time=lunch_start, lunch_end_time=lunch_end, entry_type=entry_type, department=employee.department, location=employee.department.location if employee.department else None, status=status, notes=f"{entry_type.title()} work shift", created_at=django_timezone.now() - timedelta(days=random.randint(0, 7)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 3)) ) entries.append(entry) except Exception as e: print(f"Error creating time entry for {employee.get_full_name()}: {e}") continue print(f"Created {len(entries)} time entries") return entries def create_performance_reviews(employees): """Create performance reviews for employees""" reviews = [] # Only create reviews for employees with 6+ months of service eligible_employees = [ emp for emp in employees if emp.employment_status == 'ACTIVE' and (django_timezone.now().date() - emp.hire_date).days >= 180 ] competency_areas = [ 'Clinical Skills', 'Communication', 'Teamwork', 'Professionalism', 'Quality of Work', 'Productivity', 'Problem Solving', 'Initiative', 'Reliability', 'Cultural Competency', 'Patient Care', 'Safety Compliance' ] for employee in eligible_employees: # Create 1-2 reviews per eligible employee num_reviews = random.randint(1, 2) for i in range(num_reviews): # Review period (last 6-12 months) review_period_months = random.randint(6, 12) review_date = django_timezone.now().date() - timedelta(days=random.randint(0, 90)) period_start = review_date - timedelta(days=review_period_months * 30) period_end = review_date - timedelta(days=30) review_type = random.choices( ['ANNUAL', 'PROBATIONARY', 'MID_YEAR'], weights=[60, 20, 20] )[0] # Generate overall rating (1-5, skewed toward higher ratings) overall_rating = random.choices( [2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0], weights=[5, 10, 20, 25, 25, 10, 5] )[0] # Generate competency ratings competency_ratings = {} for competency in random.sample(competency_areas, random.randint(6, 10)): rating = random.choices( [2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0], weights=[5, 10, 20, 25, 25, 10, 5] )[0] competency_ratings[competency] = rating status = random.choices( ['COMPLETED', 'ACKNOWLEDGED', 'IN_PROGRESS'], weights=[60, 30, 10] )[0] try: review = PerformanceReview.objects.create( employee=employee, review_period_start=period_start, review_period_end=period_end, review_date=review_date, review_type=review_type, overall_rating=Decimal(str(overall_rating)), competency_ratings=competency_ratings, goals_achieved=f"{employee.first_name} successfully completed assigned patient care duties and contributed to department objectives.", goals_not_achieved="Minor areas for improvement in documentation timeliness." if overall_rating < 4.0 else None, future_goals="Continue professional development and maintain high standards of patient care.", strengths=f"Strong {random.choice(['clinical skills', 'communication abilities', 'teamwork', 'dedication to patient care'])}.", areas_for_improvement="Opportunities for growth in leadership and mentoring junior staff." if overall_rating < 4.5 else None, development_plan="Recommended for advanced training programs and leadership development opportunities.", training_recommendations=f"Suggested training: {random.choice(SAUDI_TRAINING_PROGRAMS)}", employee_comments="Appreciate the feedback and committed to continuous improvement." if status == 'ACKNOWLEDGED' else None, employee_signature_date=review_date + timedelta( days=random.randint(1, 14)) if status == 'ACKNOWLEDGED' else None, status=status, notes=f"{review_type.title()} performance review completed", created_at=django_timezone.now() - timedelta(days=random.randint(1, 60)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 30)) ) reviews.append(review) except Exception as e: print(f"Error creating performance review for {employee.get_full_name()}: {e}") continue print(f"Created {len(reviews)} performance reviews") return reviews def create_training_records(employees): """Create training records for employees""" records = [] active_employees = [emp for emp in employees if emp.employment_status == 'ACTIVE'] training_by_role = { 'ALL': ['Orientation', 'Fire Safety', 'Emergency Procedures', 'HIPAA Compliance', 'Patient Safety'], 'CLINICAL': ['Basic Life Support (BLS)', 'Infection Control', 'Medication Administration', 'Wound Care Management'], 'PHYSICIAN': ['Advanced Cardiac Life Support (ACLS)', 'Pediatric Advanced Life Support (PALS)'], 'NURSE': ['IV Therapy', 'Pain Management', 'Electronic Health Records'], 'ADMIN': ['Customer Service Excellence', 'Quality Improvement', 'Arabic Language'], 'SUPPORT': ['Safety Training', 'Equipment Operation', 'Cultural Sensitivity'] } for employee in active_employees: # Mandatory training for all employees mandatory_training = training_by_role['ALL'].copy() # Role-specific training if employee.department and employee.department.department_type == 'CLINICAL': mandatory_training.extend(training_by_role['CLINICAL']) if 'Physician' in employee.job_title: mandatory_training.extend(training_by_role['PHYSICIAN']) elif 'Nurse' in employee.job_title: mandatory_training.extend(training_by_role['NURSE']) elif employee.department and employee.department.department_type == 'ADMINISTRATIVE': mandatory_training.extend(training_by_role['ADMIN']) else: mandatory_training.extend(training_by_role['SUPPORT']) # Add some random additional training all_training = list(set(mandatory_training + random.sample(SAUDI_TRAINING_PROGRAMS, random.randint(2, 5)))) for training_name in all_training: # Training date (within employment period) days_since_hire = (django_timezone.now().date() - employee.hire_date).days training_date = employee.hire_date + timedelta(days=random.randint(0, days_since_hire)) # Completion date (usually same day or within a week) completion_date = training_date + timedelta(days=random.randint(0, 7)) # Training type if training_name in ['Orientation']: training_type = 'ORIENTATION' elif training_name in ['Fire Safety', 'Emergency Procedures', 'HIPAA Compliance', 'Patient Safety']: training_type = 'MANDATORY' elif 'Certification' in training_name or any(cert in training_name for cert in ['BLS', 'ACLS', 'PALS']): training_type = 'CERTIFICATION' elif training_name in ['Safety Training', 'Infection Control']: training_type = 'SAFETY' else: training_type = 'CONTINUING_ED' # Duration based on training type if training_type == 'CERTIFICATION': duration = Decimal(str(random.randint(8, 16))) # 8-16 hours elif training_type == 'MANDATORY': duration = Decimal(str(random.randint(2, 8))) # 2-8 hours else: duration = Decimal(str(random.randint(1, 4))) # 1-4 hours # Expiry date for certifications expiry_date = None if training_type == 'CERTIFICATION': expiry_date = completion_date + timedelta(days=random.randint(365, 730)) # 1-2 years status = random.choices( ['COMPLETED', 'IN_PROGRESS', 'SCHEDULED'], weights=[80, 15, 5] )[0] # Score and pass status if status == 'COMPLETED': score = Decimal(str(random.randint(75, 100))) passed = score >= 70 else: score = None passed = False try: record = TrainingRecord.objects.create( employee=employee, training_name=training_name, training_description=f"Comprehensive {training_name.lower()} training program", training_type=training_type, training_provider=random.choice([ 'Saudi Healthcare Training Institute', 'Ministry of Health Training Center', 'King Fahd Medical Training Academy', 'Internal Training Department' ]), instructor=f"Dr. {random.choice(SAUDI_FIRST_NAMES_MALE + SAUDI_FIRST_NAMES_FEMALE)} {random.choice(SAUDI_LAST_NAMES)}", training_date=training_date, completion_date=completion_date if status == 'COMPLETED' else None, expiry_date=expiry_date, duration_hours=duration, credits_earned=duration if status == 'COMPLETED' else Decimal('0.00'), status=status, score=score, passed=passed, certificate_number=f"CERT-{random.randint(100000, 999999)}" if status == 'COMPLETED' and training_type == 'CERTIFICATION' else None, certification_body='Saudi Healthcare Certification Board' if training_type == 'CERTIFICATION' else None, training_cost=Decimal(str(random.randint(500, 5000))), notes=f"{training_name} training completed successfully" if status == 'COMPLETED' else f"{training_name} training in progress", created_at=django_timezone.now() - timedelta(days=random.randint(1, 30)), updated_at=django_timezone.now() - timedelta(days=random.randint(0, 15)) ) records.append(record) except Exception as e: print(f"Error creating training record for {employee.get_full_name()}: {e}") continue print(f"Created {len(records)} training records") return records def main(): """Main function to generate all Saudi HR data""" print("Starting Saudi Healthcare HR 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 departments print("\n1. Creating Saudi Hospital Departments...") departments = create_saudi_departments(tenants) # Create employees print("\n2. Creating Saudi Hospital Employees...") employees = create_saudi_employees(tenants, departments, 120) # Assign department heads and supervisors print("\n3. Assigning Department Heads and Supervisors...") assign_department_heads(departments, employees) assign_supervisors(employees) # Create schedules print("\n4. Creating Employee Work Schedules...") schedules = create_saudi_schedules(employees, 2) # Create schedule assignments print("\n5. Creating Schedule Assignments...") assignments = create_schedule_assignments(schedules, 30) # Create time entries print("\n6. Creating Employee Time Entries...") time_entries = create_time_entries(employees, 30) # Create performance reviews print("\n7. Creating Performance Reviews...") reviews = create_performance_reviews(employees) # Create training records print("\n8. Creating Training Records...") training_records = create_training_records(employees) print(f"\nāœ… Saudi Healthcare HR Data Generation Complete!") print(f"šŸ“Š Summary:") print(f" - Departments: {len(departments)}") print(f" - Employees: {len(employees)}") print(f" - Schedules: {len(schedules)}") print(f" - Schedule Assignments: {len(assignments)}") print(f" - Time Entries: {len(time_entries)}") print(f" - Performance Reviews: {len(reviews)}") print(f" - Training Records: {len(training_records)}") # Department distribution dept_counts = {} for employee in employees: if employee.department: dept_type = employee.department.department_type dept_counts[dept_type] = dept_counts.get(dept_type, 0) + 1 print(f"\nšŸ„ Employee Distribution by Department Type:") for dept_type, count in dept_counts.items(): print(f" - {dept_type.title()}: {count}") # Employment status distribution status_counts = {} for employee in employees: status_counts[employee.employment_status] = status_counts.get(employee.employment_status, 0) + 1 print(f"\nšŸ‘„ Employee Status Distribution:") for status, count in status_counts.items(): print(f" - {status.title()}: {count}") return { 'departments': departments, 'employees': employees, 'schedules': schedules, 'assignments': assignments, 'time_entries': time_entries, 'reviews': reviews, 'training_records': training_records } if __name__ == "__main__": main()