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.system_config 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()