Files
deskhub/DeskHub-Webseite/tests/sla_reopen_notify.php
T
2026-11-05 21:21:59 +00:00

98 lines
6.3 KiB
PHP

<?php
declare(strict_types=1);
/**
* Prüft zwei Dinge rund um „SLA überschritten“: (1) ein wieder geöffnetes (zuvor gelöstes) Ticket bekommt eine neue Frist und löst nicht sofort
* eine Überschreitung aus, (2) die Benachrichtigung geht standardmäßig nur per E-Mail an die Administratoren (Einstellung „Bearbeiter bzw. Abteilung“ bleibt möglich).
*/
putenv('DESKHUB_TESTING=1');
putenv('DESKHUB_SQLITE_PATH=:memory:');
require_once dirname(__DIR__) . '/includes/bootstrap.php';
if (!defined('DESKHUB_CRON_RUNNER')) define('DESKHUB_CRON_RUNNER', true);
require_once dirname(__DIR__) . '/cron/check_sla.php';
$failures = [];
$total = 0;
$check = function (bool $ok, string $what) use (&$failures, &$total): void {
$total++;
if (!$ok) $failures[] = $what;
};
$pdo = get_db();
$now = date('Y-m-d H:i:s');
$ago = fn(int $h) => 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";