diff --git a/zeiterfassung/allefehlbuchungen.php b/zeiterfassung/allefehlbuchungen.php
index 48598c7..5a3f7d5 100644
--- a/zeiterfassung/allefehlbuchungen.php
+++ b/zeiterfassung/allefehlbuchungen.php
@@ -12,6 +12,10 @@ if (!isset($_SESSION['userid'])) {
$user_id = $_SESSION['userid'];
$user = check_user();
+if (!is_admin_user()) {
+ die("Keine Rechte fuer diese Ansicht.");
+}
+
?>
@@ -25,6 +29,13 @@ $user = check_user();
Zeitbuchungsfehler Auswertung
+
+
+
+
+
+
+
+
+
@@ -167,4 +195,4 @@ foreach($users AS $user){
-
\ No newline at end of file
+
diff --git a/zeiterfassung/closeEmployeeTimeErrors.php b/zeiterfassung/closeEmployeeTimeErrors.php
new file mode 100644
index 0000000..1350e2c
--- /dev/null
+++ b/zeiterfassung/closeEmployeeTimeErrors.php
@@ -0,0 +1,147 @@
+ 'danger',
+ 'message' => 'Es wurde kein gueltiger Mitarbeiter uebergeben.',
+ ];
+ header("Location: allefehlbuchungen.php");
+ exit;
+}
+
+if ($hoursToClose <= 0) {
+ $_SESSION['time_error_close_result'] = [
+ 'type' => 'danger',
+ 'message' => 'Bitte eine gueltige Stundenanzahl groesser als 0 angeben.',
+ ];
+ header("Location: allefehlbuchungen.php");
+ exit;
+}
+
+try {
+ $stmt = $pdo->prepare("SELECT id, vorname, nachname FROM users WHERE id = :employee_id LIMIT 1");
+ $stmt->bindValue(':employee_id', $employeeId, PDO::PARAM_INT);
+ $stmt->execute();
+ $employee = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$employee) {
+ throw new RuntimeException('Mitarbeiter wurde nicht gefunden.');
+ }
+
+ $stmt = $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
+ GROUP BY DATE(timestamp_datetime)
+ ORDER BY datum ASC"
+ );
+ $stmt->bindValue(':employee_id', $employeeId, PDO::PARAM_INT);
+ $stmt->execute();
+ $days = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+ $invalidDates = [];
+ foreach ($days as $day) {
+ if (!isValidSequence((string)$day['day_sequence'])) {
+ $invalidDates[] = (string)$day['datum'];
+ }
+ }
+
+ if (empty($invalidDates)) {
+ $_SESSION['time_error_close_result'] = [
+ 'type' => 'info',
+ 'message' => 'Es wurden keine offenen Fehlbuchungen fuer den Mitarbeiter gefunden.',
+ ];
+ header("Location: allefehlbuchungen.php");
+ exit;
+ }
+
+ $pdo->beginTransaction();
+
+ $insertedDates = [];
+ $skippedDates = [];
+ $secondsToClose = (int)round($hoursToClose * 3600);
+
+ $lastEntryStmt = $pdo->prepare(
+ "SELECT timestamp_type, timestamp_datetime
+ FROM timestamps
+ WHERE employee_id = :employee_id
+ AND DATE(timestamp_datetime) = :datum
+ ORDER BY timestamp_datetime DESC, timestamp_id DESC
+ LIMIT 1"
+ );
+
+ $insertStmt = $pdo->prepare(
+ "INSERT INTO timestamps (employee_id, timestamp_type, timestamp_datetime, timestamp_endpoint)
+ VALUES (:employee_id, 'GEHEN', :timestamp_datetime, 0)"
+ );
+
+ foreach ($invalidDates as $invalidDate) {
+ $lastEntryStmt->bindValue(':employee_id', $employeeId, PDO::PARAM_INT);
+ $lastEntryStmt->bindValue(':datum', $invalidDate);
+ $lastEntryStmt->execute();
+ $lastEntry = $lastEntryStmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$lastEntry || (string)$lastEntry['timestamp_type'] !== 'KOMMEN') {
+ $skippedDates[] = $invalidDate;
+ continue;
+ }
+
+ $closeTimestamp = (new DateTimeImmutable((string)$lastEntry['timestamp_datetime']))
+ ->modify('+' . $secondsToClose . ' seconds')
+ ->format('Y-m-d H:i:s');
+
+ $insertStmt->bindValue(':employee_id', $employeeId, PDO::PARAM_INT);
+ $insertStmt->bindValue(':timestamp_datetime', $closeTimestamp);
+ $insertStmt->execute();
+
+ $insertedDates[] = $invalidDate;
+ }
+
+ $pdo->commit();
+
+ $message = count($insertedDates) . ' Fehlbuchungstage fuer '
+ . $employee['vorname'] . ' ' . $employee['nachname']
+ . ' wurden mit ' . rtrim(rtrim(number_format($hoursToClose, 2, '.', ''), '0'), '.')
+ . ' Stunden geschlossen.';
+
+ if (!empty($skippedDates)) {
+ $message .= ' ' . count($skippedDates) . ' Tage konnten nicht automatisch geschlossen werden.';
+ }
+
+ $_SESSION['time_error_close_result'] = [
+ 'type' => !empty($insertedDates) ? 'success' : 'warning',
+ 'message' => $message,
+ ];
+} catch (Throwable $e) {
+ if ($pdo->inTransaction()) {
+ $pdo->rollBack();
+ }
+
+ $_SESSION['time_error_close_result'] = [
+ 'type' => 'danger',
+ 'message' => 'Automatisches Schliessen fehlgeschlagen: ' . $e->getMessage(),
+ ];
+}
+
+header("Location: allefehlbuchungen.php");
+exit;