Files
service-finder/backend/app/services/cost_service.py

97 lines
4.2 KiB
Python

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