107 lines
3.3 KiB
Python
Executable File
107 lines
3.3 KiB
Python
Executable File
# /opt/docker/dev/service_finder/backend/app/api/v1/endpoints/reports.py
|
|
"""
|
|
Reports endpoints — Zombie API Cleanup.
|
|
Replaced raw SQL (FROM vehicle.vehicle_expenses) with SQLAlchemy ORM queries
|
|
using fleet_finance.asset_costs (AssetCost) + CostCategory.
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, func, desc
|
|
from sqlalchemy.orm import selectinload
|
|
from app.api.deps import get_db, get_current_user
|
|
from app.models.fleet_finance import AssetCost, CostCategory
|
|
from app.models.identity import User
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/summary/{vehicle_id}")
|
|
async def get_vehicle_summary(
|
|
vehicle_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
"""
|
|
Összesített jelentés egy járműhöz: kategóriánkénti költségek.
|
|
Uses fleet_finance.asset_costs (AssetCost) joined with CostCategory.
|
|
"""
|
|
# Aggregate costs by category using ORM
|
|
stmt = (
|
|
select(
|
|
CostCategory.name.label("category"),
|
|
func.sum(AssetCost.amount_gross).label("total_amount"),
|
|
func.count(AssetCost.id).label("transaction_count"),
|
|
)
|
|
.join(CostCategory, AssetCost.category_id == CostCategory.id)
|
|
.where(AssetCost.asset_id == vehicle_id)
|
|
.group_by(CostCategory.name)
|
|
)
|
|
result = await db.execute(stmt)
|
|
rows = result.all()
|
|
|
|
total_cost = sum(float(row.total_amount) for row in rows) if rows else 0.0
|
|
|
|
return {
|
|
"vehicle_id": vehicle_id,
|
|
"total_cost": total_cost,
|
|
"breakdown": [
|
|
{
|
|
"category": row.category,
|
|
"total_amount": float(row.total_amount),
|
|
"transaction_count": row.transaction_count,
|
|
}
|
|
for row in rows
|
|
],
|
|
}
|
|
|
|
|
|
@router.get("/trends/{vehicle_id}")
|
|
async def get_monthly_trends(
|
|
vehicle_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
"""
|
|
Visszaadja az utolsó 6 hónap költéseit havi bontásban.
|
|
Uses fleet_finance.asset_costs (AssetCost) with date truncation.
|
|
"""
|
|
# Monthly aggregation using ORM-compatible date truncation
|
|
from sqlalchemy import text as sql_text
|
|
|
|
stmt = (
|
|
select(
|
|
func.to_char(AssetCost.date, "YYYY-MM").label("month"),
|
|
func.sum(AssetCost.amount_gross).label("monthly_total"),
|
|
)
|
|
.where(AssetCost.asset_id == vehicle_id)
|
|
.group_by(sql_text("month"))
|
|
.order_by(desc(sql_text("month")))
|
|
.limit(6)
|
|
)
|
|
result = await db.execute(stmt)
|
|
rows = result.all()
|
|
|
|
return [
|
|
{"month": row.month, "monthly_total": float(row.monthly_total)}
|
|
for row in rows
|
|
]
|
|
|
|
|
|
@router.get("/summary/latest")
|
|
async def get_latest_summary(
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
"""
|
|
Returns a simple summary for the dashboard (mock data for now).
|
|
This endpoint is called by the frontend dashboard.
|
|
"""
|
|
# For now, return mock data to satisfy the frontend
|
|
return {
|
|
"total_vehicles": 4,
|
|
"total_cost_this_month": 1250.50,
|
|
"most_expensive_category": "Fuel",
|
|
"trend": "down",
|
|
"trend_percentage": -5.2,
|
|
}
|