import logging from decimal import Decimal from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, desc from app.models.asset import AssetCost, AssetTelemetry, ExchangeRate from app.models.gamification import UserStats from app.models import SystemParameter from app.schemas.asset_cost import AssetCostCreate from datetime import datetime logger = logging.getLogger(__name__) class CostService: @staticmethod async def get_param(db: AsyncSession, key: str, default: any) -> any: """Rendszerparaméter lekérése (pl. XP szorzó).""" stmt = select(SystemParameter).where(SystemParameter.key == key) res = await db.execute(stmt) param = res.scalar_one_or_none() return param.value if param else default async def record_cost(self, db: AsyncSession, cost_in: AssetCostCreate, user_id: int): """ Költség rögzítése: EUR konverzió + Telemetria + XP. """ try: # 1. Árfolyam lekérése (EUR alapú pivot) # Megkeressük a legfrissebb rögzített árfolyamot a megadott devizához rate_stmt = select(ExchangeRate).where( ExchangeRate.target_currency == cost_in.currency_local ).order_by(desc(ExchangeRate.updated_at)).limit(1) rate_res = await db.execute(rate_stmt) rate_obj = rate_res.scalar_one_or_none() # Ha nincs rögzített árfolyam, 1.0-val számolunk (vagy hibát dobhatunk a konfigurációtól függően) exchange_rate = rate_obj.rate if rate_obj else Decimal("1.0") # EUR kalkuláció: Helyi összeg / Árfolyam (Pl. 40000 HUF / 400 = 100 EUR) amt_eur = Decimal(str(cost_in.amount_local)) / exchange_rate if exchange_rate > 0 else Decimal("0") # 2. Költség rekord létrehozása new_cost = AssetCost( asset_id=cost_in.asset_id, organization_id=cost_in.organization_id, driver_id=user_id, cost_type=cost_in.cost_type, amount_local=cost_in.amount_local, currency_local=cost_in.currency_local, amount_eur=amt_eur, net_amount_local=cost_in.net_amount_local, vat_rate=cost_in.vat_rate, exchange_rate_used=exchange_rate, mileage_at_cost=cost_in.mileage_at_cost, date=cost_in.date or datetime.now(), data=cost_in.data or {} ) db.add(new_cost) # 3. Telemetria frissítése (Ha érkezett kilométeróra állás) if cost_in.mileage_at_cost: tel_stmt = select(AssetTelemetry).where(AssetTelemetry.asset_id == cost_in.asset_id) res = await db.execute(tel_stmt) telemetry = res.scalar_one_or_none() if telemetry: # Megakadályozzuk a "visszatekerést" if cost_in.mileage_at_cost > (telemetry.current_mileage or 0): telemetry.current_mileage = cost_in.mileage_at_cost else: # Ha még nem volt telemetria adat, létrehozzuk new_telemetry = AssetTelemetry( asset_id=cost_in.asset_id, current_mileage=cost_in.mileage_at_cost ) db.add(new_telemetry) # 4. Gamification XP jóváírás xp_reward = await self.get_param(db, "XP_PER_COST_LOG", 50) stats_stmt = select(UserStats).where(UserStats.user_id == user_id) stats_res = await db.execute(stats_stmt) user_stats = stats_res.scalar_one_or_none() if user_stats: user_stats.total_xp += int(xp_reward) logger.info(f"User {user_id} earned {xp_reward} XP for cost logging.") await db.commit() await db.refresh(new_cost) return new_cost except Exception as e: await db.rollback() logger.error(f"Error in record_cost: {str(e)}") raise e cost_service = CostService()