0) { $stmt = $pdo->prepare('SELECT u.*, o.name AS org_name FROM users u LEFT JOIN organizations o ON o.id = u.organization_id WHERE u.id = ?'); $stmt->execute([$userId]); $customer = $stmt->fetch(); } elseif ($guestEmail !== '') { // Gast-Anfrager (kein Konto, nur über Tickets bekannt) – keine Zeile in "users", // daher hier aus den Ticket-Daten zusammengesetzt statt per user_id nachgeschlagen. $stmt = $pdo->prepare( "SELECT requester_email AS email, MAX(requester_name) AS name, MIN(created_at) AS created_at, NULL AS phone, NULL AS org_name FROM tickets WHERE requester_email = ? AND user_id IS NULL GROUP BY requester_email" ); $stmt->execute([$guestEmail]); $customer = $stmt->fetch(); $isGuest = (bool) $customer; } else { $customer = false; } if (!$customer) { flash('error', 'Kunde nicht gefunden.'); redirect('/staff/customers.php'); } $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST') { verify_csrf(); $action = $_POST['action'] ?? ''; // Notizen und Kontaktdaten hängen an einem echten Kundenkonto (users-Tabelle) – // für Gast-Anfrager ohne Konto gibt es das nicht, siehe Hinweis oben in der Seite. if ($isGuest && in_array($action, ['add_note', 'delete_note', 'save_customer'], true)) { flash('error', 'Für Gast-Anfrager ohne Konto nicht verfügbar.'); redirect('/staff/customer_profile.php?email=' . urlencode($guestEmail)); } if ($action === 'gdpr_export' || $action === 'gdpr_erase') { if ($staff['role'] !== 'admin' || !gdpr_tools_enabled()) { flash('error', 'Die Datenschutz-Werkzeuge sind nicht verfügbar (nur Administratoren, in den Einstellungen einzuschalten).'); redirect($isGuest ? '/staff/customer_profile.php?email=' . urlencode($guestEmail) : '/staff/customer_profile.php?id=' . $userId); } $ref = $isGuest ? ['email' => $guestEmail] : ['user_id' => $userId]; if ($action === 'gdpr_export') { $data = gdpr_customer_export($pdo, $ref); audit_log($staff['id'], 'Kundendaten exportiert (' . ($isGuest ? 'Gast ' . $guestEmail : 'Kunde #' . $userId) . ')'); header('Content-Type: application/json; charset=utf-8'); header('Content-Disposition: attachment; filename="kundendaten-' . ($isGuest ? 'gast' : $userId) . '-' . date('Ymd') . '.json"'); header('X-Content-Type-Options: nosniff'); echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE); exit; } if (trim((string) ($_POST['confirm_email'] ?? '')) !== (string) $customer['email']) { flash('error', 'Zur Bestätigung muss die E-Mail-Adresse des Kunden genau eingegeben werden.'); redirect($isGuest ? '/staff/customer_profile.php?email=' . urlencode($guestEmail) : '/staff/customer_profile.php?id=' . $userId); } $res = gdpr_customer_erase($pdo, $ref, !empty($_POST['force'])); if ($res['error']) { flash('error', $res['error']); redirect($isGuest ? '/staff/customer_profile.php?email=' . urlencode($guestEmail) : '/staff/customer_profile.php?id=' . $userId); } audit_log($staff['id'], 'Kundendaten gelöscht (' . ($isGuest ? 'Gast' : 'Kunde #' . $userId) . '): ' . $res['tickets'] . ' Ticket(s) anonymisiert, ' . $res['messages'] . ' Nachricht(en) und ' . $res['files'] . ' Datei(en) entfernt'); flash('success', 'Kundendaten gelöscht: ' . $res['tickets'] . ' Ticket(s) anonymisiert, ' . $res['messages'] . ' Nachricht(en) und ' . $res['files'] . ' Datei(en) entfernt.'); redirect('/staff/customers.php'); } if ($action === 'add_note') { $note = trim($_POST['note'] ?? ''); if ($note !== '') { $pdo->prepare('INSERT INTO customer_notes (user_id, staff_id, note, created_at) VALUES (?,?,?,?)') ->execute([$userId, $staff['id'], $note, db_now()]); flash('success', 'Notiz gespeichert.'); } redirect('/staff/customer_profile.php?id=' . $userId); } if ($action === 'delete_note') { $noteId = (int) ($_POST['note_id'] ?? 0); $pdo->prepare('DELETE FROM customer_notes WHERE id=? AND user_id=?')->execute([$noteId, $userId]); redirect('/staff/customer_profile.php?id=' . $userId); } if ($action === 'save_customer') { $name = trim($_POST['name'] ?? ''); $phone = trim($_POST['phone'] ?? ''); if ($name !== '') { $pdo->prepare('UPDATE users SET name=?, phone=? WHERE id=?')->execute([$name, $phone ?: null, $userId]); flash('success', 'Kundendaten gespeichert.'); } redirect('/staff/customer_profile.php?id=' . $userId); } } // Alle Tickets dieses Kunden (Mitarbeiter sehen nur Tickets ihrer Abteilungen) [$deptSql, $deptParams] = dept_filter_sql(staff_department_ids($staff), 't.department_id'); $ticketStmt = $pdo->prepare( "SELECT t.*, p.name AS priority_name, p.color AS priority_color, d.name AS department_name, s.name AS staff_name FROM tickets t JOIN priorities p ON p.id = t.priority_id JOIN departments d ON d.id = t.department_id LEFT JOIN staff s ON s.id = t.assigned_staff_id WHERE (t.requester_email = ? OR t.user_id = ?) {$deptSql} ORDER BY t.created_at DESC LIMIT 100" ); $ticketStmt->execute([$customer['email'], $userId, ...$deptParams]); $tickets = $ticketStmt->fetchAll(); // Notizen $noteStmt = $pdo->prepare( "SELECT cn.*, COALESCE(s.name, 'Gelöschter Mitarbeiter') AS staff_name FROM customer_notes cn LEFT JOIN staff s ON s.id = cn.staff_id WHERE cn.user_id = ? ORDER BY cn.created_at DESC" ); $noteStmt->execute([$userId]); $notes = $noteStmt->fetchAll(); // Statistiken $totalTickets = count($tickets); $openTickets = count(array_filter($tickets, fn($t) => !in_array($t['status'], ['resolved','closed']))); $closedTickets = count(array_filter($tickets, fn($t) => in_array($t['status'], ['resolved','closed']))); $pageTitle = 'Kundenprofil: ' . $customer['name']; $activePage = 'customers'; require __DIR__ . '/_header.php'; ?>

Gast

← Zurück
Gast-Anfrager ohne eigenes Kundenkonto – Notizen und Kontaktdaten-Bearbeitung sind daher nicht verfügbar.

Tickets ()

Keine Tickets vorhanden.
TicketBetreffStatusPrioritätMitarbeiterErstellt
#

Interne Notizen

Noch keine Notizen.

·
Gesamt
Offen
Gelöst
Seit
Kontaktdaten

Ohne Konto nicht bearbeitbar.

Datenschutz (DSGVO)

Auskunft: Stammdaten, alle Tickets mit Nachrichten und Anhangsnamen, Notizen. Die Datei bitte vor der Weitergabe prüfen.

Tickets bleiben als anonymisierte Einträge (Nummer, Betreff, Status, Zeiten). Nachrichten und Dateien des Kunden, Notizen und das Konto werden entfernt.