frontend kínlódás

This commit is contained in:
Roo
2026-03-31 06:20:43 +00:00
parent 2508ae7452
commit c7cbe60976
46 changed files with 6091 additions and 136 deletions

View 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())

View 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())

View 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())

View 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);

View 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 $$;

View 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)

View 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())