Upload via GUI (360 Dateien)

This commit is contained in:
2026-10-30 21:49:58 +00:00
parent aed0db39ba
commit 91ae4659b5
10 changed files with 711 additions and 9 deletions
+62 -1
View File
@@ -608,6 +608,18 @@ function staff_can_access_department(array $staff, int $departmentId): bool
return $ids === null || in_array($departmentId, $ids, true);
}
/** Ist der Mitarbeiter gerade abwesend (Urlaubsmodus)? Im Urlaub gibt es keine Benachrichtigungen (Mail, Push, Android). */
function staff_is_on_vacation(int $staffId): bool
{
try {
$q = get_db()->prepare('SELECT is_on_vacation FROM staff WHERE id = ?');
$q->execute([$staffId]);
return (int) $q->fetchColumn() === 1;
} catch (Throwable $e) {
return false;
}
}
function staff_department_ids(array $staff): ?array
{
if ($staff['role'] === 'admin') {
@@ -622,9 +634,56 @@ function staff_department_ids(array $staff): ?array
foreach ($stmt->fetchAll() as $row) {
$ids[] = (int) $row['department_id'];
}
foreach (staff_substitution_department_ids($staff) as $d) $ids[] = $d;
return array_values(array_unique($ids));
}
/**
* Abteilungen, auf die ein Mitarbeiter nur als Vertretung Zugriff hat: Ist ein Kollege im Urlaub (Profil → Abwesenheit oder Plugin
* „Urlaub und Vertretung“) und hat diesen Mitarbeiter als Vertretung eingetragen, gelten dessen Abteilungen (Haupt- und zusätzliche) mit,
* solange die Abwesenheit dauert. Ketten (A vertritt B, B ist selbst im Urlaub und von C vertreten) folgen bis zu drei Stufen.
* Ist der Abwesende Administrator (sieht alle Abteilungen), kommen nur die Abteilungen der Tickets dazu, die der Vertretung gerade
* zugewiesen sind. Ohne die Spalten (Datenbank noch nicht aktualisiert) ergibt sich eine leere Liste.
* @return list<int>
*/
function staff_substitution_department_ids(array $staff): array
{
if (($staff['role'] ?? '') === 'admin' || empty($staff['id'])) return [];
$pdo = get_db();
$out = [];
try {
$frontier = [(int) $staff['id']];
$seen = $frontier;
for ($level = 0; $level < 3 && $frontier; $level++) {
$in = implode(',', array_fill(0, count($frontier), '?'));
$q = $pdo->prepare("SELECT id, role, department_id FROM staff WHERE is_active = 1 AND is_on_vacation = 1 AND vacation_substitute_id IN ($in)");
$q->execute($frontier);
$next = [];
$adminAbsent = false;
foreach ($q->fetchAll() as $abs) {
$aid = (int) $abs['id'];
if (in_array($aid, $seen, true)) continue;
$seen[] = $aid;
$next[] = $aid;
if ($abs['role'] === 'admin') { $adminAbsent = true; continue; }
if (!empty($abs['department_id'])) $out[] = (int) $abs['department_id'];
$d = $pdo->prepare('SELECT department_id FROM staff_department WHERE staff_id = ?');
$d->execute([$aid]);
foreach ($d->fetchAll(PDO::FETCH_COLUMN) as $did) $out[] = (int) $did;
}
if ($adminAbsent) {
$t = $pdo->prepare("SELECT DISTINCT department_id FROM tickets WHERE assigned_staff_id = ? AND status NOT IN ('resolved','closed')");
$t->execute([(int) $staff['id']]);
foreach ($t->fetchAll(PDO::FETCH_COLUMN) as $did) $out[] = (int) $did;
}
$frontier = $next;
}
} catch (Throwable $e) {
return [];
}
return array_values(array_unique(array_filter($out)));
}
/**
* Beim Öffnen eines noch niemandem zugewiesenen Tickets wird es dem öffnenden Mitarbeiter zugewiesen (Einstellung "Beim Öffnen
* automatisch zuweisen", Standard an). Nicht bei geschlossenen, gelösten, zusammengeführten oder als Spam markierten Tickets und nicht,
@@ -2162,8 +2221,10 @@ function save_mentions(PDO $pdo, int $ticketId, int $threadId, int $byStaffId, s
->execute([$ticketId, $threadId, $mentionedId, $byStaffId, db_now()]);
fcm_notify_mention($ticket, $mentionedId, $byStaffId); // Push auf die Android-App
// E-Mail an erwähnten Mitarbeiter
// Im Urlaub geht die Mail an die Vertretung
$mailTo = vacation_expand_ids($pdo, [$mentionedId]);
$stmt = $pdo->prepare('SELECT email, name FROM staff WHERE id=?');
$stmt->execute([$mentionedId]);
$stmt->execute([$mailTo ? $mailTo[0] : 0]);
$mentioned = $stmt->fetch();
if ($mentioned) {
$by = $pdo->prepare('SELECT name FROM staff WHERE id=?');