feat: Asset Catalog system, PostGIS integration and RobotScout V1

This commit is contained in:
2026-02-11 22:47:38 +00:00
parent a63e6c8fac
commit 09a0430384
53 changed files with 2756 additions and 426 deletions

View File

@@ -1,35 +1,99 @@
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models.asset import Asset, AssetTelemetry, AssetFinancials
from sqlalchemy import select, distinct
from app.models.asset import Asset, AssetCatalog, AssetTelemetry, AssetFinancials, AssetAssignment
from app.models.gamification import UserStats, PointRule
import uuid
import logging
async def create_new_vehicle(db: AsyncSession, user_id: int, vin: str, license_plate: str):
# 1. Alap Asset létrehozása
new_asset = Asset(
vin=vin,
license_plate=license_plate,
name=f"Teszt Autó ({license_plate})"
)
db.add(new_asset)
await db.flush() # Hogy legyen ID-ja
logger = logging.getLogger(__name__)
# 2. Modulok inicializálása (Digital Twin alapozás)
db.add(AssetTelemetry(asset_id=new_asset.id, current_mileage=0))
db.add(AssetFinancials(asset_id=new_asset.id))
class AssetService:
@staticmethod
async def get_makes(db: AsyncSession):
"""1. Szint: Márkák lekérdezése (pl. Audi, BMW)."""
stmt = select(distinct(AssetCatalog.make)).order_by(AssetCatalog.make)
result = await db.execute(stmt)
return result.scalars().all()
# 3. GAMIFICATION: Pontszerzés (ASSET_REGISTER = 100 XP)
# Megkeressük a szabályt
rule_stmt = select(PointRule).where(PointRule.action_key == "ASSET_REGISTER")
rule = (await db.execute(rule_stmt)).scalar_one_or_none()
if rule:
# Frissítjük a felhasználó XP-jét
stats_stmt = select(UserStats).where(UserStats.user_id == user_id)
stats = (await db.execute(stats_stmt)).scalar_one_or_none()
if stats:
stats.total_xp += rule.points
# Itt később jöhet a szintlépés ellenőrzése is!
@staticmethod
async def get_models(db: AsyncSession, make: str):
"""2. Szint: Típusok szűrése márka alapján (pl. A4, A6)."""
stmt = select(distinct(AssetCatalog.model)).where(AssetCatalog.make == make).order_by(AssetCatalog.model)
result = await db.execute(stmt)
return result.scalars().all()
await db.commit()
return new_asset
@staticmethod
async def get_generations(db: AsyncSession, make: str, model: str):
"""3. Szint: Generációk/Évjáratok (pl. B8 (2008-2015))."""
stmt = select(distinct(AssetCatalog.generation)).where(
AssetCatalog.make == make,
AssetCatalog.model == model
).order_by(AssetCatalog.generation)
result = await db.execute(stmt)
return result.scalars().all()
@staticmethod
async def get_engines(db: AsyncSession, make: str, model: str, generation: str):
"""4. Szint: Motorváltozatok (pl. 2.0 TDI)."""
stmt = select(AssetCatalog).where(
AssetCatalog.make == make,
AssetCatalog.model == model,
AssetCatalog.generation == generation
).order_by(AssetCatalog.engine_variant)
result = await db.execute(stmt)
return result.scalars().all()
@staticmethod
async def create_and_assign_vehicle(
db: AsyncSession,
user_id: int,
org_id: int,
vin: str,
license_plate: str,
catalog_id: int = None
):
"""Jármű rögzítése, flottához rendelése és XP jóváírás (Atomic)."""
try:
# 1. Asset létrehozása közvetlen flotta-kötéssel
new_asset = Asset(
vin=vin,
license_plate=license_plate,
catalog_id=catalog_id,
current_organization_id=org_id, # Izolációs pointer
status="active",
is_verified=False
)
db.add(new_asset)
await db.flush()
# 2. Digitális Iker történetiség (Assignment)
assignment = AssetAssignment(
asset_id=new_asset.id,
organization_id=org_id,
status="active"
)
db.add(assignment)
# 3. Digitális Iker modulok indítása
db.add(AssetTelemetry(asset_id=new_asset.id))
db.add(AssetFinancials(asset_id=new_asset.id))
# 4. GAMIFICATION: XP jóváírás
rule_stmt = select(PointRule).where(PointRule.action_key == "ASSET_REGISTER")
rule = (await db.execute(rule_stmt)).scalar_one_or_none()
if rule:
stats_stmt = select(UserStats).where(UserStats.user_id == user_id)
stats = (await db.execute(stats_stmt)).scalar_one_or_none()
if stats:
stats.total_xp += rule.points
logger.info(f"User {user_id} awarded {rule.points} XP for asset registration.")
# 5. Robot Scout Trigger (későbbi implementáció)
# await RobotScout.trigger_vin_lookup(db, new_asset.id)
await db.commit()
return new_asset
except Exception as e:
await db.rollback()
logger.error(f"Asset Creation Error: {str(e)}")
raise e