diff --git a/README.md b/README.md index 6f12165f..85424b6a 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,13 @@ Workflow-Definitionen werden im Ordner `custom/workflows/` als JSON abgelegt: ### Workflow Manager Script **Zentrale Schnittstelle:** `custom/scripts/workflow_manager.php` -Dieses Script ermöglicht die Verwaltung aller Workflows (Simple und BPM) über die Kommandozeile: +Dieses Script ermöglicht die Verwaltung aller Workflows (Simple und BPM) über die Kommandozeile. + +**Unterstützte Funktionen:** +- ✓ Kategorisierung von Workflows +- ✓ Import/Export mit Kategorie-Namen +- ✓ Übersichtliche Darstellung nach Kategorien +- ✓ Unterstützung für beide Workflow-Typen (Simple & BPM) #### Verfügbare Aktionen @@ -248,6 +254,7 @@ Löscht einen Workflow (mit Bestätigung). Funktioniert für beide Workflow-Type "trigger_type": "afterRecordSaved", "is_active": true, "description": "Beschreibung der Funktion", + "category": "Kategorie-Name", "conditions_all": [ { "comparison": "equals", @@ -272,6 +279,7 @@ Löscht einen Workflow (mit Bestätigung). Funktioniert für beide Workflow-Type ``` **Wichtige Felder:** +- `category` - **NEU:** Name der Workflow-Kategorie (optional, für bessere Organisation) - `comparison` - Vergleichsoperator (siehe Bedingungen oben) - `fieldToCompare` - Feldname für Bedingung - `subjectType` - Typ des Vergleichswerts (`value`, `field`, etc.) diff --git a/custom/scripts/workflow_manager.php b/custom/scripts/workflow_manager.php index 84321dd9..72a22ab2 100644 --- a/custom/scripts/workflow_manager.php +++ b/custom/scripts/workflow_manager.php @@ -31,8 +31,15 @@ function connectDB() { } function listWorkflows($pdo) { + // Load categories + $categories = []; + $stmt = $pdo->query("SELECT id, name FROM workflow_category WHERE deleted = 0 ORDER BY `order`, name"); + foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $cat) { + $categories[$cat['id']] = $cat['name']; + } + echo "=== BPM Flowcharts ===\n"; - $stmt = $pdo->query("SELECT id, name, target_type, is_active FROM bpmn_flowchart WHERE deleted = 0"); + $stmt = $pdo->query("SELECT id, name, target_type, is_active FROM bpmn_flowchart WHERE deleted = 0 ORDER BY name"); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($results as $row) { $active = $row['is_active'] ? '[AKTIV]' : '[INAKTIV]'; @@ -40,12 +47,21 @@ function listWorkflows($pdo) { } echo "\n=== Simple Workflows ===\n"; - $stmt = $pdo->query("SELECT id, name, entity_type, type, is_active FROM workflow WHERE deleted = 0"); + $stmt = $pdo->query("SELECT id, name, entity_type, type, is_active, category_id FROM workflow WHERE deleted = 0 ORDER BY category_id, name"); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); + + $currentCategory = null; foreach ($results as $row) { + $catId = $row['category_id']; + if ($catId !== $currentCategory) { + $currentCategory = $catId; + $catName = $catId && isset($categories[$catId]) ? $categories[$catId] : 'Ohne Kategorie'; + echo "\n [Kategorie: {$catName}]\n"; + } + $active = $row['is_active'] ? '[AKTIV]' : '[INAKTIV]'; $name = $row['name'] ?: '(unnamed)'; - echo " {$active} ID: {$row['id']}, Name: {$name}, Entity: {$row['entity_type']}, Type: {$row['type']}\n"; + echo " {$active} ID: {$row['id']}, Name: {$name}, Entity: {$row['entity_type']}, Type: {$row['type']}\n"; } } @@ -120,13 +136,23 @@ function importWorkflow($pdo, $file) { if ($type === 'simple') { // Import Simple Workflow $id = substr(bin2hex(random_bytes(12)), 0, 17); + + // Resolve category by name if provided + $categoryId = null; + if (isset($data['category'])) { + $stmt = $pdo->prepare("SELECT id FROM workflow_category WHERE name = ? AND deleted = 0"); + $stmt->execute([$data['category']]); + $cat = $stmt->fetch(PDO::FETCH_ASSOC); + $categoryId = $cat ? $cat['id'] : null; + } + $stmt = $pdo->prepare(" INSERT INTO workflow ( id, name, entity_type, type, is_active, is_internal, description, conditions_all, conditions_any, conditions_formula, actions, portal_only, scheduling, scheduling_apply_timezone, - process_order, created_at, modified_at, deleted - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0) + process_order, category_id, created_at, modified_at, deleted + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0) "); $stmt->execute([ $id, @@ -144,10 +170,12 @@ function importWorkflow($pdo, $file) { '0 0 * * *', 1, 10, + $categoryId, $now, $now ]); - echo "✓ Simple Workflow importiert: $id - {$data['name']}\n"; + $catInfo = $categoryId ? " (Kategorie: {$data['category']})" : ""; + echo "✓ Simple Workflow importiert: $id - {$data['name']}{$catInfo}\n"; } elseif ($type === 'bpm') { // Import BPM Flowchart $id = substr(bin2hex(random_bytes(12)), 0, 17); @@ -198,7 +226,7 @@ function exportWorkflow($pdo, $id, $file) { } // Try Simple Workflow - $stmt = $pdo->prepare("SELECT * FROM workflow WHERE id = ? AND deleted = 0"); + $stmt = $pdo->prepare("SELECT w.*, wc.name as category_name FROM workflow w LEFT JOIN workflow_category wc ON w.category_id = wc.id WHERE w.id = ? AND w.deleted = 0"); $stmt->execute([$id]); $row = $stmt->fetch(PDO::FETCH_ASSOC); @@ -215,6 +243,12 @@ function exportWorkflow($pdo, $id, $file) { 'conditions_formula' => $row['conditions_formula'], 'actions' => json_decode($row['actions'], true) ]; + + // Add category name if exists + if ($row['category_name']) { + $export['category'] = $row['category_name']; + } + file_put_contents($file, json_encode($export, JSON_PRETTY_PRINT)); echo "✓ Simple Workflow exportiert nach: $file\n"; return; diff --git a/custom/workflows/README.md b/custom/workflows/README.md index 06ea05ae..d17860f2 100644 --- a/custom/workflows/README.md +++ b/custom/workflows/README.md @@ -13,6 +13,7 @@ This directory contains workflow definitions in JSON format that can be imported "trigger_type": "afterRecordSaved", "is_active": true, "description": "Description of what this workflow does", + "category": "Category Name", "conditions_all": [], "conditions_any": [], "conditions_formula": null, @@ -24,6 +25,7 @@ This directory contains workflow definitions in JSON format that can be imported - `afterRecordSaved` - After record is created or updated - `afterRecordCreated` - Only after record is created - `scheduled` - Runs on a schedule +- `manual` - Manually triggered **Condition Types:** - `equals`, `notEquals`, `greaterThan`, `lessThan`, `contains`, `notContains`, `isEmpty`, `isNotEmpty`, `isTrue`, `isFalse`, `wasEqual`, `wasNotEqual`, `changed`, `notChanged`