- Handler funkce extrahovany z API souboru do api/admin/handlers/ - config.php rozdeleny na helpers.php (funkce) a constants.php (konstanty) - require_once odstranen z class souboru (AuditLog, JWTAuth, LeaveNotification) - vendor/autoload.php presunuto do config.php bootstrap - totp-handlers.php: pridany use deklarace pro TwoFactorAuth - phpstan.neon: bootstrapFiles, scanDirectories, dynamicConstantNames - Opraveny chybejici routing bloky v totp.php a session.php Vysledek: phpcs 0 errors 0 warnings, PHPStan 0 errors, ESLint 0 errors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
661 lines
19 KiB
PHP
661 lines
19 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
function getLastKmForVehicle(PDO $pdo, int $vehicleId): int
|
|
{
|
|
$stmt = $pdo->prepare('
|
|
SELECT COALESCE(
|
|
(SELECT MAX(end_km) FROM trips WHERE vehicle_id = ?),
|
|
(SELECT initial_km FROM vehicles WHERE id = ?),
|
|
0
|
|
) as last_km
|
|
');
|
|
$stmt->execute([$vehicleId, $vehicleId]);
|
|
$result = $stmt->fetch();
|
|
|
|
return $result ? (int)$result['last_km'] : 0;
|
|
}
|
|
|
|
function formatKm(int $km): string
|
|
{
|
|
return number_format($km, 0, ',', ' ') . ' km';
|
|
}
|
|
|
|
// ============================================================================
|
|
// GET Handlers
|
|
// ============================================================================
|
|
|
|
/**
|
|
* GET - Current month trips (filtered to current user)
|
|
*/
|
|
function handleGetCurrent(PDO $pdo, int $userId): void
|
|
{
|
|
$month = validateMonth();
|
|
$vehicleId = isset($_GET['vehicle_id']) ? (int)$_GET['vehicle_id'] : null;
|
|
$startDate = "{$month}-01";
|
|
$endDate = date('Y-m-t', strtotime($startDate));
|
|
|
|
$sql = "
|
|
SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model,
|
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
|
FROM trips t
|
|
JOIN vehicles v ON t.vehicle_id = v.id
|
|
JOIN users u ON t.user_id = u.id
|
|
WHERE t.trip_date BETWEEN ? AND ?
|
|
AND t.user_id = ?
|
|
";
|
|
$params = [$startDate, $endDate, $userId];
|
|
|
|
if ($vehicleId) {
|
|
$sql .= ' AND t.vehicle_id = ?';
|
|
$params[] = $vehicleId;
|
|
}
|
|
|
|
$sql .= ' ORDER BY t.trip_date DESC, t.start_km DESC';
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$trips = $stmt->fetchAll();
|
|
|
|
// Get active vehicles for selection
|
|
$stmt = $pdo->query('SELECT id, spz, name, brand, model FROM vehicles WHERE is_active = 1 ORDER BY name');
|
|
$vehicles = $stmt->fetchAll();
|
|
|
|
// Calculate totals
|
|
$totalDistance = 0;
|
|
$businessDistance = 0;
|
|
$privateDistance = 0;
|
|
|
|
foreach ($trips as $trip) {
|
|
$totalDistance += $trip['distance'];
|
|
if ($trip['is_business']) {
|
|
$businessDistance += $trip['distance'];
|
|
} else {
|
|
$privateDistance += $trip['distance'];
|
|
}
|
|
}
|
|
|
|
successResponse([
|
|
'trips' => $trips,
|
|
'vehicles' => $vehicles,
|
|
'month' => $month,
|
|
'totals' => [
|
|
'total' => $totalDistance,
|
|
'business' => $businessDistance,
|
|
'private' => $privateDistance,
|
|
'count' => count($trips),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET - Trip history with filters (filtered to current user)
|
|
*/
|
|
function handleGetHistory(PDO $pdo, int $userId): void
|
|
{
|
|
$month = validateMonth();
|
|
$vehicleId = isset($_GET['vehicle_id']) ? (int)$_GET['vehicle_id'] : null;
|
|
|
|
$startDate = "{$month}-01";
|
|
$endDate = date('Y-m-t', strtotime($startDate));
|
|
|
|
$sql = "
|
|
SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model,
|
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
|
FROM trips t
|
|
JOIN vehicles v ON t.vehicle_id = v.id
|
|
JOIN users u ON t.user_id = u.id
|
|
WHERE t.trip_date BETWEEN ? AND ?
|
|
AND t.user_id = ?
|
|
";
|
|
$params = [$startDate, $endDate, $userId];
|
|
|
|
if ($vehicleId) {
|
|
$sql .= ' AND t.vehicle_id = ?';
|
|
$params[] = $vehicleId;
|
|
}
|
|
|
|
$sql .= ' ORDER BY t.trip_date DESC, t.start_km DESC';
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$trips = $stmt->fetchAll();
|
|
|
|
// Get vehicles for filter
|
|
$stmt = $pdo->query('SELECT id, spz, name FROM vehicles WHERE is_active = 1 ORDER BY name');
|
|
$vehicles = $stmt->fetchAll();
|
|
|
|
// Calculate totals
|
|
$totalDistance = 0;
|
|
$businessDistance = 0;
|
|
|
|
foreach ($trips as $trip) {
|
|
$totalDistance += $trip['distance'];
|
|
if ($trip['is_business']) {
|
|
$businessDistance += $trip['distance'];
|
|
}
|
|
}
|
|
|
|
successResponse([
|
|
'trips' => $trips,
|
|
'vehicles' => $vehicles,
|
|
'month' => $month,
|
|
'totals' => [
|
|
'total' => $totalDistance,
|
|
'business' => $businessDistance,
|
|
'count' => count($trips),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET - Admin view of all trips
|
|
*/
|
|
function handleGetAdmin(PDO $pdo): void
|
|
{
|
|
$dateFrom = $_GET['date_from'] ?? null;
|
|
$dateTo = $_GET['date_to'] ?? null;
|
|
$vehicleId = isset($_GET['vehicle_id']) ? (int)$_GET['vehicle_id'] : null;
|
|
$filterUserId = isset($_GET['user_id']) ? (int)$_GET['user_id'] : null;
|
|
|
|
// Default to current month if no dates provided
|
|
if (!$dateFrom || !$dateTo) {
|
|
$month = date('Y-m');
|
|
$startDate = "{$month}-01";
|
|
$endDate = date('Y-m-t', strtotime($startDate));
|
|
} else {
|
|
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateFrom) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateTo)) {
|
|
errorResponse('Neplatný formát data (očekáváno YYYY-MM-DD)');
|
|
}
|
|
$startDate = $dateFrom;
|
|
$endDate = $dateTo;
|
|
}
|
|
|
|
$sql = "
|
|
SELECT t.*, v.spz, v.name as vehicle_name,
|
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
|
FROM trips t
|
|
JOIN vehicles v ON t.vehicle_id = v.id
|
|
JOIN users u ON t.user_id = u.id
|
|
WHERE t.trip_date BETWEEN ? AND ?
|
|
";
|
|
$params = [$startDate, $endDate];
|
|
|
|
if ($vehicleId) {
|
|
$sql .= ' AND t.vehicle_id = ?';
|
|
$params[] = $vehicleId;
|
|
}
|
|
|
|
if ($filterUserId) {
|
|
$sql .= ' AND t.user_id = ?';
|
|
$params[] = $filterUserId;
|
|
}
|
|
|
|
$sql .= ' ORDER BY t.trip_date DESC, t.start_km DESC';
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$trips = $stmt->fetchAll();
|
|
|
|
// Get vehicles for filter
|
|
$stmt = $pdo->query('SELECT id, spz, name FROM vehicles ORDER BY name');
|
|
$vehicles = $stmt->fetchAll();
|
|
|
|
// Get users for filter
|
|
$stmt = $pdo->query(
|
|
"SELECT id, CONCAT(first_name, ' ', last_name) as name FROM users WHERE is_active = 1 ORDER BY last_name"
|
|
);
|
|
$users = $stmt->fetchAll();
|
|
|
|
// Calculate totals
|
|
$totalDistance = 0;
|
|
$businessDistance = 0;
|
|
|
|
foreach ($trips as $trip) {
|
|
$totalDistance += $trip['distance'];
|
|
if ($trip['is_business']) {
|
|
$businessDistance += $trip['distance'];
|
|
}
|
|
}
|
|
|
|
successResponse([
|
|
'trips' => $trips,
|
|
'vehicles' => $vehicles,
|
|
'users' => $users,
|
|
'date_from' => $startDate,
|
|
'date_to' => $endDate,
|
|
'totals' => [
|
|
'total' => $totalDistance,
|
|
'business' => $businessDistance,
|
|
'count' => count($trips),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET - All vehicles (admin)
|
|
*/
|
|
function handleGetVehicles(PDO $pdo): void
|
|
{
|
|
$stmt = $pdo->query('
|
|
SELECT v.*, COUNT(t.id) as trip_count,
|
|
COALESCE(MAX(t.end_km), v.initial_km) as current_km
|
|
FROM vehicles v
|
|
LEFT JOIN trips t ON t.vehicle_id = v.id
|
|
GROUP BY v.id
|
|
ORDER BY v.is_active DESC, v.name
|
|
');
|
|
$vehicles = $stmt->fetchAll();
|
|
|
|
successResponse(['vehicles' => $vehicles]);
|
|
}
|
|
|
|
/**
|
|
* GET - Active vehicles for selection
|
|
*/
|
|
function handleGetActiveVehicles(PDO $pdo): void
|
|
{
|
|
$stmt = $pdo->query('
|
|
SELECT v.id, v.spz, v.name, v.brand, v.model,
|
|
COALESCE(MAX(t.end_km), v.initial_km) as current_km
|
|
FROM vehicles v
|
|
LEFT JOIN trips t ON t.vehicle_id = v.id
|
|
WHERE v.is_active = 1
|
|
GROUP BY v.id
|
|
ORDER BY v.name
|
|
');
|
|
$vehicles = $stmt->fetchAll();
|
|
|
|
successResponse(['vehicles' => $vehicles]);
|
|
}
|
|
|
|
/**
|
|
* GET - Last km for vehicle
|
|
*/
|
|
function handleGetLastKm(PDO $pdo): void
|
|
{
|
|
$vehicleId = (int)($_GET['vehicle_id'] ?? 0);
|
|
if (!$vehicleId) {
|
|
errorResponse('Vehicle ID je povinné');
|
|
}
|
|
|
|
$lastKm = getLastKmForVehicle($pdo, $vehicleId);
|
|
successResponse(['last_km' => $lastKm]);
|
|
}
|
|
|
|
// ============================================================================
|
|
// POST Handlers
|
|
// ============================================================================
|
|
|
|
/**
|
|
* POST - Create trip
|
|
*/
|
|
function handleCreateTrip(PDO $pdo, int $userId): void
|
|
{
|
|
$input = getJsonInput();
|
|
|
|
$vehicleId = (int)($input['vehicle_id'] ?? 0);
|
|
$tripDate = $input['trip_date'] ?? '';
|
|
$startKm = (int)($input['start_km'] ?? 0);
|
|
$endKm = (int)($input['end_km'] ?? 0);
|
|
$routeFrom = trim($input['route_from'] ?? '');
|
|
$routeTo = trim($input['route_to'] ?? '');
|
|
$isBusiness = (int)($input['is_business'] ?? 1);
|
|
$notes = trim($input['notes'] ?? '');
|
|
|
|
// Validation
|
|
if (!$vehicleId) {
|
|
errorResponse('Vyberte vozidlo');
|
|
}
|
|
if (!$tripDate) {
|
|
errorResponse('Datum jízdy je povinné');
|
|
}
|
|
if (!$startKm) {
|
|
errorResponse('Počáteční stav km je povinný');
|
|
}
|
|
if (!$endKm) {
|
|
errorResponse('Konečný stav km je povinný');
|
|
}
|
|
if (!$routeFrom) {
|
|
errorResponse('Místo odjezdu je povinné');
|
|
}
|
|
if (!$routeTo) {
|
|
errorResponse('Místo příjezdu je povinné');
|
|
}
|
|
if ($endKm <= $startKm) {
|
|
errorResponse('Konečný stav km musí být větší než počáteční');
|
|
}
|
|
|
|
// Check vehicle exists
|
|
$stmt = $pdo->prepare('SELECT id FROM vehicles WHERE id = ? AND is_active = 1');
|
|
$stmt->execute([$vehicleId]);
|
|
if (!$stmt->fetch()) {
|
|
errorResponse('Vozidlo neexistuje nebo není aktivní');
|
|
}
|
|
|
|
$stmt = $pdo->prepare('
|
|
INSERT INTO trips (vehicle_id, user_id, trip_date, start_km, end_km, route_from, route_to, is_business, notes)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
');
|
|
$stmt->execute([
|
|
$vehicleId, $userId, $tripDate, $startKm, $endKm,
|
|
$routeFrom, $routeTo, $isBusiness, $notes ?: null,
|
|
]);
|
|
|
|
$newId = (int)$pdo->lastInsertId();
|
|
AuditLog::logCreate('trips', $newId, $input, 'Vytvořen záznam jízdy');
|
|
|
|
successResponse(['id' => $newId], 'Jízda byla zaznamenána');
|
|
}
|
|
|
|
/**
|
|
* POST - Create/update vehicle (admin)
|
|
*/
|
|
function handleVehicle(PDO $pdo): void
|
|
{
|
|
$input = getJsonInput();
|
|
|
|
$id = (int)($input['id'] ?? 0);
|
|
$spz = strtoupper(trim($input['spz'] ?? ''));
|
|
$name = trim($input['name'] ?? '');
|
|
$brand = trim($input['brand'] ?? '');
|
|
$model = trim($input['model'] ?? '');
|
|
$initialKm = (int)($input['initial_km'] ?? 0);
|
|
$isActive = isset($input['is_active']) ? (int)$input['is_active'] : 1;
|
|
|
|
if (!$spz) {
|
|
errorResponse('SPZ je povinná');
|
|
}
|
|
if (!$name) {
|
|
errorResponse('Název je povinný');
|
|
}
|
|
|
|
if ($id) {
|
|
// Update
|
|
$stmt = $pdo->prepare('
|
|
UPDATE vehicles
|
|
SET spz = ?, name = ?, brand = ?, model = ?, initial_km = ?, is_active = ?
|
|
WHERE id = ?
|
|
');
|
|
$stmt->execute([$spz, $name, $brand ?: null, $model ?: null, $initialKm, $isActive, $id]);
|
|
|
|
AuditLog::logUpdate('vehicles', $id, [], $input, 'Upraveno vozidlo');
|
|
successResponse(null, 'Vozidlo bylo aktualizováno');
|
|
} else {
|
|
// Create
|
|
$stmt = $pdo->prepare('
|
|
INSERT INTO vehicles (spz, name, brand, model, initial_km, is_active)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
');
|
|
|
|
try {
|
|
$stmt->execute([$spz, $name, $brand ?: null, $model ?: null, $initialKm, $isActive]);
|
|
$newId = (int)$pdo->lastInsertId();
|
|
|
|
AuditLog::logCreate('vehicles', $newId, $input, 'Vytvořeno vozidlo');
|
|
successResponse(['id' => $newId], 'Vozidlo bylo vytvořeno');
|
|
} catch (PDOException $e) {
|
|
if ($e->getCode() == 23000) {
|
|
errorResponse('Vozidlo s touto SPZ již existuje');
|
|
}
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// PUT Handler
|
|
// ============================================================================
|
|
|
|
/**
|
|
* PUT - Update trip
|
|
*
|
|
* @param array<string, mixed> $authData
|
|
*/
|
|
function handleUpdateTrip(PDO $pdo, int $id, int $userId, array $authData): void
|
|
{
|
|
$stmt = $pdo->prepare('SELECT * FROM trips WHERE id = ?');
|
|
$stmt->execute([$id]);
|
|
$trip = $stmt->fetch();
|
|
|
|
if (!$trip) {
|
|
errorResponse('Záznam nebyl nalezen', 404);
|
|
}
|
|
|
|
// Check permission - own trips or trips.admin
|
|
if ($trip['user_id'] !== $userId && !hasPermission($authData, 'trips.admin')) {
|
|
errorResponse('Nemáte oprávnění upravit tento záznam', 403);
|
|
}
|
|
|
|
$input = getJsonInput();
|
|
|
|
$vehicleId = (int)($input['vehicle_id'] ?? $trip['vehicle_id']);
|
|
$tripDate = $input['trip_date'] ?? $trip['trip_date'];
|
|
$startKm = (int)($input['start_km'] ?? $trip['start_km']);
|
|
$endKm = (int)($input['end_km'] ?? $trip['end_km']);
|
|
$routeFrom = trim($input['route_from'] ?? $trip['route_from']);
|
|
$routeTo = trim($input['route_to'] ?? $trip['route_to']);
|
|
$isBusiness = isset($input['is_business']) ? (int)$input['is_business'] : $trip['is_business'];
|
|
$notes = trim($input['notes'] ?? $trip['notes'] ?? '');
|
|
|
|
if ($endKm <= $startKm) {
|
|
errorResponse('Konečný stav km musí být větší než počáteční');
|
|
}
|
|
|
|
$stmt = $pdo->prepare('
|
|
UPDATE trips
|
|
SET vehicle_id = ?, trip_date = ?, start_km = ?, end_km = ?,
|
|
route_from = ?, route_to = ?, is_business = ?, notes = ?
|
|
WHERE id = ?
|
|
');
|
|
$stmt->execute([$vehicleId, $tripDate, $startKm, $endKm, $routeFrom, $routeTo, $isBusiness, $notes ?: null, $id]);
|
|
|
|
AuditLog::logUpdate('trips', $id, $trip, $input, 'Upraven záznam jízdy');
|
|
|
|
successResponse(null, 'Záznam byl aktualizován');
|
|
}
|
|
|
|
// ============================================================================
|
|
// DELETE Handlers
|
|
// ============================================================================
|
|
|
|
/**
|
|
* DELETE - Delete trip
|
|
*
|
|
* @param array<string, mixed> $authData
|
|
*/
|
|
function handleDeleteTrip(PDO $pdo, int $id, int $userId, array $authData): void
|
|
{
|
|
$stmt = $pdo->prepare('SELECT * FROM trips WHERE id = ?');
|
|
$stmt->execute([$id]);
|
|
$trip = $stmt->fetch();
|
|
|
|
if (!$trip) {
|
|
errorResponse('Záznam nebyl nalezen', 404);
|
|
}
|
|
|
|
// Check permission - own trips or trips.admin
|
|
if ($trip['user_id'] !== $userId && !hasPermission($authData, 'trips.admin')) {
|
|
errorResponse('Nemáte oprávnění smazat tento záznam', 403);
|
|
}
|
|
|
|
$stmt = $pdo->prepare('DELETE FROM trips WHERE id = ?');
|
|
$stmt->execute([$id]);
|
|
|
|
AuditLog::logDelete('trips', $id, $trip, 'Smazán záznam jízdy');
|
|
|
|
successResponse(null, 'Záznam byl smazán');
|
|
}
|
|
|
|
/**
|
|
* DELETE - Delete vehicle (admin)
|
|
*/
|
|
function handleDeleteVehicle(PDO $pdo, int $id): void
|
|
{
|
|
if (!$id) {
|
|
errorResponse('ID je povinné');
|
|
}
|
|
|
|
$stmt = $pdo->prepare('SELECT * FROM vehicles WHERE id = ?');
|
|
$stmt->execute([$id]);
|
|
$vehicle = $stmt->fetch();
|
|
|
|
if (!$vehicle) {
|
|
errorResponse('Vozidlo nebylo nalezeno', 404);
|
|
}
|
|
|
|
// Check if vehicle has trips
|
|
$stmt = $pdo->prepare('SELECT COUNT(*) FROM trips WHERE vehicle_id = ?');
|
|
$stmt->execute([$id]);
|
|
$tripCount = $stmt->fetchColumn();
|
|
|
|
if ($tripCount > 0) {
|
|
errorResponse(
|
|
"Nelze smazat vozidlo s {$tripCount} záznamy jízd. Nejprve smažte záznamy jízd nebo deaktivujte vozidlo."
|
|
);
|
|
}
|
|
|
|
$stmt = $pdo->prepare('DELETE FROM vehicles WHERE id = ?');
|
|
$stmt->execute([$id]);
|
|
|
|
AuditLog::logDelete('vehicles', $id, $vehicle, 'Smazáno vozidlo');
|
|
|
|
successResponse(null, 'Vozidlo bylo smazáno');
|
|
}
|
|
|
|
// ============================================================================
|
|
// Print Handler
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Format date range for display
|
|
*/
|
|
function formatPeriodName(string $startDate, string $endDate): string
|
|
{
|
|
$start = new DateTime($startDate);
|
|
$end = new DateTime($endDate);
|
|
|
|
// If same month
|
|
if ($start->format('Y-m') === $end->format('Y-m')) {
|
|
return getCzechMonthName((int)$start->format('n')) . ' ' . $start->format('Y');
|
|
}
|
|
|
|
// If same year
|
|
if ($start->format('Y') === $end->format('Y')) {
|
|
return $start->format('j.n.') . ' - ' . $end->format('j.n.Y');
|
|
}
|
|
|
|
// Different years
|
|
return $start->format('j.n.Y') . ' - ' . $end->format('j.n.Y');
|
|
}
|
|
|
|
/**
|
|
* GET - Print data for trips (admin)
|
|
*/
|
|
function handleGetPrint(PDO $pdo): void
|
|
{
|
|
$dateFrom = $_GET['date_from'] ?? null;
|
|
$dateTo = $_GET['date_to'] ?? null;
|
|
$vehicleId = isset($_GET['vehicle_id']) && $_GET['vehicle_id'] !== '' ? (int)$_GET['vehicle_id'] : null;
|
|
$filterUserId = isset($_GET['user_id']) && $_GET['user_id'] !== '' ? (int)$_GET['user_id'] : null;
|
|
|
|
// Default to current month if no dates provided
|
|
if (!$dateFrom || !$dateTo) {
|
|
$startDate = date('Y-m-01');
|
|
$endDate = date('Y-m-t');
|
|
} else {
|
|
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateFrom) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateTo)) {
|
|
errorResponse('Neplatný formát data (očekáváno YYYY-MM-DD)');
|
|
}
|
|
$startDate = $dateFrom;
|
|
$endDate = $dateTo;
|
|
}
|
|
|
|
$sql = "
|
|
SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model,
|
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
|
FROM trips t
|
|
JOIN vehicles v ON t.vehicle_id = v.id
|
|
JOIN users u ON t.user_id = u.id
|
|
WHERE t.trip_date BETWEEN ? AND ?
|
|
";
|
|
$params = [$startDate, $endDate];
|
|
|
|
if ($vehicleId) {
|
|
$sql .= ' AND t.vehicle_id = ?';
|
|
$params[] = $vehicleId;
|
|
}
|
|
|
|
if ($filterUserId) {
|
|
$sql .= ' AND t.user_id = ?';
|
|
$params[] = $filterUserId;
|
|
}
|
|
|
|
$sql .= ' ORDER BY t.trip_date ASC, t.start_km ASC';
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$trips = $stmt->fetchAll();
|
|
|
|
// Get vehicles for filter
|
|
$stmt = $pdo->query('SELECT id, spz, name FROM vehicles ORDER BY name');
|
|
$vehicles = $stmt->fetchAll();
|
|
|
|
// Get users for filter
|
|
$stmt = $pdo->query(
|
|
"SELECT id, CONCAT(first_name, ' ', last_name) as name FROM users WHERE is_active = 1 ORDER BY last_name"
|
|
);
|
|
$users = $stmt->fetchAll();
|
|
|
|
// Calculate totals
|
|
$totalDistance = 0;
|
|
$businessDistance = 0;
|
|
$privateDistance = 0;
|
|
|
|
foreach ($trips as $trip) {
|
|
$totalDistance += $trip['distance'];
|
|
if ($trip['is_business']) {
|
|
$businessDistance += $trip['distance'];
|
|
} else {
|
|
$privateDistance += $trip['distance'];
|
|
}
|
|
}
|
|
|
|
// Get selected vehicle/user names for header
|
|
$selectedVehicleName = '';
|
|
if ($vehicleId) {
|
|
$stmt = $pdo->prepare("SELECT CONCAT(spz, ' - ', name) as name FROM vehicles WHERE id = ?");
|
|
$stmt->execute([$vehicleId]);
|
|
$v = $stmt->fetch();
|
|
$selectedVehicleName = $v ? $v['name'] : '';
|
|
}
|
|
|
|
$selectedUserName = '';
|
|
if ($filterUserId) {
|
|
$stmt = $pdo->prepare("SELECT CONCAT(first_name, ' ', last_name) as name FROM users WHERE id = ?");
|
|
$stmt->execute([$filterUserId]);
|
|
$u = $stmt->fetch();
|
|
$selectedUserName = $u ? $u['name'] : '';
|
|
}
|
|
|
|
successResponse([
|
|
'trips' => $trips,
|
|
'vehicles' => $vehicles,
|
|
'users' => $users,
|
|
'date_from' => $startDate,
|
|
'date_to' => $endDate,
|
|
'period_name' => formatPeriodName($startDate, $endDate),
|
|
'selected_vehicle' => $vehicleId,
|
|
'selected_vehicle_name' => $selectedVehicleName,
|
|
'selected_user' => $filterUserId,
|
|
'selected_user_name' => $selectedUserName,
|
|
'totals' => [
|
|
'total' => $totalDistance,
|
|
'business' => $businessDistance,
|
|
'private' => $privateDistance,
|
|
'count' => count($trips),
|
|
],
|
|
]);
|
|
}
|