import os import django # Set up Django environment os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'airport_management.settings') django.setup() import random import uuid from decimal import Decimal from datetime import date, datetime, timedelta from django.utils import timezone from django.db import models from django.contrib.auth.models import User from ebt.models import * def create_users(): """Create user accounts for the system""" users = [] # Create admin user if it doesn't exist admin_username = 'admin' if not User.objects.filter(username=admin_username).exists(): admin_user = User.objects.create_superuser( username=admin_username, email='admin@example.com', password='adminpassword', first_name='System', last_name='Administrator' ) users.append(admin_user) # Create staff users for different roles staff_data = [ {'username': 'manager1', 'email': 'manager1@example.com', 'password': 'managerpassword', 'first_name': 'Abdullah', 'last_name': 'Al-Otaibi', 'is_staff': True}, {'username': 'supervisor1', 'email': 'supervisor1@example.com', 'password': 'supervisorpassword', 'first_name': 'Mohammed', 'last_name': 'Al-Ghamdi', 'is_staff': True}, {'username': 'agent1', 'email': 'agent1@example.com', 'password': 'agentpassword', 'first_name': 'Fatima', 'last_name': 'Al-Qahtani', 'is_staff': False}, {'username': 'agent2', 'email': 'agent2@example.com', 'password': 'agentpassword', 'first_name': 'Ali', 'last_name': 'Al-Harbi', 'is_staff': False}, {'username': 'agent3', 'email': 'agent3@example.com', 'password': 'agentpassword', 'first_name': 'Nora', 'last_name': 'Al-Shammari', 'is_staff': False}, {'username': 'auditor1', 'email': 'auditor1@example.com', 'password': 'auditorpassword', 'first_name': 'Khalid', 'last_name': 'Al-Dossari', 'is_staff': True}, {'username': 'finance1', 'email': 'finance1@example.com', 'password': 'financepassword', 'first_name': 'Sara', 'last_name': 'Al-Zahrani', 'is_staff': True}, ] for data in staff_data: username = data['username'] if not User.objects.filter(username=username).exists(): user = User.objects.create_user( username=username, email=data['email'], password=data['password'], first_name=data['first_name'], last_name=data['last_name'], is_staff=data['is_staff'] ) users.append(user) return users def create_cashiers(users, airports): """Create cashier records for users""" cashiers = [] # Get list of valid users that aren't already cashiers existing_cashier_users = Cashier.objects.values_list('user_id', flat=True) available_users = [u for u in users if u.id not in existing_cashier_users] if not available_users: print("No available users to create cashiers") return cashiers # Create a cashier for each airport with multiple users where possible for airport in airports: # Create between 2 and 5 cashiers per airport, depending on available users num_cashiers = min(random.randint(2, 5), len(available_users)) for _ in range(num_cashiers): if not available_users: break # Pick a random user and remove from available list user = random.choice(available_users) available_users.remove(user) # Generate employee ID based on user and airport employee_id = f"{airport.code}-{random.randint(1000, 9999)}" # Create cashier cashier,_ = Cashier.objects.get_or_create( user=user, employee_id=employee_id, airport=airport, is_active=True, created_at=timezone.now() ) cashiers.append(cashier) return cashiers def create_cash_shifts(cashiers, num_shifts=100): """Create cash shift records for cashiers""" shifts = [] # Start date (14 days ago) start_date = timezone.now() - timedelta(days=14) # For each cashier, create a number of shifts for cashier in cashiers: # Random number of shifts per cashier over the period cashier_shifts = random.randint(3, 10) for shift_idx in range(cashier_shifts): # Create shift date/time - distribute over the period shift_day = random.randint(0, 13) # 0 to 13 days ago shift_date = start_date + timedelta(days=shift_day) # Set shift time (morning, afternoon, or night) shift_type = random.choice(['morning', 'afternoon', 'night']) if shift_type == 'morning': shift_hour = random.randint(6, 9) elif shift_type == 'afternoon': shift_hour = random.randint(12, 15) else: # night shift_hour = random.randint(18, 21) shift_minute = random.choice([0, 15, 30, 45]) # Set shift start time shift_start = shift_date.replace(hour=shift_hour, minute=shift_minute, second=0, microsecond=0) # Set shift duration (between 6 and 8 hours) shift_duration_hours = random.uniform(6, 8) # Set shift end time for closed shifts if shift_start < timezone.now() - timedelta(hours=9): # Shift is in the past and should be closed shift_end = shift_start + timedelta(hours=shift_duration_hours) status = 'closed' else: # Recent or current shift might still be open if shift_start > timezone.now(): # Future shift shift_end = None status = 'pending' elif shift_start + timedelta(hours=shift_duration_hours) < timezone.now(): # Past shift but might not be closed if random.random() < 0.9: # 90% are closed properly shift_end = shift_start + timedelta(hours=shift_duration_hours) status = 'closed' else: shift_end = None status = 'open' # Open shift that should be closed else: # Currently open shift shift_end = None status = 'open' # Set opening cash (typically between 1000-2000 SAR) opening_cash = Decimal(str(random.randint(1000, 2000))) # Set closing cash for closed shifts if status == 'closed': # Closing should roughly match opening plus cash sales, but with some variance # We'll set initial values and update them later based on actual transactions closing_cash = opening_cash + Decimal(str(random.randint(0, 2000))) else: closing_cash = None # Create shift shift, _ = CashShift.objects.get_or_create( cashier=cashier, shift_start=shift_start, shift_end=shift_end, opening_cash=opening_cash, closing_cash=closing_cash, total_sales=Decimal('0.00'), # Will be updated later cash_sales=Decimal('0.00'), # Will be updated later pos_sales=Decimal('0.00'), # Will be updated later status=status, notes=f"Auto-generated {shift_type} shift" if random.random() < 0.3 else "", created_at=shift_start ) shifts.append(shift) return shifts def create_ticket_inventory(airlines, airports): """Create ticket inventory records""" inventory_records = [] # Create ticket inventories for the last 12 months today = date.today() # Create ticket inventory for each airline at each airport for airline in airlines: for airport in airports: # Create between 1 and 3 inventory records per airline per airport num_inventories = random.randint(1, 3) for _ in range(num_inventories): # Determine inventory date (within last 12 months) months_ago = random.randint(0, 11) receive_date = today - timedelta(days=30 * months_ago) # Set expiry date (6-12 months after received) expiry_months = random.randint(6, 12) expiry_date = receive_date + timedelta(days=30 * expiry_months) # Generate EMD serial ranges serial_prefix = f"{airline.code}{airport.code}" serial_start_num = random.randint(100000, 999000) # Create inventory quantity (typically 1000-5000 tickets) quantity = random.randint(1000, 5000) serial_end_num = serial_start_num + quantity - 1 emd_serial_start = f"{serial_prefix}{serial_start_num}" emd_serial_end = f"{serial_prefix}{serial_end_num}" # Determine usage (varies based on how old the inventory is) usage_factor = min(0.9, months_ago / 12) # Older inventory has higher usage usage_factor = max(0.1, usage_factor) # Even new inventory has some usage # Add randomness to usage factor usage_factor = usage_factor * random.uniform(0.8, 1.2) usage_factor = min(0.95, usage_factor) # Cap at 95% usage quantity_used = int(quantity * usage_factor) quantity_remaining = quantity - quantity_used # Determine status based on remaining quantity if quantity_remaining <= 0: status = 'depleted' elif quantity_remaining < quantity * 0.1: status = 'low' elif expiry_date < today: status = 'expired' else: status = 'active' # Create inventory record inventory, _ = TicketInventory.objects.get_or_create( airline=airline, airport=airport, emd_serial_start=emd_serial_start, emd_serial_end=emd_serial_end, quantity_received=quantity, quantity_used=quantity_used, quantity_remaining=quantity_remaining, status=status, received_date=receive_date, expiry_date=expiry_date, notes=f"Batch {serial_start_num}" if random.random() < 0.3 else "" ) inventory_records.append(inventory) return inventory_records def create_pos_devices(airports): """Create POS devices for airports""" devices = [] # Create multiple POS devices for each airport for airport in airports: # Number of devices per airport (larger airports have more) airport_size = len(airport.name) # Simple heuristic based on name length num_devices = random.randint(2, max(3, airport_size // 3)) for i in range(num_devices): # Generate device ID device_id = f"POS-{airport.code}-{i + 1:02d}" # Generate serial number serial_number = f"M{random.randint(1000000, 9999999)}" # Assign to terminal terminal = random.choice(['T1', 'T2', 'T3', 'Main', 'Domestic', 'International']) # Set location within terminal locations = [ f"Check-in counter {random.randint(1, 50)}", f"Gate {random.choice('ABCDEFG')}-{random.randint(1, 30)}", f"EBT counter {random.randint(1, 10)}", f"Customer service desk {random.randint(1, 5)}", f"Airline office {random.randint(1, 15)}" ] location = random.choice(locations) # Set status (mostly active) status_weights = {'active': 0.85, 'maintenance': 0.1, 'inactive': 0.05} status = random.choices( list(status_weights.keys()), weights=list(status_weights.values()), k=1 )[0] # Set last reconciliation date for active devices if status == 'active': days_ago = random.randint(0, 7) # Last 7 days last_reconciliation = timezone.now() - timedelta(days=days_ago) else: last_reconciliation = None # Create device device, _ = POSDevice.objects.get_or_create( device_id=device_id, serial_number=serial_number, airport=airport, terminal=terminal, location=location, status=status, last_reconciliation=last_reconciliation, created_at=timezone.now() - timedelta(days=random.randint(30, 365)), # Created 1-12 months ago updated_at=timezone.now() - timedelta(days=random.randint(0, 30)) # Updated within last month ) devices.append(device) return devices def create_airlines(): """Create airline records""" airlines = [] # Create airlines airline_data = [ {'code': 'SV', 'name': 'Saudia', 'contact_email': 'contact@saudia.com'}, {'code': 'XY', 'name': 'flynas', 'contact_email': 'contact@flynas.com'}, {'code': 'F3', 'name': 'flyadeal', 'contact_email': 'contact@flyadeal.com'}, {'code': 'EK', 'name': 'Emirates', 'contact_email': 'contact@emirates.com'}, {'code': 'EY', 'name': 'Etihad Airways', 'contact_email': 'contact@etihad.ae'}, {'code': 'QR', 'name': 'Qatar Airways', 'contact_email': 'contact@qatarairways.com'}, {'code': 'GF', 'name': 'Gulf Air', 'contact_email': 'contact@gulfair.com'}, {'code': 'KU', 'name': 'Kuwait Airways', 'contact_email': 'contact@kuwaitairways.com'}, {'code': 'ME', 'name': 'Middle East Airlines', 'contact_email': 'contact@mea.com.lb'}, {'code': 'RJ', 'name': 'Royal Jordanian', 'contact_email': 'contact@rj.com'}, {'code': 'TK', 'name': 'Turkish Airlines', 'contact_email': 'contact@thy.com'}, {'code': 'BA', 'name': 'British Airways', 'contact_email': 'contact@ba.com'}, {'code': 'LH', 'name': 'Lufthansa', 'contact_email': 'contact@lufthansa.com'}, {'code': 'AF', 'name': 'Air France', 'contact_email': 'contact@airfrance.fr'}, {'code': 'MS', 'name': 'Egyptair', 'contact_email': 'contact@egyptair.com'}, ] for data in airline_data: # Skip if airline already exists if Airline.objects.filter(code=data['code']).exists(): airline = Airline.objects.get(code=data['code']) else: airline, _ = Airline.objects.get_or_create( code=data['code'], name=data['name'], contact_email=data['contact_email'], is_active=True, created_at=timezone.now(), updated_at=timezone.now() ) airlines.append(airline) return airlines def create_airports(): """Create airport records""" airports = [] # Create airports airport_data = [ {'code': 'RUH', 'name': 'King Khalid International Airport', 'city': 'Riyadh', 'country': 'Saudi Arabia'}, {'code': 'JED', 'name': 'King Abdulaziz International Airport', 'city': 'Jeddah', 'country': 'Saudi Arabia'}, {'code': 'DMM', 'name': 'King Fahd International Airport', 'city': 'Dammam', 'country': 'Saudi Arabia'}, {'code': 'MED', 'name': 'Prince Mohammed Bin Abdulaziz Airport', 'city': 'Medina', 'country': 'Saudi Arabia'}, {'code': 'TIF', 'name': 'Taif Regional Airport', 'city': 'Taif', 'country': 'Saudi Arabia'}, {'code': 'AHB', 'name': 'Abha International Airport', 'city': 'Abha', 'country': 'Saudi Arabia'}, {'code': 'GIZ', 'name': 'Jizan Airport', 'city': 'Jizan', 'country': 'Saudi Arabia'}, {'code': 'TUU', 'name': 'Tabuk Airport', 'city': 'Tabuk', 'country': 'Saudi Arabia'}, {'code': 'YNB', 'name': 'Yanbu Airport', 'city': 'Yanbu', 'country': 'Saudi Arabia'}, {'code': 'ELQ', 'name': 'Gassim Airport', 'city': 'Gassim', 'country': 'Saudi Arabia'}, {'code': 'DXB', 'name': 'Dubai International Airport', 'city': 'Dubai', 'country': 'United Arab Emirates'}, {'code': 'AUH', 'name': 'Abu Dhabi International Airport', 'city': 'Abu Dhabi', 'country': 'United Arab Emirates'}, {'code': 'DOH', 'name': 'Hamad International Airport', 'city': 'Doha', 'country': 'Qatar'}, {'code': 'BAH', 'name': 'Bahrain International Airport', 'city': 'Manama', 'country': 'Bahrain'}, {'code': 'KWI', 'name': 'Kuwait International Airport', 'city': 'Kuwait City', 'country': 'Kuwait'}, {'code': 'CAI', 'name': 'Cairo International Airport', 'city': 'Cairo', 'country': 'Egypt'}, {'code': 'AMM', 'name': 'Queen Alia International Airport', 'city': 'Amman', 'country': 'Jordan'}, {'code': 'BEY', 'name': 'Beirut–Rafic Hariri International Airport', 'city': 'Beirut', 'country': 'Lebanon'}, {'code': 'IST', 'name': 'Istanbul Airport', 'city': 'Istanbul', 'country': 'Turkey'}, {'code': 'LHR', 'name': 'Heathrow Airport', 'city': 'London', 'country': 'United Kingdom'}, {'code': 'CDG', 'name': 'Charles de Gaulle Airport', 'city': 'Paris', 'country': 'France'}, {'code': 'FRA', 'name': 'Frankfurt Airport', 'city': 'Frankfurt', 'country': 'Germany'}, {'code': 'FCO', 'name': 'Leonardo da Vinci–Fiumicino Airport', 'city': 'Rome', 'country': 'Italy'}, ] for data in airport_data: # Skip if airport already exists if Airport.objects.filter(code=data['code']).exists(): airport = Airport.objects.get(code=data['code']) else: airport, _ = Airport.objects.get_or_create( code=data['code'], name=data['name'], city=data['city'], state='', country=data['country'], latitude=Decimal('0.0'), longitude=Decimal('0.0'), elevation_m=Decimal('0.0'), is_active=True, created_at=timezone.now() ) airports.append(airport) return airports def create_flights(airlines, airports, num_flights=100): """Create flight data""" flights = [] # Get common aircraft types aircraft_types = { 'SV': ['Boeing 777-300ER', 'Boeing 787-9', 'Airbus A320-200', 'Airbus A330-300'], 'XY': ['Airbus A320neo', 'Airbus A320-200'], 'F3': ['Airbus A320-200'], 'EK': ['Boeing 777-300ER', 'Airbus A380-800', 'Boeing 777-200LR'], 'EY': ['Boeing 787-9', 'Boeing 777-300ER', 'Airbus A320-200'], 'QR': ['Boeing 777-300ER', 'Airbus A350-900', 'Boeing 787-8'], 'default': ['Boeing 737-800', 'Airbus A320-200', 'Boeing 777-200', 'Airbus A330-200'] } # Flight durations between popular routes (in minutes) route_durations = { ('RUH', 'JED'): 105, ('JED', 'RUH'): 110, ('RUH', 'DMM'): 70, ('DMM', 'RUH'): 75, ('JED', 'DMM'): 120, ('DMM', 'JED'): 125, ('RUH', 'DXB'): 105, ('DXB', 'RUH'): 110, ('JED', 'CAI'): 120, ('CAI', 'JED'): 125, ('RUH', 'CAI'): 180, ('CAI', 'RUH'): 185, ('RUH', 'DOH'): 75, ('DOH', 'RUH'): 80, ('JED', 'IST'): 240, ('IST', 'JED'): 245, ('default', 'default'): 120 } # Common domestic routes in Saudi Arabia domestic_routes = [ ('RUH', 'JED'), ('JED', 'RUH'), ('RUH', 'DMM'), ('DMM', 'RUH'), ('JED', 'DMM'), ('DMM', 'JED'), ('RUH', 'MED'), ('MED', 'RUH'), ('JED', 'MED'), ('MED', 'JED'), ('RUH', 'AHB'), ('AHB', 'RUH'), ('JED', 'GIZ'), ('GIZ', 'JED'), ('RUH', 'TUU'), ('TUU', 'RUH'), ('RUH', 'TIF'), ('TIF', 'RUH'), ('JED', 'TIF'), ('TIF', 'JED'), ('RUH', 'ELQ'), ('ELQ', 'RUH'), ('RUH', 'YNB'), ('YNB', 'RUH'), ] # Common international routes from Saudi Arabia international_routes = [ ('RUH', 'DXB'), ('DXB', 'RUH'), ('JED', 'DXB'), ('DXB', 'JED'), ('RUH', 'DOH'), ('DOH', 'RUH'), ('JED', 'DOH'), ('DOH', 'JED'), ('RUH', 'AUH'), ('AUH', 'RUH'), ('JED', 'CAI'), ('CAI', 'JED'), ('RUH', 'CAI'), ('CAI', 'RUH'), ('JED', 'AMM'), ('AMM', 'JED'), ('RUH', 'BAH'), ('BAH', 'RUH'), ('JED', 'IST'), ('IST', 'JED'), ('RUH', 'IST'), ('IST', 'RUH'), ('JED', 'KWI'), ('KWI', 'JED'), ('RUH', 'BEY'), ('BEY', 'RUH'), ('JED', 'LHR'), ('LHR', 'JED'), ('RUH', 'CDG'), ('CDG', 'RUH'), ] # Get all Saudi airports saudi_airports = [airport for airport in airports if airport.country == 'Saudi Arabia'] # Flight numbers for airlines flight_number_ranges = { 'SV': (1000, 1999), 'XY': (100, 999), 'F3': (100, 999), 'EK': (800, 899), 'EY': (600, 699), 'QR': (1200, 1299), 'GF': (500, 599), 'KU': (100, 199), 'ME': (400, 499), 'MS': (600, 699), 'RJ': (300, 399), 'TK': (100, 199), 'default': (1000, 9999) } # Start date for flight schedules (7 days ago) start_date = timezone.now() - timedelta(days=7) # Create flights for the next 30 days for day_offset in range(0, 30): current_date = start_date + timedelta(days=day_offset) # Create more flights for busier days (weekends) is_weekend = current_date.weekday() >= 4 # Friday and Saturday in Middle East daily_flights = int(num_flights / 20) * (2 if is_weekend else 1) for _ in range(daily_flights): # Select airline (with more weight to Saudi airlines) airline_weights = [3 if a.code in ['SV', 'XY', 'F3'] else 1 for a in airlines] airline = random.choices(airlines, weights=airline_weights, k=1)[0] # Determine if domestic or international flight is_domestic = random.random() < 0.6 if airline.code in ['SV', 'XY', 'F3'] else 0.1 # Select route if is_domestic: # Domestic route if random.random() < 0.8 and domestic_routes: origin_code, dest_code = random.choice(domestic_routes) else: # Random domestic route if len(saudi_airports) >= 2: origin, dest = random.sample(saudi_airports, 2) origin_code, dest_code = origin.code, dest.code else: # Fallback if not enough Saudi airports route = random.choice(domestic_routes or international_routes) origin_code, dest_code = route else: # International route if random.random() < 0.8 and international_routes: origin_code, dest_code = random.choice(international_routes) else: # Random international route saudi_airport = random.choice(saudi_airports) international_airport = random.choice([a for a in airports if a.country != 'Saudi Arabia']) if random.random() < 0.5: origin_code, dest_code = saudi_airport.code, international_airport.code else: origin_code, dest_code = international_airport.code, saudi_airport.code # Find the airport objects origin_airport = next((a for a in airports if a.code == origin_code), None) dest_airport = next((a for a in airports if a.code == dest_code), None) if not origin_airport or not dest_airport: continue # Generate flight number range_min, range_max = flight_number_ranges.get(airline.code, flight_number_ranges['default']) flight_number = str(random.randint(range_min, range_max)) # Generate departure time hour = random.randint(0, 23) minute = random.choice([0, 15, 30, 45]) scheduled_departure = current_date.replace(hour=hour, minute=minute, second=0, microsecond=0) # Calculate flight duration and arrival time route_key = (origin_code, dest_code) default_key = ('default', 'default') duration_minutes = route_durations.get(route_key, route_durations.get(default_key, 120)) # Add some randomness to duration duration_minutes += random.randint(-10, 20) scheduled_arrival = scheduled_departure + timedelta(minutes=duration_minutes) # Determine flight type flight_type = 'domestic' if is_domestic else 'international' # Determine flight status based on departure time now = timezone.now() actual_departure = None actual_arrival = None if scheduled_departure > now + timedelta(hours=1): status = 'scheduled' elif scheduled_departure > now: status = 'boarding' elif scheduled_arrival > now: status = 'departed' # Set actual departure time delay_minutes = random.choices( [0, random.randint(1, 15), random.randint(16, 60), random.randint(61, 180)], weights=[0.7, 0.15, 0.1, 0.05], k=1 )[0] actual_departure = scheduled_departure + timedelta(minutes=delay_minutes) else: status = 'arrived' # Set actual departure and arrival times delay_minutes = random.choices( [0, random.randint(1, 15), random.randint(16, 60), random.randint(61, 180)], weights=[0.7, 0.15, 0.1, 0.05], k=1 )[0] actual_departure = scheduled_departure + timedelta(minutes=delay_minutes) # Actual arrival might be faster or slower than scheduled arrival_variance = random.randint(-15, 30) actual_flight_duration = duration_minutes + arrival_variance actual_arrival = actual_departure + timedelta(minutes=actual_flight_duration) # Randomly cancel some flights if random.random() < 0.03: # 3% chance of cancellation status = 'cancelled' actual_departure = None actual_arrival = None # Set delays for some flights if random.random() < 0.15 and status == 'scheduled': # 15% chance of delay status = 'delayed' # Determine aircraft type aircraft_types_for_airline = aircraft_types.get(airline.code, aircraft_types['default']) aircraft_type = random.choice(aircraft_types_for_airline) # Generate aircraft registration if airline.code == 'SV': registration = f"HZ-A{random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ')}{random.randint(10, 99)}" else: country_codes = {'EK': 'A6-', 'EY': 'A6-', 'QR': 'A7-', 'GF': 'A9C-', 'KU': '9K-'} prefix = country_codes.get(airline.code, random.choice(['N', 'G-', 'F-', 'D-', 'C-', 'B-', 'VH-'])) registration = f"{prefix}{random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ')}{random.randint(100, 999)}" # Set passenger capacity based on aircraft type if 'A380' in aircraft_type: passenger_capacity = random.randint(480, 615) elif '777-300' in aircraft_type: passenger_capacity = random.randint(340, 420) elif '777-200' in aircraft_type: passenger_capacity = random.randint(280, 350) elif '787' in aircraft_type: passenger_capacity = random.randint(240, 330) elif 'A350' in aircraft_type: passenger_capacity = random.randint(300, 370) elif 'A330' in aircraft_type: passenger_capacity = random.randint(250, 330) elif '737' in aircraft_type or 'A320' in aircraft_type: passenger_capacity = random.randint(150, 200) else: passenger_capacity = random.randint(100, 350) # Set cargo capacity if 'A380' in aircraft_type: cargo_capacity_kg = Decimal(str(random.randint(40000, 60000))) elif '777' in aircraft_type: cargo_capacity_kg = Decimal(str(random.randint(20000, 35000))) elif '787' in aircraft_type: cargo_capacity_kg = Decimal(str(random.randint(15000, 25000))) elif 'A350' in aircraft_type: cargo_capacity_kg = Decimal(str(random.randint(18000, 28000))) elif 'A330' in aircraft_type: cargo_capacity_kg = Decimal(str(random.randint(15000, 25000))) elif '737' in aircraft_type or 'A320' in aircraft_type: cargo_capacity_kg = Decimal(str(random.randint(5000, 10000))) else: cargo_capacity_kg = Decimal(str(random.randint(3000, 20000))) # Set terminal and gate information departure_terminal = random.choice(['1', '2', '3', '4', 'A', 'B', 'C', 'D', 'International', 'Domestic']) departure_gate = f"{random.choice('ABCDEFG')}{random.randint(1, 50)}" arrival_terminal = random.choice(['1', '2', '3', '4', 'A', 'B', 'C', 'D', 'International', 'Domestic']) arrival_gate = f"{random.choice('ABCDEFG')}{random.randint(1, 50)}" # Create the flight flight, _ = Flight.objects.get_or_create( flight_number=flight_number, airline=airline, origin_airport=origin_airport, destination_airport=dest_airport, scheduled_departure=scheduled_departure, scheduled_arrival=scheduled_arrival, actual_departure=actual_departure, actual_arrival=actual_arrival, aircraft_type=aircraft_type, aircraft_registration=registration, flight_type=flight_type, status=status, passenger_capacity=passenger_capacity, cargo_capacity_kg=cargo_capacity_kg, departure_terminal=departure_terminal, departure_gate=departure_gate, arrival_terminal=arrival_terminal, arrival_gate=arrival_gate, notes='' ) flights.append(flight) return flights def create_passengers(flights, users): """Create passenger data for flights""" passengers = [] # Names data first_names_male = [ 'Mohammed', 'Abdullah', 'Ahmed', 'Khalid', 'Fahad', 'Ali', 'Omar', 'Ibrahim', 'Saleh', 'Saad', 'Nasser', 'Abdulaziz', 'Faisal', 'Yousef', 'Saud', 'Bandar', 'Turki', 'Majid', 'Waleed', 'Nawaf', 'Mishaal', 'Sultan', 'Talal', 'Meshari', 'Bader', 'Rayan', 'Hamad', 'Naif', 'Mansour', 'Mutlaq', 'Adel', 'Ziyad' ] first_names_female = [ 'Fatima', 'Aisha', 'Nora', 'Maha', 'Sara', 'Hessa', 'Latifa', 'Layla', 'Reema', 'Nouf', 'Mona', 'Abeer', 'Reem', 'Mariam', 'Asma', 'Amira', 'Mashael', 'Haifa', 'Najla', 'Munira', 'Samira', 'Dalal', 'Joud', 'Lamia', 'Ghadah', 'Eman', 'Nada', 'Noof', 'Shaikha', 'Hind', 'Alaa', 'Ghada' ] last_names = [ 'Al-Saud', 'Al-Qahtani', 'Al-Ghamdi', 'Al-Otaibi', 'Al-Harbi', 'Al-Shammari', 'Al-Dossari', 'Al-Zahrani', 'Al-Mutairi', 'Al-Anazi', 'Al-Shamrani', 'Al-Qurashi', 'Al-Juhani', 'Al-Maliki', 'Al-Ruwaili', 'Al-Subaie', 'Al-Khaldi', 'Al-Najjar', 'Al-Balawi', 'Al-Rashidi', 'Al-Yami', 'Al-Asiri', 'Al-Dawsari', 'Al-Mohsen', 'Al-Enezi', 'Al-Faifi', 'Al-Subhi', 'Al-Ahmari', 'Al-Hamad', 'Al-Marri', 'Al-Hajri', 'Al-Ghamidi', 'Al-Zaidi', 'Al-Buqami', 'Al-Hawawi', 'Al-Harthy' ] # Nationalities for international diversity nationalities = [ 'Saudi', 'Saudi', 'Saudi', 'Saudi', 'Saudi', # More weight to Saudi 'Emirati', 'Egyptian', 'Jordanian', 'Lebanese', 'Kuwaiti', 'Bahraini', 'Qatari', 'Omani', 'Pakistani', 'Indian', 'Filipino', 'Bangladeshi', 'American', 'British', 'French' ] # Email domains email_domains = ['gmail.com', 'hotmail.com', 'yahoo.com', 'outlook.com', 'icloud.com'] # Meal codes special_meals = ['', '', '', '', '', # More weight to no special meal 'VGML', 'KSML', 'MOML', 'DBML', 'GFML', 'PFML', 'AVML', 'SFML', 'LCML'] # Special assistance types special_assistance_types = ['', '', '', '', '', # More weight to no special assistance 'Wheelchair', 'Unaccompanied minor', 'Blind passenger', 'Deaf passenger', 'Medical oxygen', 'Service animal'] # Frequent flyer tiers ff_tiers = ['', '', '', '', '', # More weight to no tier 'Blue', 'Silver', 'Gold', 'Platinum', 'Diamond'] # Assign a random admin user as the creator admin_user = random.choice(users) if users else None # Process each flight for flight in flights: # Skip cancelled flights if flight.status == 'cancelled': continue # Only create passengers for flights that are within 2 days before/after now flight_time = flight.scheduled_departure now = timezone.now() if abs((flight_time - now).total_seconds()) > 172800: # 48 hours in seconds # For flights outside our window, only create a few passengers (10% chance) if random.random() > 0.1: continue # Determine passenger load factor (how full is the flight) if flight.status in ['departed', 'arrived']: # Departed/arrived flights tend to have higher load factors load_factor = random.uniform(0.7, 0.95) else: # Future flights have more variable load factors load_factor = random.uniform(0.4, 0.9) # Calculate number of passengers to create if flight.passenger_capacity: num_passengers = int(flight.passenger_capacity * load_factor) else: # Default if capacity not set num_passengers = random.randint(50, 150) # Create passengers for _ in range(num_passengers): # Generate basic info gender = random.choice(['M', 'F']) first_name = random.choice(first_names_male if gender == 'M' else first_names_female) last_name = random.choice(last_names) # Sometimes add a middle name if random.random() < 0.3: middle_name = random.choice(first_names_male if gender == 'M' else first_names_female) else: middle_name = '' # Generate date of birth (age distribution) age_group = random.choices(['adult', 'child', 'infant', 'senior'], weights=[0.75, 0.15, 0.05, 0.05], k=1)[0] today = date.today() if age_group == 'adult': age = random.randint(18, 65) elif age_group == 'child': age = random.randint(2, 17) elif age_group == 'infant': age = random.randint(0, 1) else: # senior age = random.randint(66, 85) birth_year = today.year - age birth_month = random.randint(1, 12) # Make sure February dates are valid max_day = 28 if birth_month == 2 else 30 if birth_month in [4, 6, 9, 11] else 31 birth_day = random.randint(1, max_day) try: date_of_birth = date(birth_year, birth_month, birth_day) except ValueError: # If invalid date, use safe defaults date_of_birth = date(birth_year, 1, 1) # Nationality nationality = random.choice(nationalities) # Contact information if random.random() < 0.7: # 70% have email email = f"{first_name.lower()}.{last_name.lower()}{random.randint(1, 999)}@{random.choice(email_domains)}" else: email = '' if random.random() < 0.8: # 80% have phone if nationality == 'Saudi': phone = f"+966 5{random.randint(10000000, 99999999)}" else: phone = f"+{random.randint(1, 999)} {random.randint(1000000, 9999999)}" else: phone = '' # Travel documents passport_number = f"{random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ')}{random.randint(10000000, 99999999)}" passport_expiry = today + timedelta(days=random.randint(30, 3650)) # 1 month to 10 years # Visa number (for some passengers) if random.random() < 0.3: visa_number = f"V{random.randint(1000000, 9999999)}" else: visa_number = '' # Generate ticket number ticket_number = f"{flight.airline.code}{random.randint(1000000000, 9999999999)}" # Generate booking reference (PNR) booking_reference = ''.join(random.choices('ABCDEFGHJKLMNPQRSTUVWXYZ23456789', k=6)) # Seat assignment if flight.status in ['boarding', 'departed', 'arrived']: # Assign seats for boarding/departed flights row = random.randint(1, 50) seat_letter = random.choice('ABCDEFGHJK') seat_number = f"{row}{seat_letter}" else: # Some passengers don't have seat assignments yet seat_number = '' if random.random() < 0.3 else f"{random.randint(1, 50)}{random.choice('ABCDEFGHJK')}" # Passenger type if age <= 1: passenger_type = 'infant' elif age <= 17: passenger_type = 'child' elif age >= 65: passenger_type = 'senior' else: passenger_type = 'adult' # Travel class with weighting travel_class_weights = {'economy': 0.85, 'business': 0.12, 'first': 0.03} travel_class = random.choices( list(travel_class_weights.keys()), weights=list(travel_class_weights.values()), k=1 )[0] # Passenger status if flight.status == 'scheduled': # Future flight - most are just checked in status_weights = {'checked_in': 0.97, 'cancelled': 0.03} elif flight.status == 'boarding': # Boarding flight - mix of checked in and boarded status_weights = {'checked_in': 0.4, 'boarded': 0.6} elif flight.status in ['departed', 'arrived']: # Flight has left - most are boarded, some no-shows status_weights = {'boarded': 0.97, 'no_show': 0.03} else: # Default/delayed flight status_weights = {'checked_in': 0.95, 'cancelled': 0.05} status = random.choices( list(status_weights.keys()), weights=list(status_weights.values()), k=1 )[0] # Baggage information if travel_class == 'economy': checked_bags_count = random.choices([0, 1, 2], weights=[0.2, 0.7, 0.1], k=1)[0] elif travel_class == 'business': checked_bags_count = random.choices([0, 1, 2, 3], weights=[0.1, 0.3, 0.5, 0.1], k=1)[0] else: # first class checked_bags_count = random.choices([0, 1, 2, 3], weights=[0.05, 0.25, 0.5, 0.2], k=1)[0] # Calculate baggage weight if checked_bags_count == 0: checked_bags_weight_kg = Decimal('0.00') else: # Weight per bag weight_per_bag = Decimal(str(random.uniform(15.0, 25.0))) checked_bags_weight_kg = round(weight_per_bag * Decimal(str(checked_bags_count)), 2) # Carry-on bags carry_on_bags_count = random.choices([0, 1, 2], weights=[0.05, 0.85, 0.1], k=1)[0] # Special requirements special_meal = random.choice(special_meals) special_assistance = random.choice(special_assistance_types) # Medical conditions (rarely populated) if random.random() < 0.05: medical_conditions_list = [ "Diabetes", "Hypertension", "Asthma", "Heart condition", "Mobility issues", "Pregnancy", "Allergies" ] medical_conditions = random.choice(medical_conditions_list) else: medical_conditions = "" # Check-in information if status in ['checked_in', 'boarded', 'no_show']: # Check-in happens 24-4 hours before flight checkin_offset = timedelta(hours=random.randint(4, 24)) check_in_time = flight.scheduled_departure - checkin_offset check_in_counter = f"{random.randint(1, 50)}" else: check_in_time = None check_in_counter = "" # Boarding information if status == 'boarded': # Boarding happens 90-30 minutes before flight boarding_offset = timedelta(minutes=random.randint(30, 90)) boarding_time = flight.scheduled_departure - boarding_offset boarding_gate = flight.departure_gate else: boarding_time = None boarding_gate = "" # Frequent flyer information if random.random() < 0.4: # 40% have frequent flyer numbers frequent_flyer_number = f"{flight.airline.code}{random.randint(10000000, 99999999)}" frequent_flyer_tier = random.choice(ff_tiers) else: frequent_flyer_number = "" frequent_flyer_tier = "" # Create the passenger passenger, _ = Passenger.objects.get_or_create( first_name=first_name, last_name=last_name, middle_name=middle_name, date_of_birth=date_of_birth, nationality=nationality, gender=gender, passport_number=passport_number, passport_expiry=passport_expiry, visa_number=visa_number, email=email, phone=phone, flight=flight, ticket_number=ticket_number, booking_reference=booking_reference, seat_number=seat_number, passenger_type=passenger_type, travel_class=travel_class, status=status, checked_bags_count=checked_bags_count, checked_bags_weight_kg=checked_bags_weight_kg, carry_on_bags_count=carry_on_bags_count, special_meal=special_meal, special_assistance=special_assistance, medical_conditions=medical_conditions, check_in_time=check_in_time, boarding_time=boarding_time, check_in_counter=check_in_counter, boarding_gate=boarding_gate, frequent_flyer_number=frequent_flyer_number, frequent_flyer_tier=frequent_flyer_tier, created_by=admin_user ) passengers.append(passenger) return passengers def create_ebt_transactions(airlines, shifts, devices): """Create EBT transactions""" transactions = [] # Saudi and Arab passenger names saudi_first_names = [ 'Mohammed', 'Abdullah', 'Ahmed', 'Khalid', 'Fahad', 'Ali', 'Omar', 'Ibrahim', 'Saleh', 'Saad', 'Nasser', 'Abdulaziz', 'Faisal', 'Yousef', 'Saud', 'Bandar', 'Fatima', 'Aisha', 'Nora', 'Maha', 'Sara', 'Hessa', 'Latifa', 'Layla', 'Reema', 'Nouf', 'Mona', 'Abeer', 'Reem', 'Mariam', 'Asma', 'Amira' ] saudi_last_names = [ 'Al-Saud', 'Al-Qahtani', 'Al-Ghamdi', 'Al-Otaibi', 'Al-Harbi', 'Al-Shammari', 'Al-Dossari', 'Al-Zahrani', 'Al-Mutairi', 'Al-Anazi', 'Al-Shamrani', 'Al-Qurashi', 'Al-Juhani', 'Al-Maliki', 'Al-Ruwaili', 'Al-Subaie', 'Al-Khaldi', 'Al-Najjar', 'Al-Balawi', 'Al-Rashidi', 'Al-Yami', 'Al-Asiri', 'Al-Dawsari', 'Al-Mohsen' ] # Flight numbers for airlines flight_patterns = { 'SV': 'SV{0}', # Saudia 'XY': 'XY{0}', # flynas 'F3': 'F3{0}', # flyadeal 'EK': 'EK{0}', # Emirates 'EY': 'EY{0}', # Etihad 'QR': 'QR{0}', # Qatar 'GF': 'GF{0}', # Gulf Air 'KU': 'KU{0}', # Kuwait 'ME': 'ME{0}', # MEA 'RJ': 'RJ{0}', # Royal Jordanian 'TK': 'TK{0}', # Turkish 'BA': 'BA{0}', # British Airways 'LH': 'LH{0}', # Lufthansa 'AF': 'AF{0}', # Air France 'MS': 'MS{0}', # Egyptair } # Common destinations from Saudi airports destinations = { 'SV': ['CAI', 'DXB', 'KHI', 'ISL', 'AMM', 'BEY', 'KWI', 'BAH', 'DOH', 'IST', 'LHR', 'CDG', 'FCO', 'JFK', 'KUL', 'CGK'], 'XY': ['CAI', 'DXB', 'AMM', 'BAH', 'KWI', 'DOH', 'IST', 'HRG', 'SSH'], 'F3': ['CAI', 'DXB', 'AMM', 'KWI', 'BAH', 'DOH'], 'EK': ['DXB'], 'EY': ['AUH'], 'QR': ['DOH'], 'GF': ['BAH'], 'KU': ['KWI'], 'ME': ['BEY'], 'RJ': ['AMM'], 'TK': ['IST'], 'BA': ['LHR'], 'LH': ['FRA', 'MUC'], 'AF': ['CDG'], 'MS': ['CAI'], } # Popular Saudi domestic routes domestic_routes = { 'SV': ['RUH', 'JED', 'DMM', 'MED', 'AHB', 'TIF', 'GIZ', 'TUU', 'YNB', 'ELQ'], 'XY': ['RUH', 'JED', 'DMM', 'MED', 'AHB', 'TIF', 'GIZ'], 'F3': ['RUH', 'JED', 'DMM', 'MED'], } for shift in shifts: # Skip some shifts to make data more realistic if random.random() > 0.8: continue # Determine number of transactions in this shift num_transactions = random.randint(5, 25) for _ in range(num_transactions): # Select a random airline with more weight to Saudi airlines airline_weights = [3 if a.code in ['SV', 'XY', 'F3'] else 1 for a in airlines] airline = random.choices(airlines, weights=airline_weights, k=1)[0] # Generate flight number flight_num = random.randint(100, 1999) if airline.code in domestic_routes and random.random() < 0.6: # Domestic flight origin = shift.cashier.airport.code destination = random.choice([d for d in domestic_routes[airline.code] if d != origin]) flight_number = flight_patterns[airline.code].format(flight_num) else: # International flight if airline.code in destinations: destination = random.choice(destinations[airline.code]) else: destination = random.choice(['LHR', 'CDG', 'FRA', 'IST', 'DXB', 'DOH', 'CAI']) flight_number = flight_patterns[airline.code].format(flight_num) # Generate passenger name first_name = random.choice(saudi_first_names) last_name = random.choice(saudi_last_names) passenger_name = f"{first_name} {last_name}" # Generate ticket number ticket_number = f"{airline.code}{random.randint(1000000000, 9999999999)}" # Generate EMD serial (sometimes blank for cash transactions) if random.random() < 0.8: emd_serial = f"{airline.code}{shift.cashier.airport.code}{random.randint(100000, 999999)}" else: emd_serial = "" # Generate baggage weight and rate weight_kg = Decimal(str(random.randint(5, 40))) # Rates vary by airline and destination if airline.code in ['SV', 'XY', 'F3']: # Saudi airlines if destination in domestic_routes.get(airline.code, []): # Domestic rate_per_kg = Decimal(str(random.randint(40, 60))) else: # International rate_per_kg = Decimal(str(random.randint(70, 120))) else: # Foreign airlines rate_per_kg = Decimal(str(random.randint(80, 150))) # Calculate total total_amount = weight_kg * rate_per_kg # Payment method (MADA is most common in KSA) payment_method_weights = {'cash': 0.3, 'mada': 0.5, 'visa': 0.1, 'mastercard': 0.07, 'amex': 0.03} payment_method = random.choices( list(payment_method_weights.keys()), weights=list(payment_method_weights.values()), k=1 )[0] # POS device for card payments pos_device = None pos_reference = "" if payment_method != 'cash': # Get POS device at the same airport airport_devices = [d for d in devices if d.airport == shift.cashier.airport and d.status == 'active'] if airport_devices: pos_device = random.choice(airport_devices) pos_reference = f"MADA{random.randint(1000000, 9999999)}" # Transaction status (mostly completed) status_weights = {'completed': 0.94, 'refunded': 0.03, 'cancelled': 0.02, 'pending': 0.01} status = random.choices( list(status_weights.keys()), weights=list(status_weights.values()), k=1 )[0] # Transaction date within shift timeframe if shift.shift_end: transaction_date = shift.shift_start + timedelta( minutes=random.randint(0, int((shift.shift_end - shift.shift_start).total_seconds() / 60))) else: transaction_date = shift.shift_start + timedelta(minutes=random.randint(0, 480)) # within 8 hours # Refund data if applicable refund_date = None refund_type = "full" refund_method = "original" refunded_by = None if status == 'refunded': refund_date = transaction_date + timedelta(hours=random.randint(1, 24)) refund_types = ['full', 'partial', 'fees'] refund_type = random.choices(refund_types, weights=[0.7, 0.2, 0.1], k=1)[0] refund_methods = ['original', 'cash', 'bank'] refund_method = random.choices(refund_methods, weights=[0.6, 0.3, 0.1], k=1)[0] refunded_by = shift.cashier.user # Notes notes_options = [ "", "Hajj/Umrah passenger", "VIP passenger", "Sports equipment", "Medical equipment", "Special handling required", "Fragile items" ] notes = random.choice(notes_options) transaction, _ = EBTTransaction.objects.get_or_create( transaction_id=uuid.uuid4(), airline=airline, flight_number=flight_number, passenger_name=passenger_name, ticket_number=ticket_number, emd_serial=emd_serial, weight_kg=weight_kg, rate_per_kg=rate_per_kg, total_amount=total_amount, payment_method=payment_method, pos_device=pos_device, pos_reference=pos_reference, cashier=shift.cashier, cash_shift=shift, status=status, transaction_date=transaction_date, refund_date=refund_date, refund_type=refund_type, refund_method=refund_method, refunded_by=refunded_by, notes=notes ) transactions.append(transaction) return transactions def create_daily_reconciliations(airports, transactions): """Create daily reconciliation records""" reconciliations = [] # Get unique dates from transactions transaction_dates = set() for transaction in transactions: # Extract just the date part transaction_date = transaction.transaction_date.date() transaction_dates.add(transaction_date) # Get admin users who might reconcile from django.contrib.auth.models import User admin_users = User.objects.filter(is_staff=True) admin_user = admin_users.first() if admin_users.exists() else None # For each airport and each date, create a reconciliation for airport in airports: for date in transaction_dates: # Only create reconciliations for some dates if random.random() > 0.7: continue # Get transactions for this airport and date day_transactions = [ t for t in transactions if t.cashier.airport == airport and t.transaction_date.date() == date ] if not day_transactions: continue # Calculate reconciliation data total_transactions = len([t for t in day_transactions if t.status == 'completed']) # Calculate totals total_sales = sum(t.total_amount for t in day_transactions if t.status == 'completed') cash_sales = sum( t.total_amount for t in day_transactions if t.status == 'completed' and t.payment_method == 'cash' ) pos_sales = sum( t.total_amount for t in day_transactions if t.status == 'completed' and t.payment_method != 'cash' ) # Bank deposits (might have slight variances) cash_variance_factor = random.uniform(0.98, 1.02) # +/- 2% pos_variance_factor = random.uniform(0.99, 1.01) # +/- 1% cash_deposited = cash_sales * Decimal(str(cash_variance_factor)) pos_settled = pos_sales * Decimal(str(pos_variance_factor)) # Calculate variances cash_variance = cash_deposited - cash_sales pos_variance = pos_settled - pos_sales # Determine status based on variance if abs(cash_variance) > 100 or abs(pos_variance) > 50: status = 'discrepancy' else: status = 'completed' # Create reconciliation record reconciliation, _ = DailyReconciliation.objects.get_or_create( date=date, airport=airport, total_transactions=total_transactions, total_sales=total_sales, cash_sales=cash_sales, pos_sales=pos_sales, cash_deposited=cash_deposited, pos_settled=pos_settled, cash_variance=cash_variance, pos_variance=pos_variance, status=status, reconciled_by=admin_user, reconciled_at=timezone.now() if status != 'pending' else None, notes=f"Automatic reconciliation for {date.strftime('%Y-%m-%d')}" if status != 'pending' else "" ) reconciliations.append(reconciliation) return reconciliations def main(): """Main function to generate all data""" # Create users print("Creating users...") users = create_users() # Create airlines print("Creating airlines...") airlines = create_airlines() # Create airports print("Creating airports...") airports = create_airports() # Create POS devices print("Creating POS devices...") devices = create_pos_devices(airports) # Create ticket inventory print("Creating ticket inventory...") inventory = create_ticket_inventory(airlines, airports) # Create cashiers print("Creating cashiers...") cashiers = create_cashiers(users, airports) # Create cash shifts print("Creating cash shifts...") shifts = create_cash_shifts(cashiers) # Create flights print("Creating flights...") flights = create_flights(airlines, airports) # Create passengers print("Creating passengers...") passengers = create_passengers(flights, users) # Create EBT transactions print("Creating EBT transactions...") transactions = create_ebt_transactions(airlines, shifts, devices) # Create daily reconciliations print("Creating daily reconciliations...") reconciliations = create_daily_reconciliations(airports, transactions) # Update cash shift totals based on transactions print("Updating cash shift totals...") for shift in CashShift.objects.all(): shift.update_sales_totals() print("Data generation complete!") print(f"Created {len(users)} users") print(f"Created {len(airlines)} airlines") print(f"Created {len(airports)} airports") print(f"Created {len(devices)} POS devices") print(f"Created {len(inventory)} ticket inventory records") print(f"Created {len(cashiers)} cashiers") print(f"Created {len(shifts)} cash shifts") print(f"Created {len(flights)} flights") print(f"Created {len(passengers)} passengers") print(f"Created {len(transactions)} transactions") print(f"Created {len(reconciliations)} reconciliations") # If running as a script if __name__ == "__main__": main()