from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, func, desc from app.models.vehicle import Vehicle from app.models.expense import VehicleEvent, ExpenseCategory from app.models.social import ServiceProvider, SourceType, ModerationStatus from app.schemas.fleet import EventCreate, TCOStats async def add_vehicle_event(db: AsyncSession, vehicle_id: int, event_data: EventCreate, user_id: int): """ Összetett logika esemény rögzítésére: 1. Provider kezelés (DIY vs Existing vs New Ad-Hoc) 2. Odometer integritás ellenőrzés 3. Mentés és Jármű frissítés """ # 1. Jármű ellenőrzése vehicle_res = await db.execute(select(Vehicle).where(Vehicle.id == vehicle_id)) vehicle = vehicle_res.scalars().first() if not vehicle: return {"error": "Vehicle not found"} # 2. Provider Logika final_provider_id = event_data.provider_id if event_data.is_diy: # Ha DIY, akkor nincs provider final_provider_id = None if not event_data.description: event_data.description = "Saját javítás (DIY)" elif event_data.provider_name and not final_provider_id: # Ha nevet kaptunk, de ID-t nem -> Keresés vagy Létrehozás # Megpróbáljuk megkeresni név alapján (case insensitive) provider_res = await db.execute(select(ServiceProvider).where(func.lower(ServiceProvider.name) == event_data.provider_name.lower())) existing_provider = provider_res.scalars().first() if existing_provider: final_provider_id = existing_provider.id else: # Nem létezik -> Létrehozunk egy "Fantom" szolgáltatót new_provider = ServiceProvider( name=event_data.provider_name, address="Unknown (User Generated)", status=ModerationStatus.pending, # Ellenőrzésre vár source=SourceType.manual, added_by_user_id=user_id ) db.add(new_provider) await db.flush() # Hogy kapjunk ID-t final_provider_id = new_provider.id print(f"--- INFO: Created Ad-Hoc Provider: {event_data.provider_name} (ID: {final_provider_id})") # 3. Odometer Logika (Biztonság) anomaly_detected = False if event_data.odometer_value < vehicle.current_odometer: # Figyelmeztetés: Csökkent a kilométerállás! anomaly_detected = True print(f"--- WARN: Odometer rollback detected for Vehicle {vehicle_id}!") # 4. Esemény mentése new_event = VehicleEvent( vehicle_id=vehicle_id, event_type=event_data.event_type, date=event_data.date, odometer_value=event_data.odometer_value, odometer_anomaly=anomaly_detected, cost_amount=event_data.cost_amount, description=event_data.description, is_diy=event_data.is_diy, service_provider_id=final_provider_id ) db.add(new_event) # 5. Jármű frissítése (Ha nőtt a km, update-eljük a current-et) if event_data.odometer_value > vehicle.current_odometer: vehicle.current_odometer = event_data.odometer_value await db.commit() await db.refresh(new_event) return new_event async def calculate_tco(db: AsyncSession, vehicle_id: int) -> TCOStats: """Teljes költség elemzés (TCO)""" # Költségek lekérése kategóriánként result = await db.execute( select(VehicleEvent.event_type, func.sum(VehicleEvent.cost_amount)) .where(VehicleEvent.vehicle_id == vehicle_id) .group_by(VehicleEvent.event_type) ) breakdown = {row[0]: row[1] for row in result.all()} total_cost = sum(breakdown.values()) # Km futás számítás vehicle_res = await db.execute(select(Vehicle).where(Vehicle.id == vehicle_id)) vehicle = vehicle_res.scalars().first() km_driven = 0 cost_per_km = 0.0 if vehicle: km_driven = max(0, vehicle.current_odometer - vehicle.initial_odometer) if km_driven > 0: cost_per_km = total_cost / km_driven return TCOStats( vehicle_id=vehicle_id, total_cost=total_cost, breakdown=breakdown, cost_per_km=round(cost_per_km, 2) )