import { FastifyInstance } from "fastify"; import prisma from "../../config/database"; import { requireAuth, requirePermission } from "../../middleware/auth"; import { logAudit } from "../../services/audit"; import { success, error, parseId } from "../../utils/response"; import { parseBody } from "../../schemas/common"; import { CreateVehicleSchema, UpdateVehicleSchema, } from "../../schemas/vehicles.schema"; export default async function vehiclesRoutes( fastify: FastifyInstance, ): Promise { fastify.get("/", { preHandler: requireAuth }, async (_request, reply) => { const vehicles = await prisma.vehicles.findMany({ orderBy: { name: "asc" }, }); // Compute current_km and trip_count from trips table const tripStats = await prisma.trips.groupBy({ by: ["vehicle_id"], _max: { end_km: true }, _count: { id: true }, }); const statsMap = new Map( tripStats.map((s) => [ s.vehicle_id, { maxKm: s._max.end_km ?? 0, count: s._count.id }, ]), ); const enriched = vehicles.map((v) => { const stats = statsMap.get(v.id); return { ...v, current_km: stats ? Math.max(v.initial_km, stats.maxKm) : v.initial_km, trip_count: stats?.count ?? 0, }; }); return success(reply, enriched); }); fastify.post( "/", { preHandler: requirePermission("vehicles.manage") }, async (request, reply) => { const parsed = parseBody(CreateVehicleSchema, request.body); if ("error" in parsed) return error(reply, parsed.error, 400); const body = parsed.data; const vehicle = await prisma.vehicles.create({ data: { spz: body.spz, name: body.name, brand: body.brand ?? null, model: body.model ?? null, initial_km: body.initial_km, actual_km: body.actual_km, is_active: body.is_active !== false, }, }); await logAudit({ request, authData: request.authData, action: "create", entityType: "vehicle", entityId: vehicle.id, description: `Vytvořeno vozidlo ${vehicle.name}`, }); return success(reply, { id: vehicle.id }, 201, "Vozidlo bylo vytvořeno"); }, ); fastify.put<{ Params: { id: string } }>( "/:id", { preHandler: requirePermission("vehicles.manage") }, async (request, reply) => { const id = parseId(request.params.id, reply); if (id === null) return; const parsed = parseBody(UpdateVehicleSchema, request.body); if ("error" in parsed) return error(reply, parsed.error, 400); const body = parsed.data; const existing = await prisma.vehicles.findUnique({ where: { id } }); if (!existing) return error(reply, "Vozidlo nenalezeno", 404); await prisma.vehicles.update({ where: { id }, data: { spz: body.spz !== undefined ? String(body.spz) : undefined, name: body.name !== undefined ? String(body.name) : undefined, brand: body.brand !== undefined ? body.brand ? String(body.brand) : null : undefined, model: body.model !== undefined ? body.model ? String(body.model) : null : undefined, initial_km: body.initial_km !== undefined ? Number(body.initial_km) : undefined, actual_km: body.actual_km !== undefined ? Number(body.actual_km) : undefined, is_active: body.is_active !== undefined ? !!body.is_active : undefined, }, }); await logAudit({ request, authData: request.authData, action: "update", entityType: "vehicle", entityId: id, description: `Upraveno vozidlo ${existing.name}`, }); return success(reply, { id }, 200, "Vozidlo bylo uloženo"); }, ); fastify.delete<{ Params: { id: string } }>( "/:id", { preHandler: requirePermission("vehicles.manage") }, async (request, reply) => { const id = parseId(request.params.id, reply); if (id === null) return; const existing = await prisma.vehicles.findUnique({ where: { id } }); if (!existing) return error(reply, "Vozidlo nenalezeno", 404); // Check for linked trips before deleting const tripCount = await prisma.trips.count({ where: { vehicle_id: id }, }); if (tripCount > 0) { return error( reply, "Vozidlo má přiřazené jízdy a nelze jej smazat", 409, ); } await prisma.vehicles.delete({ where: { id } }); await logAudit({ request, authData: request.authData, action: "delete", entityType: "vehicle", entityId: id, description: `Smazáno vozidlo ${existing.name}`, }); return success(reply, null, 200, "Vozidlo smazáno"); }, ); }