#!/usr/bin/env python3 """ Service Finder Integration Data Seeding Script Populates PostgreSQL DB with real test data for frontend integration. Inserts: 1. User: tester_pro@profibot.hu (Password: Tester123!, Role: admin) 2. Organization: "Profibot Test Fleet" in fleet.organizations 3. Vehicles: 4 real vehicles (BMW, Audi, Mercedes, Tesla) in vehicle.assets 4. Logs: Initial logs in audit.process_logs """ import asyncio import sys from datetime import datetime, timedelta from typing import List, Tuple import uuid from sqlalchemy import select, delete, text from sqlalchemy.dialects.postgresql import insert from app.db.session import AsyncSessionLocal from app.models.identity.identity import User, Person, UserRole, Wallet from app.models.marketplace.organization import Organization from app.models.vehicle.asset import Asset from app.models.audit import ProcessLog from app.core.security import get_password_hash # Environment safety check ENVIRONMENT = "development" async def cleanup_existing_integration_data(db): """Clean up previously seeded integration data (only in non-production environments).""" if ENVIRONMENT == "production": print("โš ๏ธ Production environment detected - skipping cleanup.") return print("๐Ÿงน Cleaning up previously seeded integration data...") # We need to delete in the correct order due to foreign key constraints: # There's a circular reference between User and Person: # - User has person_id (foreign key to Person) # - Person has user_id (foreign key to User, but optional) # So we need to break the circular reference by setting person.user_id = NULL first # 1. Delete integration test vehicles (by VIN pattern) result = await db.execute( delete(Asset).where(Asset.vin.like("INTEG%")) ) print(f" Deleted {result.rowcount} integration test vehicles") # 2. Delete integration test organization result = await db.execute( delete(Organization).where(Organization.name == "Profibot Test Fleet") ) print(f" Deleted {result.rowcount} integration test organization") # 3. Find integration test users and break circular references user_stmt = select(User).where( (User.email == "tester_pro@profibot.hu") | (User.email == "superadmin@profibot.hu") ) user_result = await db.execute(user_stmt) integration_users = user_result.scalars().all() for user in integration_users: # Find the person associated with this user person_stmt = select(Person).where(Person.user_id == user.id) person_result = await db.execute(person_stmt) person = person_result.scalar_one_or_none() if person: # Break the circular reference: set person.user_id = NULL person.user_id = None person.active_user_account = None await db.flush() print(f" Broke circular reference for person {person.id}") # 4. Delete wallets for integration test users for user in integration_users: wallet_stmt = select(Wallet).where(Wallet.user_id == user.id) wallet_result = await db.execute(wallet_stmt) wallet = wallet_result.scalar_one_or_none() if wallet: await db.execute(delete(Wallet).where(Wallet.id == wallet.id)) print(f" Deleted wallet for user {user.email}") # 5. Now delete the users result = await db.execute( delete(User).where( (User.email == "tester_pro@profibot.hu") | (User.email == "superadmin@profibot.hu") ) ) print(f" Deleted {result.rowcount} integration test users") # 6. Delete the persons (now that user references are broken) # Find persons that were associated with the deleted users # We need to join with users to find persons based on user email person_stmt = select(Person).join(User, Person.user_id == User.id).where( (User.email == "tester_pro@profibot.hu") | (User.email == "superadmin@profibot.hu") ) person_result = await db.execute(person_stmt) integration_persons = person_result.scalars().all() for person in integration_persons: # Double-check that no user references this person user_check_stmt = select(User).where(User.person_id == person.id) user_check_result = await db.execute(user_check_stmt) remaining_users = user_check_result.scalars().all() if remaining_users: print(f"โš ๏ธ Person {person.id} still referenced by users: {[u.email for u in remaining_users]}") # Try to break the reference by setting user.person_id = NULL for user in remaining_users: user.person_id = None await db.flush() await db.execute(delete(Person).where(Person.id == person.id)) print(f" Deleted person {person.first_name} {person.last_name}") # 7. Delete integration test logs result = await db.execute( delete(ProcessLog).where(ProcessLog.process_name == "integration_seeding") ) print(f" Deleted {result.rowcount} integration test logs") async def seed_integration_data(): """Main seeding function for integration test data.""" print("๐Ÿš€ Starting integration data seeding...") async with AsyncSessionLocal() as db: try: # Clean up old integration data first await cleanup_existing_integration_data(db) # 1. Create Person for the tester print("๐Ÿ‘ค Creating Person for tester...") person = Person( first_name="Test", last_name="User", phone="+36123456789", is_active=True, lifetime_xp=1000, penalty_points=0, social_reputation=4.5 ) db.add(person) await db.flush() # Get the person ID # 2. Create User with admin role (tester) print("๐Ÿ‘ค Creating User tester_pro@profibot.hu...") user = User( email="tester_pro@profibot.hu", hashed_password=get_password_hash("Tester123!"), role=UserRole.admin, person_id=person.id, is_active=True, subscription_plan="PREMIUM", subscription_expires_at=datetime.now() + timedelta(days=365), is_vip=True, preferred_language="hu", region_code="HU", preferred_currency="HUF", scope_level="organization", custom_permissions={}, created_at=datetime.now() ) db.add(user) await db.flush() # Get the user ID # Update person with active user reference person.user_id = user.id person.active_user_account = user # 2b. Create superadmin user (separate person) print("๐Ÿ‘‘ Creating superadmin user superadmin@profibot.hu...") superadmin_person = Person( first_name="Super", last_name="Admin", phone="+36123456788", is_active=True, lifetime_xp=5000, penalty_points=0, social_reputation=5.0 ) db.add(superadmin_person) await db.flush() superadmin_user = User( email="superadmin@profibot.hu", hashed_password=get_password_hash("Superadmin123!"), role=UserRole.superadmin, person_id=superadmin_person.id, is_active=True, subscription_plan="ENTERPRISE", subscription_expires_at=datetime.now() + timedelta(days=365), is_vip=True, preferred_language="hu", region_code="HU", preferred_currency="HUF", scope_level="system", custom_permissions={}, created_at=datetime.now() ) db.add(superadmin_user) await db.flush() superadmin_person.user_id = superadmin_user.id superadmin_person.active_user_account = superadmin_user # 3. Create Organization print("๐Ÿข Creating Organization 'Profibot Test Fleet'...") organization = Organization( name="Profibot Test Fleet", full_name="Profibot Test Fleet Kft.", owner_id=user.id, legal_owner_id=person.id, default_currency="HUF", country_code="HU", language="hu", folder_slug="profibot", first_registered_at=datetime.now(), current_lifecycle_started_at=datetime.now(), subscription_plan="PREMIUM", base_asset_limit=10, purchased_extra_slots=0, notification_settings={"notify_owner": True, "alert_days_before": [30, 15, 7, 1]}, external_integration_config={}, org_type="fleet_owner", status="active", is_active=True, is_verified=True, created_at=datetime.now(), is_ownership_transferable=True ) db.add(organization) await db.flush() # 4. Create 4 real vehicles print("๐Ÿš— Creating 4 real vehicles...") vehicles_data = [ { "vin": "INTEGBMW123456", # 13 chars "license_plate": "ABC-123", "name": "BMW X5", "year_of_manufacture": 2022, "owner_person_id": person.id, "owner_org_id": organization.id, "current_organization_id": organization.id, "status": "active", "current_mileage": 45000, "currency": "EUR", "individual_equipment": {}, "created_at": datetime.now() }, { "vin": "INTEGAUDI789012", # 14 chars "license_plate": "DEF-456", "name": "Audi A6", "year_of_manufacture": 2021, "owner_person_id": person.id, "owner_org_id": organization.id, "current_organization_id": organization.id, "status": "active", "current_mileage": 32000, "currency": "EUR", "individual_equipment": {}, "created_at": datetime.now() }, { "vin": "INTEGMB345678", # 12 chars "license_plate": "GHI-789", "name": "Mercedes E-Class", "year_of_manufacture": 2023, "owner_person_id": person.id, "owner_org_id": organization.id, "current_organization_id": organization.id, "status": "active", "current_mileage": 15000, "currency": "EUR", "individual_equipment": {}, "created_at": datetime.now() }, { "vin": "INTEGTESLA90123", # 15 chars "license_plate": "JKL-012", "name": "Tesla Model 3", "year_of_manufacture": 2023, "owner_person_id": person.id, "owner_org_id": organization.id, "current_organization_id": organization.id, "status": "active", "current_mileage": 25000, "currency": "EUR", "individual_equipment": {}, "created_at": datetime.now() } ] for i, vehicle_data in enumerate(vehicles_data, 1): vehicle = Asset(**vehicle_data) db.add(vehicle) print(f" Created vehicle {i}: {vehicle_data['name']}") # 5. Create initial process logs print("๐Ÿ“ Creating initial process logs...") # Create a single process log for the entire seeding process log = ProcessLog( process_name="integration_seeding", start_time=datetime.now(), end_time=datetime.now(), items_processed=7, # 1 user + 1 org + 4 vehicles + 1 log items_failed=0, details={ "user_email": "tester_pro@profibot.hu", "organization": "Profibot Test Fleet", "vehicle_count": 4, "makes": ["BMW", "Audi", "Mercedes-Benz", "Tesla"] } ) db.add(log) # Commit all changes await db.commit() print("โœ… Integration data seeding completed successfully!") # Print summary print("\n๐Ÿ“Š Seeding Summary:") print(f" โ€ข User: tester_pro@profibot.hu (Password: Tester123!)") print(f" โ€ข Organization: Profibot Test Fleet") print(f" โ€ข Vehicles: 4 real vehicles (BMW X5, Audi A6, Mercedes E-Class, Tesla Model 3)") print(f" โ€ข Logs: 3 process logs created") except Exception as e: await db.rollback() print(f"โŒ Error during integration data seeding: {e}") raise async def main(): """Entry point for the seeding script.""" try: await seed_integration_data() except Exception as e: print(f"๐Ÿ’ฅ Fatal error: {e}") sys.exit(1) if __name__ == "__main__": asyncio.run(main())