129 lines
6.1 KiB
PHP
129 lines
6.1 KiB
PHP
<?php
|
|
/** Problem records group related tickets and retain root-cause documentation. */
|
|
|
|
function ticket_resolution_reasons(): array
|
|
{
|
|
return [
|
|
'fixed' => 'Fehler behoben',
|
|
'guidance' => 'Anleitung oder Beratung',
|
|
'duplicate' => 'Doppelt / zusammengeführt',
|
|
'not_reproducible' => 'Nicht reproduzierbar',
|
|
'no_action' => 'Keine Maßnahme erforderlich',
|
|
'spam' => 'Spam oder Sperre',
|
|
'automated' => 'Automatisch geschlossen',
|
|
'other' => 'Sonstiges',
|
|
];
|
|
}
|
|
|
|
function ticket_problem_statuses(): array
|
|
{
|
|
return [
|
|
'investigating' => 'Wird untersucht',
|
|
'workaround' => 'Workaround verfügbar',
|
|
'monitoring' => 'Wird beobachtet',
|
|
'resolved' => 'Behoben',
|
|
];
|
|
}
|
|
|
|
function ticket_problem_number(int $id): string
|
|
{
|
|
return 'PRB-' . str_pad((string) $id, 6, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
function ticket_problems(PDO $pdo, bool $activeOnly = false): array
|
|
{
|
|
$where = $activeOnly ? "WHERE p.status <> 'resolved'" : '';
|
|
return $pdo->query("SELECT p.*, s.name AS creator_name, (SELECT COUNT(*) FROM problem_tickets pt WHERE pt.problem_id = p.id) AS ticket_count FROM problems p LEFT JOIN staff s ON s.id = p.created_by $where ORDER BY CASE WHEN p.status = 'resolved' THEN 1 ELSE 0 END, p.updated_at DESC, p.id DESC LIMIT 300")->fetchAll();
|
|
}
|
|
|
|
function ticket_problem_get(PDO $pdo, int $id): ?array
|
|
{
|
|
$stmt = $pdo->prepare('SELECT p.*, s.name AS creator_name FROM problems p LEFT JOIN staff s ON s.id = p.created_by WHERE p.id = ?');
|
|
$stmt->execute([$id]);
|
|
return $stmt->fetch() ?: null;
|
|
}
|
|
|
|
function ticket_problem_create(PDO $pdo, array $input, int $staffId): int
|
|
{
|
|
$title = trim(mb_substr((string) ($input['title'] ?? ''), 0, 200));
|
|
if ($title === '') throw new InvalidArgumentException('Bitte einen Titel für das Problem angeben.');
|
|
$status = (string) ($input['status'] ?? 'investigating');
|
|
if (!isset(ticket_problem_statuses()[$status])) $status = 'investigating';
|
|
$resolution = trim((string) ($input['resolution'] ?? ''));
|
|
if ($status === 'resolved' && $resolution === '') throw new InvalidArgumentException('Bitte dokumentieren Sie die dauerhafte Lösung, bevor Sie das Problem als behoben markieren.');
|
|
$now = db_now();
|
|
$stmt = $pdo->prepare('INSERT INTO problems (title, description, root_cause, workaround, resolution, status, created_by, updated_by, created_at, updated_at, resolved_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
|
|
$stmt->execute([
|
|
$title,
|
|
trim((string) ($input['description'] ?? '')) ?: null,
|
|
trim((string) ($input['root_cause'] ?? '')) ?: null,
|
|
trim((string) ($input['workaround'] ?? '')) ?: null,
|
|
$resolution ?: null,
|
|
$status, $staffId, $staffId, $now, $now, $status === 'resolved' ? $now : null,
|
|
]);
|
|
return (int) $pdo->lastInsertId();
|
|
}
|
|
|
|
function ticket_problem_update(PDO $pdo, int $id, array $input, int $staffId): bool
|
|
{
|
|
$title = trim(mb_substr((string) ($input['title'] ?? ''), 0, 200));
|
|
$status = (string) ($input['status'] ?? 'investigating');
|
|
if ($title === '') throw new InvalidArgumentException('Bitte einen Titel für das Problem angeben.');
|
|
if (!isset(ticket_problem_statuses()[$status])) throw new InvalidArgumentException('Der Problemstatus ist ungültig.');
|
|
$resolution = trim((string) ($input['resolution'] ?? ''));
|
|
if ($status === 'resolved' && $resolution === '') throw new InvalidArgumentException('Bitte dokumentieren Sie die dauerhafte Lösung, bevor Sie das Problem als behoben markieren.');
|
|
$current = ticket_problem_get($pdo, $id);
|
|
if (!$current) return false;
|
|
$resolvedAt = $status === 'resolved' ? ($current['resolved_at'] ?: db_now()) : null;
|
|
$stmt = $pdo->prepare('UPDATE problems SET title = ?, description = ?, root_cause = ?, workaround = ?, resolution = ?, status = ?, updated_by = ?, updated_at = ?, resolved_at = ? WHERE id = ?');
|
|
$stmt->execute([
|
|
$title,
|
|
trim((string) ($input['description'] ?? '')) ?: null,
|
|
trim((string) ($input['root_cause'] ?? '')) ?: null,
|
|
trim((string) ($input['workaround'] ?? '')) ?: null,
|
|
$resolution ?: null,
|
|
$status, $staffId, db_now(), $resolvedAt, $id,
|
|
]);
|
|
return true;
|
|
}
|
|
|
|
function ticket_problem_tickets(PDO $pdo, int $problemId): array
|
|
{
|
|
$stmt = $pdo->prepare('SELECT t.id, t.ticket_number, t.subject, t.status, t.requester_name, t.created_at, s.name AS linked_by_name FROM problem_tickets pt JOIN tickets t ON t.id = pt.ticket_id LEFT JOIN staff s ON s.id = pt.linked_by WHERE pt.problem_id = ? ORDER BY pt.linked_at DESC, t.id DESC');
|
|
$stmt->execute([$problemId]);
|
|
return $stmt->fetchAll();
|
|
}
|
|
|
|
function ticket_problem_link(PDO $pdo, int $problemId, int $ticketId, int $staffId): bool
|
|
{
|
|
if (!ticket_problem_get($pdo, $problemId)) return false;
|
|
$ticket = $pdo->prepare('SELECT id FROM tickets WHERE id = ?');
|
|
$ticket->execute([$ticketId]);
|
|
if (!$ticket->fetchColumn()) return false;
|
|
$insertIgnore = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) === 'sqlite' ? 'INSERT OR IGNORE' : 'INSERT IGNORE';
|
|
$stmt = $pdo->prepare("$insertIgnore INTO problem_tickets (problem_id, ticket_id, linked_by, linked_at) VALUES (?,?,?,?)");
|
|
$stmt->execute([$problemId, $ticketId, $staffId, db_now()]);
|
|
return true;
|
|
}
|
|
|
|
function ticket_problem_unlink(PDO $pdo, int $problemId, int $ticketId): void
|
|
{
|
|
$pdo->prepare('DELETE FROM problem_tickets WHERE problem_id = ? AND ticket_id = ?')->execute([$problemId, $ticketId]);
|
|
}
|
|
|
|
function ticket_problems_for_ticket(PDO $pdo, int $ticketId): array
|
|
{
|
|
$stmt = $pdo->prepare('SELECT p.* FROM problems p JOIN problem_tickets pt ON pt.problem_id = p.id WHERE pt.ticket_id = ? ORDER BY p.updated_at DESC, p.id DESC');
|
|
$stmt->execute([$ticketId]);
|
|
return $stmt->fetchAll();
|
|
}
|
|
|
|
function ticket_record_resolution(PDO $pdo, int $ticketId, string $reason, string $note = ''): bool
|
|
{
|
|
if (!isset(ticket_resolution_reasons()[$reason])) return false;
|
|
$pdo->prepare('UPDATE tickets SET resolution_code = ?, resolution_note = ? WHERE id = ?')
|
|
->execute([$reason, trim(mb_substr($note, 0, 2000)) ?: null, $ticketId]);
|
|
return true;
|
|
}
|
|
|