prepare(" SELECT DISTINCT u.id, u.vorname, u.nachname FROM users u INNER JOIN timestamps t ON t.employee_id = u.id WHERE u.zeiterfassung = '1' AND MONTH(t.timestamp_datetime) = :month AND YEAR(t.timestamp_datetime) = :year ORDER BY u.nachname ASC, u.vorname ASC "); $usersStmt->bindValue(':month', (int)$selectedMonth, PDO::PARAM_INT); $usersStmt->bindValue(':year', (int)$selectedYear, PDO::PARAM_INT); $usersStmt->execute(); $employees = $usersStmt->fetchAll(PDO::FETCH_ASSOC); $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); $pdf->SetCreator(PDF_CREATOR); $pdf->SetAuthor($currentUser['vorname'] . ' ' . $currentUser['nachname']); $pdf->SetTitle('Arbeitszeiten aller Mitarbeiter'); $pdf->SetSubject('Arbeitszeiten aller Mitarbeiter fuer ' . $selectedMonth . '/' . $selectedYear); $stempdate = $selectedYear . "-" . $selectedMonth . "-1"; $date = new DateTime($stempdate); $formatter = new IntlDateFormatter( "de-DE", IntlDateFormatter::LONG, IntlDateFormatter::NONE, "Europe/Berlin", IntlDateFormatter::GREGORIAN, "MMMM" ); $monthName = $formatter->format($date); $sequenceStmt = $pdo->prepare(" SELECT DATE(timestamp_datetime) AS datum, GROUP_CONCAT(timestamp_type ORDER BY timestamp_datetime) AS day_sequence FROM timestamps WHERE employee_id = :employee_id AND MONTH(timestamp_datetime) = :selectedMonth AND YEAR(timestamp_datetime) = :selectedYear GROUP BY DATE(timestamp_datetime) "); $timesStmt = $pdo->prepare(" SELECT DATE(timestamp_datetime) AS day, MIN(CASE WHEN timestamp_type = 'KOMMEN' THEN timestamp_datetime END) AS first_come, MAX(CASE WHEN timestamp_type = 'GEHEN' THEN timestamp_datetime END) AS last_go, SEC_TO_TIME(SUM( CASE WHEN timestamp_type = 'GEHEN' THEN UNIX_TIMESTAMP(timestamp_datetime) WHEN timestamp_type = 'KOMMEN' THEN -UNIX_TIMESTAMP(timestamp_datetime) ELSE 0 END )) AS total_time, SEC_TO_TIME( TIME_TO_SEC( SEC_TO_TIME( UNIX_TIMESTAMP(MAX(CASE WHEN timestamp_type = 'GEHEN' THEN timestamp_datetime END)) - UNIX_TIMESTAMP(MIN(CASE WHEN timestamp_type = 'KOMMEN' THEN timestamp_datetime END)) ) ) - TIME_TO_SEC(SEC_TO_TIME(SUM( CASE WHEN timestamp_type = 'GEHEN' THEN UNIX_TIMESTAMP(timestamp_datetime) WHEN timestamp_type = 'KOMMEN' THEN -UNIX_TIMESTAMP(timestamp_datetime) ELSE 0 END ))) ) AS difference_between_total_time_and_pause_time FROM timestamps WHERE employee_id = :employee_id AND MONTH(timestamp_datetime) = :month AND YEAR(timestamp_datetime) = :year GROUP BY DATE(timestamp_datetime) "); foreach ($employees as $employee) { $employeeId = (int)$employee['id']; $employeeName = trim($employee['vorname'] . ' ' . $employee['nachname']); $sequenceStmt->bindValue(':employee_id', $employeeId, PDO::PARAM_INT); $sequenceStmt->bindValue(':selectedMonth', (int)$selectedMonth, PDO::PARAM_INT); $sequenceStmt->bindValue(':selectedYear', (int)$selectedYear, PDO::PARAM_INT); $sequenceStmt->execute(); $sequenceRows = $sequenceStmt->fetchAll(PDO::FETCH_ASSOC); $fehlerhafteTage = []; foreach ($sequenceRows as $row) { if (!isValidSequence((string)$row['day_sequence'])) { $fehlerhafteTage[] = (string)$row['datum']; } } $pdf->AddPage(); $html = '

Arbeitszeiten - ' . $firmaName . '

'; $html .= '

Mitarbeiter: ' . htmlspecialchars($employeeName, ENT_QUOTES, 'UTF-8') . '

'; $html .= '

Monat: ' . htmlspecialchars((string)$monthName, ENT_QUOTES, 'UTF-8') . ' ' . htmlspecialchars((string)$selectedYear, ENT_QUOTES, 'UTF-8') . '

'; if (!empty($fehlerhafteTage)) { $html .= '

Fehlzeiten erkannt. Bitte erst beheben.

'; $html .= '

Betroffene Tage: ' . htmlspecialchars(implode(', ', array_map(static function (string $day): string { return date('d.m.Y', strtotime($day)); }, $fehlerhafteTage)), ENT_QUOTES, 'UTF-8') . '

'; $pdf->writeHTML($html, true, false, true, false, ''); continue; } $timesStmt->bindValue(':employee_id', $employeeId, PDO::PARAM_INT); $timesStmt->bindValue(':month', (int)$selectedMonth, PDO::PARAM_INT); $timesStmt->bindValue(':year', (int)$selectedYear, PDO::PARAM_INT); $timesStmt->execute(); $timesData = []; while ($row = $timesStmt->fetch(PDO::FETCH_ASSOC)) { $day = date('d', strtotime($row['day'])); $timesData[$day] = $row; } $html .= ''; $html .= ''; $totalSeconds = 0; for ($day = 1; $day <= 31; $day++) { $daytwo = str_pad((string)$day, 2, '0', STR_PAD_LEFT); if (isset($timesData[$daytwo])) { $row = $timesData[$daytwo]; $html .= ''; if (!empty($row['total_time'])) { [$hours, $minutes, $seconds] = explode(':', $row['total_time']); $totalSeconds += ((int)$hours * 3600) + ((int)$minutes * 60) + (int)$seconds; } } else { $html .= ''; } } $hours = floor($totalSeconds / 3600); $mins = floor(($totalSeconds / 60) % 60); $secs = floor($totalSeconds % 60); $totalTime = sprintf('%02d:%02d:%02d', $hours, $mins, $secs); $html .= ''; $html .= '
TagStartPauseEndeGesamtzeitaufgezeichnet am:Bemerkung
' . $day . '' . date('H:i:s', strtotime($row['first_come'])) . '' . $row['difference_between_total_time_and_pause_time'] . '' . date('H:i:s', strtotime($row['last_go'])) . '' . $row['total_time'] . '' . date('d.m.Y', strtotime($row['day'])) . '
' . $day . '
Gesamt' . $totalTime . '
'; $pdf->writeHTML($html, true, false, true, false, ''); } $pdf->Output('Arbeitszeiten_alle_' . $selectedYear . '_' . str_pad((string)$selectedMonth, 2, '0', STR_PAD_LEFT) . '.pdf', 'I'); } catch (PDOException $e) { echo "Datenbankfehler: " . $e->getMessage(); } ?>