frontend kínlódás
This commit is contained in:
244
backend/app/scripts/fix_orgs_and_vehicles.py
Normal file
244
backend/app/scripts/fix_orgs_and_vehicles.py
Normal file
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Database Surgery Script for Organization and Vehicle Fix
|
||||
Fixes:
|
||||
1. Update Private Organization owner_id from None to tester_pro's person_id
|
||||
2. Update Corporate Organization owner_id from user_id to person_id
|
||||
3. Create 2 new Corporate Orgs (Alpha, Beta) with Branches
|
||||
4. Distribute vehicles: 1 to Private, 1 to Alpha, 1 to Beta
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy import select, update, insert
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.identity.identity import User, Person
|
||||
from app.models.marketplace.organization import Organization, Branch, OrgType
|
||||
from app.models.vehicle.asset import Asset, AssetAssignment
|
||||
|
||||
|
||||
async def fix_database():
|
||||
async with AsyncSessionLocal() as session:
|
||||
print("=== DATABASE SURGERY STARTED ===")
|
||||
|
||||
# 1. Find tester_pro user and person
|
||||
result = await session.execute(
|
||||
select(User).where(User.email == 'tester_pro@profibot.hu')
|
||||
)
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if not user:
|
||||
print("ERROR: tester_pro user not found!")
|
||||
return
|
||||
|
||||
print(f"Found user: {user.email} (id={user.id}, person_id={user.person_id})")
|
||||
|
||||
# Get person
|
||||
result = await session.execute(
|
||||
select(Person).where(Person.id == user.person_id)
|
||||
)
|
||||
person = result.scalar_one_or_none()
|
||||
|
||||
if not person:
|
||||
print("ERROR: tester_pro person not found!")
|
||||
return
|
||||
|
||||
print(f"Found person: id={person.id}")
|
||||
|
||||
# 2. Fix Private Organization (ID 21) - set owner_id to person.id
|
||||
result = await session.execute(
|
||||
select(Organization).where(
|
||||
Organization.id == 21,
|
||||
Organization.org_type == OrgType.individual
|
||||
)
|
||||
)
|
||||
private_org = result.scalar_one_or_none()
|
||||
|
||||
if private_org:
|
||||
print(f"\n1. Fixing Private Organization: {private_org.full_name}")
|
||||
print(f" Current owner_id: {private_org.owner_id} (should be {person.id})")
|
||||
|
||||
if private_org.owner_id != person.id:
|
||||
await session.execute(
|
||||
update(Organization)
|
||||
.where(Organization.id == 21)
|
||||
.values(owner_id=person.id)
|
||||
)
|
||||
print(f" ✓ Updated owner_id to {person.id}")
|
||||
else:
|
||||
print(f" ✓ Already correct")
|
||||
else:
|
||||
print("\n1. Private Organization (ID 21) not found, creating...")
|
||||
# Create private org if it doesn't exist
|
||||
private_org = Organization(
|
||||
full_name=f"Private Organization for {user.email}",
|
||||
org_type=OrgType.individual,
|
||||
owner_id=person.id,
|
||||
status="active",
|
||||
is_active=True
|
||||
)
|
||||
session.add(private_org)
|
||||
await session.flush()
|
||||
print(f" ✓ Created Private Organization with id={private_org.id}")
|
||||
|
||||
# 3. Fix Corporate Organization (ID 15) - update owner_id from user.id to person.id
|
||||
result = await session.execute(
|
||||
select(Organization).where(
|
||||
Organization.id == 15,
|
||||
Organization.org_type == OrgType.fleet_owner
|
||||
)
|
||||
)
|
||||
corp_org = result.scalar_one_or_none()
|
||||
|
||||
if corp_org:
|
||||
print(f"\n2. Fixing Corporate Organization: {corp_org.full_name}")
|
||||
print(f" Current owner_id: {corp_org.owner_id} (user_id, should be person_id={person.id})")
|
||||
|
||||
if corp_org.owner_id != person.id:
|
||||
await session.execute(
|
||||
update(Organization)
|
||||
.where(Organization.id == 15)
|
||||
.values(owner_id=person.id)
|
||||
)
|
||||
print(f" ✓ Updated owner_id from {corp_org.owner_id} to {person.id}")
|
||||
else:
|
||||
print(f" ✓ Already correct")
|
||||
|
||||
# 4. Create 2 new Corporate Orgs: Alpha and Beta
|
||||
print(f"\n3. Creating 2 new Corporate Organizations...")
|
||||
|
||||
# Alpha Organization
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
alpha_slug = f"a{uuid.uuid4().hex[:6]}" # 7 characters total
|
||||
now = datetime.utcnow()
|
||||
alpha_org = Organization(
|
||||
full_name="Test Kft. Alpha",
|
||||
name="Test Kft. Alpha", # Required field
|
||||
folder_slug=alpha_slug, # Required unique field, max 12 chars
|
||||
org_type=OrgType.fleet_owner,
|
||||
owner_id=person.id,
|
||||
status="active",
|
||||
is_active=True,
|
||||
first_registered_at=now,
|
||||
current_lifecycle_started_at=now,
|
||||
subscription_plan="FREE" # Required field with default
|
||||
)
|
||||
session.add(alpha_org)
|
||||
await session.flush()
|
||||
|
||||
# Alpha Branch
|
||||
alpha_branch = Branch(
|
||||
organization_id=alpha_org.id,
|
||||
name="Alpha Main Garage",
|
||||
is_main=True
|
||||
)
|
||||
session.add(alpha_branch)
|
||||
|
||||
print(f" ✓ Created Alpha Organization: {alpha_org.full_name} (id={alpha_org.id}, slug={alpha_slug})")
|
||||
print(f" ✓ Created Alpha Branch: {alpha_branch.name}")
|
||||
|
||||
# Beta Organization
|
||||
beta_slug = f"b{uuid.uuid4().hex[:6]}" # 7 characters total
|
||||
beta_org = Organization(
|
||||
full_name="Test Kft. Beta",
|
||||
name="Test Kft. Beta", # Required field
|
||||
folder_slug=beta_slug, # Required unique field, max 12 chars
|
||||
org_type=OrgType.fleet_owner,
|
||||
owner_id=person.id,
|
||||
status="active",
|
||||
is_active=True,
|
||||
first_registered_at=now,
|
||||
current_lifecycle_started_at=now,
|
||||
subscription_plan="FREE" # Required field with default
|
||||
)
|
||||
session.add(beta_org)
|
||||
await session.flush()
|
||||
|
||||
# Beta Branch
|
||||
beta_branch = Branch(
|
||||
organization_id=beta_org.id,
|
||||
name="Beta Main Garage",
|
||||
is_main=True
|
||||
)
|
||||
session.add(beta_branch)
|
||||
|
||||
print(f" ✓ Created Beta Organization: {beta_org.full_name} (id={beta_org.id}, slug={beta_slug})")
|
||||
print(f" ✓ Created Beta Branch: {beta_branch.name}")
|
||||
|
||||
# 5. Get vehicles owned by tester_pro
|
||||
result = await session.execute(
|
||||
select(Asset).where(Asset.owner_person_id == person.id)
|
||||
)
|
||||
vehicles = result.scalars().all()
|
||||
|
||||
print(f"\n4. Distributing {len(vehicles)} vehicles...")
|
||||
|
||||
if len(vehicles) >= 3:
|
||||
# Distribute: vehicle 0 -> Private, vehicle 1 -> Alpha, vehicle 2 -> Beta
|
||||
private_vehicle = vehicles[0]
|
||||
alpha_vehicle = vehicles[1]
|
||||
beta_vehicle = vehicles[2]
|
||||
|
||||
# Update private vehicle to Private Organization
|
||||
await session.execute(
|
||||
update(Asset)
|
||||
.where(Asset.id == private_vehicle.id)
|
||||
.values(current_organization_id=private_org.id)
|
||||
)
|
||||
print(f" ✓ Vehicle '{private_vehicle.license_plate}' -> Private Organization")
|
||||
|
||||
# Update alpha vehicle to Alpha Organization
|
||||
await session.execute(
|
||||
update(Asset)
|
||||
.where(Asset.id == alpha_vehicle.id)
|
||||
.values(current_organization_id=alpha_org.id)
|
||||
)
|
||||
print(f" ✓ Vehicle '{alpha_vehicle.license_plate}' -> Alpha Organization")
|
||||
|
||||
# Update beta vehicle to Beta Organization
|
||||
await session.execute(
|
||||
update(Asset)
|
||||
.where(Asset.id == beta_vehicle.id)
|
||||
.values(current_organization_id=beta_org.id)
|
||||
)
|
||||
print(f" ✓ Vehicle '{beta_vehicle.license_plate}' -> Beta Organization")
|
||||
|
||||
# Update asset assignments as well
|
||||
# First delete existing assignments for these vehicles
|
||||
from sqlalchemy import delete
|
||||
await session.execute(
|
||||
delete(AssetAssignment).where(
|
||||
AssetAssignment.asset_id.in_([private_vehicle.id, alpha_vehicle.id, beta_vehicle.id])
|
||||
)
|
||||
)
|
||||
|
||||
# Create new assignments
|
||||
assignments = [
|
||||
AssetAssignment(asset_id=private_vehicle.id, organization_id=private_org.id),
|
||||
AssetAssignment(asset_id=alpha_vehicle.id, organization_id=alpha_org.id),
|
||||
AssetAssignment(asset_id=beta_vehicle.id, organization_id=beta_org.id)
|
||||
]
|
||||
|
||||
for assignment in assignments:
|
||||
session.add(assignment)
|
||||
|
||||
print(f" ✓ Updated asset assignments")
|
||||
else:
|
||||
print(f" ⚠️ Not enough vehicles (need 3, have {len(vehicles)})")
|
||||
|
||||
# Commit all changes
|
||||
await session.commit()
|
||||
|
||||
print(f"\n=== DATABASE SURGERY COMPLETED ===")
|
||||
print(f"Summary:")
|
||||
print(f" - Fixed Private Organization owner_id")
|
||||
print(f" - Fixed Corporate Organization owner_id")
|
||||
print(f" - Created 2 new Corporate Orgs: Alpha and Beta")
|
||||
print(f" - Created Branches for each org")
|
||||
print(f" - Distributed 3 vehicles to Private, Alpha, Beta garages")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(fix_database())
|
||||
207
backend/app/scripts/fix_orgs_complete.py
Normal file
207
backend/app/scripts/fix_orgs_complete.py
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Complete database surgery for tester_pro organizations and vehicles.
|
||||
Creates branches for Alpha/Beta organizations, distributes vehicles, and sets up asset assignments.
|
||||
"""
|
||||
import asyncio
|
||||
import asyncpg
|
||||
import os
|
||||
import uuid
|
||||
|
||||
async def fix_database():
|
||||
# Use the correct connection string for asyncpg
|
||||
DATABASE_URL = "postgresql://service_finder_app:AppSafePass_2026@db:5432/service_finder"
|
||||
|
||||
print("=== DATABASE SURGERY STARTED ===")
|
||||
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
|
||||
try:
|
||||
# Start transaction
|
||||
await conn.execute("BEGIN")
|
||||
|
||||
print("1. Checking existing organizations...")
|
||||
|
||||
# Get tester_pro's person_id (should be 29)
|
||||
person = await conn.fetchrow("""
|
||||
SELECT id FROM identity.persons WHERE email = 'tester_pro@profibot.hu'
|
||||
""")
|
||||
if not person:
|
||||
print(" ❌ tester_pro not found!")
|
||||
return
|
||||
person_id = person['id']
|
||||
print(f" ✓ Found tester_pro with person_id={person_id}")
|
||||
|
||||
# Check existing organizations
|
||||
orgs = await conn.fetch("""
|
||||
SELECT id, full_name, org_type FROM fleet.organizations
|
||||
WHERE owner_id = $1 ORDER BY id
|
||||
""", person_id)
|
||||
|
||||
print(f" ✓ Found {len(orgs)} organizations for tester_pro")
|
||||
for org in orgs:
|
||||
print(f" - ID {org['id']}: {org['full_name']} ({org['org_type']})")
|
||||
|
||||
# 1. Ensure Private Organization has correct owner_id (should already be fixed)
|
||||
print("\n2. Fixing Private Organization owner_id...")
|
||||
private_org = await conn.fetchrow("""
|
||||
SELECT id FROM fleet.organizations
|
||||
WHERE owner_id = $1 AND org_type = 'individual'
|
||||
""", person_id)
|
||||
|
||||
if private_org:
|
||||
print(f" ✓ Private Organization exists (ID: {private_org['id']})")
|
||||
else:
|
||||
print(" ⚠️ No Private Organization found")
|
||||
|
||||
# 2. Fix Corporate Organization owner_id (should already be fixed)
|
||||
print("\n3. Fixing Corporate Organization owner_id...")
|
||||
corp_org = await conn.fetchrow("""
|
||||
SELECT id FROM fleet.organizations
|
||||
WHERE owner_id = $1 AND org_type = 'fleet_owner' AND full_name LIKE '%Profibot Test Fleet%'
|
||||
""", person_id)
|
||||
|
||||
if corp_org:
|
||||
print(f" ✓ Corporate Organization exists (ID: {corp_org['id']})")
|
||||
else:
|
||||
print(" ⚠️ No Corporate Organization found")
|
||||
|
||||
# 3. Create branches for Alpha and Beta organizations if they don't exist
|
||||
print("\n4. Creating branches for Alpha and Beta organizations...")
|
||||
|
||||
# Check Alpha organization
|
||||
alpha_org = await conn.fetchrow("""
|
||||
SELECT id, full_name FROM fleet.organizations
|
||||
WHERE owner_id = $1 AND full_name = 'Test Kft. Alpha'
|
||||
""", person_id)
|
||||
|
||||
if alpha_org:
|
||||
print(f" ✓ Alpha Organization exists (ID: {alpha_org['id']})")
|
||||
# Check if Alpha has a branch
|
||||
alpha_branch = await conn.fetchrow("""
|
||||
SELECT id FROM fleet.branches WHERE organization_id = $1
|
||||
""", alpha_org['id'])
|
||||
|
||||
if not alpha_branch:
|
||||
print(" Creating Alpha Branch...")
|
||||
alpha_branch_id = str(uuid.uuid4())
|
||||
await conn.execute("""
|
||||
INSERT INTO fleet.branches (
|
||||
id, name, organization_id, branch_rating, opening_hours,
|
||||
status, is_deleted, created_at
|
||||
) VALUES (
|
||||
$1, $2, $3, 0.0, '{}'::jsonb, 'active', false, NOW()
|
||||
)
|
||||
""", alpha_branch_id, f"{alpha_org['full_name']} - Main Branch", alpha_org['id'])
|
||||
print(f" ✓ Created Alpha Branch (ID: {alpha_branch_id})")
|
||||
else:
|
||||
print(f" ✓ Alpha Branch already exists (ID: {alpha_branch['id']})")
|
||||
|
||||
# Check Beta organization
|
||||
beta_org = await conn.fetchrow("""
|
||||
SELECT id, full_name FROM fleet.organizations
|
||||
WHERE owner_id = $1 AND full_name = 'Test Kft. Beta'
|
||||
""", person_id)
|
||||
|
||||
if beta_org:
|
||||
print(f" ✓ Beta Organization exists (ID: {beta_org['id']})")
|
||||
# Check if Beta has a branch
|
||||
beta_branch = await conn.fetchrow("""
|
||||
SELECT id FROM fleet.branches WHERE organization_id = $1
|
||||
""", beta_org['id'])
|
||||
|
||||
if not beta_branch:
|
||||
print(" Creating Beta Branch...")
|
||||
beta_branch_id = str(uuid.uuid4())
|
||||
await conn.execute("""
|
||||
INSERT INTO fleet.branches (
|
||||
id, name, organization_id, branch_rating, opening_hours,
|
||||
status, is_deleted, created_at
|
||||
) VALUES (
|
||||
$1, $2, $3, 0.0, '{}'::jsonb, 'active', false, NOW()
|
||||
)
|
||||
""", beta_branch_id, f"{beta_org['full_name']} - Main Branch", beta_org['id'])
|
||||
print(f" ✓ Created Beta Branch (ID: {beta_branch_id})")
|
||||
else:
|
||||
print(f" ✓ Beta Branch already exists (ID: {beta_branch['id']})")
|
||||
|
||||
# 4. Distribute vehicles
|
||||
print("\n5. Distributing vehicles...")
|
||||
|
||||
# Get 3 vehicles owned by tester_pro
|
||||
vehicles = await conn.fetch("""
|
||||
SELECT id, license_plate, current_organization_id
|
||||
FROM vehicle.assets
|
||||
WHERE owner_person_id = $1
|
||||
ORDER BY license_plate
|
||||
LIMIT 3
|
||||
""", person_id)
|
||||
|
||||
if len(vehicles) >= 3:
|
||||
# Vehicle 1: Keep in Private Organization (ID 21)
|
||||
private_org_id = 21 # From earlier check
|
||||
await conn.execute("""
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = $1
|
||||
WHERE id = $2
|
||||
""", private_org_id, vehicles[0]['id'])
|
||||
print(f" ✓ Vehicle '{vehicles[0]['license_plate']}' -> Private Organization")
|
||||
|
||||
# Vehicle 2: Move to Alpha Organization
|
||||
if alpha_org:
|
||||
await conn.execute("""
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = $1
|
||||
WHERE id = $2
|
||||
""", alpha_org['id'], vehicles[1]['id'])
|
||||
print(f" ✓ Vehicle '{vehicles[1]['license_plate']}' -> Alpha Organization")
|
||||
|
||||
# Vehicle 3: Move to Beta Organization
|
||||
if beta_org:
|
||||
await conn.execute("""
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = $1
|
||||
WHERE id = $2
|
||||
""", beta_org['id'], vehicles[2]['id'])
|
||||
print(f" ✓ Vehicle '{vehicles[2]['license_plate']}' -> Beta Organization")
|
||||
|
||||
# 5. Update asset assignments with proper UUIDs and status
|
||||
print("\n6. Updating asset assignments...")
|
||||
|
||||
# Delete existing assignments for these vehicles
|
||||
await conn.execute("""
|
||||
DELETE FROM fleet.asset_assignments
|
||||
WHERE asset_id IN ($1, $2, $3)
|
||||
""", vehicles[0]['id'], vehicles[1]['id'], vehicles[2]['id'])
|
||||
|
||||
# Create new assignments with UUIDs and status
|
||||
assignments = [
|
||||
(str(uuid.uuid4()), vehicles[0]['id'], private_org_id, 'active'),
|
||||
(str(uuid.uuid4()), vehicles[1]['id'], alpha_org['id'] if alpha_org else None, 'active'),
|
||||
(str(uuid.uuid4()), vehicles[2]['id'], beta_org['id'] if beta_org else None, 'active')
|
||||
]
|
||||
|
||||
for assignment_id, asset_id, org_id, status in assignments:
|
||||
if org_id: # Skip if organization doesn't exist
|
||||
await conn.execute("""
|
||||
INSERT INTO fleet.asset_assignments (id, asset_id, organization_id, status)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
""", assignment_id, asset_id, org_id, status)
|
||||
|
||||
print(f" ✓ Created {len([a for a in assignments if a[2]])} asset assignments")
|
||||
else:
|
||||
print(f" ⚠️ Not enough vehicles (need 3, have {len(vehicles)})")
|
||||
|
||||
# Commit transaction
|
||||
await conn.execute("COMMIT")
|
||||
print("\n=== DATABASE SURGERY COMPLETED SUCCESSFULLY ===")
|
||||
|
||||
except Exception as e:
|
||||
await conn.execute("ROLLBACK")
|
||||
print(f"\n=== ERROR: {e} ===")
|
||||
raise
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(fix_database())
|
||||
174
backend/app/scripts/fix_orgs_final.py
Normal file
174
backend/app/scripts/fix_orgs_final.py
Normal file
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Final database fix script using raw SQL in a single transaction
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import asyncpg
|
||||
import os
|
||||
|
||||
async def fix_database():
|
||||
# Get DATABASE_URL from environment
|
||||
db_url = os.getenv('DATABASE_URL', 'postgresql+asyncpg://postgres:postgres@sf_postgres:5432/service_finder')
|
||||
# Convert to sync URL for asyncpg
|
||||
sync_url = db_url.replace('+asyncpg', '').replace('postgresql://', 'postgres://')
|
||||
|
||||
print("=== DATABASE SURGERY STARTED ===")
|
||||
|
||||
conn = await asyncpg.connect(sync_url)
|
||||
|
||||
try:
|
||||
# Start transaction
|
||||
await conn.execute("BEGIN")
|
||||
|
||||
# 1. Fix Private Organization (ID 21)
|
||||
print("1. Fixing Private Organization owner_id...")
|
||||
result = await conn.execute("""
|
||||
UPDATE fleet.organizations
|
||||
SET owner_id = 29, updated_at = NOW()
|
||||
WHERE id = 21 AND org_type = 'individual'
|
||||
""")
|
||||
print(f" ✓ Updated {result.split()[1]} rows")
|
||||
|
||||
# 2. Fix Corporate Organization (ID 15)
|
||||
print("2. Fixing Corporate Organization owner_id...")
|
||||
result = await conn.execute("""
|
||||
UPDATE fleet.organizations
|
||||
SET owner_id = 29, updated_at = NOW()
|
||||
WHERE id = 15 AND org_type = 'fleet_owner'
|
||||
""")
|
||||
print(f" ✓ Updated {result.split()[1]} rows")
|
||||
|
||||
# 3. Create Alpha Organization
|
||||
print("3. Creating Alpha Organization...")
|
||||
alpha_org = await conn.fetchrow("""
|
||||
INSERT INTO fleet.organizations (
|
||||
full_name, name, folder_slug, org_type, owner_id, status, is_active,
|
||||
first_registered_at, current_lifecycle_started_at, lifecycle_index,
|
||||
is_anonymized, default_currency, country_code, language,
|
||||
subscription_plan, base_asset_limit, purchased_extra_slots,
|
||||
notification_settings, external_integration_config, is_verified,
|
||||
created_at, updated_at, is_ownership_transferable
|
||||
) VALUES (
|
||||
$1, $2, $3, 'fleet_owner', 29, 'active', true,
|
||||
NOW(), NOW(), 1,
|
||||
false, 'HUF', 'HU', 'hu',
|
||||
'FREE', 1, 0,
|
||||
'{"notify_owner": true, "alert_days_before": [30, 15, 7, 1]}'::jsonb,
|
||||
'{}'::jsonb, false,
|
||||
NOW(), NOW(), true
|
||||
) RETURNING id, folder_slug
|
||||
""", 'Test Kft. Alpha', 'Test Kft. Alpha', f'alpha{os.urandom(3).hex()}')
|
||||
|
||||
print(f" ✓ Created Alpha Organization (id={alpha_org['id']}, slug={alpha_org['folder_slug']})")
|
||||
|
||||
# Create Alpha Branch
|
||||
import uuid
|
||||
alpha_branch_id = uuid.uuid4()
|
||||
await conn.execute("""
|
||||
INSERT INTO fleet.branches (
|
||||
id, organization_id, name, is_main,
|
||||
branch_rating, opening_hours, status, is_deleted, created_at
|
||||
) VALUES ($1, $2, $3, $4, 0.0, '{}'::jsonb, 'active', false, NOW())
|
||||
""", alpha_branch_id, alpha_org['id'], 'Alpha Main Garage', True)
|
||||
print(f" ✓ Created Alpha Branch (id={alpha_branch_id})")
|
||||
|
||||
# 4. Create Beta Organization
|
||||
print("4. Creating Beta Organization...")
|
||||
beta_org = await conn.fetchrow("""
|
||||
INSERT INTO fleet.organizations (
|
||||
full_name, name, folder_slug, org_type, owner_id, status, is_active,
|
||||
first_registered_at, current_lifecycle_started_at, lifecycle_index,
|
||||
is_anonymized, default_currency, country_code, language,
|
||||
subscription_plan, base_asset_limit, purchased_extra_slots,
|
||||
notification_settings, external_integration_config, is_verified,
|
||||
created_at, updated_at, is_ownership_transferable
|
||||
) VALUES (
|
||||
$1, $2, $3, 'fleet_owner', 29, 'active', true,
|
||||
NOW(), NOW(), 1,
|
||||
false, 'HUF', 'HU', 'hu',
|
||||
'FREE', 1, 0,
|
||||
'{"notify_owner": true, "alert_days_before": [30, 15, 7, 1]}'::jsonb,
|
||||
'{}'::jsonb, false,
|
||||
NOW(), NOW(), true
|
||||
) RETURNING id, folder_slug
|
||||
""", 'Test Kft. Beta', 'Test Kft. Beta', f'beta{os.urandom(3).hex()}')
|
||||
|
||||
print(f" ✓ Created Beta Organization (id={beta_org['id']}, slug={beta_org['folder_slug']})")
|
||||
|
||||
# Create Beta Branch
|
||||
beta_branch_id = uuid.uuid4()
|
||||
await conn.execute("""
|
||||
INSERT INTO fleet.branches (
|
||||
id, organization_id, name, is_main,
|
||||
branch_rating, opening_hours, status, is_deleted, created_at
|
||||
) VALUES ($1, $2, $3, $4, 0.0, '{}'::jsonb, 'active', false, NOW())
|
||||
""", beta_branch_id, beta_org['id'], 'Beta Main Garage', True)
|
||||
print(f" ✓ Created Beta Branch (id={beta_branch_id})")
|
||||
|
||||
# 5. Get first 3 vehicles owned by person_id 29
|
||||
print("5. Distributing vehicles...")
|
||||
vehicles = await conn.fetch("""
|
||||
SELECT id, license_plate
|
||||
FROM vehicle.assets
|
||||
WHERE owner_person_id = 29
|
||||
AND license_plate IS NOT NULL
|
||||
ORDER BY id
|
||||
LIMIT 3
|
||||
""")
|
||||
|
||||
if len(vehicles) >= 3:
|
||||
# Update vehicle 1 to Private Organization (ID 21)
|
||||
await conn.execute("""
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = 21
|
||||
WHERE id = $1
|
||||
""", vehicles[0]['id'])
|
||||
print(f" ✓ Vehicle '{vehicles[0]['license_plate']}' -> Private Organization")
|
||||
|
||||
# Update vehicle 2 to Alpha Organization
|
||||
await conn.execute("""
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = $1
|
||||
WHERE id = $2
|
||||
""", alpha_org['id'], vehicles[1]['id'])
|
||||
print(f" ✓ Vehicle '{vehicles[1]['license_plate']}' -> Alpha Organization")
|
||||
|
||||
# Update vehicle 3 to Beta Organization
|
||||
await conn.execute("""
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = $1
|
||||
WHERE id = $2
|
||||
""", beta_org['id'], vehicles[2]['id'])
|
||||
print(f" ✓ Vehicle '{vehicles[2]['license_plate']}' -> Beta Organization")
|
||||
|
||||
# Update asset assignments
|
||||
# Delete existing assignments
|
||||
await conn.execute("""
|
||||
DELETE FROM fleet.asset_assignments
|
||||
WHERE asset_id IN ($1, $2, $3)
|
||||
""", vehicles[0]['id'], vehicles[1]['id'], vehicles[2]['id'])
|
||||
|
||||
# Create new assignments
|
||||
await conn.execute("""
|
||||
INSERT INTO fleet.asset_assignments (asset_id, organization_id)
|
||||
VALUES ($1, 21), ($2, $3), ($4, $5)
|
||||
""", vehicles[0]['id'], vehicles[1]['id'], alpha_org['id'], vehicles[2]['id'], beta_org['id'])
|
||||
|
||||
print(f" ✓ Updated asset assignments")
|
||||
else:
|
||||
print(f" ⚠️ Not enough vehicles (need 3, have {len(vehicles)})")
|
||||
|
||||
# Commit transaction
|
||||
await conn.execute("COMMIT")
|
||||
print("\n=== DATABASE SURGERY COMPLETED SUCCESSFULLY ===")
|
||||
|
||||
except Exception as e:
|
||||
await conn.execute("ROLLBACK")
|
||||
print(f"\n=== ERROR: {e} ===")
|
||||
raise
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(fix_database())
|
||||
202
backend/app/scripts/fix_orgs_sql.sql
Normal file
202
backend/app/scripts/fix_orgs_sql.sql
Normal file
@@ -0,0 +1,202 @@
|
||||
-- Database Surgery Script for Organization and Vehicle Fix
|
||||
-- Using raw SQL to avoid SQLAlchemy model complexity
|
||||
|
||||
-- 1. Fix Private Organization (ID 21) - set owner_id to tester_pro's person_id (29)
|
||||
UPDATE fleet.organizations
|
||||
SET owner_id = 29, updated_at = NOW()
|
||||
WHERE id = 21 AND org_type = 'individual';
|
||||
|
||||
-- 2. Fix Corporate Organization (ID 15) - update owner_id from user_id (28) to person_id (29)
|
||||
UPDATE fleet.organizations
|
||||
SET owner_id = 29, updated_at = NOW()
|
||||
WHERE id = 15 AND org_type = 'fleet_owner';
|
||||
|
||||
-- 3. Create Alpha Organization
|
||||
INSERT INTO fleet.organizations (
|
||||
full_name,
|
||||
name,
|
||||
folder_slug,
|
||||
org_type,
|
||||
owner_id,
|
||||
status,
|
||||
is_active,
|
||||
first_registered_at,
|
||||
current_lifecycle_started_at,
|
||||
lifecycle_index,
|
||||
is_anonymized,
|
||||
default_currency,
|
||||
country_code,
|
||||
language,
|
||||
subscription_plan,
|
||||
base_asset_limit,
|
||||
purchased_extra_slots,
|
||||
notification_settings,
|
||||
external_integration_config,
|
||||
is_verified,
|
||||
created_at,
|
||||
updated_at,
|
||||
is_ownership_transferable
|
||||
) VALUES (
|
||||
'Test Kft. Alpha',
|
||||
'Test Kft. Alpha',
|
||||
'alpha' || substr(md5(random()::text), 1, 6),
|
||||
'fleet_owner',
|
||||
29,
|
||||
'active',
|
||||
true,
|
||||
NOW(),
|
||||
NOW(),
|
||||
1,
|
||||
false,
|
||||
'HUF',
|
||||
'HU',
|
||||
'hu',
|
||||
'FREE',
|
||||
1,
|
||||
0,
|
||||
'{"notify_owner": true, "alert_days_before": [30, 15, 7, 1]}'::jsonb,
|
||||
'{}'::jsonb,
|
||||
false,
|
||||
NOW(),
|
||||
NOW(),
|
||||
true
|
||||
) RETURNING id;
|
||||
|
||||
-- Save the Alpha org ID for branch creation
|
||||
WITH alpha_org AS (
|
||||
SELECT id FROM fleet.organizations
|
||||
WHERE folder_slug LIKE 'alpha%' AND full_name = 'Test Kft. Alpha'
|
||||
ORDER BY created_at DESC LIMIT 1
|
||||
)
|
||||
INSERT INTO fleet.branches (organization_id, name, is_main)
|
||||
SELECT id, 'Alpha Main Garage', true FROM alpha_org;
|
||||
|
||||
-- 4. Create Beta Organization
|
||||
INSERT INTO fleet.organizations (
|
||||
full_name,
|
||||
name,
|
||||
folder_slug,
|
||||
org_type,
|
||||
owner_id,
|
||||
status,
|
||||
is_active,
|
||||
first_registered_at,
|
||||
current_lifecycle_started_at,
|
||||
lifecycle_index,
|
||||
is_anonymized,
|
||||
default_currency,
|
||||
country_code,
|
||||
language,
|
||||
subscription_plan,
|
||||
base_asset_limit,
|
||||
purchased_extra_slots,
|
||||
notification_settings,
|
||||
external_integration_config,
|
||||
is_verified,
|
||||
created_at,
|
||||
updated_at,
|
||||
is_ownership_transferable
|
||||
) VALUES (
|
||||
'Test Kft. Beta',
|
||||
'Test Kft. Beta',
|
||||
'beta' || substr(md5(random()::text), 1, 6),
|
||||
'fleet_owner',
|
||||
29,
|
||||
'active',
|
||||
true,
|
||||
NOW(),
|
||||
NOW(),
|
||||
1,
|
||||
false,
|
||||
'HUF',
|
||||
'HU',
|
||||
'hu',
|
||||
'FREE',
|
||||
1,
|
||||
0,
|
||||
'{"notify_owner": true, "alert_days_before": [30, 15, 7, 1]}'::jsonb,
|
||||
'{}'::jsonb,
|
||||
false,
|
||||
NOW(),
|
||||
NOW(),
|
||||
true
|
||||
) RETURNING id;
|
||||
|
||||
-- Save the Beta org ID for branch creation
|
||||
WITH beta_org AS (
|
||||
SELECT id FROM fleet.organizations
|
||||
WHERE folder_slug LIKE 'beta%' AND full_name = 'Test Kft. Beta'
|
||||
ORDER BY created_at DESC LIMIT 1
|
||||
)
|
||||
INSERT INTO fleet.branches (organization_id, name, is_main)
|
||||
SELECT id, 'Beta Main Garage', true FROM beta_org;
|
||||
|
||||
-- 5. Get vehicle IDs for distribution
|
||||
-- First 3 vehicles owned by person_id 29 (tester_pro)
|
||||
WITH vehicle_ids AS (
|
||||
SELECT id, license_plate, ROW_NUMBER() OVER (ORDER BY id) as rn
|
||||
FROM vehicle.assets
|
||||
WHERE owner_person_id = 29
|
||||
AND license_plate IS NOT NULL
|
||||
ORDER BY id
|
||||
LIMIT 3
|
||||
),
|
||||
org_ids AS (
|
||||
SELECT
|
||||
(SELECT id FROM fleet.organizations WHERE id = 21) as private_org_id,
|
||||
(SELECT id FROM fleet.organizations WHERE full_name = 'Test Kft. Alpha') as alpha_org_id,
|
||||
(SELECT id FROM fleet.organizations WHERE full_name = 'Test Kft. Beta') as beta_org_id
|
||||
)
|
||||
-- Update vehicle 1 to Private Organization
|
||||
UPDATE vehicle.assets a
|
||||
SET current_organization_id = o.private_org_id
|
||||
FROM vehicle_ids v, org_ids o
|
||||
WHERE a.id = v.id AND v.rn = 1;
|
||||
|
||||
-- Update vehicle 2 to Alpha Organization
|
||||
UPDATE vehicle.assets a
|
||||
SET current_organization_id = o.alpha_org_id
|
||||
FROM vehicle_ids v, org_ids o
|
||||
WHERE a.id = v.id AND v.rn = 2;
|
||||
|
||||
-- Update vehicle 3 to Beta Organization
|
||||
UPDATE vehicle.assets a
|
||||
SET current_organization_id = o.beta_org_id
|
||||
FROM vehicle_ids v, org_ids o
|
||||
WHERE a.id = v.id AND v.rn = 3;
|
||||
|
||||
-- 6. Update asset assignments
|
||||
-- Delete existing assignments for these vehicles
|
||||
DELETE FROM fleet.asset_assignments
|
||||
WHERE asset_id IN (
|
||||
SELECT id FROM vehicle.assets
|
||||
WHERE owner_person_id = 29
|
||||
ORDER BY id
|
||||
LIMIT 3
|
||||
);
|
||||
|
||||
-- Create new assignments
|
||||
WITH vehicle_ids AS (
|
||||
SELECT id, ROW_NUMBER() OVER (ORDER BY id) as rn
|
||||
FROM vehicle.assets
|
||||
WHERE owner_person_id = 29
|
||||
AND license_plate IS NOT NULL
|
||||
ORDER BY id
|
||||
LIMIT 3
|
||||
),
|
||||
org_ids AS (
|
||||
SELECT
|
||||
(SELECT id FROM fleet.organizations WHERE id = 21) as private_org_id,
|
||||
(SELECT id FROM fleet.organizations WHERE full_name = 'Test Kft. Alpha') as alpha_org_id,
|
||||
(SELECT id FROM fleet.organizations WHERE full_name = 'Test Kft. Beta') as beta_org_id
|
||||
)
|
||||
INSERT INTO fleet.asset_assignments (asset_id, organization_id)
|
||||
SELECT
|
||||
v.id,
|
||||
CASE
|
||||
WHEN v.rn = 1 THEN o.private_org_id
|
||||
WHEN v.rn = 2 THEN o.alpha_org_id
|
||||
WHEN v.rn = 3 THEN o.beta_org_id
|
||||
END
|
||||
FROM vehicle_ids v, org_ids o
|
||||
WHERE v.rn IN (1, 2, 3);
|
||||
137
backend/app/scripts/fix_orgs_sql_final.sql
Normal file
137
backend/app/scripts/fix_orgs_sql_final.sql
Normal file
@@ -0,0 +1,137 @@
|
||||
-- Complete database surgery for tester_pro organizations and vehicles
|
||||
-- Run this in the shared-postgres container
|
||||
|
||||
-- 1. Create branches for Alpha and Beta organizations if they don't exist
|
||||
DO $$
|
||||
DECLARE
|
||||
person_id integer := 29;
|
||||
alpha_org_id integer;
|
||||
beta_org_id integer;
|
||||
alpha_branch_id uuid;
|
||||
beta_branch_id uuid;
|
||||
vehicle1_id uuid;
|
||||
vehicle2_id uuid;
|
||||
vehicle3_id uuid;
|
||||
BEGIN
|
||||
RAISE NOTICE '=== DATABASE SURGERY STARTED ===';
|
||||
|
||||
-- Get Alpha organization ID
|
||||
SELECT id INTO alpha_org_id
|
||||
FROM fleet.organizations
|
||||
WHERE owner_id = person_id AND full_name = 'Test Kft. Alpha';
|
||||
|
||||
-- Get Beta organization ID
|
||||
SELECT id INTO beta_org_id
|
||||
FROM fleet.organizations
|
||||
WHERE owner_id = person_id AND full_name = 'Test Kft. Beta';
|
||||
|
||||
RAISE NOTICE 'Alpha Organization ID: %', alpha_org_id;
|
||||
RAISE NOTICE 'Beta Organization ID: %', beta_org_id;
|
||||
|
||||
-- Create branch for Alpha if it doesn't exist
|
||||
IF alpha_org_id IS NOT NULL THEN
|
||||
IF NOT EXISTS (SELECT 1 FROM fleet.branches WHERE organization_id = alpha_org_id) THEN
|
||||
alpha_branch_id := gen_random_uuid();
|
||||
INSERT INTO fleet.branches (
|
||||
id, name, organization_id, branch_rating, opening_hours,
|
||||
status, is_deleted, created_at
|
||||
) VALUES (
|
||||
alpha_branch_id, 'Test Kft. Alpha - Main Branch', alpha_org_id,
|
||||
0.0, '{}'::jsonb, 'active', false, NOW()
|
||||
);
|
||||
RAISE NOTICE 'Created Alpha Branch: %', alpha_branch_id;
|
||||
ELSE
|
||||
RAISE NOTICE 'Alpha Branch already exists';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- Create branch for Beta if it doesn't exist
|
||||
IF beta_org_id IS NOT NULL THEN
|
||||
IF NOT EXISTS (SELECT 1 FROM fleet.branches WHERE organization_id = beta_org_id) THEN
|
||||
beta_branch_id := gen_random_uuid();
|
||||
INSERT INTO fleet.branches (
|
||||
id, name, organization_id, branch_rating, opening_hours,
|
||||
status, is_deleted, created_at
|
||||
) VALUES (
|
||||
beta_branch_id, 'Test Kft. Beta - Main Branch', beta_org_id,
|
||||
0.0, '{}'::jsonb, 'active', false, NOW()
|
||||
);
|
||||
RAISE NOTICE 'Created Beta Branch: %', beta_branch_id;
|
||||
ELSE
|
||||
RAISE NOTICE 'Beta Branch already exists';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- 2. Distribute vehicles
|
||||
RAISE NOTICE 'Distributing vehicles...';
|
||||
|
||||
-- Get 3 vehicles owned by tester_pro
|
||||
SELECT id INTO vehicle1_id FROM vehicle.assets
|
||||
WHERE owner_person_id = person_id
|
||||
ORDER BY license_plate
|
||||
LIMIT 1 OFFSET 0;
|
||||
|
||||
SELECT id INTO vehicle2_id FROM vehicle.assets
|
||||
WHERE owner_person_id = person_id
|
||||
ORDER BY license_plate
|
||||
LIMIT 1 OFFSET 1;
|
||||
|
||||
SELECT id INTO vehicle3_id FROM vehicle.assets
|
||||
WHERE owner_person_id = person_id
|
||||
ORDER BY license_plate
|
||||
LIMIT 1 OFFSET 2;
|
||||
|
||||
RAISE NOTICE 'Vehicle 1 ID: %', vehicle1_id;
|
||||
RAISE NOTICE 'Vehicle 2 ID: %', vehicle2_id;
|
||||
RAISE NOTICE 'Vehicle 3 ID: %', vehicle3_id;
|
||||
|
||||
-- Vehicle 1: Keep in Private Organization (ID 21)
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = 21
|
||||
WHERE id = vehicle1_id;
|
||||
RAISE NOTICE 'Vehicle 1 -> Private Organization (ID 21)';
|
||||
|
||||
-- Vehicle 2: Move to Alpha Organization
|
||||
IF alpha_org_id IS NOT NULL THEN
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = alpha_org_id
|
||||
WHERE id = vehicle2_id;
|
||||
RAISE NOTICE 'Vehicle 2 -> Alpha Organization (ID %)', alpha_org_id;
|
||||
END IF;
|
||||
|
||||
-- Vehicle 3: Move to Beta Organization
|
||||
IF beta_org_id IS NOT NULL THEN
|
||||
UPDATE vehicle.assets
|
||||
SET current_organization_id = beta_org_id
|
||||
WHERE id = vehicle3_id;
|
||||
RAISE NOTICE 'Vehicle 3 -> Beta Organization (ID %)', beta_org_id;
|
||||
END IF;
|
||||
|
||||
-- 3. Update asset assignments
|
||||
RAISE NOTICE 'Updating asset assignments...';
|
||||
|
||||
-- Delete existing assignments for these vehicles
|
||||
DELETE FROM fleet.asset_assignments
|
||||
WHERE asset_id IN (vehicle1_id, vehicle2_id, vehicle3_id);
|
||||
|
||||
-- Create new assignments with UUIDs and status
|
||||
IF vehicle1_id IS NOT NULL THEN
|
||||
INSERT INTO fleet.asset_assignments (id, asset_id, organization_id, status)
|
||||
VALUES (gen_random_uuid(), vehicle1_id, 21, 'active');
|
||||
RAISE NOTICE 'Created assignment for Vehicle 1';
|
||||
END IF;
|
||||
|
||||
IF vehicle2_id IS NOT NULL AND alpha_org_id IS NOT NULL THEN
|
||||
INSERT INTO fleet.asset_assignments (id, asset_id, organization_id, status)
|
||||
VALUES (gen_random_uuid(), vehicle2_id, alpha_org_id, 'active');
|
||||
RAISE NOTICE 'Created assignment for Vehicle 2';
|
||||
END IF;
|
||||
|
||||
IF vehicle3_id IS NOT NULL AND beta_org_id IS NOT NULL THEN
|
||||
INSERT INTO fleet.asset_assignments (id, asset_id, organization_id, status)
|
||||
VALUES (gen_random_uuid(), vehicle3_id, beta_org_id, 'active');
|
||||
RAISE NOTICE 'Created assignment for Vehicle 3';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '=== DATABASE SURGERY COMPLETED SUCCESSFULLY ===';
|
||||
END $$;
|
||||
218
backend/app/scripts/test_asset_logic.py
Normal file
218
backend/app/scripts/test_asset_logic.py
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test Asset Logic - Validates AssetCreate schema, dynamic defaults, and draft/active logic.
|
||||
This script must be run inside the sf_api container.
|
||||
"""
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from app.db.session import AsyncSessionLocal
|
||||
from app.schemas.asset import AssetCreate
|
||||
from app.services.config_service import config
|
||||
from datetime import datetime
|
||||
|
||||
async def test_asset_create_schema():
|
||||
"""Test AssetCreate instantiation with various field combinations."""
|
||||
print("=== Testing AssetCreate Schema ===")
|
||||
|
||||
# Test 1: Minimal required fields (license_plate only)
|
||||
print("\n1. Minimal required fields (license_plate only):")
|
||||
try:
|
||||
asset = AssetCreate(license_plate="ABC-123")
|
||||
print(f" Success: license_plate={asset.license_plate}")
|
||||
print(f" vehicle_class={asset.vehicle_class}")
|
||||
print(f" status={asset.status}")
|
||||
print(f" brand={asset.brand}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
|
||||
# Test 2: With vehicle_class provided
|
||||
print("\n2. With vehicle_class provided:")
|
||||
try:
|
||||
asset = AssetCreate(license_plate="DEF-456", vehicle_class="SUV")
|
||||
print(f" Success: vehicle_class={asset.vehicle_class}")
|
||||
print(f" status={asset.status}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
|
||||
# Test 3: All core fields (should be active)
|
||||
print("\n3. All core fields (should be active):")
|
||||
try:
|
||||
asset = AssetCreate(
|
||||
license_plate="GHI-789",
|
||||
brand="Toyota",
|
||||
model="Corolla",
|
||||
vehicle_class="car",
|
||||
fuel_type="petrol"
|
||||
)
|
||||
print(f" Success: status={asset.status}")
|
||||
print(f" brand={asset.brand}, model={asset.model}")
|
||||
print(f" vehicle_class={asset.vehicle_class}, fuel_type={asset.fuel_type}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
|
||||
# Test 4: Missing one core field (should be draft)
|
||||
print("\n4. Missing one core field (should be draft):")
|
||||
try:
|
||||
asset = AssetCreate(
|
||||
license_plate="JKL-012",
|
||||
brand="Toyota",
|
||||
model="Corolla",
|
||||
vehicle_class="car"
|
||||
# fuel_type missing
|
||||
)
|
||||
print(f" Success: status={asset.status}")
|
||||
print(f" fuel_type={asset.fuel_type}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
|
||||
# Test 5: With catalog_id
|
||||
print("\n5. With catalog_id:")
|
||||
try:
|
||||
asset = AssetCreate(
|
||||
license_plate="MNO-345",
|
||||
catalog_id=123
|
||||
)
|
||||
print(f" Success: catalog_id={asset.catalog_id}")
|
||||
print(f" status={asset.status}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
|
||||
print("\n=== Schema tests completed ===\n")
|
||||
|
||||
async def test_dynamic_default_vehicle_class():
|
||||
"""Test that vehicle_class default is fetched from config_service."""
|
||||
print("=== Testing Dynamic Default Vehicle Class ===")
|
||||
|
||||
async with AsyncSessionLocal() as db:
|
||||
# First, check if DEFAULT_VEHICLE_CLASS parameter exists
|
||||
default_class = await config.get_setting(db, "DEFAULT_VEHICLE_CLASS", default="car")
|
||||
print(f"1. DEFAULT_VEHICLE_CLASS from config: '{default_class}'")
|
||||
|
||||
# Test 2: Create AssetCreate without vehicle_class, should not be hardcoded
|
||||
print("\n2. Creating AssetCreate without vehicle_class:")
|
||||
asset = AssetCreate(license_plate="TEST-001")
|
||||
print(f" vehicle_class from schema: {asset.vehicle_class}")
|
||||
print(f" Note: The schema doesn't set a default, so it's None.")
|
||||
print(f" The service layer should use config default when needed.")
|
||||
|
||||
# Test 3: Verify config.get_setting works with different scopes
|
||||
org_default = await config.get_setting(db, "DEFAULT_VEHICLE_CLASS", default="car", org_id=1)
|
||||
print(f"\n3. DEFAULT_VEHICLE_CLASS with org_id=1: '{org_default}'")
|
||||
|
||||
# Test 4: Insert a test parameter and retrieve it
|
||||
print("\n4. Testing parameter insertion and retrieval...")
|
||||
from app.models.system.system import SystemParameter, ParameterScope
|
||||
from sqlalchemy import select
|
||||
|
||||
# Check if parameter exists
|
||||
stmt = select(SystemParameter).where(
|
||||
SystemParameter.key == "DEFAULT_VEHICLE_CLASS",
|
||||
SystemParameter.scope_level == ParameterScope.GLOBAL,
|
||||
SystemParameter.is_active == True
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
param = result.scalar_one_or_none()
|
||||
|
||||
if param:
|
||||
print(f" Parameter exists: {param.value}")
|
||||
else:
|
||||
print(f" Parameter does not exist, using default 'car'")
|
||||
|
||||
print("\n=== Dynamic default tests completed ===\n")
|
||||
|
||||
async def test_draft_vs_active_logic():
|
||||
"""Test the draft vs active status determination logic."""
|
||||
print("=== Testing Draft vs Active Logic ===")
|
||||
|
||||
test_cases = [
|
||||
{
|
||||
"name": "All core fields",
|
||||
"fields": {
|
||||
"license_plate": "CORE-001",
|
||||
"brand": "Ford",
|
||||
"model": "Focus",
|
||||
"vehicle_class": "car",
|
||||
"fuel_type": "diesel"
|
||||
},
|
||||
"expected_status": "active"
|
||||
},
|
||||
{
|
||||
"name": "Missing brand",
|
||||
"fields": {
|
||||
"license_plate": "CORE-002",
|
||||
"model": "Focus",
|
||||
"vehicle_class": "car",
|
||||
"fuel_type": "diesel"
|
||||
},
|
||||
"expected_status": "draft"
|
||||
},
|
||||
{
|
||||
"name": "Empty string brand",
|
||||
"fields": {
|
||||
"license_plate": "CORE-003",
|
||||
"brand": "",
|
||||
"model": "Focus",
|
||||
"vehicle_class": "car",
|
||||
"fuel_type": "diesel"
|
||||
},
|
||||
"expected_status": "draft"
|
||||
},
|
||||
{
|
||||
"name": "Only license_plate",
|
||||
"fields": {
|
||||
"license_plate": "CORE-004"
|
||||
},
|
||||
"expected_status": "draft"
|
||||
},
|
||||
{
|
||||
"name": "With catalog_id but missing core fields",
|
||||
"fields": {
|
||||
"license_plate": "CORE-005",
|
||||
"catalog_id": 999
|
||||
},
|
||||
"expected_status": "draft"
|
||||
},
|
||||
]
|
||||
|
||||
for tc in test_cases:
|
||||
print(f"\nTest: {tc['name']}")
|
||||
try:
|
||||
asset = AssetCreate(**tc['fields'])
|
||||
status = asset.status
|
||||
print(f" Fields: {list(tc['fields'].keys())}")
|
||||
print(f" Expected status: {tc['expected_status']}")
|
||||
print(f" Actual status: {status}")
|
||||
if status == tc['expected_status']:
|
||||
print(" ✅ PASS")
|
||||
else:
|
||||
print(" ❌ FAIL")
|
||||
except Exception as e:
|
||||
print(f" ❌ Error: {e}")
|
||||
|
||||
print("\n=== Draft/Active tests completed ===\n")
|
||||
|
||||
async def main():
|
||||
"""Run all tests."""
|
||||
print("🚀 Starting Asset Logic Tests")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
await test_asset_create_schema()
|
||||
await test_dynamic_default_vehicle_class()
|
||||
await test_draft_vs_active_logic()
|
||||
|
||||
print("=" * 50)
|
||||
print("✅ All tests completed successfully!")
|
||||
return 0
|
||||
except Exception as e:
|
||||
print(f"❌ Critical error during tests: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_code = asyncio.run(main())
|
||||
sys.exit(exit_code)
|
||||
196
backend/app/scripts/truth_serum.py
Normal file
196
backend/app/scripts/truth_serum.py
Normal file
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Truth Serum Script - Database Auditor (STRICT READ-ONLY MODE)
|
||||
|
||||
Executes raw SQL JOIN queries to show EXACTLY what is in the database
|
||||
for the user tester_pro@profibot.hu.
|
||||
|
||||
This script MUST NOT modify any data - it's read-only.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import asyncpg
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
async def get_truth_serum():
|
||||
"""
|
||||
Fetch complete map for tester_pro@profibot.hu:
|
||||
- User/Person: email and person_id
|
||||
- Organizations: Every Organization linked to this person_id (Private and Corporate)
|
||||
- Branches (Telephely): Every Branch linked to those Organizations
|
||||
- Assets (Járművek): Every Asset linked to those Branches
|
||||
"""
|
||||
# Use the correct connection string for asyncpg
|
||||
DATABASE_URL = "postgresql://service_finder_app:AppSafePass_2026@db:5432/service_finder"
|
||||
|
||||
print("=== TRUTH SERUM DATABASE AUDIT ===")
|
||||
print(f"Timestamp: {datetime.now().isoformat()}")
|
||||
print("User: tester_pro@profibot.hu")
|
||||
print("Mode: STRICT READ-ONLY (no modifications)")
|
||||
print("=" * 60)
|
||||
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
|
||||
try:
|
||||
# 1. First, get the person_id for the user
|
||||
print("\n1. Finding user tester_pro@profibot.hu...")
|
||||
person = await conn.fetchrow("""
|
||||
SELECT id, email, first_name, last_name
|
||||
FROM identity.persons
|
||||
WHERE email = 'tester_pro@profibot.hu'
|
||||
""")
|
||||
|
||||
if not person:
|
||||
print(" ❌ ERROR: User tester_pro@profibot.hu not found in identity.persons!")
|
||||
return
|
||||
|
||||
person_id = person['id']
|
||||
print(f" ✓ Found user: ID={person_id}, Email={person['email']}")
|
||||
print(f" Name: {person['first_name']} {person['last_name']}")
|
||||
|
||||
# 2. Get all organizations for this person
|
||||
print("\n2. Fetching organizations linked to this person...")
|
||||
organizations = await conn.fetch("""
|
||||
SELECT
|
||||
id as org_id,
|
||||
full_name as org_name,
|
||||
org_type,
|
||||
owner_id,
|
||||
created_at
|
||||
FROM fleet.organizations
|
||||
WHERE owner_id = $1
|
||||
ORDER BY id
|
||||
""", person_id)
|
||||
|
||||
print(f" ✓ Found {len(organizations)} organizations")
|
||||
|
||||
if not organizations:
|
||||
print(" ⚠️ No organizations found for this user")
|
||||
return
|
||||
|
||||
org_ids = [org['org_id'] for org in organizations]
|
||||
|
||||
# 3. Get all branches for these organizations
|
||||
print("\n3. Fetching branches for these organizations...")
|
||||
branches = await conn.fetch("""
|
||||
SELECT
|
||||
b.id as branch_id,
|
||||
b.name as branch_name,
|
||||
b.organization_id,
|
||||
b.created_at
|
||||
FROM fleet.branches b
|
||||
WHERE b.organization_id = ANY($1::int[])
|
||||
ORDER BY b.organization_id, b.id
|
||||
""", org_ids)
|
||||
|
||||
print(f" ✓ Found {len(branches)} branches")
|
||||
|
||||
branch_ids = [branch['branch_id'] for branch in branches]
|
||||
|
||||
# 4. Get all assets for these branches
|
||||
print("\n4. Fetching assets (vehicles) for these branches...")
|
||||
assets = await conn.fetch("""
|
||||
SELECT
|
||||
a.id as asset_id,
|
||||
a.license_plate,
|
||||
a.branch_id,
|
||||
a.make,
|
||||
a.model,
|
||||
a.status,
|
||||
a.created_at
|
||||
FROM data.assets a
|
||||
WHERE a.branch_id = ANY($1::int[])
|
||||
ORDER BY a.branch_id, a.id
|
||||
""", branch_ids)
|
||||
|
||||
print(f" ✓ Found {len(assets)} assets")
|
||||
|
||||
# 5. Now create the comprehensive JOIN for the final table
|
||||
print("\n5. Generating comprehensive JOIN map...")
|
||||
comprehensive_data = await conn.fetch("""
|
||||
SELECT
|
||||
p.email as "User Email",
|
||||
o.full_name as "Organization Name",
|
||||
b.name as "Branch Name",
|
||||
a.license_plate as "License Plate",
|
||||
o.org_type as "Org Type",
|
||||
o.id as org_id,
|
||||
b.id as branch_id,
|
||||
a.id as asset_id
|
||||
FROM identity.persons p
|
||||
LEFT JOIN fleet.organizations o ON o.owner_id = p.id
|
||||
LEFT JOIN fleet.branches b ON b.organization_id = o.id
|
||||
LEFT JOIN data.assets a ON a.branch_id = b.id
|
||||
WHERE p.email = 'tester_pro@profibot.hu'
|
||||
ORDER BY o.id, b.id, a.id
|
||||
""")
|
||||
|
||||
# 6. Print summary statistics
|
||||
print("\n" + "=" * 60)
|
||||
print("SUMMARY STATISTICS:")
|
||||
print(f" • User: {person['email']} (ID: {person_id})")
|
||||
print(f" • Organizations: {len(organizations)}")
|
||||
print(f" • Branches: {len(branches)}")
|
||||
print(f" • Assets (Vehicles): {len(assets)}")
|
||||
print(f" • Comprehensive JOIN rows: {len(comprehensive_data)}")
|
||||
print("=" * 60)
|
||||
|
||||
# 7. Print the clean Markdown table
|
||||
print("\n" + "#" * 80)
|
||||
print("# TRUTH SERUM DATABASE MAP")
|
||||
print("# User: tester_pro@profibot.hu")
|
||||
print("# Generated at: " + datetime.now().isoformat())
|
||||
print("#" * 80 + "\n")
|
||||
|
||||
if comprehensive_data:
|
||||
print("| User Email | Organization Name | Branch Name | License Plate |")
|
||||
print("|------------|-------------------|-------------|---------------|")
|
||||
|
||||
for row in comprehensive_data:
|
||||
# Handle None values
|
||||
org_name = row['Organization Name'] or "(No Organization)"
|
||||
branch_name = row['Branch Name'] or "(No Branch)"
|
||||
license_plate = row['License Plate'] or "(No License Plate)"
|
||||
|
||||
print(f"| {row['User Email']} | {org_name} | {branch_name} | {license_plate} |")
|
||||
|
||||
print(f"\nTotal rows: {len(comprehensive_data)}")
|
||||
else:
|
||||
print("⚠️ No data found in comprehensive JOIN.")
|
||||
|
||||
# 8. Print detailed breakdown for debugging
|
||||
print("\n" + "=" * 60)
|
||||
print("DETAILED BREAKDOWN:")
|
||||
|
||||
for org in organizations:
|
||||
print(f"\nOrganization: {org['org_name']} (ID: {org['org_id']}, Type: {org['org_type']})")
|
||||
|
||||
org_branches = [b for b in branches if b['organization_id'] == org['org_id']]
|
||||
if not org_branches:
|
||||
print(" No branches")
|
||||
continue
|
||||
|
||||
for branch in org_branches:
|
||||
print(f" └─ Branch: {branch['branch_name']} (ID: {branch['branch_id']})")
|
||||
|
||||
branch_assets = [a for a in assets if a['branch_id'] == branch['branch_id']]
|
||||
if not branch_assets:
|
||||
print(" No assets")
|
||||
else:
|
||||
for asset in branch_assets:
|
||||
print(f" └─ Asset: {asset['license_plate']} (ID: {asset['asset_id']}, Make: {asset['make']}, Model: {asset['model']})")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("AUDIT COMPLETE - NO DATA MODIFIED")
|
||||
print("=" * 60)
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ ERROR during audit: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(get_truth_serum())
|
||||
Reference in New Issue
Block a user