diff --git a/.liquibase/Data_alias/basic/2020.0.0/Workflow/insert_WorkflowTrigger_keyword.xml b/.liquibase/Data_alias/basic/2020.0.0/Workflow/insert_WorkflowTrigger_keyword.xml
index e901ae91aeef743e1aaf46aebee6110c38c92b44..84768e108968818962bae30f61a4f9cd7a686d11 100644
--- a/.liquibase/Data_alias/basic/2020.0.0/Workflow/insert_WorkflowTrigger_keyword.xml
+++ b/.liquibase/Data_alias/basic/2020.0.0/Workflow/insert_WorkflowTrigger_keyword.xml
@@ -5,11 +5,38 @@
         <insert tableName="AB_KEYWORD_ENTRY">
             <column name="AB_KEYWORD_ENTRYID" value="c823c666-ca18-4795-9f2d-d9dbfb7d4028"/>
             <column name="KEYID" value="WORKFLOWTRIGGERMANUAL"/>
-            <column name="TITLE" value="Manual"/>
+            <column name="TITLE" value="Manually"/>
             <column name="CONTAINER" value="WorkflowTrigger"/>
             <column name="SORTING" valueNumeric="1"/>
             <column name="ISACTIVE" valueNumeric="1"/>
             <column name="ISESSENTIAL" valueNumeric="1"/>
         </insert>
+        <insert tableName="AB_KEYWORD_ENTRY">
+            <column name="AB_KEYWORD_ENTRYID" value="30b9c5d2-0aa2-489d-8746-ddb53d6e235d"/>
+            <column name="KEYID" value="WORKFLOWTRIGGERINSERT"/>
+            <column name="TITLE" value="Create"/>
+            <column name="CONTAINER" value="WorkflowTrigger"/>
+            <column name="SORTING" valueNumeric="2"/>
+            <column name="ISACTIVE" valueNumeric="1"/>
+            <column name="ISESSENTIAL" valueNumeric="1"/>
+        </insert>
+        <insert tableName="AB_KEYWORD_ENTRY">
+            <column name="AB_KEYWORD_ENTRYID" value="5101860e-84c9-49ae-8947-383c0c819090"/>
+            <column name="KEYID" value="WORKFLOWTRIGGERUPDATE"/>
+            <column name="TITLE" value="Update"/>
+            <column name="CONTAINER" value="WorkflowTrigger"/>
+            <column name="SORTING" valueNumeric="3"/>
+            <column name="ISACTIVE" valueNumeric="1"/>
+            <column name="ISESSENTIAL" valueNumeric="1"/>
+        </insert>
+        <insert tableName="AB_KEYWORD_ENTRY">
+            <column name="AB_KEYWORD_ENTRYID" value="b72d5352-7de0-4d54-89db-c4e2e87352c9"/>
+            <column name="KEYID" value="WORKFLOWTRIGGERDELETE"/>
+            <column name="TITLE" value="Delete"/>
+            <column name="CONTAINER" value="WorkflowTrigger"/>
+            <column name="SORTING" valueNumeric="4"/>
+            <column name="ISACTIVE" valueNumeric="1"/>
+            <column name="ISESSENTIAL" valueNumeric="1"/>
+        </insert>
     </changeSet>
 </databaseChangeLog>
diff --git a/entity/KeywordEntry_entity/KeywordEntry_entity.aod b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
index 97d0a04b687225ded27fa0facf1d6d1dade8e92a..5231bebe241192ed798b654e67e1f04db545fa66 100644
--- a/entity/KeywordEntry_entity/KeywordEntry_entity.aod
+++ b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
@@ -547,6 +547,12 @@
           <fieldName>KeywordRecordSeparator</fieldName>
           <isConsumer v="false" />
         </entityDependency>
+        <entityDependency>
+          <name>24b11c85-618a-494b-980b-a94b56523b78</name>
+          <entityName>WorkflowStartConfig_entity</entityName>
+          <fieldName>TriggerKeyword</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
       </dependencies>
       <children>
         <entityParameter>
diff --git a/entity/Offer_entity/Offer_entity.aod b/entity/Offer_entity/Offer_entity.aod
index 0dc262774b4defc008127a315fea09b510ff4b58..69c67fb8fa4f2bc2bcb54d8738b23fce39327dc3 100644
--- a/entity/Offer_entity/Offer_entity.aod
+++ b/entity/Offer_entity/Offer_entity.aod
@@ -11,6 +11,7 @@
   <grantDeleteProcess>%aditoprj%/entity/Offer_entity/grantDeleteProcess.js</grantDeleteProcess>
   <contentTitleProcess>%aditoprj%/entity/Offer_entity/contentTitleProcess.js</contentTitleProcess>
   <afterUiInit>%aditoprj%/entity/Offer_entity/afterUiInit.js</afterUiInit>
+  <afterOperatingState>%aditoprj%/entity/Offer_entity/afterOperatingState.js</afterOperatingState>
   <iconId>VAADIN:CART</iconId>
   <titlePlural>Offers</titlePlural>
   <recordContainer>db</recordContainer>
@@ -970,6 +971,7 @@
       <conditionProcess>%aditoprj%/entity/Offer_entity/recordcontainers/db/conditionProcess.js</conditionProcess>
       <orderClauseProcess>%aditoprj%/entity/Offer_entity/recordcontainers/db/orderClauseProcess.js</orderClauseProcess>
       <onDBInsert>%aditoprj%/entity/Offer_entity/recordcontainers/db/onDBInsert.js</onDBInsert>
+      <onDBUpdate>%aditoprj%/entity/Offer_entity/recordcontainers/db/onDBUpdate.js</onDBUpdate>
       <onDBDelete>%aditoprj%/entity/Offer_entity/recordcontainers/db/onDBDelete.js</onDBDelete>
       <linkInformation>
         <linkInformation>
diff --git a/entity/Offer_entity/afterOperatingState.js b/entity/Offer_entity/afterOperatingState.js
new file mode 100644
index 0000000000000000000000000000000000000000..95c27335097d5a484f25b37e679dbc332eb8302a
--- /dev/null
+++ b/entity/Offer_entity/afterOperatingState.js
@@ -0,0 +1,8 @@
+import("system.vars");
+import("Workflow_lib");
+
+if (vars.exists("$context.workflowQueue") && vars.get("$context.workflowQueue"))
+{
+    WorkflowStarter.inserted(vars.get("$context.workflowQueue"));
+    vars.set("$context.workflowQueue", null);
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/startworkflow/onActionProcess.js b/entity/Offer_entity/entityfields/startworkflow/onActionProcess.js
index 109808533837ead1af5863dd586b14ce7cac17f5..287769a40ca72c10ec841bc2c7366cc2f5fc40df 100644
--- a/entity/Offer_entity/entityfields/startworkflow/onActionProcess.js
+++ b/entity/Offer_entity/entityfields/startworkflow/onActionProcess.js
@@ -1,3 +1,4 @@
+import("system.vars");
 import("Workflow_lib");
 
-WorkflowUtils.openNewInstance();
\ No newline at end of file
+WorkflowUtils.openNewInstance({sum : Number(vars.get("$field.TotalGross"))});
\ No newline at end of file
diff --git a/entity/Offer_entity/recordcontainers/db/onDBDelete.js b/entity/Offer_entity/recordcontainers/db/onDBDelete.js
index 066cc33ad00409ba655054ad2bfe48743f2d26ad..d8cefb4480fcfc34ebab17f14a34abed738e7946 100644
--- a/entity/Offer_entity/recordcontainers/db/onDBDelete.js
+++ b/entity/Offer_entity/recordcontainers/db/onDBDelete.js
@@ -1,6 +1,9 @@
+import("Workflow_lib");
 import("Sql_lib");
 import("system.vars");
 import("system.db");
 
 newWhere("OFFERITEM.OFFER_ID", "$field.OFFERID")
-    .deleteData(true, "OFFERITEM");
\ No newline at end of file
+    .deleteData(true, "OFFERITEM");
+    
+WorkflowStarter.deleted({sum : Number(vars.get("$field.TotalGross"))});
\ No newline at end of file
diff --git a/entity/Offer_entity/recordcontainers/db/onDBInsert.js b/entity/Offer_entity/recordcontainers/db/onDBInsert.js
index 74f0bb15903ab295028f738c2b747ef22c014234..a9f2f683d4f3b70566d76035df058dc371de621f 100644
--- a/entity/Offer_entity/recordcontainers/db/onDBInsert.js
+++ b/entity/Offer_entity/recordcontainers/db/onDBInsert.js
@@ -1,3 +1,4 @@
+import("Workflow_lib");
 import("system.db");
 import("system.datetime");
 import("system.util");
@@ -17,4 +18,7 @@ if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
         var activityLinkValues = [util.getNewUUID(), activityId,  datetime.date(), vars.get("$sys.user"), "Offer", vars.get("$field.OFFERID")];
         db.insertData("ACTIVITYLINK", activityLinkColumns, null, activityLinkValues);
     }
-}
\ No newline at end of file
+}
+
+//start the execution in afterOperatingState, because here the dataset is not yet inserted
+vars.set("$context.workflowQueue", {sum : Number(vars.get("$field.TotalGross"))});
diff --git a/entity/Offer_entity/recordcontainers/db/onDBUpdate.js b/entity/Offer_entity/recordcontainers/db/onDBUpdate.js
new file mode 100644
index 0000000000000000000000000000000000000000..da0448574647fe3db14786094ad959161f12dd6a
--- /dev/null
+++ b/entity/Offer_entity/recordcontainers/db/onDBUpdate.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("Workflow_lib");
+
+WorkflowStarter.updated({sum : Number(vars.get("$field.TotalGross"))});
\ No newline at end of file
diff --git a/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod b/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
index 0151f2bee19abad65888332ad53b601b84ff629d..74998e878cfd0acc8289e3b51af2e46c2f7bd3a3 100644
--- a/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
+++ b/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
@@ -166,7 +166,7 @@
     </entityParameter>
     <entityActionField>
       <name>downloadXML</name>
-      <title>Download Process</title>
+      <title>Export process</title>
       <onActionProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/downloadxml/onActionProcess.js</onActionProcess>
       <iconId>VAADIN:DOWNLOAD</iconId>
     </entityActionField>
diff --git a/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod b/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod
index 8bbbdfbf26fee36b2d81c7ee839c5ca43d2d54d7..dfc7866a26bdcf20470590202be0be6e29974a74 100644
--- a/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod
+++ b/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod
@@ -16,12 +16,14 @@
       <name>OBJECT_TYPE</name>
       <title>Module</title>
       <consumer>Contexts</consumer>
+      <mandatory v="true" />
     </entityField>
     <entityField>
       <name>TRIGGER_EVENT</name>
       <title>Trigger</title>
-      <state>INVISIBLE</state>
+      <consumer>TriggerKeyword</consumer>
       <valueProcess>%aditoprj%/entity/WorkflowStartConfig_entity/entityfields/trigger_event/valueProcess.js</valueProcess>
+      <displayValueProcess>%aditoprj%/entity/WorkflowStartConfig_entity/entityfields/trigger_event/displayValueProcess.js</displayValueProcess>
     </entityField>
     <entityField>
       <name>PROCESSDEFINITION_KEY</name>
@@ -60,6 +62,20 @@
         </entityParameter>
       </children>
     </entityConsumer>
+    <entityConsumer>
+      <name>TriggerKeyword</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>KeywordEntry_entity</entityName>
+        <fieldName>SpecificContainerKeywords</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>ContainerName_param</name>
+          <valueProcess>%aditoprj%/entity/WorkflowStartConfig_entity/entityfields/triggerkeyword/children/containername_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -100,6 +116,10 @@
           <isFilterable v="true" />
           <isLookupFilter v="true" />
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>TRIGGER_EVENT.displayValue</name>
+          <expression>%aditoprj%/entity/WorkflowStartConfig_entity/recordcontainers/db/recordfieldmappings/trigger_event.displayvalue/expression.js</expression>
+        </dbRecordFieldMapping>
       </recordFieldMappings>
     </dbRecordContainer>
   </recordContainers>
diff --git a/entity/WorkflowStartConfig_entity/entityfields/trigger_event/displayValueProcess.js b/entity/WorkflowStartConfig_entity/entityfields/trigger_event/displayValueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..05284487d59644cf76933c47b6ce1e2f1f74fa33
--- /dev/null
+++ b/entity/WorkflowStartConfig_entity/entityfields/trigger_event/displayValueProcess.js
@@ -0,0 +1,6 @@
+import("system.result");
+import("system.vars");
+import("Keyword_lib");
+import("KeywordRegistry_basic");
+
+result.string(KeywordUtils.getViewValue($KeywordRegistry.workflowTrigger(), vars.get("$field.TRIGGER_EVENT")));
diff --git a/entity/WorkflowStartConfig_entity/entityfields/triggerkeyword/children/containername_param/valueProcess.js b/entity/WorkflowStartConfig_entity/entityfields/triggerkeyword/children/containername_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..dee07a7bcce5662c3c52ee83659e3c64fcf52d10
--- /dev/null
+++ b/entity/WorkflowStartConfig_entity/entityfields/triggerkeyword/children/containername_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("KeywordRegistry_basic");
+import("system.result");
+
+result.string($KeywordRegistry.workflowTrigger());
\ No newline at end of file
diff --git a/entity/WorkflowStartConfig_entity/recordcontainers/db/recordfieldmappings/trigger_event.displayvalue/expression.js b/entity/WorkflowStartConfig_entity/recordcontainers/db/recordfieldmappings/trigger_event.displayvalue/expression.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ee3ee979911e2eafa98e22f4248461c3174df54
--- /dev/null
+++ b/entity/WorkflowStartConfig_entity/recordcontainers/db/recordfieldmappings/trigger_event.displayvalue/expression.js
@@ -0,0 +1,6 @@
+import("system.result");
+import("Keyword_lib");
+import("KeywordRegistry_basic");
+
+var sql = KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.workflowTrigger(), "WORKFLOWSTARTCONFIG.TRIGGER_EVENT");
+result.string(sql);
\ No newline at end of file
diff --git a/process/Contact_lib/process.js b/process/Contact_lib/process.js
index 44046c6d1dd4117b39ddf1e1747fe975e05bbf4c..fe11f0c5301b5a46d2f5f7e518ed75e12c46a066 100644
--- a/process/Contact_lib/process.js
+++ b/process/Contact_lib/process.js
@@ -442,9 +442,7 @@ ContactUtils.getCommRestrictionCondition = function (pMedium, pNoRestriction, pS
                                                     .where("anyContact.CONTACTID = CONTACT.CONTACTID")
             )
         )
-    var cond = "exists ?";
-    if (pNoRestriction)
-        cond = "not " + cond;
+    var cond = pNoRestriction ? SqlBuilder.NOT_EXISTS() : SqlBuilder.EXISTS();
     return newWhere(null, existsQuery, cond);
 }
 
diff --git a/process/KeywordRegistry_basic/process.js b/process/KeywordRegistry_basic/process.js
index cd7f3dafa3218f8f0f2c2dac565340114ebff62a..acd2d0759470dd593c389f8975f171e890fc62fd 100644
--- a/process/KeywordRegistry_basic/process.js
+++ b/process/KeywordRegistry_basic/process.js
@@ -233,4 +233,7 @@ $KeywordRegistry.importFields = function(){return "ImportFields";};
 $KeywordRegistry.dupStatus = function(){return "DupStatus";};
 
 $KeywordRegistry.workflowTrigger = function(){return "WorkflowTrigger";};
-$KeywordRegistry.workflowTrigger$manual = function(){return "WORKFLOWTRIGGERMANUAL";};
\ No newline at end of file
+$KeywordRegistry.workflowTrigger$manual = function(){return "WORKFLOWTRIGGERMANUAL";};
+$KeywordRegistry.workflowTrigger$create = function(){return "WORKFLOWTRIGGERINSERT";};
+$KeywordRegistry.workflowTrigger$update = function(){return "WORKFLOWTRIGGERUPDATE";};
+$KeywordRegistry.workflowTrigger$delete = function(){return "WORKFLOWTRIGGERDELETE";};
\ No newline at end of file
diff --git a/process/Liquibase_lib/process.js b/process/Liquibase_lib/process.js
index b6939ec1251629d4124e12ad3cbec3bb38f08475..f9c9cd59c90eeaa0390c58964c39957977bc59e8 100644
--- a/process/Liquibase_lib/process.js
+++ b/process/Liquibase_lib/process.js
@@ -140,7 +140,7 @@ LiquiUtils._getDataXml = function(pAuthor, pLobPath, pTableName, pColumns, pCond
     var changesetId;
     if (pGenerateChangeSetIdFromArguments)
     {
-        changesetId = Array.prototype.slice.call(arguments);//todo: use Array.from instead when supported (>= rhino 1.7.11)
+        changesetId = Array.prototype.slice.call(arguments);//todo: use Array.from instead when supported (>= rhino 1.7.11) (#1038664)
         changesetId = changesetId.reduce(function (accumulator, currentValue){
             return (currentValue !== null && currentValue !== undefined ? accumulator + JSON.stringify(currentValue) : accumulator);
         }, "");
diff --git a/process/UpdateOffer_workflowService/UpdateOffer_workflowService.aod b/process/UpdateOffer_workflowService/UpdateOffer_workflowService.aod
new file mode 100644
index 0000000000000000000000000000000000000000..a58c778e5c2597c39271a4d9035caddf4285cdbe
--- /dev/null
+++ b/process/UpdateOffer_workflowService/UpdateOffer_workflowService.aod
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1">
+  <name>UpdateOffer_workflowService</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <process>%aditoprj%/process/UpdateOffer_workflowService/process.js</process>
+  <alias>Data_alias</alias>
+  <variants>
+    <element>WORKFLOW</element>
+  </variants>
+</process>
diff --git a/process/UpdateOffer_workflowService/process.js b/process/UpdateOffer_workflowService/process.js
new file mode 100644
index 0000000000000000000000000000000000000000..2dba16a0004ac0bff8542b922bab1c2d9e85e9ab
--- /dev/null
+++ b/process/UpdateOffer_workflowService/process.js
@@ -0,0 +1,15 @@
+import("system.vars");
+import("Sql_lib");
+import("system.db");
+import("KeywordRegistry_basic");
+
+var variables = JSON.parse(vars.get("$local.value"));
+
+if (variables.targetContext && variables.targetContext == "Offer" && variables.targetId)
+{
+    var status = variables.approved || variables.approved == undefined
+        ? $KeywordRegistry.offerStatus$checked()
+        : $KeywordRegistry.offerStatus$open();
+    
+    newWhere("OFFER.OFFERID", variables.targetId).updateFields({"STATUS" : status});
+}
\ No newline at end of file
diff --git a/process/Workflow_lib/process.js b/process/Workflow_lib/process.js
index bd10175d3cb4fc81dcf222df64a2f230249e1c9d..86ccde364efa7d5bb739931f6f45dd0bdb44aab1 100644
--- a/process/Workflow_lib/process.js
+++ b/process/Workflow_lib/process.js
@@ -3,6 +3,7 @@ import("system.neon");
 import("Context_lib");
 import("system.vars");
 import("system.workflow");
+import("KeywordRegistry_basic");
 
 /**
  * functions for working with workflows
@@ -34,15 +35,7 @@ WorkflowUtils.getPossibleWorkflowDefinitions = function (pContext, pAction)
  */
 WorkflowUtils.openNewInstance = function (pVariables, pTargetId, pTargetContext)
 {
-    if (!pVariables)
-        pVariables = {};
-    if (pTargetId === undefined)
-        pTargetId = vars.get("$sys.uid");
-    if (pTargetContext === undefined)
-        pTargetContext = ContextUtils.getCurrentContextId();
-    
-    pVariables.targetId = pTargetId;
-    pVariables.targetContext = pTargetContext;
+    pVariables = WorkflowUtils.appendMandatoryVariables(pVariables, pTargetId, pTargetContext)
     
     neon.openContext("WorkflowInstance", null, null, neon.OPERATINGSTATE_NEW, {
         "ProcessVariables_param" : JSON.stringify(pVariables),
@@ -61,4 +54,61 @@ WorkflowUtils.getPossibleTargetContexts = function ()
         "Offer",
         "Salesproject"
     ];
-}
\ No newline at end of file
+}
+
+WorkflowUtils.appendMandatoryVariables = function (pVariables, pTargetId, pTargetContext)
+{
+    if (!pVariables)
+        pVariables = {};
+    if (pTargetId === undefined)
+        pTargetId = vars.get("$sys.uid");
+    if (pTargetContext === undefined)
+        pTargetContext = ContextUtils.getCurrentContextId();
+    
+    pVariables.targetId = pTargetId;
+    pVariables.targetContext = pTargetContext;
+    
+    return pVariables;
+}
+
+function WorkflowStarter () {}
+
+WorkflowStarter.TRIGGER_INSERT = function ()
+{
+    return $KeywordRegistry.workflowTrigger$create();
+}
+
+WorkflowStarter.TRIGGER_UPDATE = function ()
+{
+    return $KeywordRegistry.workflowTrigger$update();
+}
+
+WorkflowStarter.TRIGGER_DELETE = function ()
+{
+    return $KeywordRegistry.workflowTrigger$delete();
+}
+
+WorkflowStarter.inserted = function (pVariables, pTargetId, pTargetContext)
+{
+    WorkflowStarter._startProcessByAction(WorkflowStarter.TRIGGER_INSERT(), pVariables, pTargetId, pTargetContext);
+}
+
+WorkflowStarter.updated = function (pVariables, pTargetId, pTargetContext)
+{
+    WorkflowStarter._startProcessByAction(WorkflowStarter.TRIGGER_UPDATE(), pVariables, pTargetId, pTargetContext);
+}
+
+WorkflowStarter.deleted = function (pVariables, pTargetId, pTargetContext)
+{
+    WorkflowStarter._startProcessByAction(WorkflowStarter.TRIGGER_DELETE(), pVariables, pTargetId, pTargetContext);
+}
+
+WorkflowStarter._startProcessByAction = function (pAction, pVariables, pTargetId, pTargetContext)
+{
+    pVariables = WorkflowUtils.appendMandatoryVariables(pVariables, pTargetId, pTargetContext);
+    var context = pVariables.targetContext;
+    WorkflowUtils.getPossibleWorkflowDefinitions(context, pAction).forEach(function (processKey)
+    {
+        workflow.startProcessByKey(processKey, pVariables);
+    });
+}