'start and end required']); exit; } $events = []; try { $branch = 'unknown'; $debugMode = isset($_GET['debug']) && ($_GET['debug'] == '1' || $_GET['debug'] === 'true'); // Vacations: support a personal-only mode, admin mode, and public/team mode if ($onlyPersonal) { $branch = 'onlyPersonal'; if ($onlyApproved) { $branch = 'onlyPersonal_onlyApproved'; $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date"); $stmt->execute([$_SESSION['userid'], $end, $start]); } else { if ($includeRejected) { $branch = 'onlyPersonal_includeRejected'; $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date"); $stmt->execute([$_SESSION['userid'], $end, $start]); } else { $branch = 'onlyPersonal_excludeRejected'; $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date"); $stmt->execute([$_SESSION['userid'], $end, $start]); } } } elseif ($isAdmin) { $branch = 'admin'; if ($onlyApproved) { $branch = 'admin_onlyApproved'; $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date"); $stmt->execute([$end, $start]); } else { // By default admins see genehmigt + beantragt; include_rejected=1 can override if ($includeRejected) { $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date"); $stmt->execute([$end, $start]); } else { $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date"); $stmt->execute([$end, $start]); } } } else { $branch = 'public_or_regular'; if ($public && $onlyApproved) { $branch = 'public_onlyApproved'; // public team view: show all approved vacations (read-only) $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date"); $stmt->execute([$end, $start]); } elseif ($public && $publicAll) { $branch = 'public_publicAll'; // public team view: explicitly show only approved (genehmigt) and pending (beantragt) vacations $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date"); $stmt->execute([$end, $start]); } else { if ($onlyApproved) { $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date"); $stmt->execute([$_SESSION['userid'], $end, $start]); } else { // By default exclude rejected ('abgelehnt') for regular users; include if include_rejected=1 if ($includeRejected) { $branch = 'regular_includeRejected'; $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date"); $stmt->execute([$_SESSION['userid'], $end, $start]); } else { $branch = 'regular_excludeRejected'; $stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date"); $stmt->execute([$_SESSION['userid'], $end, $start]); } } } } try { $vacations = $stmt->fetchAll(); // If debug mode is enabled, prepare meta information if ($debugMode) { $rawStatuses = array_map(function($r){ return $r['status'] ?? null; }, $vacations); $meta = [ 'branch' => $branch, 'count' => count($vacations), 'raw_statuses' => $rawStatuses ]; } foreach ($vacations as $v) { // Normalize status: collapse whitespace (including NBSP), trim, lowercase if (isset($v['status'])) { $normalized = preg_replace('/\s+/u', ' ', $v['status']); $status = mb_strtolower(trim($normalized)); } else { $status = ''; } // Defensive filter: do not expose rejected ('abgelehnt') entries to non-admins if (!$isAdmin && !$includeRejected && mb_stripos($status, 'abgelehnt') !== false) { continue; } $isApproved = (mb_stripos($status, 'genehmigt') !== false); if ($isAdmin) { $title = $v['vorname'] . ' ' . $v['nachname'] . ' (' . ($v['status'] ?? 'beantragt') . ')'; } else { $title = $isApproved ? 'Urlaub' : 'Urlaubsantrag'; } // Safely compute end date; fallback to start_date if invalid try { $endInclusive = (new DateTime($v['end_date']))->modify('+1 day')->format('Y-m-d'); } catch (Exception $e) { $endInclusive = $v['start_date']; } $events[] = [ 'id' => 'vac_' . $v['id'], 'title' => $title, 'start' => $v['start_date'], 'end' => $endInclusive, 'allDay' => true, 'color' => ($isApproved) ? '#28a745' : '#ffc107', 'extendedProps' => [ 'type' => 'user', 'user_id' => $v['user_id'], 'status' => $v['status'], 'comment' => $v['comment_user'] ?? '' ] ]; } } catch (Exception $ex) { header('Content-Type: application/json; charset=utf-8'); $payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()]; echo json_encode($payload); exit; } } catch (Exception $ex) { header('Content-Type: application/json; charset=utf-8'); $payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()]; echo json_encode($payload); exit; } // Company holidays (visible to all) $stmt = $pdo->prepare("SELECT * FROM company_holidays WHERE start_date <= ? AND end_date >= ? ORDER BY start_date"); $stmt->execute([$end, $start]); $holidays = $stmt->fetchAll(); foreach ($holidays as $h) { $endInclusive = (new DateTime($h['end_date']))->modify('+1 day')->format('Y-m-d'); $events[] = [ 'id' => 'com_' . $h['id'], 'title' => $h['description'] ?: 'Betriebsurlaub', 'start' => $h['start_date'], 'end' => $endInclusive, 'allDay' => true, 'color' => '#007bff', 'extendedProps' => [ 'type' => 'company', 'description' => $h['description'] ] ]; } header('Content-Type: application/json; charset=utf-8'); if ($debugMode) { echo json_encode(['events' => $events, 'meta' => $meta]); } else { echo json_encode($events); } ?>