date('Y-m-d H:i:s', time() - $h * 3600); $dept = (int) $pdo->query('SELECT id FROM departments ORDER BY id LIMIT 1')->fetchColumn(); $pdo->exec('UPDATE priorities SET response_hours = 4, resolution_hours = 48'); $prio = (int) $pdo->query('SELECT id FROM priorities ORDER BY id LIMIT 1')->fetchColumn(); $pdo->exec('DELETE FROM staff'); $ins = $pdo->prepare('INSERT INTO staff (name, email, password_hash, role, department_id, is_active, created_at) VALUES (?,?,?,?,?,1,?)'); $ins->execute(['Chef', 'chef@test.de', 'x', 'admin', $dept, $now]); $ins->execute(['Agent', 'agent@test.de', 'x', 'agent', $dept, $now]); $agent = (int) $pdo->lastInsertId(); $ins->execute(['Kollege', 'kollege@test.de', 'x', 'agent', $dept, $now]); $mk = function (string $n, string $status, array $o = []) use ($pdo, $dept, $prio, $now, $agent): int { $pdo->prepare('INSERT INTO tickets (ticket_number, subject, requester_name, requester_email, department_id, priority_id, status, source, assigned_staff_id, resolution_due_at, first_response_due_at, first_responded_at, resolved_at, is_overdue, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)') ->execute([$n, 'S ' . $n, 'K', 'k@example.org', $dept, $prio, $status, 'web', $agent, $o['due'] ?? null, $o['rdue'] ?? null, $o['first'] ?? null, $o['resolved'] ?? null, $o['overdue'] ?? 0, $o['created'] ?? $now, $now]); return (int) $pdo->lastInsertId(); }; $row = fn(int $id) => $pdo->query("SELECT * FROM tickets WHERE id = {$id}")->fetch(PDO::FETCH_ASSOC); // ── Wieder geöffnet: neue Frist ────────────────────────────────────────────── $old = $ago(100); $t = $mk('R-1', 'open', ['due' => $ago(50), 'rdue' => $ago(90), 'first' => $ago(95), 'resolved' => $ago(60), 'overdue' => 1, 'created' => $old]); ticket_sla_status_transition($pdo, $t, 'resolved', 'open'); $r = $row($t); $check($r['resolution_due_at'] > $now && $r['is_overdue'] == 0, 'gelöst → offen: neue Lösungsfrist in der Zukunft, nicht mehr überfällig: ' . json_encode([$r['resolution_due_at'], $r['is_overdue']])); $expected = strtotime($r['resolution_due_at']) - time(); $check($expected > 47 * 3600 && $expected < 49 * 3600, 'neue Frist = 48 Stunden der Priorität ab jetzt'); $h = $pdo->query("SELECT COUNT(*) FROM ticket_sla_history WHERE ticket_id = {$t} AND event_type = 'restarted'")->fetchColumn(); $check((int) $h === 1, 'im SLA-Verlauf steht „neu gestartet“'); $res = run_check_sla($pdo, false); $check($res['newlyOverdue'] === 0, 'der SLA-Job meldet für das wieder geöffnete Ticket nichts: ' . json_encode($res['newlyOverdue'])); $check((int) $row($t)['is_overdue'] === 0, 'Ticket bleibt nicht überfällig'); $t2 = $mk('R-2', 'open', ['due' => $ago(50), 'overdue' => 1, 'created' => $old]); ticket_sla_status_transition($pdo, $t2, 'closed', 'open'); $check($row($t2)['resolution_due_at'] > $now, 'geschlossen → offen: ebenfalls neue Frist'); $t3 = $mk('R-3', 'pending', ['due' => $ago(50), 'overdue' => 1, 'created' => $old]); ticket_sla_status_transition($pdo, $t3, 'resolved', 'pending'); $r3 = $row($t3); $check($r3['resolution_due_at'] > $now && $r3['sla_paused_at'] !== null, 'gelöst → wartet auf Kunde: neue Frist, die Uhr ist pausiert'); // Keine Änderung bei anderen Übergängen $due = $ago(30); $t4 = $mk('R-4', 'answered', ['due' => $due, 'created' => $old]); ticket_sla_status_transition($pdo, $t4, 'open', 'answered'); $check($row($t4)['resolution_due_at'] === $due, 'offen → beantwortet: Frist bleibt'); $t5 = $mk('R-5', 'closed', ['due' => $due, 'created' => $old]); ticket_sla_status_transition($pdo, $t5, 'resolved', 'closed'); $check($row($t5)['resolution_due_at'] === $due, 'gelöst → geschlossen: Frist bleibt'); $t6 = $mk('R-6', 'open', ['due' => $due, 'created' => $old]); ticket_sla_status_transition($pdo, $t6, 'open', 'open'); $check($row($t6)['resolution_due_at'] === $due, 'gleicher Status: nichts passiert'); $t7 = $mk('R-7', 'open', ['due' => $due, 'overdue' => 1, 'created' => $old]); $check(ticket_sla_restart($pdo, 999999) === null, 'unbekanntes Ticket: kein Fehler'); // ── Wer benachrichtigt wird ────────────────────────────────────────────────── $tk = ['assigned_staff_id' => $agent, 'department_id' => $dept]; $check(sla_notify_mode() === 'admins', 'Standard: nur Administratoren'); $rec = array_map('strtolower', sla_overdue_recipients($pdo, $tk)); $check($rec === ['chef@test.de'], 'Empfänger: nur der Administrator, nicht Bearbeiter oder Abteilung: ' . json_encode($rec)); set_setting('sla_notify_mode', 'assignee'); $rec = array_map('strtolower', sla_overdue_recipients($pdo, $tk)); $check($rec === ['agent@test.de'], 'Einstellung „Bearbeiter bzw. Abteilung“: der Bearbeiter: ' . json_encode($rec)); set_setting('sla_notify_mode', 'unsinn'); $check(sla_notify_mode() === 'admins', 'ungültige Einstellung fällt auf Administratoren zurück'); set_setting('sla_notify_mode', 'admins'); $check(sla_overdue_recipients($pdo, ['assigned_staff_id' => null, 'department_id' => $dept]) === ['chef@test.de'], 'auch ohne Bearbeiter: nur der Administrator'); fcm_notify_overdue(['ticket_number' => 'X', 'department_id' => $dept, 'assigned_staff_id' => $agent]); $check(true, 'Push im Administrator-Modus ohne Fehler übersprungen'); if ($failures) { fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n"); exit(1); } echo "SLA reopen and notify checks passed ({$total} Prüfungen).\n";