92 lines
4.7 KiB
PHP
92 lines
4.7 KiB
PHP
<?php
|
|
/**
|
|
* Verknüpfte Tickets: beliebige Tickets lassen sich miteinander verbinden (verwandt, doppelt, blockiert), unabhängig von den
|
|
* „Problemen“ (includes/problems.php). Eine Verknüpfung wird einmal gespeichert (ticket_id → linked_ticket_id) und von beiden
|
|
* Tickets aus angezeigt, mit der jeweils passenden Bezeichnung.
|
|
*/
|
|
|
|
/** @return array<string,array{0:string,1:string}> Art => [Bezeichnung vom Quell-Ticket aus, Bezeichnung vom Ziel-Ticket aus] */
|
|
function ticket_link_types(): array
|
|
{
|
|
return [
|
|
'related' => ['Verwandt mit', 'Verwandt mit'],
|
|
'duplicate' => ['Doppelt zu', 'Hat Duplikat'],
|
|
'blocks' => ['Blockiert', 'Blockiert durch'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Verknüpft zwei Tickets. Gibt eine Fehlermeldung zurück oder null bei Erfolg.
|
|
* Der Mitarbeiter muss beide Tickets sehen dürfen ($deptScope: Abteilungs-IDs des Mitarbeiters, null = alle).
|
|
*/
|
|
function ticket_link_add(PDO $pdo, int $ticketId, string $targetNumber, string $type, int $staffId, ?array $deptScope = null): ?string
|
|
{
|
|
if (!isset(ticket_link_types()[$type])) return 'Ungültige Art der Verknüpfung.';
|
|
$targetNumber = ltrim(trim($targetNumber), '#');
|
|
if ($targetNumber === '') return 'Bitte eine Ticketnummer angeben.';
|
|
$stmt = $pdo->prepare('SELECT id, department_id FROM tickets WHERE ticket_number = ?');
|
|
$stmt->execute([$targetNumber]);
|
|
$target = $stmt->fetch();
|
|
if (!$target) return 'Ticket #' . $targetNumber . ' wurde nicht gefunden.';
|
|
$targetId = (int) $target['id'];
|
|
if ($targetId === $ticketId) return 'Ein Ticket lässt sich nicht mit sich selbst verknüpfen.';
|
|
if ($deptScope !== null && !in_array((int) $target['department_id'], array_map('intval', $deptScope), true)) {
|
|
return 'Ticket #' . $targetNumber . ' gehört zu einer Abteilung, auf die Sie keinen Zugriff haben.';
|
|
}
|
|
$exists = $pdo->prepare('SELECT 1 FROM ticket_links WHERE (ticket_id = ? AND linked_ticket_id = ?) OR (ticket_id = ? AND linked_ticket_id = ?)');
|
|
$exists->execute([$ticketId, $targetId, $targetId, $ticketId]);
|
|
if ($exists->fetchColumn()) return 'Die beiden Tickets sind bereits verknüpft.';
|
|
$pdo->prepare('INSERT INTO ticket_links (ticket_id, linked_ticket_id, link_type, created_by, created_at) VALUES (?,?,?,?,?)')
|
|
->execute([$ticketId, $targetId, $type, $staffId > 0 ? $staffId : null, db_now()]);
|
|
return null;
|
|
}
|
|
|
|
/** Entfernt eine Verknüpfung, sofern sie zu diesem Ticket gehört. */
|
|
function ticket_link_remove(PDO $pdo, int $linkId, int $ticketId): bool
|
|
{
|
|
$stmt = $pdo->prepare('DELETE FROM ticket_links WHERE id = ? AND (ticket_id = ? OR linked_ticket_id = ?)');
|
|
$stmt->execute([$linkId, $ticketId, $ticketId]);
|
|
return $stmt->rowCount() > 0;
|
|
}
|
|
|
|
/**
|
|
* Alle Verknüpfungen eines Tickets aus dessen Sicht. Tickets aus Abteilungen, die der Mitarbeiter nicht sehen darf, bleiben weg.
|
|
* @return list<array{id:int,type:string,label:string,number:string,subject:string,status:string}>
|
|
*/
|
|
function ticket_links_for(PDO $pdo, int $ticketId, ?array $deptScope = null): array
|
|
{
|
|
$stmt = $pdo->prepare(
|
|
'SELECT l.id, l.ticket_id, l.linked_ticket_id, l.link_type, t.ticket_number, t.subject, t.status, t.department_id
|
|
FROM ticket_links l
|
|
JOIN tickets t ON t.id = CASE WHEN l.ticket_id = ? THEN l.linked_ticket_id ELSE l.ticket_id END
|
|
WHERE l.ticket_id = ? OR l.linked_ticket_id = ?
|
|
ORDER BY l.id'
|
|
);
|
|
$stmt->execute([$ticketId, $ticketId, $ticketId]);
|
|
$types = ticket_link_types();
|
|
$scope = $deptScope === null ? null : array_map('intval', $deptScope);
|
|
$out = [];
|
|
foreach ($stmt->fetchAll() as $row) {
|
|
if ($scope !== null && !in_array((int) $row['department_id'], $scope, true)) continue;
|
|
$outgoing = (int) $row['ticket_id'] === $ticketId;
|
|
$labels = $types[$row['link_type']] ?? ['Verknüpft mit', 'Verknüpft mit'];
|
|
$out[] = [
|
|
'id' => (int) $row['id'], 'type' => (string) $row['link_type'], 'label' => $outgoing ? $labels[0] : $labels[1],
|
|
'number' => (string) $row['ticket_number'], 'subject' => (string) $row['subject'], 'status' => (string) $row['status'],
|
|
];
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/** Offene Tickets, die dieses Ticket blockieren (Hinweis vor dem Schließen). */
|
|
function ticket_open_blockers(PDO $pdo, int $ticketId): array
|
|
{
|
|
return array_values(array_filter(ticket_links_for($pdo, $ticketId), fn($l) => $l['type'] === 'blocks' && $l['label'] === 'Blockiert durch' && !in_array($l['status'], ['resolved', 'closed'], true)));
|
|
}
|
|
|
|
/** Beim Löschen eines Tickets die Verknüpfungen mit entfernen. */
|
|
function ticket_links_purge(PDO $pdo, int $ticketId): void
|
|
{
|
|
$pdo->prepare('DELETE FROM ticket_links WHERE ticket_id = ? OR linked_ticket_id = ?')->execute([$ticketId, $ticketId]);
|
|
}
|