query('SELECT id, name FROM priorities ORDER BY sort_order')->fetchAll(); $staffList = $pdo->query('SELECT id, name FROM staff WHERE is_active = 1 ORDER BY name')->fetchAll(); $depts = $pdo->query('SELECT id, name FROM departments ORDER BY name')->fetchAll(); try { $rules = $pdo->query( 'SELECT er.*, p.name AS prio_name, s.name AS staff_name, d.name AS dept_name, cp.name AS cond_prio_name, (SELECT COUNT(*) FROM escalation_log el WHERE el.rule_id = er.id) AS applied_count FROM escalation_rules er LEFT JOIN priorities p ON p.id = er.action_set_priority_id LEFT JOIN staff s ON s.id = er.action_assign_staff_id LEFT JOIN departments d ON d.id = er.condition_dept_id LEFT JOIN priorities cp ON cp.id = er.condition_priority_id ORDER BY er.sort_order, er.id' )->fetchAll(); } catch (Throwable $e) { $rules = []; } api_json([ 'priorities' => array_map(fn(array $p) => ['id' => (int) $p['id'], 'name' => $p['name']], $priorities), 'staffOptions' => array_map(fn(array $s) => ['id' => (int) $s['id'], 'name' => $s['name']], $staffList), 'departments' => array_map(fn(array $d) => ['id' => (int) $d['id'], 'name' => $d['name']], $depts), 'rules' => array_map(fn(array $r) => [ 'id' => (int) $r['id'], 'name' => $r['name'], 'isActive' => (bool) $r['is_active'], 'triggerType' => $r['trigger_type'], 'triggerHours' => (int) $r['trigger_hours'], 'conditionStatus' => $r['condition_status'], 'conditionPriorityId' => $r['condition_priority_id'] !== null ? (int) $r['condition_priority_id'] : null, 'conditionPriorityName' => $r['cond_prio_name'], 'conditionDeptId' => $r['condition_dept_id'] !== null ? (int) $r['condition_dept_id'] : null, 'conditionDeptName' => $r['dept_name'], 'actionSetPriorityId' => $r['action_set_priority_id'] !== null ? (int) $r['action_set_priority_id'] : null, 'actionSetPriorityName' => $r['prio_name'], 'actionAssignStaffId' => $r['action_assign_staff_id'] !== null ? (int) $r['action_assign_staff_id'] : null, 'actionAssignStaffName' => $r['staff_name'], 'actionSetStatus' => $r['action_set_status'], 'actionNotifyAdmin' => (bool) $r['action_notify_admin'], 'actionNotifyStaff' => (bool) $r['action_notify_staff'], 'sortOrder' => (int) $r['sort_order'], 'appliedCount' => (int) $r['applied_count'], ], $rules), ]); } $body = api_request_body(); $action = $body['action'] ?? ''; if ($action === 'toggle') { $id = (int) ($body['id'] ?? 0); $pdo->prepare('UPDATE escalation_rules SET is_active = 1 - is_active WHERE id = ?')->execute([$id]); api_json(['ok' => true]); } if ($action === 'delete') { $id = (int) ($body['id'] ?? 0); $pdo->prepare('DELETE FROM escalation_rules WHERE id = ?')->execute([$id]); $pdo->prepare('DELETE FROM escalation_log WHERE rule_id = ?')->execute([$id]); audit_log($staff['id'], "Eskalationsregel gelöscht: #$id (Mobile App)"); api_json(['ok' => true]); } if ($action === 'save') { $id = (int) ($body['id'] ?? 0); $name = trim((string) ($body['name'] ?? '')); $isActive = !empty($body['isActive']) ? 1 : 0; $triggerType = (string) ($body['triggerType'] ?? 'no_reply'); $triggerHours = max(1, (int) ($body['triggerHours'] ?? 24)); $condStatus = trim((string) ($body['conditionStatus'] ?? '')); $condPrioId = isset($body['conditionPriorityId']) && $body['conditionPriorityId'] !== null ? (int) $body['conditionPriorityId'] : null; $condDeptId = isset($body['conditionDeptId']) && $body['conditionDeptId'] !== null ? (int) $body['conditionDeptId'] : null; $actPrioId = isset($body['actionSetPriorityId']) && $body['actionSetPriorityId'] !== null ? (int) $body['actionSetPriorityId'] : null; $actStaffId = isset($body['actionAssignStaffId']) && $body['actionAssignStaffId'] !== null ? (int) $body['actionAssignStaffId'] : null; $actStatus = (string) ($body['actionSetStatus'] ?? ''); $actNotAdmin = !empty($body['actionNotifyAdmin']) ? 1 : 0; $actNotStaff = !empty($body['actionNotifyStaff']) ? 1 : 0; $sortOrder = (int) ($body['sortOrder'] ?? 0); if ($name === '') { api_error(422, 'NAME_REQUIRED', 'Bitte einen Namen angeben.'); } if (!in_array($triggerType, ESCALATION_TRIGGER_TYPES, true)) { api_error(422, 'INVALID_TRIGGER', 'Ungültiger Trigger.'); } if ($actStatus !== '' && !in_array($actStatus, ESCALATION_SET_STATUSES, true)) { api_error(422, 'INVALID_STATUS', 'Ungültiger Zielstatus.'); } $data = [$name, $isActive, $triggerType, $triggerHours, $condStatus ?: null, $condPrioId, $condDeptId, $actPrioId, $actStaffId, $actStatus ?: null, $actNotAdmin, $actNotStaff, $sortOrder]; if ($id) { $existsStmt = $pdo->prepare('SELECT COUNT(*) FROM escalation_rules WHERE id = ?'); $existsStmt->execute([$id]); if (!(bool) $existsStmt->fetchColumn()) { api_error(404, 'RULE_NOT_FOUND', 'Die Regel wurde nicht gefunden.'); } $pdo->prepare( 'UPDATE escalation_rules SET name=?,is_active=?,trigger_type=?,trigger_hours=?, condition_status=?,condition_priority_id=?,condition_dept_id=?, action_set_priority_id=?,action_assign_staff_id=?,action_set_status=?, action_notify_admin=?,action_notify_staff=?,sort_order=? WHERE id=?' )->execute(array_merge($data, [$id])); audit_log($staff['id'], "Eskalationsregel geändert: $name (Mobile App)"); $newId = $id; } else { $pdo->prepare( 'INSERT INTO escalation_rules (name,is_active,trigger_type,trigger_hours, condition_status,condition_priority_id,condition_dept_id, action_set_priority_id,action_assign_staff_id,action_set_status, action_notify_admin,action_notify_staff,sort_order,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)' )->execute(array_merge($data, [db_now()])); $newId = (int) $pdo->lastInsertId(); audit_log($staff['id'], "Eskalationsregel erstellt: $name (Mobile App)"); } api_json(['id' => $newId]); } api_error(422, 'INVALID_ACTION', 'Unbekannte Aktion.');