104 lines
4.8 KiB
PHP
104 lines
4.8 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
require_once __DIR__ . '/common.php';
|
||
|
||
api_require_method('PATCH', 'POST');
|
||
$staff = api_require_staff();
|
||
$body = api_request_body();
|
||
$number = trim((string) ($body['number'] ?? ''));
|
||
if ($number === '') {
|
||
api_error(422, 'TICKET_NUMBER_REQUIRED', 'Eine Ticketnummer ist erforderlich.');
|
||
}
|
||
$pdo = get_db();
|
||
$ticket = api_find_ticket($pdo, $staff, $number);
|
||
if ($ticket['source'] !== 'chat') {
|
||
$lockedByName = ticket_locked_by_other($ticket, (int) $staff['id'], $pdo);
|
||
if ($lockedByName) {
|
||
api_error(409, 'TICKET_LOCKED', "Dieses Ticket wird gerade von \"$lockedByName\" bearbeitet.");
|
||
}
|
||
}
|
||
$updates = [];
|
||
$params = [];
|
||
$now = db_now();
|
||
$chatJustClosed = false;
|
||
|
||
if (array_key_exists('status', $body) && $body['status'] !== $ticket['status']) {
|
||
$status = (string) $body['status'];
|
||
if (!in_array($status, MOBILE_API_STATUSES, true)) {
|
||
api_error(422, 'INVALID_STATUS', 'Der Status ist ungültig.');
|
||
}
|
||
api_require_permission($staff, in_array($status, ['resolved', 'closed'], true) ? 'close_ticket' : 'reply_ticket', (int) $ticket['department_id']);
|
||
$updates[] = 'status = ?';
|
||
$params[] = $status;
|
||
if ($status === 'resolved' && empty($ticket['resolved_at'])) {
|
||
$updates[] = 'resolved_at = ?';
|
||
$params[] = $now;
|
||
}
|
||
if ($status === 'closed' && empty($ticket['closed_at'])) {
|
||
$updates[] = 'closed_at = ?';
|
||
$params[] = $now;
|
||
}
|
||
// Live-Chat, der über die App geschlossen wird, bekommt denselben Chatverlauf-Mail-
|
||
// Versand wie über staff/live_chat.php (Aktion "end") – siehe unten nach dem UPDATE.
|
||
$chatJustClosed = $status === 'closed' && $ticket['source'] === 'chat';
|
||
}
|
||
|
||
if (array_key_exists('assignedStaffId', $body)) {
|
||
$assignedId = $body['assignedStaffId'] === null ? null : filter_var($body['assignedStaffId'], FILTER_VALIDATE_INT);
|
||
if ($assignedId === false) {
|
||
api_error(422, 'INVALID_ASSIGNEE', 'Die Mitarbeiter-ID ist ungültig.');
|
||
}
|
||
if ($assignedId !== null) {
|
||
$agentStmt = $pdo->prepare('SELECT COUNT(*) FROM staff WHERE id = ? AND is_active = 1');
|
||
$agentStmt->execute([$assignedId]);
|
||
if (!(bool) $agentStmt->fetchColumn()) {
|
||
api_error(422, 'INVALID_ASSIGNEE', 'Der ausgewählte Mitarbeiter ist nicht verfügbar.');
|
||
}
|
||
}
|
||
$currentId = $ticket['assigned_staff_id'] === null ? null : (int) $ticket['assigned_staff_id'];
|
||
if ($assignedId !== $currentId) {
|
||
api_require_permission($staff, 'assign_ticket', (int) $ticket['department_id']);
|
||
$updates[] = 'assigned_staff_id = ?';
|
||
$params[] = $assignedId;
|
||
}
|
||
}
|
||
|
||
if (!$updates) {
|
||
api_json(['ticket' => api_ticket_summary($ticket)]);
|
||
}
|
||
$updates[] = 'updated_at = ?';
|
||
$params[] = $now;
|
||
$params[] = $ticket['id'];
|
||
$pdo->prepare('UPDATE tickets SET ' . implode(', ', $updates) . ' WHERE id = ?')->execute($params);
|
||
if (array_key_exists('status', $body) && $body['status'] !== $ticket['status']) {
|
||
[$label] = status_label((string) $body['status']);
|
||
log_activity($pdo, (int) $ticket['id'], (int) $staff['id'], 'Status geändert: ' . $label . ' (Mobile App)');
|
||
}
|
||
if (array_key_exists('assignedStaffId', $body)) {
|
||
log_activity($pdo, (int) $ticket['id'], (int) $staff['id'], 'Zuweisung geändert (Mobile App)');
|
||
if ($assignedId !== null && $assignedId !== $currentId) fcm_notify_assignment($ticket, $assignedId, (int) $staff['id']); // Push auf die Android-App des neuen Bearbeiters
|
||
}
|
||
if ($chatJustClosed && $ticket['requester_email']) {
|
||
try {
|
||
$transcriptStmt = $pdo->prepare(
|
||
'SELECT tt.author_type AS authorType, tt.message, tt.created_at AS createdAt, s.name AS staff_name
|
||
FROM ticket_threads tt LEFT JOIN staff s ON s.id = tt.staff_id
|
||
WHERE tt.ticket_id = ? AND tt.is_internal_note = 0 ORDER BY tt.created_at ASC, tt.id ASC'
|
||
);
|
||
$transcriptStmt->execute([$ticket['id']]);
|
||
$transcriptMessages = array_map(fn(array $m) => [
|
||
'authorType' => $m['authorType'],
|
||
'authorName' => $m['staff_name'],
|
||
'message' => $m['message'],
|
||
'createdAt' => $m['createdAt'],
|
||
], $transcriptStmt->fetchAll());
|
||
notify_customer_chat_transcript($ticket, $transcriptMessages);
|
||
} catch (Throwable $e) {
|
||
error_log('ticket_update (Mobile App) transcript mail: ' . $e->getMessage());
|
||
}
|
||
}
|
||
$updated = api_find_ticket($pdo, $staff, $number);
|
||
if ($updated['status'] !== $ticket['status']) webhook_dispatch($pdo, 'ticket.status_changed', (int) $ticket['id'], ['previousStatus' => $ticket['status']]);
|
||
if ((int) ($updated['assigned_staff_id'] ?? 0) !== (int) ($ticket['assigned_staff_id'] ?? 0)) webhook_dispatch($pdo, 'ticket.assigned', (int) $ticket['id']);
|
||
api_json(['ticket' => api_ticket_summary($updated)]);
|