import os import django # Set up Django environment os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hospital_management.settings') django.setup() import random import uuid from datetime import datetime, timedelta from decimal import Decimal from django.utils import timezone as django_timezone from django.db import transaction, connection from core.models import Tenant from accounts.models import User from inventory.models import InventoryItem, InventoryStock, InventoryLocation, PurchaseOrder, PurchaseOrderItem, \ Supplier # Test database connection def test_database_connection(): """Test if database connection is working""" try: with connection.cursor() as cursor: cursor.execute("SELECT 1") result = cursor.fetchone() print(f"Database connection test: {'SUCCESS' if result else 'FAILED'}") return result is not None except Exception as e: print(f"Database connection error: {e}") return False # Saudi Arabian Inventory Data SAUDI_MEDICAL_CATEGORIES = [ 'Pharmaceuticals', 'Medical Devices', 'Surgical Instruments', 'Laboratory Supplies', 'Radiology Supplies', 'PPE & Safety', 'Wound Care', 'IV Therapy', 'Respiratory Care', 'Cardiology Equipment', 'Orthopedic Supplies', 'Emergency Supplies', 'Cleaning & Disinfection', 'Office Supplies', 'Food & Nutrition' ] SAUDI_PHARMACEUTICAL_SUBCATEGORIES = { 'Pharmaceuticals': [ 'Antibiotics', 'Analgesics', 'Cardiovascular', 'Diabetes Care', 'Respiratory', 'Oncology', 'Psychiatric', 'Emergency Drugs', 'Anesthetics', 'Vaccines', 'IV Solutions', 'Blood Products' ] } SAUDI_MEDICAL_MANUFACTURERS = [ 'Saudi Pharmaceutical Industries (SPIMACO)', 'Tabuk Pharmaceuticals', 'Jamjoom Pharmaceuticals', 'Al-Jazeera Pharmaceutical Industries', 'Medical Supplies Company', 'Saudi Medical Supplies', 'Gulf Pharmaceutical Industries', 'Middle East Healthcare', 'Arabian Medical Equipment', 'Riyadh Pharma', 'Johnson & Johnson Saudi', 'Pfizer Saudi Arabia', 'Novartis Saudi', 'Roche Saudi Arabia', 'Abbott Saudi Arabia' ] SAUDI_STORAGE_LOCATIONS = { 'buildings': ['Main Hospital', 'Outpatient Clinic', 'Emergency Wing', 'Research Center', 'Administrative Building'], 'floors': ['Ground Floor', 'First Floor', 'Second Floor', 'Third Floor', 'Basement'], 'rooms': ['Pharmacy', 'Central Supply', 'OR Storage', 'ICU Supply', 'Ward Storage', 'Emergency Supply'], 'zones': ['Zone A', 'Zone B', 'Zone C', 'Zone D'], 'aisles': ['Aisle 1', 'Aisle 2', 'Aisle 3', 'Aisle 4', 'Aisle 5'], 'shelves': ['Shelf A', 'Shelf B', 'Shelf C', 'Shelf D', 'Shelf E'], 'bins': ['Bin 1', 'Bin 2', 'Bin 3', 'Bin 4', 'Bin 5'] } SAUDI_SUPPLIER_DATA = [ { 'name': 'Saudi Medical Supply Co.', 'type': 'DISTRIBUTOR', 'city': 'Riyadh', 'phone': '+966-11-234-5678' }, { 'name': 'Gulf Medical Equipment', 'type': 'MANUFACTURER', 'city': 'Dammam', 'phone': '+966-13-345-6789' }, { 'name': 'Arabian Healthcare Supplies', 'type': 'WHOLESALER', 'city': 'Jeddah', 'phone': '+966-12-456-7890' }, { 'name': 'Riyadh Medical Trading', 'type': 'DISTRIBUTOR', 'city': 'Riyadh', 'phone': '+966-11-567-8901' }, { 'name': 'Al-Dawaa Medical', 'type': 'MANUFACTURER', 'city': 'Medina', 'phone': '+966-14-678-9012' }, { 'name': 'Nahdi Medical Company', 'type': 'RETAILER', 'city': 'Jeddah', 'phone': '+966-12-789-0123' }, { 'name': 'United Pharmaceuticals', 'type': 'MANUFACTURER', 'city': 'Khobar', 'phone': '+966-13-890-1234' }, { 'name': 'Middle East Medical', 'type': 'DISTRIBUTOR', 'city': 'Taif', 'phone': '+966-12-901-2345' }, { 'name': 'Kingdom Medical Supplies', 'type': 'WHOLESALER', 'city': 'Buraidah', 'phone': '+966-16-012-3456' }, { 'name': 'Eastern Province Medical Co.', 'type': 'DISTRIBUTOR', 'city': 'Dhahran', 'phone': '+966-13-123-4567' } ] SAUDI_CITIES = [ 'Riyadh', 'Jeddah', 'Mecca', 'Medina', 'Dammam', 'Khobar', 'Dhahran', 'Taif', 'Buraidah', 'Tabuk', 'Hail', 'Khamis Mushait', 'Hofuf', 'Jubail', 'Hafar Al-Batin', 'Yanbu', 'Abha', 'Najran', 'Qatif', 'Sakaka' ] COMMON_MEDICAL_ITEMS = [ # Pharmaceuticals {'name': 'Paracetamol 500mg', 'category': 'Pharmaceuticals', 'subcategory': 'Analgesics', 'unit': 'TAB', 'controlled': False}, {'name': 'Amoxicillin 250mg', 'category': 'Pharmaceuticals', 'subcategory': 'Antibiotics', 'unit': 'CAP', 'controlled': False}, {'name': 'Insulin Regular', 'category': 'Pharmaceuticals', 'subcategory': 'Diabetes Care', 'unit': 'VIAL', 'controlled': False}, {'name': 'Morphine 10mg/ml', 'category': 'Pharmaceuticals', 'subcategory': 'Analgesics', 'unit': 'AMP', 'controlled': True}, {'name': 'Diazepam 5mg', 'category': 'Pharmaceuticals', 'subcategory': 'Psychiatric', 'unit': 'TAB', 'controlled': True}, {'name': 'Normal Saline 0.9%', 'category': 'Pharmaceuticals', 'subcategory': 'IV Solutions', 'unit': 'BAG', 'controlled': False}, # Medical Devices {'name': 'Disposable Syringe 5ml', 'category': 'Medical Devices', 'subcategory': 'Injection Equipment', 'unit': 'PCS', 'controlled': False}, {'name': 'Blood Pressure Cuff', 'category': 'Medical Devices', 'subcategory': 'Monitoring Equipment', 'unit': 'PCS', 'controlled': False}, {'name': 'ECG Electrodes', 'category': 'Medical Devices', 'subcategory': 'Cardiology Equipment', 'unit': 'PCS', 'controlled': False}, {'name': 'Surgical Gloves Size M', 'category': 'PPE & Safety', 'subcategory': 'Protective Equipment', 'unit': 'PAIR', 'controlled': False}, # Surgical Instruments {'name': 'Scalpel Blade #15', 'category': 'Surgical Instruments', 'subcategory': 'Cutting Instruments', 'unit': 'PCS', 'controlled': False}, {'name': 'Forceps Straight', 'category': 'Surgical Instruments', 'subcategory': 'Grasping Instruments', 'unit': 'PCS', 'controlled': False}, # Laboratory Supplies {'name': 'Blood Collection Tube EDTA', 'category': 'Laboratory Supplies', 'subcategory': 'Collection Tubes', 'unit': 'PCS', 'controlled': False}, {'name': 'Urine Container', 'category': 'Laboratory Supplies', 'subcategory': 'Collection Containers', 'unit': 'PCS', 'controlled': False}, ] def generate_saudi_item_code(): """Generate Saudi medical item code""" return f"SAU-{random.randint(100000, 999999)}" def generate_saudi_lot_number(): """Generate Saudi lot number""" return f"LOT{random.randint(2024, 2025)}{random.randint(100, 999)}" def generate_saudi_po_number(): """Generate Saudi purchase order number""" return f"PO-{random.randint(2024, 2025)}-{random.randint(1000, 9999)}" def create_saudi_suppliers(tenants): """Create Saudi suppliers""" suppliers = [] for tenant in tenants: print(f"Creating suppliers for {tenant.name}...") # Get or create creator try: creators = User.objects.filter(tenant=tenant) creator = random.choice(list(creators)) if creators.exists() else None except Exception as e: print(f"Warning: Could not get creator: {e}") creator = None for i, supplier_data in enumerate(SAUDI_SUPPLIER_DATA): supplier_code = f"SUP-{i + 1:03d}" # Ensure unique supplier code counter = 1 original_code = supplier_code try: while Supplier.objects.filter(tenant=tenant, supplier_code=supplier_code).exists(): supplier_code = f"{original_code}-{counter}" counter += 1 except Exception as e: print(f"Warning: Could not check existing suppliers: {e}") try: # Use atomic transaction instead of savepoint with transaction.atomic(): supplier = Supplier.objects.create( tenant=tenant, supplier_code=supplier_code, name=supplier_data['name'], supplier_type=supplier_data['type'], contact_person=f"Manager - {supplier_data['name']}", phone=supplier_data['phone'], email=f"contact@{supplier_data['name'].lower().replace(' ', '').replace('.', '')}.sa", website=f"https://www.{supplier_data['name'].lower().replace(' ', '').replace('.', '')}.sa", address_line_1=f"{random.randint(1, 999)} King {random.choice(['Fahd', 'Abdullah', 'Saud'])} Road", city=supplier_data['city'], state=f"{supplier_data['city']} Province", postal_code=f"{random.randint(10000, 99999)}", country='Saudi Arabia', tax_id=f"TAX-{random.randint(100000000, 999999999)}", payment_terms=random.choice(['NET_30', 'NET_60', 'COD']), performance_rating=Decimal(str(random.uniform(3.5, 5.0))), on_time_delivery_rate=Decimal(str(random.uniform(85, 98))), quality_rating=Decimal(str(random.uniform(3.5, 5.0))), is_active=True, is_preferred=random.choice([True, False]), certifications=[ {'name': 'ISO 13485', 'number': f"ISO-{random.randint(10000, 99999)}", 'expiry': '2025-12-31'}, {'name': 'Saudi FDA', 'number': f"SFDA-{random.randint(10000, 99999)}", 'expiry': '2025-06-30'} ], notes=f"Saudi medical supplier - {supplier_data['name']}", created_by=creator ) suppliers.append(supplier) print(f"Created supplier: {supplier_code}") except Exception as e: print(f"Error creating supplier {supplier_code}: {e}") continue print(f"Created {len(suppliers)} suppliers") return suppliers def create_saudi_inventory_locations(tenants, locations_per_tenant=20): """Create Saudi inventory locations""" locations = [] for tenant in tenants: print(f"Creating inventory locations for {tenant.name}...") for i in range(locations_per_tenant): location_code = f"LOC-{i + 1:03d}" building = random.choice(SAUDI_STORAGE_LOCATIONS['buildings']) floor = random.choice(SAUDI_STORAGE_LOCATIONS['floors']) room = random.choice(SAUDI_STORAGE_LOCATIONS['rooms']) zone = random.choice(SAUDI_STORAGE_LOCATIONS['zones']) if random.choice([True, False]) else None aisle = random.choice(SAUDI_STORAGE_LOCATIONS['aisles']) if random.choice([True, False]) else None shelf = random.choice(SAUDI_STORAGE_LOCATIONS['shelves']) if random.choice([True, False]) else None bin_location = random.choice(SAUDI_STORAGE_LOCATIONS['bins']) if random.choice([True, False]) else None location_type = random.choice(['WAREHOUSE', 'PHARMACY', 'NURSING_UNIT', 'OR_STORAGE', 'CENTRAL_SUPPLY']) # Temperature controlled for pharmaceuticals temp_controlled = random.choice([True, False]) temp_min = random.choice([2, 15, 20]) if temp_controlled else None temp_max = random.choice([8, 25, 30]) if temp_controlled else None # Humidity controlled humidity_controlled = random.choice([True, False]) humidity_min = random.randint(30, 45) if humidity_controlled else None humidity_max = random.randint(55, 70) if humidity_controlled else None # Secure location for controlled substances secure_location = random.choice([True, False]) # Get or create manager try: managers = User.objects.filter(tenant=tenant) manager = random.choice(list(managers)) if managers.exists() else None except Exception as e: print(f"Warning: Could not get manager: {e}") manager = None try: # Use atomic transaction instead of savepoint with transaction.atomic(): location = InventoryLocation.objects.create( tenant=tenant, location_code=location_code, name=f"{building} - {room}", description=f"Storage location in {building}, {floor}, {room}", location_type=location_type, building=building, floor=floor, room=room, zone=zone, aisle=aisle, shelf=shelf, bin=bin_location, capacity_cubic_feet=Decimal(str(random.randint(100, 1000))), max_weight_pounds=Decimal(str(random.randint(500, 5000))), temperature_controlled=temp_controlled, temperature_min=temp_min, temperature_max=temp_max, humidity_controlled=humidity_controlled, humidity_min=humidity_min, humidity_max=humidity_max, secure_location=secure_location, access_control=random.choice( ['KEYCARD', 'PIN', 'BIOMETRIC', 'KEY']) if secure_location else None, is_active=True, location_manager=manager, notes=f"Created for {tenant.name} inventory management", created_by=manager ) locations.append(location) print(f"Created location: {location_code}") except Exception as e: print(f"Error creating location {location_code}: {e}") continue print(f"Created {len(locations)} inventory locations") return locations def create_saudi_inventory_items(tenants, items_per_tenant=100): """Create Saudi inventory items""" items = [] for tenant in tenants: print(f"Creating inventory items for {tenant.name}...") # Get or create creator try: creators = User.objects.filter(tenant=tenant) creator = random.choice(list(creators)) if creators.exists() else None except Exception as e: print(f"Warning: Could not get creator: {e}") creator = None # Create mix of common items and random items items_to_create = COMMON_MEDICAL_ITEMS.copy() # Add random items for i in range(items_per_tenant - len(COMMON_MEDICAL_ITEMS)): category = random.choice(SAUDI_MEDICAL_CATEGORIES) subcategory = SAUDI_PHARMACEUTICAL_SUBCATEGORIES.get(category, [f"{category} Supplies"])[ 0] if category in SAUDI_PHARMACEUTICAL_SUBCATEGORIES else f"{category} Supplies" items_to_create.append({ 'name': f"{category} Item {i + 1}", 'category': category, 'subcategory': subcategory, 'unit': random.choice(['PCS', 'BOX', 'VIAL', 'TAB', 'CAP', 'ML', 'GM']), 'controlled': random.choice([True, False]) if category == 'Pharmaceuticals' else False }) for item_data in items_to_create[:items_per_tenant]: item_code = generate_saudi_item_code() # Ensure unique item code counter = 1 original_code = item_code try: while InventoryItem.objects.filter(tenant=tenant, item_code=item_code).exists(): item_code = f"{original_code}-{counter}" counter += 1 except Exception as e: print(f"Warning: Could not check existing items: {e}") manufacturer = random.choice(SAUDI_MEDICAL_MANUFACTURERS) # Generate costs in SAR unit_cost = Decimal(str(random.uniform(10, 1000))) list_price = unit_cost * Decimal(str(random.uniform(1.2, 3.0))) # Storage requirements storage_temp_min = random.choice([2, 15, 20]) if random.choice([True, False]) else None storage_temp_max = random.choice([8, 25, 30]) if storage_temp_min else None # Controlled substance info controlled = item_data.get('controlled', False) dea_schedule = random.choice(['II', 'III', 'IV', 'V']) if controlled else None try: # Use atomic transaction instead of savepoint with transaction.atomic(): item = InventoryItem.objects.create( tenant=tenant, item_code=item_code, item_name=item_data['name'], description=f"Medical supply item for {tenant.name}", category=item_data['category'], subcategory=item_data['subcategory'], item_type=random.choice(['STOCK', 'NON_STOCK', 'SERVICE', 'KIT']), manufacturer=manufacturer, model_number=f"MOD-{random.randint(1000, 9999)}" if random.choice([True, False]) else None, part_number=f"PN-{random.randint(100000, 999999)}" if random.choice([True, False]) else None, upc_code=str(random.randint(100000000000, 999999999999)) if random.choice( [True, False]) else None, ndc_code=f"{random.randint(10000, 99999)}-{random.randint(100, 999)}-{random.randint(10, 99)}" if item_data['category'] == 'Pharmaceuticals' else None, unit_of_measure=item_data['unit'], package_size=random.randint(1, 100), package_type=random.choice(['BOTTLE', 'BOX', 'VIAL', 'TUBE', 'POUCH']), unit_cost=unit_cost, list_price=list_price, storage_temperature_min=storage_temp_min, storage_temperature_max=storage_temp_max, storage_humidity_min=random.randint(30, 45) if random.choice([True, False]) else None, storage_humidity_max=random.randint(55, 70) if random.choice([True, False]) else None, storage_requirements="Store in cool, dry place" if random.choice([True, False]) else None, has_expiration=True if item_data['category'] == 'Pharmaceuticals' else random.choice( [True, False]), shelf_life_days=random.randint(365, 1095) if item_data[ 'category'] == 'Pharmaceuticals' else None, fda_approved=random.choice([True, False]), controlled_substance=controlled, dea_schedule=dea_schedule, is_active=True, is_tracked=True, is_serialized=random.choice([True, False]), is_lot_tracked=True if item_data['category'] == 'Pharmaceuticals' else random.choice( [True, False]), reorder_point=random.randint(10, 100), reorder_quantity=random.randint(50, 500), max_stock_level=random.randint(200, 1000), clinical_use=f"Used for {item_data['subcategory'].lower()} treatment" if random.choice( [True, False]) else None, notes=f"Saudi medical supply item - {item_data['name']}", created_by=creator ) items.append(item) except Exception as e: print(f"Error creating item {item_code}: {e}") continue print(f"Created {len(items)} inventory items") return items def create_saudi_inventory_stock(items, locations, stock_entries_per_item=2): """Create Saudi inventory stock entries""" stocks = [] for item in items: print(f"Creating stock for {item.item_name}...") # Get locations for this tenant tenant_locations = [loc for loc in locations if loc.tenant == item.tenant] if not tenant_locations: continue for _ in range(min(stock_entries_per_item, len(tenant_locations))): location = random.choice(tenant_locations) # Generate stock details lot_number = generate_saudi_lot_number() if item.is_lot_tracked else None serial_number = f"SN{random.randint(100000, 999999)}" if item.is_serialized else None quantity_on_hand = random.randint(0, 500) quantity_reserved = random.randint(0, min(quantity_on_hand, 50)) # Dates received_date = django_timezone.now().date() - timedelta(days=random.randint(1, 365)) expiration_date = received_date + timedelta( days=item.shelf_life_days) if item.has_expiration and item.shelf_life_days else None # Costs unit_cost = item.unit_cost * Decimal(str(random.uniform(0.9, 1.1))) # Some variation # Quality status quality_status = 'AVAILABLE' if expiration_date and expiration_date <= django_timezone.now().date(): quality_status = 'EXPIRED' elif expiration_date and expiration_date <= django_timezone.now().date() + timedelta(days=30): quality_status = 'EXPIRING_SOON' elif random.choice([True, False, False, False]): # 25% chance quality_status = random.choice(['QUARANTINED', 'DAMAGED', 'RECALLED']) try: # Use atomic transaction instead of savepoint with transaction.atomic(): stock = InventoryStock.objects.create( inventory_item=item, location=location, lot_number=lot_number, serial_number=serial_number, quantity_on_hand=quantity_on_hand, quantity_reserved=quantity_reserved, received_date=received_date, expiration_date=expiration_date, unit_cost=unit_cost, quality_status=quality_status, notes=f"Stock entry for {item.item_name} at {location.name}" ) stocks.append(stock) except Exception as e: print(f"Error creating stock for {item.item_code}: {e}") continue print(f"Created {len(stocks)} stock entries") return stocks def create_saudi_purchase_orders(tenants, suppliers, orders_per_tenant=10): """Create Saudi purchase orders""" orders = [] for tenant in tenants: print(f"Creating purchase orders for {tenant.name}...") # Get suppliers for this tenant tenant_suppliers = [supplier for supplier in suppliers if supplier.tenant == tenant] if not tenant_suppliers: print(f"No suppliers found for {tenant.name}, skipping purchase orders...") continue # Get users who can create POs try: requesters = User.objects.filter(tenant=tenant) approvers = User.objects.filter(tenant=tenant) requester = random.choice(list(requesters)) if requesters.exists() else None approver = random.choice(list(approvers)) if approvers.exists() else None except Exception as e: print(f"Warning: Could not get users: {e}") requester = None approver = None # Get delivery locations try: locations = InventoryLocation.objects.filter(tenant=tenant) delivery_location = random.choice(list(locations)) if locations.exists() else None except Exception as e: print(f"Warning: Could not get locations: {e}") delivery_location = None for i in range(orders_per_tenant): po_number = generate_saudi_po_number() # Ensure unique PO number counter = 1 original_po = po_number try: while PurchaseOrder.objects.filter(tenant=tenant, po_number=po_number).exists(): po_number = f"{original_po}-{counter}" counter += 1 except Exception as e: print(f"Warning: Could not check existing POs: {e}") supplier = random.choice(tenant_suppliers) # Generate dates order_date = django_timezone.now().date() - timedelta(days=random.randint(1, 90)) requested_delivery = order_date + timedelta(days=random.randint(7, 30)) # Determine status status = random.choices( ['DRAFT', 'PENDING_APPROVAL', 'APPROVED', 'SENT', 'PARTIAL_RECEIVED', 'RECEIVED', 'CANCELLED'], weights=[10, 15, 10, 20, 15, 25, 5] )[0] # Generate amounts in SAR subtotal = Decimal(str(random.uniform(1000, 50000))) tax_rate = Decimal('0.15') # 15% VAT in Saudi Arabia tax_amount = subtotal * tax_rate shipping_amount = Decimal(str(random.uniform(100, 1000))) total_amount = subtotal + tax_amount + shipping_amount try: # Use atomic transaction instead of savepoint with transaction.atomic(): order = PurchaseOrder.objects.create( tenant=tenant, po_number=po_number, supplier=supplier, # Now using the Supplier object order_date=order_date, requested_delivery_date=requested_delivery, promised_delivery_date=requested_delivery + timedelta( days=random.randint(0, 7)) if status != 'DRAFT' else None, actual_delivery_date=requested_delivery + timedelta(days=random.randint(-3, 10)) if status in [ 'RECEIVED', 'PARTIAL_RECEIVED'] else None, order_type=random.choice(['STANDARD', 'RUSH', 'EMERGENCY', 'BLANKET']), priority=random.choice(['LOW', 'NORMAL', 'HIGH', 'URGENT']), subtotal=subtotal, tax_amount=tax_amount, shipping_amount=shipping_amount, total_amount=total_amount, status=status, delivery_location=delivery_location, delivery_instructions=f"Deliver to {delivery_location.name} during business hours" if delivery_location else None, payment_terms=random.choice(['NET_30', 'NET_60', 'COD', 'PREPAID']), requested_by=requester, approved_by=approver if status not in ['DRAFT', 'PENDING_APPROVAL'] else None, approval_date=order_date + timedelta(days=random.randint(1, 5)) if status not in ['DRAFT', 'PENDING_APPROVAL'] else None, notes=f"Purchase order for {tenant.name} medical supplies", created_by=requester ) orders.append(order) except Exception as e: print(f"Error creating PO {po_number}: {e}") continue print(f"Created {len(orders)} purchase orders") return orders def create_saudi_purchase_order_items(orders, items): """Create Saudi purchase order items""" po_items = [] for order in orders: print(f"Creating items for PO {order.po_number}...") # Get items for this tenant tenant_items = [item for item in items if item.tenant == order.tenant] if not tenant_items: continue # Create 1-10 items per order num_items = random.randint(1, min(10, len(tenant_items))) selected_items = random.sample(tenant_items, num_items) for line_num, item in enumerate(selected_items, 1): quantity_ordered = random.randint(10, 500) quantity_received = 0 if order.status in ['PARTIAL_RECEIVED', 'RECEIVED']: if order.status == 'RECEIVED': quantity_received = quantity_ordered else: quantity_received = random.randint(0, quantity_ordered) # Price variations unit_price = item.unit_cost * Decimal(str(random.uniform(0.8, 1.2))) total_price = unit_price * quantity_ordered status = 'PENDING' if order.status == 'RECEIVED': status = 'RECEIVED' elif order.status == 'PARTIAL_RECEIVED': status = 'PARTIAL_RECEIVED' if quantity_received < quantity_ordered else 'RECEIVED' elif order.status == 'CANCELLED': status = 'CANCELLED' try: # Use atomic transaction instead of savepoint with transaction.atomic(): po_item = PurchaseOrderItem.objects.create( purchase_order=order, line_number=line_num, inventory_item=item, quantity_ordered=quantity_ordered, quantity_received=quantity_received, unit_price=unit_price, total_price=total_price, requested_delivery_date=order.requested_delivery_date, status=status, notes=f"PO item for {item.item_name}" ) po_items.append(po_item) except Exception as e: print(f"Error creating PO item for {item.item_code}: {e}") continue print(f"Created {len(po_items)} purchase order items") return po_items def main(): """Main function to create all Saudi inventory data""" print("Starting Saudi inventory data generation...") # Test database connection first if not test_database_connection(): print("Database connection failed. Please check your database configuration.") return # Get tenants try: tenants = list(Tenant.objects.filter(is_active=True)) if not tenants: print("No active tenants found. Please create tenants first.") return print(f"Found {len(tenants)} active tenants") except Exception as e: print(f"Error getting tenants: {e}") return # Create suppliers first (required for purchase orders) suppliers = create_saudi_suppliers(tenants) # Create inventory locations locations = create_saudi_inventory_locations(tenants, locations_per_tenant=15) # Create inventory items items = create_saudi_inventory_items(tenants, items_per_tenant=50) # Create inventory stock stocks = create_saudi_inventory_stock(items, locations, stock_entries_per_item=2) # Create purchase orders orders = create_saudi_purchase_orders(tenants, suppliers, orders_per_tenant=8) # Create purchase order items po_items = create_saudi_purchase_order_items(orders, items) print("\n=== Saudi Inventory Data Generation Complete ===") print(f"Created {len(suppliers)} suppliers") print(f"Created {len(locations)} inventory locations") print(f"Created {len(items)} inventory items") print(f"Created {len(stocks)} stock entries") print(f"Created {len(orders)} purchase orders") print(f"Created {len(po_items)} purchase order items") if __name__ == "__main__": main()