# facility_management_data_generator.py import os import django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hospital_management.settings') django.setup() import random import uuid from decimal import Decimal from datetime import datetime, timedelta, date from django.utils import timezone from django.db import transaction from core.models import Tenant # Setup Django environment # Import models from accounts.models import User from facility_management.models import * # Set random seed for reproducibility random.seed(42) def create_users(): """Create sample Saudi hospital users (facilities + clinical ops).""" saudi_staff = [ ('mohammed_fm', 'Mohammed', 'Al-Qahtani', 'Facilities Manager'), ('ibrahim_bme', 'Ibrahim', 'Al-Otaibi', 'Biomedical Engineer'), ('abdullah_main', 'Abdullah', 'Al-Zahrani', 'Maintenance Supervisor'), ('khalid_elec', 'Khalid', 'Al-Harbi', 'Electrical Engineer'), ('ahmed_civil', 'Ahmed', 'Al-Ghamdi', 'Civil Engineer'), ('fahad_hvac', 'Fahad', 'Al-Dossari', 'HVAC Specialist'), ('saad_safety', 'Saad', 'Al-Mutairi', 'Safety & Fire Officer'), ('ali_it', 'Ali', 'Al-Shammari', 'Health IT Manager'), ('nora_admin', 'Nora', 'Al-Anazi', 'Administrative Coordinator'), ('aisha_ops', 'Aisha', 'Al-Qurashi', 'Hospital Operations Coordinator'), ] users = [] tenant = Tenant.objects.get(pk=1) for username, first_name, last_name, _ in saudi_staff: user, created = User.objects.get_or_create( tenant=tenant, username=username, defaults={ 'email': f'{username}@ksa-hospital.gov.sa', 'first_name': first_name, 'last_name': last_name, } ) if created: user.set_password('password123') user.save() users.append(user) return users, {u.username: u for u in users} def create_buildings(users): """ Create hospital campus buildings in KSA. NOTE: We keep the field name 'airport_code' for compatibility with your model. Treat it as a 'campus_code' (e.g., RHF = Riyadh Health Facility, etc.). CLINICAL = 'CLINICAL', 'Clinical' NON_CLINICAL = 'NON_CLINICAL', 'Non Clinical' OTHER = 'OTHER', 'Other' """ tenant=Tenant.objects.get(pk=1) buildings_data = [ # Riyadh campus { 'tenant': tenant, 'name': 'Main Hospital (Inpatient Tower)', 'code': 'RHF-MAIN', 'building_type': 'CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 12, 'total_area_sqm': Decimal('210000.00'), 'construction_year': 2014, 'architect': 'Dar Al-Handasah', 'contractor': 'Al Bawani', 'last_major_renovation': date(2022, 4, 15), 'facility_manager': users['mohammed_fm'], }, { 'tenant': tenant, 'name': 'Outpatient Clinics', 'code': 'RHF-OPD', 'building_type': 'CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 6, 'total_area_sqm': Decimal('95000.00'), 'construction_year': 2018, 'architect': 'Zuhair Fayez Partnership', 'contractor': 'Al Kifah', 'facility_manager': users['aisha_ops'] }, { 'tenant': tenant, 'name': 'Emergency Department & Trauma Center', 'code': 'RHF-ED', 'building_type': 'CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 3, 'total_area_sqm': Decimal('45000.00'), 'construction_year': 2016, 'architect': 'Omrania & Associates', 'contractor': 'El Seif', 'facility_manager': users['saad_safety'] }, { 'tenant': tenant, 'name': 'Surgical Centre (ORs & Recovery)', 'code': 'RHF-SURG', 'building_type': 'CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 4, 'total_area_sqm': Decimal('60000.00'), 'construction_year': 2019, 'architect': 'Arab Engineering Bureau', 'contractor': 'Nesma & Partners', 'facility_manager': users['ibrahim_bme'] }, { 'tenant': tenant, 'name': 'Diagnostic & Imaging Centre', 'code': 'RHF-DIAG', 'building_type': 'CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 4, 'total_area_sqm': Decimal('38000.00'), 'construction_year': 2017, 'architect': 'Dar Al Riyadh', 'contractor': 'Almabani', 'facility_manager': users['ali_it'] }, { 'tenant': tenant, 'name': 'Laboratory & Blood Bank', 'code': 'RHF-LAB', 'building_type': 'CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 5, 'total_area_sqm': Decimal('42000.00'), 'construction_year': 2015, 'architect': 'IDOM', 'contractor': 'Al Rashid Trading & Contracting', 'facility_manager': users['abdullah_main'] }, { 'tenant': tenant, 'name': 'Maternity & Children Hospital', 'code': 'RHF-MCH', 'building_type': 'CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 8, 'total_area_sqm': Decimal('120000.00'), 'construction_year': 2020, 'architect': 'Perkins&Will', 'contractor': 'TAV Construction', 'facility_manager': users['ahmed_civil'] }, { 'tenant': tenant, 'name': 'Support Services (CSSD/Laundry/Kitchen)', 'code': 'RHF-SUPPORT', 'building_type': 'NON_CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 3, 'total_area_sqm': Decimal('30000.00'), 'construction_year': 2016, 'architect': 'Khatib & Alami', 'contractor': 'Al Bawani', 'facility_manager': users['fahad_hvac'] }, { 'tenant': tenant, 'name': 'Administration', 'code': 'RHF-ADMIN', 'building_type': 'NON_CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 7, 'total_area_sqm': Decimal('25000.00'), 'construction_year': 2015, 'architect': 'Omrania & Associates', 'contractor': 'Al Bawani', 'facility_manager': users['aisha_ops'] }, { 'tenant': tenant, 'name': 'Mosque', 'code': 'RHF-MOSQ', 'building_type': 'OTHER', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 1, 'total_area_sqm': Decimal('3500.00'), 'construction_year': 2016, 'architect': 'Omrania & Associates', 'contractor': 'Saudi Binladin Group', 'facility_manager': users['mohammed_fm'] }, { 'tenant': tenant, 'name': 'Central Utility Plant', 'code': 'RHF-UTIL', 'building_type': 'OTHER', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 2, 'total_area_sqm': Decimal('12000.00'), 'construction_year': 2014, 'architect': 'HOK', 'contractor': 'Al Bawani', 'facility_manager': users['khalid_elec'] }, { 'tenant': tenant, 'name': 'Parking Garage P1', 'code': 'RHF-P1', 'building_type': 'NON_CLINICAL', 'address': 'Riyadh Health Campus, Riyadh 11564, Saudi Arabia', 'floor_count': 5, 'total_area_sqm': Decimal('65000.00'), 'construction_year': 2019, 'architect': 'Zuhair Fayez Partnership', 'contractor': 'Al Bawani', 'facility_manager': users['ahmed_civil'] }, # Jeddah micro-campus (shorter list) { 'tenant': tenant, 'name': 'Jeddah General Hospital', 'code': 'JHF-MAIN', 'building_type': 'CLINICAL', 'address': 'Jeddah Health Campus, Jeddah 23337, Saudi Arabia', 'floor_count': 9, 'total_area_sqm': Decimal('160000.00'), 'construction_year': 2013, 'architect': 'AECOM', 'contractor': 'Saudi Oger', 'last_major_renovation': date(2021, 11, 5), 'facility_manager': users['mohammed_fm'] }, { 'tenant': tenant, 'name': 'Jeddah OPD & Imaging', 'code': 'JHF-OPD', 'building_type': 'CLINICAL', 'address': 'Jeddah Health Campus, Jeddah 23337, Saudi Arabia', 'floor_count': 5, 'total_area_sqm': Decimal('60000.00'), 'construction_year': 2016, 'architect': 'Dar Al-Handasah', 'contractor': 'Almabani', 'facility_manager': users['ali_it'] }, ] buildings = [] for data in buildings_data: building, _ = Building.objects.get_or_create( code=data['code'], defaults=data ) buildings.append(building) return buildings def create_floors(buildings): """Create floors appropriate for hospital buildings (with basements for plant areas).""" floors = [] floor_names = { -2: 'الطابق تحت الأرضي الثاني (Sub-Basement)', -1: 'الطابق تحت الأرضي (Basement)', 0: 'الطابق الأرضي (Ground Floor)', 1: 'الطابق الأول (First Floor)', 2: 'الطابق الثاني (Second Floor)', 3: 'الطابق الثالث (Third Floor)', 4: 'الطابق الرابع (Fourth Floor)', 5: 'الطابق الخامس (Fifth Floor)', 6: 'الطابق السادس (Sixth Floor)', 7: 'الطابق السابع (Seventh Floor)', 8: 'الطابق الثامن (Eighth Floor)', 9: 'الطابق التاسع (Ninth Floor)', 10: 'الطابق العاشر (Tenth Floor)', 11: 'الطابق الحادي عشر (Eleventh Floor)', 12: 'الطابق الثاني عشر (Twelfth Floor)', } for b in buildings: has_basement = b.building_type in ['inpatient', 'surgical', 'diagnostic', 'lab', 'support', 'office', 'utility'] and b.floor_count >= 3 if b.building_type == 'inpatient' and b.floor_count >= 10: floor_range = range(-1 if has_basement else 0, b.floor_count) elif has_basement: floor_range = range(-1, b.floor_count) else: floor_range = range(0, b.floor_count) base_area = (b.total_area_sqm / (len(floor_range) or 1)) if b.total_area_sqm else Decimal('1000.00') for n in floor_range: name = floor_names.get(n, (f'الطابق {n} (Floor {n})' if n >= 0 else f'الطابق تحت الأرضي {abs(n)} (Basement {abs(n)})')) area_sqm = base_area * Decimal(str(random.uniform(0.92, 1.08))) # Ceiling heights (higher in lobbies/OR/diagnostic) if n == 0 and b.building_type in ['inpatient','outpatient','emergency','surgical','diagnostic']: ceiling_height = Decimal('5.50') elif b.building_type in ['surgical','diagnostic'] and n >= 1: ceiling_height = Decimal('4.00') elif n < 0: ceiling_height = Decimal('3.20') else: ceiling_height = Decimal('3.60') is_public_access = ( (b.building_type in ['outpatient','emergency'] and n >= 0) or (b.building_type == 'inpatient' and n in [0,1]) or (b.building_type == 'parking') or (b.code.endswith('MOSQ')) ) floor, _ = Floor.objects.get_or_create( building=b, floor_number=n, defaults={ 'name': name, 'area_sqm': area_sqm, 'ceiling_height_m': ceiling_height, 'is_public_access': is_public_access } ) floors.append(floor) return floors def create_rooms(floors): """Create rooms/clinical spaces per floor for hospitals.""" rooms = [] room_types_by_building = { 'inpatient': ['patient_room', 'nurse_station', 'icu_room', 'isolation', 'negative_pressure', 'storage', 'restroom', 'mechanical', 'electrical', 'server'], 'outpatient': ['consult_room', 'clinic_room', 'procedure_room', 'pharmacy_dispensing', 'waiting', 'triage', 'restroom', 'storage', 'server'], 'emergency': ['triage', 'resuscitation', 'fast_track', 'isolation', 'ct_room', 'xray_room', 'waiting', 'nurse_station', 'restroom', 'storage'], 'surgical': ['operating_room', 'preop', 'recovery', 'cssd', 'sterilization', 'anesthesia_storage', 'restroom', 'mechanical', 'electrical'], 'diagnostic': ['mri_room', 'ct_room', 'xray_room', 'ultrasound', 'mammo_room', 'waiting', 'control_room', 'restroom', 'storage'], 'lab': ['lab_blood', 'lab_micro', 'lab_chemistry', 'lab_pathology', 'blood_bank', 'storage', 'restroom', 'mechanical'], 'maternity': ['ld_room', 'nicu', 'picu', 'patient_room', 'nurse_station', 'isolation', 'restroom', 'storage'], 'support': ['cssd', 'laundry', 'kitchen', 'storage', 'mechanical', 'electrical'], 'utility': ['mechanical', 'electrical', 'medical_gas', 'boiler', 'chiller', 'storage'], 'parking': ['security', 'mechanical', 'electrical'], 'office': ['office', 'meeting_room', 'server', 'restroom', 'storage'], 'other': ['prayer_room', 'restroom', 'storage'], } special_rooms = { 'RHF-ED': [ {'room_number': 'G001', 'name': 'منطقة الفرز (Triage Area)', 'room_type': 'triage'}, {'room_number': 'G002', 'name': 'غرفة الإنعاش 1 (Resuscitation 1)', 'room_type': 'resuscitation'}, {'room_number': 'G003', 'name': 'غرفة الإنعاش 2 (Resuscitation 2)', 'room_type': 'resuscitation'}, {'room_number': 'G004', 'name': 'غرفة الأشعة المقطعية (CT Room)', 'room_type': 'ct_room'}, {'room_number': 'G005', 'name': 'غرفة أشعة (X-Ray Room)', 'room_type': 'xray_room'}, ], 'RHF-SURG': [ {'room_number': '201', 'name': 'غرفة عمليات 1 (Operating Room 1)', 'room_type': 'operating_room'}, {'room_number': '202', 'name': 'غرفة عمليات 2 (Operating Room 2)', 'room_type': 'operating_room'}, {'room_number': '203', 'name': 'منطقة التعقيم المركزي (CSSD)', 'room_type': 'cssd'}, {'room_number': '101', 'name': 'منطقة ما قبل العملية (Pre-Op)', 'room_type': 'preop'}, {'room_number': '102', 'name': 'منطقة الإفاقة (Recovery)', 'room_type': 'recovery'}, ], 'RHF-DIAG': [ {'room_number': 'B001', 'name': 'غرفة الرنين المغناطيسي (MRI 1)', 'room_type': 'mri_room'}, {'room_number': 'B002', 'name': 'غرفة الرنين المغناطيسي (MRI 2)', 'room_type': 'mri_room'}, {'room_number': 'A101', 'name': 'غرفة الأشعة المقطعية (CT 1)', 'room_type': 'ct_room'}, {'room_number': 'A201', 'name': 'غرفة الماموغرام (Mammography)', 'room_type': 'mammo_room'}, {'room_number': 'A301', 'name': 'غرفة موجات فوق صوتية (Ultrasound)', 'room_type': 'ultrasound'}, ], 'RHF-LAB': [ {'room_number': '201', 'name': 'مختبر الكيمياء (Chemistry Lab)', 'room_type': 'lab_chemistry'}, {'room_number': '202', 'name': 'مختبر الدم (Hematology Lab)', 'room_type': 'lab_blood'}, {'room_number': '203', 'name': 'بنك الدم (Blood Bank)', 'room_type': 'blood_bank'}, {'room_number': '204', 'name': 'مختبر الأحياء الدقيقة (Microbiology Lab)', 'room_type': 'lab_micro'}, ], 'RHF-MCH': [ {'room_number': '501', 'name': 'غرفة الولادة (L&D 1)', 'room_type': 'ld_room'}, {'room_number': '502', 'name': 'غرفة الولادة (L&D 2)', 'room_type': 'ld_room'}, {'room_number': '301', 'name': 'العناية المركزة لحديثي الولادة (NICU)', 'room_type': 'nicu'}, ], 'RHF-MOSQ': [ {'room_number': '001', 'name': 'صالة الصلاة الرئيسية (Main Prayer Hall)', 'room_type': 'prayer_room'}, {'room_number': '002', 'name': 'قسم النساء (Women\'s Area)', 'room_type': 'prayer_room'}, {'room_number': '003', 'name': 'غرفة الإمام (Imam Room)', 'room_type': 'office'}, {'room_number': '004', 'name': 'مغاسل/وضوء (Ablution)', 'room_type': 'restroom'}, ], } for floor in floors: b = floor.building btype = b.building_type # baseline room count proportional to area if floor.area_sqm: num_rooms = int(floor.area_sqm / Decimal('120.0')) num_rooms = min(max(num_rooms, 6), 40) else: num_rooms = random.randint(6, 20) # Inject special rooms on key buildings (mostly ground & clinical floors) if b.code in special_rooms and floor.floor_number in [0, 1, 2]: for sr in special_rooms[b.code]: room, _ = Room.objects.get_or_create( floor=floor, room_number=sr['room_number'], defaults={ 'name': sr['name'], 'room_type': sr['room_type'], 'area_sqm': Decimal(str(random.uniform(25, 160))), 'capacity': random.randint(1, 12), 'occupancy_status': 'occupied', 'is_accessible': True, 'has_hvac': True, 'has_electrical': True, 'has_plumbing': sr['room_type'] in ['restroom','cssd','sterilization','ld_room'], 'has_internet': True } ) num_rooms = max(5, num_rooms - len(special_rooms[b.code])) # available room types rtypes = room_types_by_building.get(btype, room_types_by_building['other']) for i in range(1, num_rooms + 1): floor_prefix = f'B{abs(floor.floor_number)}' if floor.floor_number < 0 else f'{floor.floor_number}' room_number = f'{floor_prefix}{i:03d}' rtype = random.choice(rtypes) # Name by type name_map = { 'patient_room': 'غرفة مريض', 'icu_room': 'غرفة عناية مركزة', 'nurse_station': 'محطة تمريض', 'isolation': 'غرفة عزل', 'negative_pressure': 'غرفة ضغط سلبي', 'operating_room': 'غرفة عمليات', 'preop': 'منطقة ما قبل العملية', 'recovery': 'منطقة الإفاقة', 'cssd': 'التعقيم المركزي', 'sterilization': 'غرفة التعقيم', 'triage': 'الفرز', 'resuscitation': 'إنعاش', 'fast_track': 'علاج سريع', 'ct_room': 'غرفة أشعة مقطعية', 'xray_room': 'غرفة أشعة', 'mri_room': 'غرفة رنين مغناطيسي', 'ultrasound': 'غرفة موجات فوق صوتية', 'mammo_room': 'غرفة ماموغرام', 'lab_blood': 'مختبر دم', 'lab_micro': 'مختبر أحياء دقيقة', 'lab_chemistry': 'مختبر كيمياء', 'blood_bank': 'بنك الدم', 'ld_room': 'غرفة ولادة', 'nicu': 'العناية المركزة لحديثي الولادة', 'picu': 'عناية مركزة أطفال', 'pharmacy_dispensing': 'صرف الأدوية', 'clinic_room': 'غرفة عيادة', 'consult_room': 'غرفة استشارة', 'waiting': 'منطقة انتظار', 'prayer_room': 'مصلى', 'anesthesia_storage': 'مخزن تخدير', 'medical_gas': 'غرفة غازات طبية', } base_name = name_map.get(rtype, rtype.replace('_',' ').title()) name = f'{base_name} {i}' if rtype not in ['nurse_station','cssd','sterilization','medical_gas'] else base_name # Area/capacity by type if rtype in ['operating_room']: area = Decimal(str(random.uniform(45, 65))) capacity = 6 elif rtype in ['icu_room','isolation','negative_pressure','ld_room']: area = Decimal(str(random.uniform(22, 35))) capacity = 2 elif rtype in ['patient_room','clinic_room','consult_room']: area = Decimal(str(random.uniform(16, 28))) capacity = 2 elif rtype in ['ct_room','xray_room','mri_room','mammo_room','ultrasound','lab_blood','lab_micro','lab_chemistry','blood_bank','cssd','sterilization']: area = Decimal(str(random.uniform(20, 55))) capacity = 4 elif rtype in ['preop','recovery','triage','resuscitation','fast_track','waiting']: area = Decimal(str(random.uniform(18, 50))) capacity = random.randint(4, 20) else: area = Decimal(str(random.uniform(12, 40))) capacity = random.randint(1, 8) has_plumbing = rtype in ['patient_room','icu_room','isolation','negative_pressure','ld_room','cssd','sterilization','lab_blood','lab_micro','lab_chemistry','blood_bank'] has_internet = True room, _ = Room.objects.get_or_create( floor=floor, room_number=room_number, defaults={ 'name': name, 'room_type': rtype, 'area_sqm': area, 'capacity': capacity, 'occupancy_status': random.choice(['VACANT','OCCUPIED','MAINTENANCE']), 'is_accessible': rtype not in ['mechanical','electrical','server'], # 'lease_start_date': None, # 'lease_end_date': None, # 'monthly_rent': None, # 'has_hvac': True, # 'has_electrical': True, # 'has_plumbing': has_plumbing, # 'has_internet': has_internet, 'notes': '' } ) rooms.append(room) return rooms def create_asset_categories(): """Create hospital asset categories (clinical + facility).""" categories = [ # MEDICAL (prefix MED- / LAB-) {'name': 'MRI Scanners', 'code': 'MED-MRI', 'description': 'Magnetic Resonance Imaging systems'}, {'name': 'CT Scanners', 'code': 'MED-CT', 'description': 'Computed Tomography systems'}, {'name': 'X-Ray Systems', 'code': 'MED-XR', 'description': 'General radiography equipment'}, {'name': 'Ultrasound Machines', 'code': 'MED-US', 'description': 'Ultrasound imaging devices'}, {'name': 'Mammography Units', 'code': 'MED-MAM', 'description': 'Breast imaging systems'}, {'name': 'Ventilators', 'code': 'MED-VNT', 'description': 'Mechanical ventilation units'}, {'name': 'Anesthesia Machines', 'code': 'MED-ANES', 'description': 'OR anesthesia delivery systems'}, {'name': 'Patient Monitors', 'code': 'MED-MON', 'description': 'Bedside multiparameter monitors'}, {'name': 'Infusion Pumps', 'code': 'MED-INF', 'description': 'Infusion and syringe pumps'}, {'name': 'Defibrillators', 'code': 'MED-DEF', 'description': 'Defibrillators & AEDs'}, {'name': 'Operating Tables', 'code': 'MED-ORTB', 'description': 'Surgical operating tables'}, {'name': 'OR Lights', 'code': 'MED-ORLT', 'description': 'Surgical lights'}, {'name': 'Autoclaves/Sterilizers', 'code': 'MED-STER', 'description': 'Steam sterilizers for CSSD'}, {'name': 'Blood Bank Refrigerators','code': 'MED-BBFR', 'description': 'Blood storage refrigerators'}, {'name': 'Dialysis Machines', 'code': 'MED-DIAL', 'description': 'Hemodialysis systems'}, {'name': 'Medical Gas Systems', 'code': 'MED-GAS', 'description': 'O2/Vac/Air manifolds & alarms'}, {'name': 'Automated Dispensing', 'code': 'MED-ADISP', 'description': 'Pharmacy dispensing cabinets'}, {'name': 'Lab Analyzers', 'code': 'LAB-ANLYZ', 'description': 'Clinical lab analyzers'}, # IT & COMMS (hospital) {'name': 'PACS', 'code': 'IT-PACS', 'description': 'Picture Archiving & Communication'}, {'name': 'Hospital Information System','code':'IT-HIS', 'description': 'Core HIS/EHR servers'}, {'name': 'Nurse Call', 'code': 'IT-NCALL', 'description': 'Nurse call systems'}, {'name': 'Pneumatic Tube System', 'code': 'IT-PTS', 'description': 'Hospital pneumatic tube network'}, # FACILITY (reuse many of yours) {'name': 'Chillers', 'code': 'HVAC-CHL', 'description': 'Water chillers for AC'}, {'name': 'Air Handling Units', 'code': 'HVAC-AHU', 'description': 'AHUs'}, {'name': 'Cooling Towers', 'code': 'HVAC-CT', 'description': 'Cooling towers'}, {'name': 'Split AC Units', 'code': 'HVAC-SPLIT','description': 'Split AC'}, {'name': 'VRF Systems', 'code': 'HVAC-VRF', 'description': 'VRF systems'}, {'name': 'Generators', 'code': 'ELEC-GEN', 'description': 'Backup generators'}, {'name': 'Transformers', 'code': 'ELEC-TRAN', 'description': 'Power transformers'}, {'name': 'UPS Systems', 'code': 'ELEC-UPS', 'description': 'UPS'}, {'name': 'Distribution Boards', 'code': 'ELEC-DB', 'description': 'Electrical DBs'}, {'name': 'Lighting Systems', 'code': 'ELEC-LIGHT','description': 'Lighting systems'}, {'name': 'Water Pumps', 'code': 'PLMB-PUMP', 'description': 'Water pumps'}, {'name': 'Water Tanks', 'code': 'PLMB-TANK', 'description': 'Water tanks'}, {'name': 'Sanitary Fixtures', 'code': 'PLMB-SAN', 'description': 'Sanitary fixtures'}, {'name': 'Fire Alarm Systems', 'code': 'FIRE-ALARM','description': 'Fire alarm'}, {'name': 'Fire Sprinklers', 'code': 'FIRE-SPR', 'description': 'Sprinklers'}, {'name': 'Fire Extinguishers', 'code': 'FIRE-EXT', 'description': 'Extinguishers'}, {'name': 'Elevators', 'code': 'TRAN-ELEV', 'description': 'Elevators'}, {'name': 'Escalators', 'code': 'TRAN-ESC', 'description': 'Escalators'}, {'name': 'CCTV Systems', 'code': 'SEC-CCTV', 'description': 'Surveillance systems'}, {'name': 'Access Control', 'code': 'SEC-ACC', 'description': 'Access control'}, {'name': 'Network Equipment', 'code': 'IT-NET', 'description': 'Network routers/switches'}, {'name': 'Servers', 'code': 'IT-SRV', 'description': 'Servers'}, {'name': 'Seating', 'code': 'FURN-SEAT', 'description': 'Waiting area seating'}, {'name': 'Counters', 'code': 'FURN-COUNT','description': 'Reception/Pharmacy counters'}, {'name': 'Signage', 'code': 'FURN-SIGN', 'description': 'Wayfinding signage'}, ] out = [] for c in categories: cat, _ = AssetCategory.objects.get_or_create( code=c['code'], defaults={'name': c['name'], 'description': c['description'], 'is_active': True} ) out.append(cat) return out def create_assets(buildings, floors, rooms, asset_categories, users): """Create hospital assets mapped to clinical spaces and facility systems.""" assets = [] # quick lookups cat = {c.code: c for c in asset_categories} manufacturers = { # Clinical 'MED-MRI': ['Siemens Healthineers','GE Healthcare','Philips','Canon Medical'], 'MED-CT': ['Siemens Healthineers','GE Healthcare','Philips','Canon Medical'], 'MED-XR': ['GE Healthcare','Philips','Siemens Healthineers','Shimadzu'], 'MED-US': ['GE Healthcare','Philips','Siemens Healthineers','Mindray','Samsung Medison'], 'MED-MAM': ['Hologic','GE Healthcare','Siemens Healthineers','Fujifilm'], 'MED-VNT': ['Dräger','GE Healthcare','Hamilton Medical','Mindray','Philips'], 'MED-ANES': ['Dräger','GE Healthcare','Mindray','Fabius'], 'MED-MON': ['Philips','GE Healthcare','Mindray','Nihon Kohden'], 'MED-INF': ['B. Braun','BD','Mindray','Fresenius Kabi'], 'MED-DEF': ['Zoll','Philips','Physio-Control','Mindray'], 'MED-ORTB': ['Maquet','Getinge','Stryker','Hillrom'], 'MED-ORLT': ['Stryker','Dräger','Getinge'], 'MED-STER': ['Getinge','Steris','Belimed'], 'MED-BBFR': ['Helmer Scientific','Thermo Fisher','PHCbi'], 'MED-DIAL': ['Fresenius Medical Care','B. Braun','Nipro'], 'MED-GAS': ['BeaconMedaes','Atlas Copco','Parker','Ceodeux'], 'MED-ADISP':['BD Pyxis','Omnicell'], 'LAB-ANLYZ':['Roche','Abbott','Siemens Healthineers','Beckman Coulter'], # IT 'IT-PACS': ['Agfa','INFINITT','Sectra','GE Healthcare'], 'IT-HIS': ['InterSystems','Cerner/Oracle','Epic','Dedalus'], 'IT-NCALL': ['Ascom','Hillrom','Rauland','Jeron'], 'IT-PTS': ['Swisslog','TransLogic'], # Facility 'HVAC-CHL': ['Carrier','Trane','York','Daikin','Zamil'], 'HVAC-AHU': ['Carrier','Trane','York','Al Salem Johnson Controls','Zamil'], 'HVAC-CT': ['Baltimore Aircoil','Evapco','Marley','Zamil'], 'HVAC-SPLIT':['Carrier','LG','Samsung','Zamil','Gree'], 'HVAC-VRF': ['Daikin','Mitsubishi Electric','LG','Samsung'], 'ELEC-GEN': ['Caterpillar','Cummins','MTU','Perkins','Kohler'], 'ELEC-TRAN':['ABB','Siemens','Schneider Electric','GE','Saudi Transformers'], 'ELEC-UPS': ['APC','Eaton','Schneider Electric','Emerson','ABB'], 'ELEC-DB': ['ABB','Schneider Electric','Siemens','Legrand','Hager'], 'ELEC-LIGHT':['Philips','Osram','Zumtobel','Fagerhult','Lucibel'], 'PLMB-PUMP':['Grundfos','Wilo','KSB','Xylem','Ebara'], 'PLMB-TANK':['National Plastic','United Steel Industrial','Dutco Tennant'], 'PLMB-SAN': ['Kohler','American Standard','TOTO','Grohe','Roca'], 'FIRE-ALARM':['Siemens','Honeywell','Johnson Controls','Bosch','Simplex'], 'FIRE-SPR': ['Tyco','Viking','Reliable','Globe','Victaulic'], 'FIRE-EXT': ['Amerex','Badger','Kidde','Buckeye','Saudi Fire Equipment'], 'TRAN-ELEV':['KONE','Otis','Schindler','ThyssenKrupp','Mitsubishi Electric'], 'TRAN-ESC': ['KONE','Otis','Schindler','ThyssenKrupp','Mitsubishi Electric'], 'SEC-CCTV': ['Axis','Bosch','Hikvision','Hanwha Techwin','Avigilon'], 'SEC-ACC': ['HID','Lenel','Honeywell','Johnson Controls','Bosch'], 'IT-NET': ['Cisco','HPE','Juniper','Huawei','Arista'], 'IT-SRV': ['Dell EMC','HPE','IBM','Lenovo','Oracle'], } # helper for assignment def assigned_user_for(code): if code.startswith('MED') or code.startswith('LAB'): return users['ibrahim_bme'] if code.startswith('HVAC'): return users['fahad_hvac'] if code.startswith('ELEC'): return users['khalid_elec'] if code.startswith('IT'): return users['ali_it'] if code.startswith('SEC'): return users['saad_safety'] return users['abdullah_main'] # convenience: rooms by type rooms_by_type = {} for r in rooms: rooms_by_type.setdefault(r.room_type, []).append(r) # 1) Facility backbone per building (similar to your airport logic) for b in buildings: b_rooms = [r for r in rooms if r.floor.building == b] b_floors = [f for f in floors if f.building == b] # Chillers (for most clinical/support/office buildings) if b.building_type in ['inpatient','outpatient','emergency','surgical','diagnostic','lab','maternity','support','office','utility']: num_chillers = max(1, int(float(b.total_area_sqm or 20000) / 20000)) for i in range(1, num_chillers + 1): code = 'HVAC-CHL' if cat.get(code): manuf = random.choice(manufacturers[code]) model = f"{manuf} {random.choice([500,750,1000,1500])}RT" asset_id = f"{b.code}-CHLR-{i:02d}" mech = [r for r in b_rooms if r.room_type in ['mechanical','chiller'] and r.floor.floor_number <= 0] room = random.choice(mech) if mech else None floor = room.floor if room else b_floors[0] if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} Chiller {i}", category=cat[code], building=b, floor=floor, room=room, location_description="Chiller Plant" if not room else "", manufacturer=manuf, model=model, serial_number=f"CHR{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365,3650)), purchase_cost=Decimal(str(random.uniform(200000, 600000))), current_value=Decimal(str(random.uniform(100000, 450000))), status='operational', condition=random.choice(['excellent','good','good','fair']), assigned_to=assigned_user_for(code) )) # AHUs code = 'HVAC-AHU' if cat.get(code): num_ahus = max(2, int(float(b.total_area_sqm or 10000) / 5000)) for i in range(1, num_ahus + 1): manuf = random.choice(manufacturers[code]) model = f"{manuf} Series {random.randint(1000,9999)}" asset_id = f"{b.code}-AHU-{i:02d}" floor = random.choice(b_floors) mech_on_floor = [r for r in b_rooms if r.room_type == 'mechanical' and r.floor == floor] room = random.choice(mech_on_floor) if mech_on_floor else None if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} AHU {i}", category=cat[code], building=b, floor=floor, room=room, location_description=f"AHU {floor.floor_number}-{i}" if not room else "", manufacturer=manuf, model=model, serial_number=f"AHU{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2920)), purchase_cost=Decimal(str(random.uniform(60000, 180000))), current_value=Decimal(str(random.uniform(30000, 110000))), status=random.choices(['operational','maintenance'], weights=[0.9,0.1])[0], condition=random.choice(['excellent','good','good','fair']), assigned_to=assigned_user_for(code) )) # Generators code = 'ELEC-GEN' if cat.get(code): manuf = random.choice(manufacturers[code]) model = f"{manuf} {random.choice([750,1000,1500,2000])}kVA" asset_id = f"{b.code}-GEN-01" elec_rooms = [r for r in b_rooms if r.room_type == 'electrical' and r.floor.floor_number <= 0] room = random.choice(elec_rooms) if elec_rooms else None floor = room.floor if room else b_floors[0] if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} Backup Generator", category=cat[code], building=b, floor=floor, room=room, location_description="Emergency Generator Room" if not room else "", manufacturer=manuf, model=model, serial_number=f"GEN{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365,3650)), purchase_cost=Decimal(str(random.uniform(250000, 600000))), current_value=Decimal(str(random.uniform(120000, 450000))), status='operational', condition=random.choice(['excellent','good','good','fair']), assigned_to=assigned_user_for(code) )) # Elevators (multi-storey) if b.floor_count > 1 and cat.get('TRAN-ELEV'): num_elev = max(2, int(b.floor_count / 2)) for i in range(1, num_elev + 1): manuf = random.choice(manufacturers['TRAN-ELEV']) asset_id = f"{b.code}-ELV-{i:02d}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} Elevator {i}", category=cat['TRAN-ELEV'], building=b, location_description=f"Elevator Core {i}", manufacturer=manuf, model=f"{manuf} {random.choice(['Passenger','Service'])}", serial_number=f"ELV{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365,3650)), purchase_cost=Decimal(str(random.uniform(150000, 350000))), current_value=Decimal(str(random.uniform(80000, 250000))), status=random.choices(['operational','maintenance'], weights=[0.9,0.1])[0], condition=random.choice(['excellent','good','good','fair']), assigned_to=users['ibrahim_bme'], warranty_start_date=timezone.now().date() - timedelta(days=random.randint(365,1825)), warranty_end_date=timezone.now().date() + timedelta(days=random.randint(-365,1825)), service_provider=random.choice(["KONE Saudi Arabia","Otis Saudi Arabia","Schindler Saudi"]) )) # Pneumatic Tube System (replace airport BHS) if b.building_type in ['inpatient','outpatient','emergency','lab'] and cat.get('IT-PTS'): asset_id = f"{b.code}-PTS-01" if not Asset.objects.filter(asset_id=asset_id).exists(): manuf = random.choice(manufacturers['IT-PTS']) assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} Pneumatic Tube System", category=cat['IT-PTS'], building=b, location_description="Hospital-wide network", manufacturer=manuf, model=f"{manuf} PTS", serial_number=f"PTS{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2190)), purchase_cost=Decimal(str(random.uniform(1500000, 4000000))), current_value=Decimal(str(random.uniform(900000, 3000000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ali_it'], service_provider=manuf + " Services" )) # Nurse Call (building level) if b.building_type in ['inpatient','maternity'] and cat.get('IT-NCALL'): asset_id = f"{b.code}-NCALL-01" if not Asset.objects.filter(asset_id=asset_id).exists(): manuf = random.choice(manufacturers['IT-NCALL']) assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} Nurse Call System", category=cat['IT-NCALL'], building=b, location_description="Wards & ICU", manufacturer=manuf, model=f"{manuf} NurseCall", serial_number=f"NCL{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2190)), purchase_cost=Decimal(str(random.uniform(500000, 1500000))), current_value=Decimal(str(random.uniform(300000, 1000000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ali_it'] )) # PACS/HIS (IT backbone) if b.code.endswith('DIAG') and cat.get('IT-PACS'): asset_id = f"{b.code}-PACS-01" if not Asset.objects.filter(asset_id=asset_id).exists(): manuf = random.choice(manufacturers['IT-PACS']) assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} PACS", category=cat['IT-PACS'], building=b, location_description="Data Center / Radiology", manufacturer=manuf, model=f"{manuf} PACS Cluster", serial_number=f"PACS{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2190)), purchase_cost=Decimal(str(random.uniform(1200000, 4000000))), current_value=Decimal(str(random.uniform(700000, 2500000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ali_it'] )) if b.code.endswith('ADMIN') and cat.get('IT-HIS'): asset_id = f"{b.code}-HIS-01" if not Asset.objects.filter(asset_id=asset_id).exists(): manuf = random.choice(manufacturers['IT-HIS']) assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} HIS/EHR", category=cat['IT-HIS'], building=b, location_description="Data Center", manufacturer=manuf, model=f"{manuf} HIS", serial_number=f"HIS{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2190)), purchase_cost=Decimal(str(random.uniform(2000000, 6000000))), current_value=Decimal(str(random.uniform(1200000, 4000000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ali_it'] )) # Security systems if cat.get('SEC-CCTV'): asset_id = f"{b.code}-CCTV-01" if not Asset.objects.filter(asset_id=asset_id).exists(): manuf = random.choice(manufacturers['SEC-CCTV']) assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} CCTV System", category=cat['SEC-CCTV'], building=b, location_description="Throughout building", manufacturer=manuf, model=f"{manuf} CCTV", serial_number=f"CCTV{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2190)), purchase_cost=Decimal(str(random.uniform(200000, 1000000))), current_value=Decimal(str(random.uniform(120000, 800000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['saad_safety'], service_provider="Saudi Security Systems" )) # 2) Clinical assets by room type # Imaging for room in rooms_by_type.get('mri_room', []): code = 'MED-MRI' if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-MRI-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"MRI - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} 1.5T", serial_number=f"MRI{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2920)), purchase_cost=Decimal(str(random.uniform(4000000, 9000000))), current_value=Decimal(str(random.uniform(2000000, 6000000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ibrahim_bme'] )) for room in rooms_by_type.get('ct_room', []): code = 'MED-CT' if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-CT-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"CT - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} 128-slice", serial_number=f"CT{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2920)), purchase_cost=Decimal(str(random.uniform(2500000, 6000000))), current_value=Decimal(str(random.uniform(1200000, 4000000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ibrahim_bme'] )) for room in rooms_by_type.get('xray_room', []): code = 'MED-XR' if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-XR-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"X-Ray - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} DR System", serial_number=f"XR{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2920)), purchase_cost=Decimal(str(random.uniform(800000, 1800000))), current_value=Decimal(str(random.uniform(400000, 1200000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ibrahim_bme'] )) # OR equipment for room in rooms_by_type.get('operating_room', []): for code, name, model in [ ('MED-ANES', 'Anesthesia Machine', 'Anesthesia System'), ('MED-ORTB', 'Operating Table', 'Surgical Table'), ('MED-ORLT', 'OR Light', 'Surgical Light'), ('MED-MON', 'Patient Monitor', 'Multiparameter Monitor'), ]: if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-{code.split('-')[1]}-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"{name} - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} {model}", serial_number=f"{code.replace('-','')}{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), purchase_cost=Decimal(str(random.uniform(80000, 300000))), current_value=Decimal(str(random.uniform(40000, 200000))), status='operational', condition=random.choice(['excellent','good','good','fair']), assigned_to=users['ibrahim_bme'] )) # ICU for room in rooms_by_type.get('icu_room', []): for code in ['MED-VNT','MED-MON','MED-INF','MED-DEF']: if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-{code.split('-')[1]}-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"{code.split('-')[1]} - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} Unit", serial_number=f"{code.replace('-','')}{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), purchase_cost=Decimal(str(random.uniform(15000, 90000))), current_value=Decimal(str(random.uniform(8000, 60000))), status='operational', condition=random.choice(['excellent','good','good','fair']), assigned_to=users['ibrahim_bme'] )) # CSSD & Blood Bank & Pharmacy for room in rooms_by_type.get('cssd', []): code = 'MED-STER' if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-STER-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"Autoclave - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} Steam Sterilizer", serial_number=f"STER{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), purchase_cost=Decimal(str(random.uniform(200000, 600000))), current_value=Decimal(str(random.uniform(120000, 400000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ibrahim_bme'] )) for room in rooms_by_type.get('blood_bank', []): code = 'MED-BBFR' if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-BBFR-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"Blood Bank Fridge - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} BB Fridge", serial_number=f"BBF{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2920)), purchase_cost=Decimal(str(random.uniform(40000, 120000))), current_value=Decimal(str(random.uniform(20000, 90000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ibrahim_bme'] )) for room in rooms_by_type.get('pharmacy_dispensing', []): code = 'MED-ADISP' if cat.get(code): manuf = random.choice(manufacturers[code]) asset_id = f"{room.floor.building.code}-ADISP-{room.room_number}" if not Asset.objects.filter(asset_id=asset_id).exists(): assets.append(Asset.objects.create( asset_id=asset_id, name=f"Automated Dispensing - {room.room_number}", category=cat[code], building=room.floor.building, floor=room.floor, room=room, manufacturer=manuf, model=f"{manuf} ADC", serial_number=f"ADC{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 2920)), purchase_cost=Decimal(str(random.uniform(250000, 600000))), current_value=Decimal(str(random.uniform(120000, 400000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ibrahim_bme'] )) # Medical Gas manifolds in utility/support for b in buildings: if b.building_type in ['utility','support'] and cat.get('MED-GAS'): asset_id = f"{b.code}-MGAS-01" if not Asset.objects.filter(asset_id=asset_id).exists(): manuf = random.choice(manufacturers['MED-GAS']) assets.append(Asset.objects.create( asset_id=asset_id, name=f"{b.name} Medical Gas Manifold", category=cat['MED-GAS'], building=b, location_description="MGPS Room", manufacturer=manuf, model=f"{manuf} MGPS", serial_number=f"MGAS{random.randint(100000,999999)}", purchase_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), purchase_cost=Decimal(str(random.uniform(300000, 900000))), current_value=Decimal(str(random.uniform(180000, 700000))), status='operational', condition=random.choice(['excellent','good']), assigned_to=users['ibrahim_bme'] )) return assets def create_maintenance_types(): """Create maintenance types""" maintenance_types_data = [ { 'name': 'Preventive Maintenance', 'code': 'PM', 'description': 'Regular scheduled maintenance to prevent breakdowns', 'estimated_duration_hours': Decimal('4.00') }, { 'name': 'Corrective Maintenance', 'code': 'CM', 'description': 'Repairs to fix equipment failures or malfunctions', 'estimated_duration_hours': Decimal('6.00') }, { 'name': 'Emergency Repair', 'code': 'ER', 'description': 'Immediate repairs for critical systems', 'estimated_duration_hours': Decimal('3.00') }, { 'name': 'Safety Inspection', 'code': 'SI', 'description': 'Inspection to ensure safety compliance', 'estimated_duration_hours': Decimal('2.00') }, { 'name': 'Overhaul', 'code': 'OH', 'description': 'Complete disassembly and renewal of equipment', 'estimated_duration_hours': Decimal('24.00') }, { 'name': 'Cleaning', 'code': 'CL', 'description': 'Cleaning of equipment and systems', 'estimated_duration_hours': Decimal('2.00') }, { 'name': 'Calibration', 'code': 'CB', 'description': 'Calibration of instruments and controls', 'estimated_duration_hours': Decimal('1.50') }, { 'name': 'Software Update', 'code': 'SU', 'description': 'Update of system software and firmware', 'estimated_duration_hours': Decimal('2.00') }, { 'name': 'Replacement', 'code': 'RP', 'description': 'Replacement of worn parts or components', 'estimated_duration_hours': Decimal('4.00') }, { 'name': 'Inspection', 'code': 'IN', 'description': 'General inspection of equipment', 'estimated_duration_hours': Decimal('1.00') } ] maintenance_types = [] for data in maintenance_types_data: maint_type, created = MaintenanceType.objects.get_or_create( code=data['code'], defaults={ 'name': data['name'], 'description': data['description'], 'estimated_duration_hours': data['estimated_duration_hours'], 'is_active': True } ) maintenance_types.append(maint_type) return maintenance_types def create_maintenance_requests(buildings, floors, rooms, assets, maintenance_types, users): """Create hospital-flavored maintenance requests.""" requests = [] issues = [ {'title': 'جهاز التنفس يعرض إنذار (Ventilator Alarm)', 'description': 'إنذار ضغط عالي في جهاز التنفس بوحدة العناية. (High-pressure alarm on ICU ventilator.)', 'maintenance_type':'CM','priority':'urgent'}, {'title': 'تسرب أكسجين في MGPS (O₂ Leak)', 'description': 'رائحة أكسجين ملحوظة في غرفة الغازات الطبية. (Notable O₂ smell in MGPS room.)', 'maintenance_type':'ER','priority':'emergency'}, {'title': 'تعطل جهاز التعقيم (Autoclave Down)', 'description': 'تعطل جهاز التعقيم في CSSD. (Autoclave fault in CSSD.)', 'maintenance_type':'ER','priority':'high'}, {'title': 'انقطاع نظام نداء التمريض (Nurse Call Outage)', 'description': 'تعطل نقاط نداء التمريض في جناح 5B. (Nurse call endpoints down in ward 5B.)', 'maintenance_type':'CM','priority':'high'}, {'title': 'ارتفاع حرارة بنك الدم (Blood Bank Temp High)', 'description': 'درجة حرارة ثلاجة بنك الدم مرتفعة. (Blood bank fridge temp out of range.)', 'maintenance_type':'ER','priority':'urgent'}, {'title': 'خلل في جهاز CT (CT Fault)', 'description': 'رمز خطأ متكرر في جهاز الأشعة المقطعية. (Recurring fault code on CT.)', 'maintenance_type':'CM','priority':'high'}, {'title': 'مشكلة ضغط سلبي (Negative Pressure Issue)', 'description': 'عدم ثبات الضغط السلبي بغرفة العزل. (Negative pressure not holding.)', 'maintenance_type':'IN','priority':'medium'}, {'title': 'تسرب مياه (Water Leak)', 'description': 'تسرب من سقف جناح المرضى. (Ceiling water leak on inpatient floor.)', 'maintenance_type':'ER','priority':'urgent'}, {'title': 'إضاءة غرفة العمليات وميض (OR Light Flicker)', 'description': 'وميض في إضاءة غرفة العمليات. (OR lights flickering.)', 'maintenance_type':'CM','priority':'high'}, {'title': 'ضوضاء شديدة AHU (AHU Noise)', 'description': 'صوت غير طبيعي في AHU الطابق 3. (Unusual noise in AHU L3.)', 'maintenance_type':'IN','priority':'medium'}, {'title': 'توقف مصعد (Elevator Stopped)', 'description': 'المصعد رقم 2 متوقف. (Elevator #2 stopped.)', 'maintenance_type':'ER','priority':'high'}, {'title': 'تحديث برنامج PACS (PACS Update)', 'description': 'تحديث أمني عاجل لنظام PACS. (Urgent security patch for PACS.)', 'maintenance_type':'SU','priority':'medium'}, ] # asset-bound requests for asset in random.sample(assets, min(60, len(assets))): issue = random.choice(issues) mtype = next((mt for mt in maintenance_types if mt.code == issue['maintenance_type']), maintenance_types[0]) status = random.choices(['completed','in_progress','assigned','submitted','on_hold'], weights=[0.35,0.2,0.1,0.25,0.1])[0] requested_date = timezone.now() - timedelta(days=random.randint(1, 90)) scheduled_date = requested_date + timedelta(days=random.randint(1, 7)) if status != 'submitted' else None started_date = scheduled_date + timedelta(hours=random.randint(1, 24)) if status in ['in_progress','completed'] else None completed_date = started_date + timedelta(hours=random.randint(1, 48)) if status == 'completed' else None # assign by category prefix if asset.category.code.startswith('HVAC'): assigned_to = users['fahad_hvac'] elif asset.category.code.startswith('ELEC'): assigned_to = users['khalid_elec'] elif asset.category.code.startswith(('MED','LAB')): assigned_to = users['ibrahim_bme'] elif asset.category.code.startswith('IT'): assigned_to = users['ali_it'] elif asset.category.code.startswith('SEC'): assigned_to = users['saad_safety'] else: assigned_to = users['abdullah_main'] if status == 'submitted': assigned_to = None est = Decimal(str(random.uniform(800, 8000))) if status != 'submitted' else None actual = est * Decimal(str(random.uniform(0.8, 1.25))) if status == 'completed' else None request_id = f"MR-{timezone.now().strftime('%Y%m%d')}-{random.randint(1000, 9999)}" if not MaintenanceRequest.objects.filter(request_id=request_id).exists(): requests.append(MaintenanceRequest.objects.create( request_id=request_id, title=issue['title'], description=issue['description'], maintenance_type=mtype, building=asset.building, floor=asset.floor, room=asset.room, asset=asset, priority=issue['priority'], status=status, requested_by=random.choice(list(users.values())), assigned_to=assigned_to, requested_date=requested_date, scheduled_date=scheduled_date, started_date=started_date, completed_date=completed_date, estimated_cost=est, actual_cost=actual, notes='', completion_notes=random.choice([ 'تم الإصلاح والاختبار بنجاح. (Fixed and tested)', 'استبدال القطعة المعطلة. (Replaced faulty part)', 'ترقية البرنامج واستقرار النظام. (Patched and stabilized)' ]) if status == 'completed' else '' )) # room-level (no specific asset) for room in random.sample(rooms, min(40, len(rooms))): issue = random.choice(issues) mtype = next((mt for mt in maintenance_types if mt.code == issue['maintenance_type']), maintenance_types[0]) status = random.choices(['completed','in_progress','assigned','submitted','on_hold'], weights=[0.3,0.2,0.1,0.3,0.1])[0] requested_date = timezone.now() - timedelta(days=random.randint(1, 60)) scheduled_date = requested_date + timedelta(days=random.randint(1, 5)) if status != 'submitted' else None started_date = scheduled_date + timedelta(hours=random.randint(1, 24)) if status in ['in_progress','completed'] else None completed_date = started_date + timedelta(hours=random.randint(1, 48)) if status == 'completed' else None assigned_to = random.choice([users['abdullah_main'], users['ibrahim_bme'], users['fahad_hvac']]) if status != 'submitted' else None request_id = f"MR-{timezone.now().strftime('%Y%m%d')}-{random.randint(1000, 9999)}" if not MaintenanceRequest.objects.filter(request_id=request_id).exists(): requests.append(MaintenanceRequest.objects.create( request_id=request_id, title=issue['title'], description=issue['description'], maintenance_type=mtype, building=room.floor.building, floor=room.floor, room=room, priority=issue['priority'], status=status, requested_by=random.choice(list(users.values())), assigned_to=assigned_to, requested_date=requested_date, scheduled_date=scheduled_date, started_date=started_date, completed_date=completed_date, notes='' )) return requests def create_maintenance_schedules(assets, maintenance_types, users): """Create maintenance schedules""" schedules = [] # Create scheduled maintenance for critical assets critical_asset_types = ['HVAC-CHL', 'ELEC-GEN', 'TRAN-ELEV', 'TRAN-ESC', 'TRAN-BHS', 'FIRE-ALARM'] critical_assets = [a for a in assets if a.category.code in critical_asset_types] for asset in critical_assets: # Select appropriate maintenance type if asset.category.code.startswith('HVAC'): maint_type_code = 'PM' frequency = random.choice(['quarterly', 'monthly']) name = f"Scheduled HVAC Maintenance - {asset.name}" elif asset.category.code.startswith('ELEC'): maint_type_code = 'PM' frequency = 'monthly' name = f"Electrical System Maintenance - {asset.name}" elif asset.category.code.startswith('TRAN'): maint_type_code = 'PM' frequency = 'monthly' name = f"Transportation System Maintenance - {asset.name}" elif asset.category.code.startswith('FIRE'): maint_type_code = 'SI' frequency = 'quarterly' name = f"Fire System Safety Inspection - {asset.name}" else: maint_type_code = 'PM' frequency = random.choice(['semi_annual', 'quarterly']) name = f"Scheduled Maintenance - {asset.name}" maint_type = next((mt for mt in maintenance_types if mt.code == maint_type_code), maintenance_types[0]) # Determine who's responsible if asset.category.code.startswith('HVAC'): assigned_to = users['fahad_hvac'] elif asset.category.code.startswith('ELEC'): assigned_to = users['khalid_elec'] elif asset.category.code.startswith('TRAN'): assigned_to = users['ibrahim_eng'] elif asset.category.code.startswith('FIRE'): assigned_to = users['saad_safety'] else: assigned_to = users['abdullah_main'] # Dates start_date = timezone.now().date() - timedelta(days=random.randint(90, 365)) end_date = start_date + timedelta(days=365 * 2) # 2 year schedule next_due_date = timezone.now().date() + timedelta(days=random.randint(1, 90)) # Check if schedule already exists for this asset if not MaintenanceSchedule.objects.filter(asset=asset, name=name).exists(): schedule = MaintenanceSchedule.objects.create( name=name, description=f"Regular maintenance schedule for {asset.name}", maintenance_type=maint_type, asset=asset, building=asset.building, frequency=frequency, frequency_interval=1, start_date=start_date, end_date=end_date, assigned_to=assigned_to, estimated_duration_hours=maint_type.estimated_duration_hours, is_active=True, last_generated_date=timezone.now().date() - timedelta(days=random.randint(30, 90)), next_due_date=next_due_date ) schedules.append(schedule) # Create some building-wide maintenance schedules for building in set(a.building for a in assets): # HVAC Cleaning Schedule name = f"{building.name} - HVAC System Cleaning" maint_type = next((mt for mt in maintenance_types if mt.code == 'CL'), maintenance_types[0]) if not MaintenanceSchedule.objects.filter(building=building, name=name).exists(): schedule = MaintenanceSchedule.objects.create( name=name, description="Regular cleaning of all HVAC components including filters, coils, and ducts", maintenance_type=maint_type, building=building, frequency='quarterly', frequency_interval=1, start_date=timezone.now().date() - timedelta(days=random.randint(90, 365)), end_date=timezone.now().date() + timedelta(days=365 * 2), assigned_to=users['fahad_hvac'], estimated_duration_hours=Decimal('16.00'), is_active=True, next_due_date=timezone.now().date() + timedelta(days=random.randint(1, 90)) ) schedules.append(schedule) # Fire Safety Inspection name = f"{building.name} - Fire Safety Systems Inspection" maint_type = next((mt for mt in maintenance_types if mt.code == 'SI'), maintenance_types[0]) if not MaintenanceSchedule.objects.filter(building=building, name=name).exists(): schedule = MaintenanceSchedule.objects.create( name=name, description="Comprehensive inspection of all fire safety systems including alarms, sprinklers, and extinguishers", maintenance_type=maint_type, building=building, frequency='monthly', frequency_interval=1, start_date=timezone.now().date() - timedelta(days=random.randint(90, 365)), end_date=timezone.now().date() + timedelta(days=365 * 2), assigned_to=users['saad_safety'], estimated_duration_hours=Decimal('8.00'), is_active=True, next_due_date=timezone.now().date() + timedelta(days=random.randint(1, 30)) ) schedules.append(schedule) return schedules def create_vendors(): """Create service vendors""" vendors_data = [ { 'name': 'Saudi HVAC Services Co.', 'vendor_type': 'hvac', 'contact_person': 'Mohammed Al-Harbi', 'email': 'info@saudihvac.com', 'phone': '+966 11 482 3456', 'address': 'Industrial Area, Riyadh, Saudi Arabia', 'license_number': 'LIC-22-45678', 'rating': Decimal('4.50') }, { 'name': 'Al Faisal Maintenance', 'vendor_type': 'maintenance', 'contact_person': 'Abdullah Al-Faisal', 'email': 'info@alfaisalmaint.com.sa', 'phone': '+966 11 463 7890', 'address': 'King Fahd Road, Riyadh, Saudi Arabia', 'license_number': 'LIC-23-12345', 'rating': Decimal('4.20') }, { 'name': 'Zamil Air Conditioners', 'vendor_type': 'hvac', 'contact_person': 'Khalid Al-Zamil', 'email': 'service@zamilac.com', 'phone': '+966 13 847 5678', 'address': 'Dammam Industrial City, Dammam, Saudi Arabia', 'license_number': 'LIC-19-34567', 'rating': Decimal('4.80') }, { 'name': 'Saudi Electrical Services Ltd.', 'vendor_type': 'electrical', 'contact_person': 'Ibrahim Al-Saud', 'email': 'service@saudielectrical.com.sa', 'phone': '+966 12 667 8901', 'address': 'Industrial Zone, Jeddah, Saudi Arabia', 'license_number': 'LIC-21-56789', 'rating': Decimal('4.30') }, { 'name': 'KONE Saudi Arabia', 'vendor_type': 'maintenance', 'contact_person': 'Omar Al-Tuwairqi', 'email': 'service.sa@kone.com', 'phone': '+966 11 465 0123', 'address': 'Olaya District, Riyadh, Saudi Arabia', 'license_number': 'LIC-20-67890', 'rating': Decimal('4.60') }, { 'name': 'Al Jazirah Cleaning Services', 'vendor_type': 'cleaning', 'contact_person': 'Ahmed Al-Juhani', 'email': 'info@aljaziraservices.com', 'phone': '+966 11 482 3456', 'address': 'Malaz District, Riyadh, Saudi Arabia', 'license_number': 'LIC-22-78901', 'rating': Decimal('3.90') }, { 'name': 'Saudi Security Systems', 'vendor_type': 'security', 'contact_person': 'Majid Al-Otaibi', 'email': 'info@saudisecurity.com.sa', 'phone': '+966 12 665 4321', 'address': 'Palestine Street, Jeddah, Saudi Arabia', 'license_number': 'LIC-21-89012', 'rating': Decimal('4.40') }, { 'name': 'Dar Al-Handasah Consultants', 'vendor_type': 'maintenance', 'contact_person': 'Saad Al-Shaikh', 'email': 'riyadh@dargroup.com', 'phone': '+966 11 464 5678', 'address': 'King Faisal Foundation Building, Riyadh, Saudi Arabia', 'license_number': 'LIC-18-90123', 'rating': Decimal('4.70') }, { 'name': 'Al-Yamama Plumbing & Water Systems', 'vendor_type': 'plumbing', 'contact_person': 'Fahad Al-Yamani', 'email': 'service@alyamama.com.sa', 'phone': '+966 13 845 6789', 'address': 'King Abdulaziz Road, Dammam, Saudi Arabia', 'license_number': 'LIC-20-01234', 'rating': Decimal('4.10') }, { 'name': 'Saudi Fire Protection Co.', 'vendor_type': 'maintenance', 'contact_person': 'Ali Al-Qahtani', 'email': 'info@saudifire.com', 'phone': '+966 11 482 9012', 'address': 'Industrial City, Riyadh, Saudi Arabia', 'license_number': 'LIC-19-12345', 'rating': Decimal('4.50') }, ] vendors = [] for data in vendors_data: # Add insurance data data['insurance_policy'] = f"INS-{random.randint(10000, 99999)}" data['insurance_expiry'] = timezone.now().date() + timedelta(days=random.randint(30, 730)) data['total_contracts'] = random.randint(3, 25) data['is_active'] = True vendor, created = Vendor.objects.get_or_create( name=data['name'], defaults=data ) vendors.append(vendor) return vendors def create_service_contracts(buildings, vendors, users): """Create service contracts""" contracts = [] # Match vendors with appropriate buildings for vendor in vendors: # How many contracts should this vendor have num_contracts = random.randint(1, 3) for _ in range(num_contracts): # Select a building building = random.choice(buildings) # Contract duration 1-3 years duration_days = random.randint(365, 365 * 3) start_date = timezone.now().date() - timedelta(days=random.randint(0, 730)) end_date = start_date + timedelta(days=duration_days) # Determine contract status if end_date < timezone.now().date(): status = 'expired' elif start_date > timezone.now().date(): status = 'draft' else: status = 'active' # Contract value depends on vendor type and building size if vendor.vendor_type == 'cleaning': value_base = 50000 elif vendor.vendor_type in ['hvac', 'electrical', 'maintenance']: value_base = 200000 else: value_base = 100000 # Adjust for building size if building.total_area_sqm: size_factor = float(building.total_area_sqm) / 50000.0 size_factor = min(max(size_factor, 0.5), 5.0) # Limit factor range else: size_factor = 1.0 contract_value = Decimal(str(value_base * size_factor * random.uniform(0.8, 1.2))) # Generate contract title if vendor.vendor_type == 'hvac': title = f"{building.name} HVAC Maintenance Contract" service_areas = "All HVAC systems including chillers, AHUs, and ventilation systems" elif vendor.vendor_type == 'electrical': title = f"{building.name} Electrical Systems Service Contract" service_areas = "Electrical distribution systems, lighting, and power backup systems" elif vendor.vendor_type == 'cleaning': title = f"{building.name} Cleaning Services Contract" service_areas = "All public areas, offices, and restrooms" elif vendor.vendor_type == 'security': title = f"{building.name} Security Systems Maintenance" service_areas = "CCTV, access control, and security systems" elif vendor.vendor_type == 'plumbing': title = f"{building.name} Plumbing and Water Systems Maintenance" service_areas = "Water supply, drainage, and sanitary systems" else: title = f"{building.name} General Maintenance Services" service_areas = "General building systems and equipment" # Generate contract number contract_number = f"SC-{building.code}-{vendor.vendor_type.upper()[:3]}-{random.randint(1000, 9999)}" # Manager depends on contract type if vendor.vendor_type == 'hvac': manager = users['fahad_hvac'] elif vendor.vendor_type == 'electrical': manager = users['khalid_elec'] elif vendor.vendor_type == 'security': manager = users['saad_safety'] else: manager = users['mohammed_fm'] if not ServiceContract.objects.filter(contract_number=contract_number).exists(): contract = ServiceContract.objects.create( contract_number=contract_number, vendor=vendor, title=title, description=f"Service contract with {vendor.name} for {building.name}", start_date=start_date, end_date=end_date, contract_value=contract_value, payment_terms=random.choice(['Net 30', 'Net 45', 'Net 60']), service_areas=service_areas, status=status, auto_renewal=random.choice([True, False]), renewal_notice_days=30, contract_manager=manager, notes="" ) # Add buildings to contract contract.buildings.add(building) contracts.append(contract) return contracts def create_inspections(buildings, users): """Create hospital inspections (CBAHI/SFDA/etc.).""" inspections = [] insp_types = [ {'type':'safety', 'title_prefix':'Safety Compliance Inspection', 'inspector':'saad_safety', 'org':'Saudi Civil Defense'}, {'type':'fire', 'title_prefix':'Fire Safety Systems Inspection', 'inspector':'saad_safety', 'org':'Saudi Civil Defense Fire Dept'}, {'type':'infection', 'title_prefix':'Infection Control Audit', 'inspector':'aisha_ops', 'org':'Ministry of Health - Infection Control'}, {'type':'biomed', 'title_prefix':'Biomedical Equipment Audit', 'inspector':'ibrahim_bme', 'org':'Saudi Food & Drug Authority (SFDA)'}, {'type':'cbahi', 'title_prefix':'CBAHI Accreditation Survey', 'inspector':'aisha_ops', 'org':'CBAHI'}, {'type':'radiation', 'title_prefix':'Radiation Safety Inspection', 'inspector':'ibrahim_bme', 'org':'Radiation Protection - KSA'}, {'type':'environment', 'title_prefix':'Environmental Health Inspection', 'inspector':'aisha_ops', 'org':'Saudi Environmental Agency'}, {'type':'electrical', 'title_prefix':'Electrical Systems Safety Inspection', 'inspector':'khalid_elec', 'org':'Saudi Electrical Engineering Dept'}, {'type':'hvac', 'title_prefix':'HVAC Performance Audit', 'inspector':'fahad_hvac', 'org':'Saudi HVAC Association'}, ] for b in buildings: for _ in range(random.randint(2, 5)): t = random.choice(insp_types) scheduled_date = timezone.now() - timedelta(days=random.randint(1, 180)) if scheduled_date > timezone.now(): status = 'scheduled'; started_date = None; completed_date = None elif scheduled_date + timedelta(days=1) > timezone.now(): status = 'in_progress'; started_date = scheduled_date + timedelta(hours=random.randint(1,8)); completed_date = None else: status = 'completed'; started_date = scheduled_date + timedelta(hours=random.randint(1,4)); completed_date = started_date + timedelta(hours=random.randint(2,8)) inspection_id = f"INS-{timezone.now().strftime('%Y%m%d')}-{random.randint(1000, 9999)}" if not Inspection.objects.filter(inspection_id=inspection_id).exists(): insp = Inspection.objects.create( inspection_id=inspection_id, inspection_type=t['type'], title=f"{t['title_prefix']} - {b.name}", description=f"Comprehensive {t['type']} inspection of {b.name}", building=b, scheduled_date=scheduled_date, estimated_duration_hours=Decimal(str(random.uniform(2.0, 8.0))), inspector=users[t['inspector']], inspector_external=f"Inspector from {t['org']}", inspector_organization=t['org'], status=status, started_date=started_date, completed_date=completed_date ) if status == 'completed': overall = random.choices(['Pass','Conditional Pass','Fail'], weights=[0.7,0.2,0.1])[0] insp.overall_rating = overall if overall == 'Pass': insp.findings = "Compliant with KSA regulations; minor recommendations." insp.recommendations = "Maintain schedules; update logs as per CBAHI." insp.requires_followup = False elif overall == 'Conditional Pass': insp.findings = "Mostly compliant; several items need attention within 30 days." insp.recommendations = "Close findings within 30 days; submit action plan to CBAHI/SFDA." insp.requires_followup = True insp.followup_date = (completed_date + timedelta(days=30)).date() else: insp.findings = "Significant non-conformities detected." insp.recommendations = "Immediate remediation and reinspection required." insp.requires_followup = True insp.followup_date = (completed_date + timedelta(days=14)).date() insp.save() # Scope (a few floors/rooms) if b.floors.exists(): for fl in random.sample(list(b.floors.all()), min(3, b.floors.count())): insp.floors.add(fl) if fl.rooms.exists(): for r in random.sample(list(fl.rooms.all()), min(5, fl.rooms.count())): insp.rooms.add(r) inspections.append(insp) return inspections def create_energy_meters(buildings, users): """Create energy meters""" meters = [] # Create different types of meters for each building for building in buildings: # Electricity meters meter_id = f"{building.code}-ELEC-01" if not EnergyMeter.objects.filter(meter_id=meter_id).exists(): elec_meter = EnergyMeter.objects.create( meter_id=meter_id, meter_type='electricity', building=building, location_description="Main Electrical Room", manufacturer=random.choice(["Schneider Electric", "ABB", "Siemens", "GE", "Eaton"]), model=f"PowerLogic {random.randint(1000, 9999)}", serial_number=f"E{random.randint(100000, 999999)}", installation_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), current_reading=Decimal(str(random.uniform(50000, 5000000))), last_reading_date=timezone.now() - timedelta(days=random.randint(1, 30)), is_active=True, calibration_date=timezone.now().date() - timedelta(days=random.randint(30, 365)), next_calibration_date=timezone.now().date() + timedelta(days=random.randint(30, 365)) ) meters.append(elec_meter) # Water meter meter_id = f"{building.code}-WATER-01" if not EnergyMeter.objects.filter(meter_id=meter_id).exists(): water_meter = EnergyMeter.objects.create( meter_id=meter_id, meter_type='water', building=building, location_description="Main Water Supply Room", manufacturer=random.choice(["Zenner", "Itron", "Kamstrup", "Elster", "Badger Meter"]), model=f"FlowMaster {random.randint(100, 999)}", serial_number=f"W{random.randint(100000, 999999)}", installation_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), current_reading=Decimal(str(random.uniform(5000, 500000))), last_reading_date=timezone.now() - timedelta(days=random.randint(1, 30)), is_active=True, calibration_date=timezone.now().date() - timedelta(days=random.randint(30, 365)), next_calibration_date=timezone.now().date() + timedelta(days=random.randint(30, 365)) ) meters.append(water_meter) # Add gas meter for buildings with HVAC systems if building.building_type in ['terminal', 'office', 'maintenance']: meter_id = f"{building.code}-GAS-01" if not EnergyMeter.objects.filter(meter_id=meter_id).exists(): gas_meter = EnergyMeter.objects.create( meter_id=meter_id, meter_type='gas', building=building, location_description="Gas Supply Room", manufacturer=random.choice(["Elster", "Itron", "Dresser", "Actaris", "Sensus"]), model=f"GasTracker {random.randint(100, 999)}", serial_number=f"G{random.randint(100000, 999999)}", installation_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), current_reading=Decimal(str(random.uniform(1000, 100000))), last_reading_date=timezone.now() - timedelta(days=random.randint(1, 30)), is_active=True, calibration_date=timezone.now().date() - timedelta(days=random.randint(30, 365)), next_calibration_date=timezone.now().date() + timedelta(days=random.randint(30, 365)) ) meters.append(gas_meter) # Add chilled water meter for large terminals if building.building_type == 'terminal' and building.total_area_sqm and building.total_area_sqm > Decimal( '100000'): meter_id = f"{building.code}-CHW-01" if not EnergyMeter.objects.filter(meter_id=meter_id).exists(): chw_meter = EnergyMeter.objects.create( meter_id=meter_id, meter_type='chilled_water', building=building, location_description="Chiller Plant Room", manufacturer=random.choice(["Kamstrup", "Siemens", "Danfoss", "Honeywell", "Belimo"]), model=f"CoolTrack {random.randint(100, 999)}", serial_number=f"C{random.randint(100000, 999999)}", installation_date=timezone.now().date() - timedelta(days=random.randint(365, 3650)), current_reading=Decimal(str(random.uniform(10000, 1000000))), last_reading_date=timezone.now() - timedelta(days=random.randint(1, 30)), is_active=True, calibration_date=timezone.now().date() - timedelta(days=random.randint(30, 365)), next_calibration_date=timezone.now().date() + timedelta(days=random.randint(30, 365)) ) meters.append(chw_meter) return meters def create_energy_readings(meters, users): """Create historical energy readings""" readings = [] # Create 12 months of monthly readings for each meter for meter in meters: prev_reading = meter.current_reading * Decimal('0.7') # Start at 70% of current for month in range(12, 0, -1): reading_date = timezone.now() - timedelta(days=30 * month + random.randint(0, 5)) # Calculate consumption growth # Summer months (May-Sept) have higher consumption in Saudi Arabia month_num = reading_date.month if meter.meter_type == 'electricity' and 5 <= month_num <= 9: growth_factor = random.uniform(1.05, 1.15) # Higher consumption in summer for AC elif meter.meter_type == 'water' and 5 <= month_num <= 9: growth_factor = random.uniform(1.03, 1.08) # Higher water use in summer else: growth_factor = random.uniform(0.95, 1.05) # Normal variation # Create reading new_reading = prev_reading * Decimal(str(growth_factor)) consumption = new_reading - prev_reading # Calculate cost based on meter type and consumption if meter.meter_type == 'electricity': unit_cost = Decimal('0.18') # SAR per kWh elif meter.meter_type == 'water': unit_cost = Decimal('2.5') # SAR per cubic meter elif meter.meter_type == 'gas': unit_cost = Decimal('0.9') # SAR per cubic meter else: unit_cost = Decimal('0.15') # SAR per kWh equivalent cost = consumption * unit_cost # Check if reading already exists if not EnergyReading.objects.filter(meter=meter, reading_date=reading_date).exists(): # Create the reading reading = EnergyReading.objects.create( meter=meter, reading_date=reading_date, reading_value=new_reading, consumption=consumption, cost=cost, read_by=users['nora_admin'], is_estimated=False, notes="" ) readings.append(reading) prev_reading = new_reading return readings def create_space_reservations(rooms, users): """Create space reservations (conference/training/sim labs/clinics).""" reservations = [] reservable = [r for r in rooms if r.room_type in ['meeting_room','consult_room','clinic_room','other','prayer_room']] titles = [ 'اجتماع الجودة السريرية (Clinical Quality Meeting)', 'لجنة مكافحة العدوى (Infection Control Committee)', 'مؤتمر علمي (Scientific Conference)', 'تدريب الطوارئ (ED Training)', 'محاكاة غرفة العمليات (OR Simulation)', 'اجتماع إدارة الأسرة (Bed Management Meeting)', 'اجتماع شهري (Monthly Meeting)', 'مراجعة مؤشرات الأداء (KPI Review)' ] for i in range(50): room = random.choice(reservable) if reservable else random.choice(rooms) is_past = random.random() < 0.6 if is_past: start = timezone.now() - timedelta(days=random.randint(1,90), hours=random.randint(1,8)) duration = random.randint(1,4) end = start + timedelta(hours=duration) status = random.choices(['completed','no_show','cancelled'], weights=[0.8,0.1,0.1])[0] else: start = timezone.now() + timedelta(days=random.randint(1,60), hours=random.randint(1,8)) duration = random.randint(1,4) end = start + timedelta(hours=duration) status = random.choices(['confirmed','pending'], weights=[0.7,0.3])[0] reserved_by = random.choice(list(users.values())) reservation_id = f"RES-{timezone.now().strftime('%Y%m%d')}-{i+1:04d}" if not SpaceReservation.objects.filter(reservation_id=reservation_id).exists(): r = SpaceReservation.objects.create( reservation_id=reservation_id, room=room, title=random.choice(titles), description="Hospital meeting/training reservation", start_datetime=start, end_datetime=end, reserved_by=reserved_by, contact_person=f"{reserved_by.first_name} {reserved_by.last_name}", contact_email=reserved_by.email, contact_phone="+966 5" + str(random.randint(10000000, 99999999)), expected_attendees=random.randint(4, 30), setup_requirements=random.choice(["Standard setup", "U-shape arrangement", "Theater style", ""]), catering_required=random.choice([True, False]), av_equipment_required=True, status=status, hourly_rate=Decimal(str(random.randint(50, 250))) if room.room_type == 'meeting_room' else None, notes="" ) if status == 'confirmed': r.approved_by = users['nora_admin'] r.approved_at = start - timedelta(days=random.randint(1,10)) r.save() reservations.append(r) return reservations @transaction.atomic def main(): """Generate all sample data""" print("Generating KSA facility management data...") users, users_dict = create_users() print("✓ Created users") buildings = create_buildings(users_dict) print("✓ Created buildings") floors = create_floors(buildings) print("✓ Created floors") rooms = create_rooms(floors) print("✓ Created rooms") asset_categories = create_asset_categories() print("✓ Created asset categories") assets = create_assets(buildings, floors, rooms, asset_categories, users_dict) print("✓ Created assets") maintenance_types = create_maintenance_types() print("✓ Created maintenance types") maintenance_requests = create_maintenance_requests(buildings, floors, rooms, assets, maintenance_types, users_dict) print("✓ Created maintenance requests") maintenance_schedules = create_maintenance_schedules(assets, maintenance_types, users_dict) print("✓ Created maintenance schedules") vendors = create_vendors() print("✓ Created vendors") service_contracts = create_service_contracts(buildings, vendors, users_dict) print("✓ Created service contracts") inspections = create_inspections(buildings, users_dict) print("✓ Created inspections") energy_meters = create_energy_meters(buildings, users_dict) print("✓ Created energy meters") energy_readings = create_energy_readings(energy_meters, users_dict) print("✓ Created energy readings") space_reservations = create_space_reservations(rooms, users_dict) print("✓ Created space reservations") print("Data generation complete!") if __name__ == "__main__": main()