query('SELECT * FROM departments WHERE is_active = 1 ORDER BY name')->fetchAll(); $priorities = $pdo->query('SELECT * FROM priorities ORDER BY sort_order')->fetchAll(); $helpTopics = help_topic_options($pdo); $allAgents = $pdo->query('SELECT id, name FROM staff WHERE is_active = 1 ORDER BY name')->fetchAll(); $customFields = $pdo->query('SELECT * FROM custom_fields WHERE is_active = 1 AND department_id IS NULL ORDER BY sort_order, label')->fetchAll(); // Abteilungen auf zugängliche einschränken if ($myDeptIds !== null) { $departments = array_filter($departments, fn($d) => in_array((int) $d['id'], $myDeptIds, true)); } $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST') { verify_csrf(); $requesterName = trim($_POST['requester_name'] ?? ''); $requesterEmail = trim($_POST['requester_email'] ?? ''); $subject = trim($_POST['subject'] ?? ''); $message = sanitize_staff_html(trim($_POST['message'] ?? '')); $internalNote = sanitize_staff_html(trim($_POST['internal_note'] ?? '')); $source = in_array($_POST['source'] ?? '', ['phone','staff','web']) ? $_POST['source'] : 'phone'; $deptId = (int) ($_POST['department_id'] ?? ($departments[0]['id'] ?? 0)); $prioId = (int) ($_POST['priority_id'] ?? ($priorities[0]['id'] ?? 0)); $helpTopicId = ($_POST['help_topic_id'] ?? '') !== '' ? (int) $_POST['help_topic_id'] : null; $assignedId = ($_POST['assigned_staff_id'] ?? '') !== '' ? (int) $_POST['assigned_staff_id'] : null; if ($requesterName === '') $errors[] = 'Bitte Name des Anfragers angeben.'; if ($requesterEmail !== '' && !filter_var($requesterEmail, FILTER_VALIDATE_EMAIL)) { $errors[] = 'Bitte eine gültige E-Mail-Adresse angeben (oder das Feld leer lassen).'; } if ($subject === '') $errors[] = 'Bitte einen Betreff angeben.'; if (trim(strip_tags($message)) === '') $errors[] = 'Bitte eine Beschreibung eingeben.'; if (!$errors) { // Sperrliste prüfen (nur wenn E-Mail vorhanden) if ($requesterEmail !== '' && is_banned($requesterEmail)) { $errors[] = 'Diese E-Mail-Adresse steht auf der Sperrliste.'; } } if (!$errors) { // Ticket-Regeln anwenden $ruleResult = evaluate_ticket_rules($pdo, [ 'subject' => $subject, 'message' => strip_tags($message), 'requester_email' => $requesterEmail, 'requester_name' => $requesterName, 'source' => $source, ]); if ($ruleResult['set_department'] !== null) $deptId = $ruleResult['set_department']; if ($ruleResult['set_priority'] !== null) $prioId = $ruleResult['set_priority']; if ($ruleResult['set_help_topic'] !== null) $helpTopicId = $ruleResult['set_help_topic']; if ($ruleResult['assign_staff'] !== null && $assignedId === null) $assignedId = $ruleResult['assign_staff']; $prioStmt = $pdo->prepare('SELECT * FROM priorities WHERE id = ?'); $prioStmt->execute([$prioId]); $priority = $prioStmt->fetch(); $sla = calc_sla_dates($priority, null, (int) $deptId, $helpTopicId ? (int) $helpTopicId : null); $now = db_now(); $ticketNumber = generate_ticket_number($pdo); // Bekannten registrierten Kunden nachschlagen $userId = null; if ($requesterEmail !== '') { $userStmt = $pdo->prepare('SELECT id FROM users WHERE LOWER(email) = LOWER(?)'); $userStmt->execute([$requesterEmail]); $userId = $userStmt->fetchColumn() ?: null; } $pdo->prepare( 'INSERT INTO tickets (ticket_number, subject, user_id, requester_name, requester_email, department_id, help_topic_id, priority_id, status, source, assigned_staff_id, first_response_due_at, resolution_due_at, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)' )->execute([ $ticketNumber, $subject, $userId, $requesterName, $requesterEmail, $deptId, $helpTopicId, $prioId, 'open', $source, $assignedId, $sla['first_response_due_at'], $sla['resolution_due_at'], $now, $now, ]); $ticketId = (int) $pdo->lastInsertId(); // Erste Nachricht eintragen (öffentlich, vom Mitarbeiter im Namen des Kunden) $pdo->prepare( 'INSERT INTO ticket_threads (ticket_id, author_type, staff_id, message, is_internal_note, created_at) VALUES (?,?,?,?,0,?)' )->execute([$ticketId, 'staff', $staff['id'], $message, $now]); // Optionale interne Notiz if (trim(strip_tags($internalNote)) !== '') { $pdo->prepare( 'INSERT INTO ticket_threads (ticket_id, author_type, staff_id, message, is_internal_note, created_at) VALUES (?,?,?,?,1,?)' )->execute([$ticketId, 'staff', $staff['id'], $internalNote, $now]); } // Individuelle Felder if ($customFields) { $cfStmt = $pdo->prepare('INSERT INTO ticket_field_values (ticket_id, custom_field_id, value) VALUES (?,?,?)'); foreach ($customFields as $f) { $fn = 'custom_' . $f['id']; $val = $f['field_type'] === 'checkbox' ? (!empty($_POST[$fn]) ? '1' : '0') : trim($_POST[$fn] ?? ''); if ($val !== '' && $val !== '0') $cfStmt->execute([$ticketId, $f['id'], $val]); } } log_activity($pdo, $ticketId, $staff['id'], "Ticket durch Mitarbeiter erstellt (Quelle: {$source})"); webhook_dispatch($pdo, 'ticket.created', $ticketId); foreach ($ruleResult['add_tags'] as $tagName) apply_tag_to_ticket($pdo, $ticketId, $tagName); if ($ruleResult['matched_rules']) { log_activity($pdo, $ticketId, $staff['id'], 'Ticket-Regel: ' . implode(', ', $ruleResult['matched_rules'])); } // Eingangsbestätigung an Kunden (nur wenn E-Mail vorhanden und nicht interne Quelle) if ($requesterEmail !== '' && !empty($_POST['notify_customer'])) { $deptStmt = $pdo->prepare('SELECT name, email FROM departments WHERE id = ?'); $deptStmt->execute([$deptId]); $dept = $deptStmt->fetch(); notify_customer_ticket_created([ 'ticket_number' => $ticketNumber, 'subject' => $subject, 'requester_name' => $requesterName, 'requester_email' => $requesterEmail, 'department_id' => $deptId, 'department_name' => $dept['name'] ?? null, ]); } flash('success', "Ticket #{$ticketNumber} erfolgreich erstellt."); redirect('/staff/ticket_view.php?n=' . urlencode($ticketNumber)); } } // Ticket-Vorlagen: ?template=ID füllt das Formular vor $ticketTemplates = []; $activeTemplateId = 0; try { $ticketTemplates = ticket_templates_list($pdo); if ($_SERVER['REQUEST_METHOD'] !== 'POST' && (int) ($_GET['template'] ?? 0) > 0) { $tpl = ticket_template_get($pdo, (int) $_GET['template']); if ($tpl) { $activeTemplateId = (int) $tpl['id']; $_POST['subject'] = (string) $tpl['subject']; $_POST['message'] = nl2br(e((string) ($tpl['body'] ?? ''))); // der Editor erwartet HTML if ($tpl['department_id']) $_POST['department_id'] = (string) $tpl['department_id']; if ($tpl['help_topic_id']) $_POST['help_topic_id'] = (string) $tpl['help_topic_id']; if ($tpl['priority_id']) $_POST['priority_id'] = (string) $tpl['priority_id']; } } } catch (Throwable $e) { $ticketTemplates = []; } $pageTitle = 'Ticket erstellen'; $activePage = 'tickets'; require __DIR__ . '/_header.php'; ?>
Ticket im Namen eines Kunden anlegen – z.B. bei Telefonanrufen oder Vor-Ort-Anfragen.