From 3f10213b9048e2d4f3015f70ae408f5da38d8f68 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 26 Jan 2023 21:54:13 +0100 Subject: [PATCH] org -> unit change, some new functionality --- Admin/Install/Workflow.install.json | 362 ++++++++++++++++++++++++++++ Admin/Install/Workflow.php | 43 ++++ Admin/Install/db.json | 5 + Admin/Installer.php | 2 +- Controller/ApiController.php | 8 +- Docs/Dev/en/workflow.md | 47 ++++ 6 files changed, 462 insertions(+), 5 deletions(-) create mode 100644 Admin/Install/Workflow.install.json create mode 100644 Admin/Install/Workflow.php create mode 100644 Docs/Dev/en/workflow.md diff --git a/Admin/Install/Workflow.install.json b/Admin/Install/Workflow.install.json new file mode 100644 index 0000000..b152cd9 --- /dev/null +++ b/Admin/Install/Workflow.install.json @@ -0,0 +1,362 @@ +{ + "triggers": [ + "PRE:Module:Workflow:workflow_template-create", + "POST:Module:Workflow:workflow_template-create", + "PRE:Module:Workflow:workflow_template-update", + "POST:Module:Workflow:workflow_template-update", + "PRE:Module:Workflow:workflow_template-delete", + "POST:Module:Workflow:workflow_template-delete", + + "PRE:Module:Workflow:workflow_instance-create", + "POST:Module:Workflow:workflow_instance-create", + "PRE:Module:Workflow:workflow_instance-update", + "POST:Module:Workflow:workflow_instance-update", + "PRE:Module:Workflow:workflow_instance-delete", + "POST:Module:Workflow:workflow_instance-delete" + ], + "actions": { + "1005500001": { + "name": "If", + "description": { + "en": "Check condition", + "de": "Überprüfe Bedingung" + }, + "function_type": "API", + "function": "apiValidateCondition", + "inputs": [ + "field_name", + "field_value", + "field_value_type", + "field_comparison", + "{*}" + ], + "outputs": [ + "true|false" + ], + "settings": { + "field_name": { + "type": "input", + "subtype": "text", + "default": "*", + "pattern": null, + "examples": [], + "required": true, + "title": { + "en": "Field name", + "de": "Feld name" + }, + "description": { + "en": "", + "de": "" + } + }, + "field_value": { + "type": "input", + "subtype": "text", + "default": "*", + "pattern": null, + "examples": [], + "required": true, + "title": { + "en": "Field value", + "de": "Feld value" + }, + "description": { + "en": "", + "de": "" + } + }, + "field_comparison": { + "type": "select", + "subtype": null, + "default": "=", + "pattern": null, + "examples": [], + "required": true, + "title": { + "en": "Field comparison", + "de": "Feld comparison" + }, + "description": { + "en": "", + "de": "" + }, + "options": [ + { + "value": "=", + "text": { + "": "=" + } + }, + { + "value": "!=", + "text": { + "": "!=" + } + }, + { + "value": ">", + "text": { + "": ">" + } + }, + { + "value": "<", + "text": { + "": "<" + } + }, + { + "value": ">=", + "text": { + "": ">=" + } + }, + { + "value": "<=", + "text": { + "": "<=" + } + } + ] + }, + "field_value_type": { + "type": "select", + "subtype": null, + "default": null, + "pattern": null, + "examples": [], + "required": true, + "title": { + "en": "Field value type", + "de": "Feld value type" + }, + "description": { + "en": "", + "de": "" + }, + "options": [ + { + "value": "int", + "text": { + "en": "Integer", + "de": "Ganze Zahl" + } + }, + { + "value": "float", + "text": { + "en": "Decimal number", + "den": "Dezimalzahl" + } + }, + { + "value": "datetime", + "text": { + "en": "Date/Time", + "de": "Datum/Zeit" + } + }, + { + "value": "string", + "text": { + "en": "Text", + "de": "Text" + } + }, + { + "value": "bool", + "text": { + "en": "True/False", + "de": "Wahr/Falsch" + } + } + ] + } + }, + "1005500002": { + "name": "Adapter", + "description": { + "en": "Takes input data and forwards the data to another action. Check the outputs and inputs of the actions to create the correct mapping.", + "de": "Übernimmt Eingangsdaten und leitet diese an eine andere Aktion weiter. Überprüfe die Ausgaben und Eingaben der jeweiligen Aktionen um die korrekten Verknüpfungen zu erstellen." + }, + "function_type": "API", + "function": "apiAdapter", + "inputs": [ + "map", + "{*}" + ], + "outputs": [ + "{*}" + ], + "settings": { + "map": { + "type": "textarea", + "subtype": null, + "default": null, + "pattern": null, + "examples": [ + "output1 -> input1\noutput1.name -> input2" + ], + "required": true, + "title": { + "en": "Adapter", + "de": "Adapter" + }, + "description": { + "en": "", + "de": "" + } + } + } + }, + "1005500003": { + "name": "Listen Trigger", + "description": { + "en": "Listens to trigger", + "de": "Wartet auf Trigger" + }, + "function_type": "API", + "function": "apiListenToTrigger", + "inputs": [ + "type", + "trigger", + "delete", + "{*}" + ], + "outputs": [ + "{*}" + ], + "settings": { + "type": { + "type": "select", + "subtype": null, + "default": "1", + "pattern": null, + "examples": [], + "required": true, + "title": { + "en": "Type", + "de": "Type" + }, + "options": [ + { + "value": "1", + "text": { + "en": "Existing Trigger", + "de": "Bestehender Trigger" + } + }, + { + "value": "2", + "text": { + "en": "New Trigger", + "de": "Neuer Trigger" + } + } + ], + "description": { + "en": "", + "de": "" + } + }, + "trigger": { + "type": "input", + "subtype": "text", + "default": null, + "pattern": null, + "examples": [ + "PRE:Module:Billing:bill-create", + "PRE:Module:Billing:bill-update.*", + "PRE:Module:Billing:bill-update-{$id}" + ], + "required": true, + "title": { + "en": "Trigger", + "de": "Trigger" + }, + "description": { + "en": "", + "de": "" + } + }, + "delete": { + "type": "select", + "subtype": null, + "default": "1", + "pattern": null, + "examples": [], + "required": true, + "title": { + "en": "Type", + "de": "Type" + }, + "options": [ + { + "value": "1", + "text": { + "en": "Never", + "de": "Niemals" + } + }, + { + "value": "2", + "text": { + "en": "After trigger execution", + "de": "Nach Triggerausführung" + } + }, + { + "value": "3", + "text": { + "en": "After workflow execution", + "de": "Nach Workflowausführung" + } + } + ], + "description": { + "en": "", + "de": "" + } + }, + } + }, + "1005500004": { + "name": "Run Trigger", + "description": { + "en": "Takes input data and forwards the data to another action. Check the outputs and inputs of the actions to create the correct mapping.", + "de": "Übernimmt Eingangsdaten und leitet diese an eine andere Aktion weiter. Überprüfe die Ausgaben und Eingaben der jeweiligen Aktionen um die korrekten Verknüpfungen zu erstellen." + }, + "function_type": "API", + "function": "apiAdapter", + "inputs": [ + "map", + "{*}" + ], + "outputs": [ + "{*}" + ], + "settings": { + "map": { + "type": "textarea", + "subtype": null, + "default": null, + "pattern": null, + "examples": [ + "output1 -> input1\noutput1.name -> input2" + ], + "required": true, + "title": { + "en": "Adapter", + "de": "Adapter" + }, + "description": { + "en": "", + "de": "" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Admin/Install/Workflow.php b/Admin/Install/Workflow.php new file mode 100644 index 0000000..fab10c1 --- /dev/null +++ b/Admin/Install/Workflow.php @@ -0,0 +1,43 @@ + __DIR__ . '/Workflow.install.json']); + } +} diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 81810f1..8f11597 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -74,6 +74,11 @@ "type": "INT", "null": false }, + "workflow_instance_data": { + "name": "workflow_instance_data", + "type": "TEXT", + "null": false + }, "workflow_instance_template": { "name": "workflow_instance_template", "type": "INT", diff --git a/Admin/Installer.php b/Admin/Installer.php index 6b69c10..2d78443 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -75,7 +75,7 @@ final class Installer extends InstallerAbstract }; $apiApp->dbPool = $app->dbPool; - $apiApp->orgId = $app->orgId; + $apiApp->unitId = $app->unitId; $apiApp->accountManager = $app->accountManager; $apiApp->appSettings = $app->appSettings; $apiApp->moduleManager = $app->moduleManager; diff --git a/Controller/ApiController.php b/Controller/ApiController.php index df25ed7..db7f105 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -163,10 +163,10 @@ final class ApiController extends Controller // is allowed to read if (!$this->app->accountManager->get($accountId)->hasPermission( - PermissionType::READ, $this->app->orgId, null, self::NAME, PermissionCategory::INSTANCE, $instance->getId() + PermissionType::READ, $this->app->unitId, null, self::NAME, PermissionCategory::INSTANCE, $instance->getId() ) || ($isExport && !$this->app->accountManager->get($accountId)->hasPermission( - PermissionType::READ, $this->app->orgId, $this->app->appName, self::NAME, PermissionCategory::EXPORT + PermissionType::READ, $this->app->unitId, $this->app->appName, self::NAME, PermissionCategory::EXPORT )) ) { $response->header->status = RequestStatusCode::R_403; @@ -416,7 +416,7 @@ final class ApiController extends Controller // is allowed to create if (!$this->app->accountManager->get($request->header->account)->hasPermission( - PermissionType::CREATE, $this->app->orgId, null, self::NAME, PermissionCategory::TEMPLATE) + PermissionType::CREATE, $this->app->unitId, null, self::NAME, PermissionCategory::TEMPLATE) ) { $response->header->status = RequestStatusCode::R_403; @@ -466,7 +466,7 @@ final class ApiController extends Controller $template = $this->createTemplateFromRequest($request, $collection->getId()); - $this->createModel($request->header->account, $template, WorkflowTemplateMapper::class, 'template', $request->getOrigin()); + $this->createModel($request->header->account, $template, WorkflowTemplateMapper::class, 'workflow_template', $request->getOrigin()); // replace placeholders foreach ($uploaded as $upload) { diff --git a/Docs/Dev/en/workflow.md b/Docs/Dev/en/workflow.md new file mode 100644 index 0000000..cd581de --- /dev/null +++ b/Docs/Dev/en/workflow.md @@ -0,0 +1,47 @@ + +Every workflow can have up to 2 triggers (one existing trigger and one workflow specific trigger (trigger id)) + +Creating: + +```mermaid +graph TD; + CREATE_TEMPLATE((Create))-->REGISTER_TRIGGER[Register template trigger] + REGISTER_TRIGGER-->HAS_OTHER_TRIGGER{Has other trigger} + HAS_OTHER_TRIGGER--YES-->REGISTER_TRIGGER_2[Register existing trigger] +``` + +Running: + +```mermaid +graph TD; + MAIN_TRIGGER((Trigger))-->CREATE_INSTANCE[Create Instance in DB] + MAIN_TRIGGER-->HAS_SUB_TRIGGERS{Has Sub Triggers} + HAS_SUB_TRIGGERS--YES-->REGISTER_TRIGGER[Register sub triggers] + MAIN_TRIGGER-->RUN_CODE_1[Run Code] + RUN_CODE_1-->FORWARD_1[Run Code] + FORWARD_1-->CONDITION{Condition} + CONDITION-->RUN_CODE_3[Run Code] +``` + +How do workflow elements transfer data from one action to the next? +1. Through request/response objects? + 1. Action 1 creates response + 2. Workflow takes result and forms new request (expands original request) + 3. Action 2 takes request and performs action + +This means that after every action a general workflow function has to take over and generate the next request. However this is to be expected anyways? + +// Sample Workflows + +Billing: + +1. Get active subscriptions for the day + 1. option1: date (default = now) + 2. option2: client (default = wildcard for all) + 3. option3: payment type (default = cc, future = multiselect) +2. Create new invoice based on subscription +3. Is successful + 1. yes: send email + 2. no: inform sales person + deactivate benefits + +