hospital-management/inventory_data.py
2025-08-12 13:33:25 +03:00

1078 lines
44 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.contrib.auth import get_user_model
from core.models import Tenant
from inventory.models import InventoryItem, InventoryStock, InventoryLocation, PurchaseOrder, PurchaseOrderItem, \
Supplier
User = get_user_model()
# Saudi Arabian Inventory Data
SAUDI_MEDICAL_CATEGORIES = [
'Pharmaceuticals',
'Medical Devices',
'Surgical Instruments',
'Laboratory Supplies',
'PPE & Safety',
'IV Therapy',
'Emergency Supplies'
]
SAUDI_SUPPLIERS = [
'Saudi Medical Supply Co.',
'Gulf Medical Equipment',
'Arabian Healthcare Supplies',
'Riyadh Medical Trading',
'Al-Dawaa Medical',
'Nahdi Medical Company',
'United Pharmaceuticals'
]
SAUDI_CITIES = ['Riyadh', 'Jeddah', 'Dammam', 'Medina', 'Taif', 'Khobar']
MEDICAL_ITEMS = [
{'name': 'Paracetamol 500mg', 'category': 'Pharmaceuticals', 'unit': 'TAB'},
{'name': 'Disposable Syringe 5ml', 'category': 'Medical Devices', 'unit': 'PCS'},
{'name': 'Surgical Gloves Size M', 'category': 'PPE & Safety', 'unit': 'PAIR'},
{'name': 'Blood Collection Tube', 'category': 'Laboratory Supplies', 'unit': 'PCS'},
{'name': 'IV Bag Normal Saline', 'category': 'IV Therapy', 'unit': 'BAG'},
{'name': 'Emergency Oxygen Mask', 'category': 'Emergency Supplies', 'unit': 'PCS'}
]
def create_saudi_suppliers(tenants):
"""Create Saudi suppliers"""
suppliers = []
for tenant in tenants:
print(f"Creating suppliers for {tenant.name}...")
for i, supplier_name in enumerate(SAUDI_SUPPLIERS):
supplier_code = f"SUP-{tenant.id}-{i + 1:03d}"
try:
supplier = Supplier.objects.create(
tenant=tenant,
supplier_code=supplier_code,
name=supplier_name,
supplier_type='DISTRIBUTOR',
city=random.choice(SAUDI_CITIES),
country='Saudi Arabia',
is_active=True
)
suppliers.append(supplier)
print(f" ✓ Created supplier: {supplier_name}")
except Exception as e:
print(f" ✗ Error creating supplier {supplier_name}: {e}")
continue
print(f"Created {len(suppliers)} suppliers")
return suppliers
def create_saudi_inventory_locations(tenants):
"""Create Saudi inventory locations"""
locations = []
storage_rooms = ['Pharmacy', 'Central Supply', 'OR Storage', 'ICU Supply', 'Ward Storage']
for tenant in tenants:
print(f"Creating locations for {tenant.name}...")
for i, room in enumerate(storage_rooms):
location_code = f"LOC-{tenant.id}-{i + 1:03d}"
try:
location = InventoryLocation.objects.create(
tenant=tenant,
location_code=location_code,
name=f"{room} - {tenant.city}",
description=f"Storage location in {room}",
location_type='WAREHOUSE',
building='Main Hospital',
floor='Ground Floor',
room=room,
is_active=True
)
locations.append(location)
print(f" ✓ Created location: {location.name}")
except Exception as e:
print(f" ✗ Error creating location {room}: {e}")
continue
print(f"Created {len(locations)} locations")
return locations
def create_saudi_inventory_items(tenants):
"""Create Saudi inventory items"""
items = []
for tenant in tenants:
print(f"Creating items for {tenant.name}...")
for i, item_data in enumerate(MEDICAL_ITEMS):
item_code = f"ITM-{tenant.id}-{i + 1:03d}"
try:
item = InventoryItem.objects.create(
tenant=tenant,
item_code=item_code,
item_name=item_data['name'],
description=f"Medical item: {item_data['name']}",
category=item_data['category'],
subcategory=item_data['category'],
item_type='STOCK',
manufacturer='Saudi Medical Industries',
unit_of_measure=item_data['unit'],
package_size=1,
unit_cost=Decimal(str(random.uniform(10, 100))),
list_price=Decimal(str(random.uniform(15, 150))),
has_expiration=item_data['category'] == 'Pharmaceuticals',
is_active=True,
is_tracked=True,
reorder_point=random.randint(10, 50),
reorder_quantity=random.randint(100, 500),
max_stock_level=random.randint(500, 1000)
)
items.append(item)
print(f" ✓ Created item: {item.item_name}")
except Exception as e:
print(f" ✗ Error creating item {item_data['name']}: {e}")
continue
print(f"Created {len(items)} items")
return items
def create_saudi_inventory_stock(items, locations):
"""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
location = random.choice(tenant_locations)
try:
stock = InventoryStock.objects.create(
inventory_item=item,
location=location,
quantity_on_hand=random.randint(50, 500),
quantity_reserved=random.randint(0, 20),
received_date=django_timezone.now().date() - timedelta(days=random.randint(1, 90)),
expiration_date=django_timezone.now().date() + timedelta(days=365) if item.has_expiration else None,
unit_cost=item.unit_cost,
quality_status='AVAILABLE'
)
stocks.append(stock)
print(f" ✓ Created stock for: {item.item_name}")
except Exception as e:
print(f" ✗ Error creating stock for {item.item_name}: {e}")
continue
print(f"Created {len(stocks)} stock entries")
return stocks
def create_saudi_purchase_orders(tenants, suppliers):
"""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...")
continue
# Get delivery locations
try:
locations = InventoryLocation.objects.filter(tenant=tenant)
delivery_location = locations.first() if locations.exists() else None
except:
delivery_location = None
for i in range(3): # Create 3 orders per tenant
po_number = f"PO-{tenant.id}-{django_timezone.now().year}-{i + 1:04d}"
supplier = random.choice(tenant_suppliers)
try:
order = PurchaseOrder.objects.create(
tenant=tenant,
po_number=po_number,
supplier=supplier,
order_date=django_timezone.now().date() - timedelta(days=random.randint(1, 30)),
requested_delivery_date=django_timezone.now().date() + timedelta(days=random.randint(7, 30)),
order_type='STANDARD',
priority='NORMAL',
subtotal=Decimal(str(random.uniform(1000, 10000))),
tax_amount=Decimal('0.00'),
shipping_amount=Decimal('0.00'),
total_amount=Decimal(str(random.uniform(1000, 10000))),
status='DRAFT',
delivery_location=delivery_location,
payment_terms='NET_30'
)
orders.append(order)
print(f" ✓ Created PO: {po_number}")
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 2-3 items per order
num_items = min(3, 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, 100)
unit_price = item.unit_cost * Decimal(str(random.uniform(0.9, 1.1)))
total_price = unit_price * quantity_ordered
try:
po_item = PurchaseOrderItem.objects.create(
purchase_order=order,
line_number=line_num,
inventory_item=item,
quantity_ordered=quantity_ordered,
quantity_received=0,
unit_price=unit_price,
total_price=total_price,
requested_delivery_date=order.requested_delivery_date,
status='PENDING'
)
po_items.append(po_item)
print(f" ✓ Created PO item: {item.item_name}")
except Exception as e:
print(f" ✗ Error creating PO item for {item.item_name}: {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...")
# Get tenants
try:
tenants = list(Tenant.objects.filter(is_active=True)[:5]) # Limit to first 5 tenants
if not tenants:
print("❌ No active tenants found. Please run core_data.py first.")
return
print(f"📋 Found {len(tenants)} active tenants")
except Exception as e:
print(f"❌ Error getting tenants: {e}")
return
# Create data step by step
print("\n1⃣ Creating Suppliers...")
suppliers = create_saudi_suppliers(tenants)
if not suppliers:
print("❌ No suppliers created. Stopping.")
return
print("\n2⃣ Creating Locations...")
locations = create_saudi_inventory_locations(tenants)
if not locations:
print("❌ No locations created. Stopping.")
return
print("\n3⃣ Creating Items...")
items = create_saudi_inventory_items(tenants)
if not items:
print("❌ No items created. Stopping.")
return
print("\n4⃣ Creating Stock...")
stocks = create_saudi_inventory_stock(items, locations)
print("\n5⃣ Creating Purchase Orders...")
orders = create_saudi_purchase_orders(tenants, suppliers)
print("\n6⃣ Creating Purchase Order Items...")
po_items = create_saudi_purchase_order_items(orders, items)
print("\n🎉 Saudi Inventory Data Generation Complete!")
print(f"📊 Summary:")
print(f" - Suppliers: {len(suppliers)}")
print(f" - Locations: {len(locations)}")
print(f" - Items: {len(items)}")
print(f" - Stock Entries: {len(stocks)}")
print(f" - Purchase Orders: {len(orders)}")
print(f" - PO Items: {len(po_items)}")
if __name__ == "__main__":
main()
# 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
#
# from core.models import Tenant
# from accounts.models import User
# from inventory.models import InventoryItem, InventoryStock, InventoryLocation, PurchaseOrder, PurchaseOrderItem, \
# Supplier
#
# # 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(creators) if creators.exists() else None
# except:
# 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:
# pass
#
# try:
# with transaction.savepoint():
# 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)
#
# 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', 'DEPARTMENT', 'MOBILE', 'EXTERNAL'])
#
# # 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(managers) if managers.exists() else None
# except:
# manager = None
#
# try:
# with transaction.savepoint():
# 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)
#
# 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(creators) if creators.exists() else None
# except:
# 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:
# pass
#
# 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:
# with transaction.savepoint():
# 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:
# with transaction.savepoint():
# 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(requesters) if requesters.exists() else None
# approver = random.choice(approvers) if approvers.exists() else None
# except:
# requester = None
# approver = None
#
# # Get delivery locations
# try:
# locations = InventoryLocation.objects.filter(tenant=tenant)
# delivery_location = random.choice(locations) if locations.exists() else None
# except:
# 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:
# pass
#
# 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:
# with transaction.savepoint():
# 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:
# with transaction.savepoint():
# 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...")
#
# # 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()