'Betreff', 'message' => 'Nachricht', 'requester_email' => 'Absender-E-Mail', 'requester_name' => 'Absender-Name', 'source' => 'Kanal (web/email)']; const RULE_OPERATORS = ['contains' => 'enthält', 'not_contains' => 'enthält nicht', 'equals' => 'ist genau', 'starts_with' => 'beginnt mit', 'ends_with' => 'endet mit']; const RULE_ACTIONS = ['set_department' => 'Abteilung setzen', 'set_priority' => 'Priorität setzen', 'set_help_topic' => 'Hilfe-Thema setzen', 'assign_staff' => 'Mitarbeiter zuweisen', 'add_tag' => 'Tag hinzufügen', 'auto_reply' => 'Auto-Antwort senden', 'close' => 'Ticket schließen', 'reject' => 'Ticket verwerfen (z.B. Spam)']; if ($_SERVER['REQUEST_METHOD'] === 'GET') { $departments = departments_for_select($pdo, array_map('intval', $pdo->query("SELECT action_value FROM ticket_rule_actions WHERE action_type = 'set_department'")->fetchAll(PDO::FETCH_COLUMN))); $priorities = $pdo->query('SELECT id, name FROM priorities ORDER BY sort_order')->fetchAll(); $helpTopics = $pdo->query('SELECT id, name FROM help_topics ORDER BY name')->fetchAll(); $staffList = $pdo->query("SELECT id, name FROM staff WHERE is_active = 1 ORDER BY name")->fetchAll(); $cannedResponses = $pdo->query('SELECT id, title FROM canned_responses ORDER BY title')->fetchAll(); $deptById = array_column($departments, 'name', 'id'); $prioById = array_column($priorities, 'name', 'id'); $topicById = array_column($helpTopics, 'name', 'id'); $staffById = array_column($staffList, 'name', 'id'); $cannedById = array_column($cannedResponses, 'title', 'id'); $rules = $pdo->query('SELECT * FROM ticket_rules ORDER BY sort_order, id')->fetchAll(); $condStmt = $pdo->prepare('SELECT field, operator, value FROM ticket_rule_conditions WHERE rule_id = ? ORDER BY id'); $actStmt = $pdo->prepare('SELECT action_type, action_value FROM ticket_rule_actions WHERE rule_id = ? ORDER BY id'); $rulesOut = []; foreach ($rules as $r) { $condStmt->execute([$r['id']]); $actStmt->execute([$r['id']]); $actionsOut = []; foreach ($actStmt->fetchAll() as $a) { $type = $a['action_type']; $value = $a['action_value']; $label = match ($type) { 'set_department' => $deptById[$value] ?? null, 'set_priority' => $prioById[$value] ?? null, 'set_help_topic' => $topicById[$value] ?? null, 'assign_staff' => $staffById[$value] ?? null, 'auto_reply' => $cannedById[$value] ?? null, 'add_tag' => $value, 'reject', 'close' => null, default => null, }; $actionsOut[] = ['type' => $type, 'value' => $value, 'valueLabel' => $label]; } $rulesOut[] = [ 'id' => (int) $r['id'], 'name' => $r['name'], 'matchType' => $r['match_type'], 'isActive' => (bool) $r['is_active'], 'sortOrder' => (int) $r['sort_order'], 'conditions' => $condStmt->fetchAll(), 'actions' => $actionsOut, ]; } api_json([ 'fieldOptions' => array_map(fn($v, $l) => ['value' => $v, 'label' => $l], array_keys(RULE_FIELDS), RULE_FIELDS), 'operatorOptions' => array_map(fn($v, $l) => ['value' => $v, 'label' => $l], array_keys(RULE_OPERATORS), RULE_OPERATORS), 'actionOptions' => array_map(fn($v, $l) => ['value' => $v, 'label' => $l], array_keys(RULE_ACTIONS), RULE_ACTIONS), 'departments' => array_map(fn(array $d) => ['id' => (int) $d['id'], 'name' => $d['name']], $departments), 'priorities' => array_map(fn(array $p) => ['id' => (int) $p['id'], 'name' => $p['name']], $priorities), 'helpTopics' => array_map(fn(array $t) => ['id' => (int) $t['id'], 'name' => $t['name']], $helpTopics), 'staffOptions' => array_map(fn(array $s) => ['id' => (int) $s['id'], 'name' => $s['name']], $staffList), 'cannedResponses' => array_map(fn(array $c) => ['id' => (int) $c['id'], 'name' => $c['title']], $cannedResponses), 'rules' => $rulesOut, 'autoCloseEnabled' => get_setting('auto_close_enabled', '0') === '1', 'autoCloseDays' => (int) get_setting('auto_close_days', '7'), ]); } $body = api_request_body(); $action = $body['action'] ?? ''; if ($action === 'toggle') { $id = (int) ($body['id'] ?? 0); $pdo->prepare('UPDATE ticket_rules SET is_active = 1 - is_active WHERE id = ?')->execute([$id]); api_json(['ok' => true]); } if ($action === 'save_auto_close') { $enabled = !empty($body['enabled']) ? '1' : '0'; $days = max(1, min(90, (int) ($body['days'] ?? 7))); set_setting('auto_close_enabled', $enabled); set_setting('auto_close_days', (string) $days); audit_log($staff['id'], 'Automatisches Schließen geändert (Mobile App)'); api_json(['ok' => true]); } if ($action === 'delete') { $id = (int) ($body['id'] ?? 0); $pdo->prepare('DELETE FROM ticket_rule_conditions WHERE rule_id = ?')->execute([$id]); $pdo->prepare('DELETE FROM ticket_rule_actions WHERE rule_id = ?')->execute([$id]); $pdo->prepare('DELETE FROM ticket_rules WHERE id = ?')->execute([$id]); audit_log($staff['id'], "Ticket-Regel gelöscht: #$id (Mobile App)"); api_json(['ok' => true]); } if ($action === 'save') { $id = (int) ($body['id'] ?? 0); $name = trim((string) ($body['name'] ?? '')); $matchType = ($body['matchType'] ?? 'all') === 'any' ? 'any' : 'all'; $isActive = !empty($body['isActive']) ? 1 : 0; $sortOrder = (int) ($body['sortOrder'] ?? 0); $rawConditions = is_array($body['conditions'] ?? null) ? $body['conditions'] : []; $rawActions = is_array($body['actions'] ?? null) ? $body['actions'] : []; if ($name === '') api_error(422, 'NAME_REQUIRED', 'Bitte einen Namen angeben.'); $conditions = []; foreach ($rawConditions as $c) { $field = (string) ($c['field'] ?? ''); $operator = (string) ($c['operator'] ?? ''); $value = trim((string) ($c['value'] ?? '')); if ($value === '' || !isset(RULE_FIELDS[$field]) || !isset(RULE_OPERATORS[$operator])) continue; $conditions[] = ['field' => $field, 'operator' => $operator, 'value' => $value]; } if (!$conditions) api_error(422, 'CONDITIONS_REQUIRED', 'Bitte mindestens eine Bedingung mit einem Wert angeben.'); $actionsToSave = []; foreach ($rawActions as $a) { $type = (string) ($a['type'] ?? ''); if (!isset(RULE_ACTIONS[$type])) continue; $noValue = in_array($type, ['reject', 'close'], true); $value = $noValue ? '1' : trim((string) ($a['value'] ?? '')); if (!$noValue && $value === '') continue; $actionsToSave[] = ['type' => $type, 'value' => $value]; } if (!$actionsToSave) api_error(422, 'ACTIONS_REQUIRED', 'Bitte mindestens eine Aktion festlegen.'); if ($id) { $existsStmt = $pdo->prepare('SELECT COUNT(*) FROM ticket_rules WHERE id = ?'); $existsStmt->execute([$id]); if (!(bool) $existsStmt->fetchColumn()) api_error(404, 'RULE_NOT_FOUND', 'Die Regel wurde nicht gefunden.'); $pdo->prepare('UPDATE ticket_rules SET name=?, match_type=?, is_active=?, sort_order=? WHERE id=?') ->execute([$name, $matchType, $isActive, $sortOrder, $id]); $pdo->prepare('DELETE FROM ticket_rule_conditions WHERE rule_id = ?')->execute([$id]); $pdo->prepare('DELETE FROM ticket_rule_actions WHERE rule_id = ?')->execute([$id]); audit_log($staff['id'], "Ticket-Regel aktualisiert: $name (Mobile App)"); $ruleId = $id; } else { $pdo->prepare('INSERT INTO ticket_rules (name, match_type, is_active, sort_order, created_at) VALUES (?,?,?,?,?)') ->execute([$name, $matchType, $isActive, $sortOrder, db_now()]); $ruleId = (int) $pdo->lastInsertId(); audit_log($staff['id'], "Ticket-Regel erstellt: $name (Mobile App)"); } $condStmt = $pdo->prepare('INSERT INTO ticket_rule_conditions (rule_id, field, operator, value) VALUES (?,?,?,?)'); foreach ($conditions as $c) { $condStmt->execute([$ruleId, $c['field'], $c['operator'], $c['value']]); } $actStmt = $pdo->prepare('INSERT INTO ticket_rule_actions (rule_id, action_type, action_value) VALUES (?,?,?)'); foreach ($actionsToSave as $a) { $actStmt->execute([$ruleId, $a['type'], $a['value']]); } api_json(['id' => $ruleId]); } api_error(422, 'INVALID_ACTION', 'Unbekannte Aktion.');