diff --git a/.liquibase/Data_alias/basic/2020.1.2/AddNullableToDateNew.xml b/.liquibase/Data_alias/basic/2020.1.2/AddNullableToDateNew.xml
new file mode 100644
index 0000000000000000000000000000000000000000..86989600807b32fba76fc6b052f08f007cb4f390
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2020.1.2/AddNullableToDateNew.xml
@@ -0,0 +1,13 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+    <changeSet id="0aa81d84-7456-4240-91e0-a915f38abbd7" author="s.pongratz" >
+        <addNotNullConstraint columnName="DATE_NEW" tableName="CAMPAIGNCOST" columnDataType="DATETIME" validate="true"/>
+        <addNotNullConstraint columnName="DATE_NEW" tableName="CAMPAIGNPARTICIPANT" columnDataType="DATETIME" validate="true"/>
+        <addNotNullConstraint columnName="DATE_NEW" tableName="CAMPAIGNSTEP" columnDataType="DATETIME" validate="true"/>
+        <addNotNullConstraint columnName="DATE_NEW" tableName="DOCUMENTTEMPLATELINK" columnDataType="DATETIME" validate="true"/>
+        <addNotNullConstraint columnName="DATE_NEW" tableName="DUPLICATESCANNER" columnDataType="DATETIME" validate="true"/>
+        <addNotNullConstraint columnName="DATE_NEW" tableName="DUPLICATESCANNERRESULTFIELDCONFIG" columnDataType="DATETIME" validate="true"/>
+        <addNotNullConstraint columnName="DATE_NEW" tableName="CAMPAIGN" columnDataType="DATETIME" validate="true"/>
+    </changeSet>
+</databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_ComunicationMedium_IdDatatype.xml b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_ComunicationMedium_IdDatatype.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3e4f1fbd5b8f119ecc58649bab722422cfdf571b
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_ComunicationMedium_IdDatatype.xml
@@ -0,0 +1,7 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+    <changeSet author="b.ulrich" id="a9f53bcd-b541-4a46-bd40-a21f7fae7aba">
+        <modifyDataType columnName="MEDIUM_ID" newDataType="CHAR(36)" tableName="COMMUNICATION"/> 
+    </changeSet>
+</databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_DocumentTemplatePlaceOfUseDatatype.xml b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_DocumentTemplatePlaceOfUseDatatype.xml
new file mode 100644
index 0000000000000000000000000000000000000000..14c64bfefe06b69e868de85bdf8ab9fcd6a093c1
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_DocumentTemplatePlaceOfUseDatatype.xml
@@ -0,0 +1,7 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+    <changeSet author="b.ulrich" id="5a0d5d3f-e849-4584-8082-481b1411d1fc">
+        <modifyDataType columnName="DOCUMENTTEMPLATE_ID" newDataType="CHAR(36)" tableName="DOCUMENTTEMPLATE"/> 
+    </changeSet>
+</databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_ExportTemplateDatatype.xml b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_ExportTemplateDatatype.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7de92277180d51eb97a2cb562328e8e46751b43d
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/alter_ExportTemplateDatatype.xml
@@ -0,0 +1,10 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+    <changeSet author="b.ulrich" id="77ee7dcd-cf5b-47ea-a59a-2b1230fad818">
+        <modifyDataType columnName="EXPORTTEMPLATE_ID" newDataType="CHAR(36)" tableName="EXPORTTEMPLATEPLACEOFUSE"/>
+        <modifyDataType columnName="EXPORTTEMPLATE_ID" newDataType="CHAR(36)" tableName="EXPORTTEMPLATEFIELD"/>
+        <modifyDataType columnName="EXPORTTEMPLATE_ID" newDataType="CHAR(36)" tableName="EXPORTTEMPLATESELECTION"/>
+        
+    </changeSet>
+</databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/changelog.xml b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/changelog.xml
new file mode 100644
index 0000000000000000000000000000000000000000..571beb0ce88383160aafd6aa92cbaa3eac91172f
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2020.1.2/AlterDatatypeOfKeyColumnsToChar/changelog.xml
@@ -0,0 +1,7 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+                   <include relativeToChangelogFile="true" file="alter_DocumentTemplatePlaceOfUseDatatype.xml"/>
+                   <include relativeToChangelogFile="true" file="alter_ExportTemplateDatatype.xml"/>
+                   <include relativeToChangelogFile="true" file="alter_ComunicationMedium_IdDatatype.xml"/>
+</databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2020.1.2/changelog.xml b/.liquibase/Data_alias/basic/2020.1.2/changelog.xml
new file mode 100644
index 0000000000000000000000000000000000000000..98f643b71426d12718ef4175e9569864d3f0574b
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2020.1.2/changelog.xml
@@ -0,0 +1,7 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+    <include file="AlterDocumentTemplatePlaceOfUseDatatype/changelog.xml" relativeToChangelogFile="true"/>
+    <include file="AddNullableToDateNew.xml" relativeToChangelogFile="true" />
+    <include file="insert_workflowCategory_keyword.xml" relativeToChangelogFile="true"/>
+</databaseChangeLog>
diff --git a/.liquibase/Data_alias/changelog.xml b/.liquibase/Data_alias/changelog.xml
index 50c63b65a63025ae582f679ca7b2051471c3fd9e..a8cc53b406959a8797b32a02af71dd93e1576384 100644
--- a/.liquibase/Data_alias/changelog.xml
+++ b/.liquibase/Data_alias/changelog.xml
@@ -13,6 +13,7 @@
     <include relativeToChangelogFile="true" file="basic/2020.0.3/changelog.xml"/>
     <include relativeToChangelogFile="true" file="basic/2020.1.0/changelog.xml"/>
     <include relativeToChangelogFile="true" file="basic/2020.1.1/changelog.xml"/>
+    <include relativeToChangelogFile="true" file="basic/2020.1.2/changelog.xml"/>
     
     <!--enable this only when you definetly want to overwrite the existing data with demo records:--> 
     <!--<include relativeToChangelogFile="true" file="basic/_demoData/changelog.xml" context="example"/>-->
diff --git a/entity/Activity_entity/Activity_entity.aod b/entity/Activity_entity/Activity_entity.aod
index d4c06eaeedeef0b7f545ecd501cc99da61458769..c9558baefe3e2cfb98c86980090279cc36383154 100644
--- a/entity/Activity_entity/Activity_entity.aod
+++ b/entity/Activity_entity/Activity_entity.aod
@@ -611,6 +611,16 @@
       <title> number of connections</title>
       <valueProcess>%aditoprj%/entity/Activity_entity/entityfields/countlinks/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -712,6 +722,15 @@
           <name>entryDateDateFormat.value</name>
           <expression>%aditoprj%/entity/Activity_entity/recordcontainers/db/recordfieldmappings/entrydatedateformat.value/expression.js</expression>
         </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>ACTIVITY.ACTIVITYID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Activity_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/AnyContact_entity/AnyContact_entity.aod b/entity/AnyContact_entity/AnyContact_entity.aod
index 764fffc4fd77721dcdae4ec59576865446464b97..b9e852b3b2ae077b24a41200d051dad37e408a9a 100644
--- a/entity/AnyContact_entity/AnyContact_entity.aod
+++ b/entity/AnyContact_entity/AnyContact_entity.aod
@@ -4,7 +4,7 @@
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <documentation>%aditoprj%/entity/AnyContact_entity/documentation.adoc</documentation>
   <contentTitleProcess>%aditoprj%/entity/AnyContact_entity/contentTitleProcess.js</contentTitleProcess>
-  <afterUiInit>%aditoprj%/entity/AnyContact_entity/afterUiInit.js</afterUiInit>
+  <onInit>%aditoprj%/entity/AnyContact_entity/onInit.js</onInit>
   <imageProcess>%aditoprj%/entity/AnyContact_entity/imageProcess.js</imageProcess>
   <recordContainer>db</recordContainer>
   <entityFields>
diff --git a/entity/Contact_entity/afterUiInit.js b/entity/AnyContact_entity/onInit.js
similarity index 89%
rename from entity/Contact_entity/afterUiInit.js
rename to entity/AnyContact_entity/onInit.js
index ad4324c7682881b8e9ca470e334269ae822ec522..a75a8d405e273b1b3e026251a305676c2ccbd9ad 100644
--- a/entity/Contact_entity/afterUiInit.js
+++ b/entity/AnyContact_entity/onInit.js
@@ -8,7 +8,7 @@ var statusFilterElement = {
         "name":"STATUS",
         "operator":"NOT_EQUAL",
         "key":$KeywordRegistry.contactStatus$inactive(),
-        "contenttype": vars.get("$property.STATUS.contentType")
+        "contenttype": "TEXT"
 };
     
 statusFilterElement.value = KeywordUtils.getViewValue($KeywordRegistry.contactStatus(), statusFilterElement.key);
diff --git a/entity/AttributeUsage_entity/entityfields/date_new/valueProcess.js b/entity/AttributeUsage_entity/entityfields/date_new/valueProcess.js
deleted file mode 100644
index 7acb3c80848f54a4c6dfee5efa7a5b8514dd4a71..0000000000000000000000000000000000000000
--- a/entity/AttributeUsage_entity/entityfields/date_new/valueProcess.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import("system.vars");
-import("system.result");
-import("system.neon");
-
-if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-    result.string(vars.getString("$sys.date"));
\ No newline at end of file
diff --git a/entity/AttributeUsage_entity/entityfields/user_new/valueProcess.js b/entity/AttributeUsage_entity/entityfields/user_new/valueProcess.js
deleted file mode 100644
index a8a5e28793c742f8f3e10907976e746faf43c67c..0000000000000000000000000000000000000000
--- a/entity/AttributeUsage_entity/entityfields/user_new/valueProcess.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import("system.vars");
-import("system.result");
-import("system.neon");
-
-if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-    result.string(vars.getString("$sys.user"));
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/date_new/valueProcess.js b/entity/Attribute_entity/entityfields/date_new/valueProcess.js
deleted file mode 100644
index 7acb3c80848f54a4c6dfee5efa7a5b8514dd4a71..0000000000000000000000000000000000000000
--- a/entity/Attribute_entity/entityfields/date_new/valueProcess.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import("system.vars");
-import("system.result");
-import("system.neon");
-
-if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-    result.string(vars.getString("$sys.date"));
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/keywordattributetype/children/containername_param/valueProcess.js b/entity/Attribute_entity/entityfields/keywordattributetype/children/containername_param/valueProcess.js
deleted file mode 100644
index dc6dfca332983312b5fc1181f8a357c182ac603f..0000000000000000000000000000000000000000
--- a/entity/Attribute_entity/entityfields/keywordattributetype/children/containername_param/valueProcess.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import("system.result");
-import("Keyword_lib");
-import("KeywordRegistry_basic");
-
-result.string($KeywordRegistry.attributeType());
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/user_new/valueProcess.js b/entity/Attribute_entity/entityfields/user_new/valueProcess.js
deleted file mode 100644
index a8a5e28793c742f8f3e10907976e746faf43c67c..0000000000000000000000000000000000000000
--- a/entity/Attribute_entity/entityfields/user_new/valueProcess.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import("system.vars");
-import("system.result");
-import("system.neon");
-
-if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-    result.string(vars.getString("$sys.user"));
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/content/displayValueProcess.js b/entity/BulkMail_entity/entityfields/content/displayValueProcess.js
index 9f3bd46ac569f4ba80d5da76c4f455d8976e1f69..9081043c5eb4d74ae63d2f2f6f947ec6abd4e4b5 100644
--- a/entity/BulkMail_entity/entityfields/content/displayValueProcess.js
+++ b/entity/BulkMail_entity/entityfields/content/displayValueProcess.js
@@ -13,7 +13,7 @@ if (vars.get("$sys.viewmode") == neon.FRAME_VIEWMODE_DATASET && vars.get("$field
     var template = new DocumentTemplate(util.encodeBase64String(vars.get("$field.content")), vars.get("$field.templateType"), undefined, true)
     
     var contactId = EmployeeUtils.getCurrentContactId();
-    var preview = template.getReplacedContentByContactId(contactId, false, true);
+    var preview = template.setOptions({onlyBody : true}).getReplacedContentByContactId(contactId);
     
     result.string(preview);
 }
\ No newline at end of file
diff --git a/entity/CampaignParticipant_entity/entityfields/campaign_id/onValueChange.js b/entity/CampaignParticipant_entity/entityfields/campaign_id/onValueChange.js
index f5f6c5c6594a1a57fb3aaa41b59dfd0768bfc430..07c57c1e196e3db902ee7f56434ab85cdcda55af 100644
--- a/entity/CampaignParticipant_entity/entityfields/campaign_id/onValueChange.js
+++ b/entity/CampaignParticipant_entity/entityfields/campaign_id/onValueChange.js
@@ -2,7 +2,7 @@ import("system.neon");
 import("Campaign_lib");
 import("system.vars");
 
-if(vasr.get("$sys.operatingstate") == neon.OPERATINGSTATE_NEW)
+if(vars.get("$sys.operatingstate") == neon.OPERATINGSTATE_NEW)
 {
     var stepId = CampaignUtils.getDefaultCampaignStep(vars.get("local.value"));
     neon.setFieldValue("$field.CAMPAIGNSTEP_ID", stepId);
diff --git a/entity/CampaignParticipant_entity/entityfields/participantscommrestiction/children/contactid_param/valueProcess.js b/entity/CampaignParticipant_entity/entityfields/participantscommrestiction/children/contactid_param/valueProcess.js
deleted file mode 100644
index f5825a6c09c99e0530939a270bcd81cfbc0c2d5b..0000000000000000000000000000000000000000
--- a/entity/CampaignParticipant_entity/entityfields/participantscommrestiction/children/contactid_param/valueProcess.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import("system.result");
-import("system.vars");
-
-result.string(vars.getString("$field.CONTACT_ID"));
\ No newline at end of file
diff --git a/entity/CampaignParticipant_entity/entityfields/selectedcampaign/onValueChange.js b/entity/CampaignParticipant_entity/entityfields/selectedcampaign/onValueChange.js
deleted file mode 100644
index 2bf64744b6548030c6db0cb825f376192bfdf5e1..0000000000000000000000000000000000000000
--- a/entity/CampaignParticipant_entity/entityfields/selectedcampaign/onValueChange.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import("system.neon");
-
-
-neon.setFieldValue("$field.SYSTEMTEMPLATE", templateId);
\ No newline at end of file
diff --git a/entity/CampaignStep_entity/recordcontainers/db/recordfieldmappings/state.displayvalue/expression.js b/entity/CampaignStep_entity/recordcontainers/db/recordfieldmappings/state.displayvalue/expression.js
deleted file mode 100644
index f0e8a44adee3749dafae8e5cba1b67c52701e01a..0000000000000000000000000000000000000000
--- a/entity/CampaignStep_entity/recordcontainers/db/recordfieldmappings/state.displayvalue/expression.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import("system.result");
-import("Keyword_lib");
-import("KeywordRegistry_basic");
-
-var sql = KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.campaignStepState(), "CAMPAIGNSTEP.STATUS");
-result.string(sql);
\ No newline at end of file
diff --git a/entity/Campaign_entity/Campaign_entity.aod b/entity/Campaign_entity/Campaign_entity.aod
index 670482332006d4df90769fefe39e6f12635b9b99..de16292a1e8c52c655473bcbcc51f4279cd8d74d 100644
--- a/entity/Campaign_entity/Campaign_entity.aod
+++ b/entity/Campaign_entity/Campaign_entity.aod
@@ -521,6 +521,16 @@
       <name>CAMPAIGN_OBEJCTTYPE</name>
       <valueProcess>%aditoprj%/entity/Campaign_entity/entityfields/campaign_obejcttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -618,6 +628,11 @@
           <name>CURRENCY.displayValue</name>
           <expression>%aditoprj%/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/currency.displayvalue/expression.js</expression>
         </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>CAMPAIGN.CAMPAIGNID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/Contact_entity/Contact_entity.aod b/entity/Contact_entity/Contact_entity.aod
index 5c0c8448cd84839a753fd36b32d653fcbfc16827..82c35b3c618ecc933e74b694daa96ad9f97cbfa4 100644
--- a/entity/Contact_entity/Contact_entity.aod
+++ b/entity/Contact_entity/Contact_entity.aod
@@ -8,7 +8,7 @@
   <grantUpdateProcess>%aditoprj%/entity/Contact_entity/grantUpdateProcess.js</grantUpdateProcess>
   <grantDeleteProcess>%aditoprj%/entity/Contact_entity/grantDeleteProcess.js</grantDeleteProcess>
   <contentTitleProcess>%aditoprj%/entity/Contact_entity/contentTitleProcess.js</contentTitleProcess>
-  <afterUiInit>%aditoprj%/entity/Contact_entity/afterUiInit.js</afterUiInit>
+  <onInit>%aditoprj%/entity/Contact_entity/onInit.js</onInit>
   <onValidation>%aditoprj%/entity/Contact_entity/onValidation.js</onValidation>
   <iconId>VAADIN:USERS</iconId>
   <titlePlural>Contacts</titlePlural>
diff --git a/entity/AnyContact_entity/afterUiInit.js b/entity/Contact_entity/onInit.js
similarity index 100%
rename from entity/AnyContact_entity/afterUiInit.js
rename to entity/Contact_entity/onInit.js
diff --git a/entity/Contract_entity/Contract_entity.aod b/entity/Contract_entity/Contract_entity.aod
index cccbd3df7cfeb22642e01140bc30e3d38954e889..fb236573b87078dbed11c50579022ff4e8edbfb8 100644
--- a/entity/Contract_entity/Contract_entity.aod
+++ b/entity/Contract_entity/Contract_entity.aod
@@ -387,6 +387,15 @@
       <name>CONTRACT_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Contract_entity/entityfields/contract_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -524,6 +533,15 @@
           <isFilterable v="true" />
           <filtertype>EXTENDED</filtertype>
         </consumerMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Contract_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>CONTRACT.CONTRACTID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/DocumentTemplate_entity/entityfields/content/displayValueProcess.js b/entity/DocumentTemplate_entity/entityfields/content/displayValueProcess.js
index 56246f908f33ecb844a4444ac3b6e740a69f5bad..d7715c0880e88f57908a1d752d6e4f03e98d69c9 100644
--- a/entity/DocumentTemplate_entity/entityfields/content/displayValueProcess.js
+++ b/entity/DocumentTemplate_entity/entityfields/content/displayValueProcess.js
@@ -17,7 +17,7 @@ if (vars.exists("$context.currentTemplateType"))
         var template = new DocumentTemplate(util.encodeBase64String(vars.get("$field.Content")), type, "unknown", true)
 
         var contactId = EmployeeUtils.getCurrentContactId();
-        var preview = template.getReplacedContentByContactId(contactId, false, true);
+        var preview = template.setOptions({onlyBody : true}).getReplacedContentByContactId(contactId);
 
         if (type == DocumentTemplate.types.TXT)
             result.string(text.text2html(preview, false));
diff --git a/entity/Email_entity/Email_entity.aod b/entity/Email_entity/Email_entity.aod
index 670910b84410344ceb0bc8d6f47d8d1ea5cf3202..fc65d44a8a9fde47fccacef66a19b03e60160dfc 100644
--- a/entity/Email_entity/Email_entity.aod
+++ b/entity/Email_entity/Email_entity.aod
@@ -124,6 +124,10 @@
       <iconId>VAADIN:AT</iconId>
       <stateProcess>%aditoprj%/entity/Email_entity/entityfields/sendmail/stateProcess.js</stateProcess>
     </entityActionField>
+    <entityParameter>
+      <name>AdditionalPlaceholders_param</name>
+      <expose v="true" />
+    </entityParameter>
   </entityFields>
   <recordContainers>
     <datalessRecordContainer>
diff --git a/entity/Email_entity/entityfields/sendmail/onActionProcess.js b/entity/Email_entity/entityfields/sendmail/onActionProcess.js
index 3042a292b76f3871dc01286424cf353a51e85412..a7bdf5af9030a2f9352c7f5ccd597d334995fd35 100644
--- a/entity/Email_entity/entityfields/sendmail/onActionProcess.js
+++ b/entity/Email_entity/entityfields/sendmail/onActionProcess.js
@@ -16,6 +16,16 @@ var notificationMsg = vars.get("$param.NotificationMsg_param");
 var notificationTitle = translate.text("Offer status changed");
 var subject = vars.get("$field.subject");
 
+var additionalPlaceholders = null;
+if (vars.exists("$param.AdditionalPlaceholders_param") && vars.get("$param.AdditionalPlaceholders_param"))
+{
+    additionalPlaceholders = JSON.parse(vars.get("$param.AdditionalPlaceholders_param")).map(function (placeholder)
+    {
+        //assign the values from the JSON to a new Placeholder, so that the resulting object is an actual instance of Placeholder
+        return Object.assign(new Placeholder(), placeholder);
+    });
+}
+
 var eml = EmailWritingUtils.openMailTemplate(
     vars.get("$field.RECIPIENT"), 
     EmployeeUtils.getCurrentContactId(), 
@@ -24,8 +34,9 @@ var eml = EmailWritingUtils.openMailTemplate(
     bindata,
     attachments,
     subject,
-    emailFilename
-    );
+    emailFilename,
+    additionalPlaceholders
+);
 
 
 if (notificationMsg)
diff --git a/entity/ExportTemplateField_entity/entityfields/field/dropDownProcess.js b/entity/ExportTemplateField_entity/entityfields/field/dropDownProcess.js
index f5b8c998801e7aafdb45582d7a566614367a30a2..3c830477d519292b231f502d1caa9cffc392f984 100644
--- a/entity/ExportTemplateField_entity/entityfields/field/dropDownProcess.js
+++ b/entity/ExportTemplateField_entity/entityfields/field/dropDownProcess.js
@@ -9,7 +9,7 @@ import("system.text")
 
     
 var placeholders = PlaceholderUtils.getPlaceholders(null, true).map(function (placeholder){
-    return [placeholder.placeholderName, placeholder.title || placeholder.placeholderName];
+    return [placeholder.getFormattedName(), placeholder.title || placeholder.getFormattedName()];
 })
 
 result.object(placeholders);
\ No newline at end of file
diff --git a/entity/KeywordEntry_entity/KeywordEntry_entity.aod b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
index 1d23aa80c139ba8f466111374bda9a644bdef202..2d0edd64d5ba7e6d9b3e6463f32144b574509094 100644
--- a/entity/KeywordEntry_entity/KeywordEntry_entity.aod
+++ b/entity/KeywordEntry_entity/KeywordEntry_entity.aod
@@ -577,6 +577,12 @@
           <fieldName>KeywordVisitRecommendationPriority</fieldName>
           <isConsumer v="false" />
         </entityDependency>
+        <entityDependency>
+          <name>54410e7f-e5e6-4dd1-8f60-7864ed907aed</name>
+          <entityName>WorkflowDefinition_entity</entityName>
+          <fieldName>CategoryKeyword</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
       </dependencies>
       <children>
         <entityParameter>
diff --git a/entity/Letter_entity/Letter_entity.aod b/entity/Letter_entity/Letter_entity.aod
index 8bab19f92a2debbaf0ff15063e43609467f98db8..42b787aba50fed27e48bcf4adacbb4875786be2a 100644
--- a/entity/Letter_entity/Letter_entity.aod
+++ b/entity/Letter_entity/Letter_entity.aod
@@ -72,6 +72,10 @@
       <state>DISABLED</state>
       <stateProcess>%aditoprj%/entity/Letter_entity/entityfields/downloadletterandcreateactivity/stateProcess.js</stateProcess>
     </entityActionField>
+    <entityParameter>
+      <name>AdditionalPlaceholders_param</name>
+      <expose v="true" />
+    </entityParameter>
   </entityFields>
   <recordContainers>
     <datalessRecordContainer>
diff --git a/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js b/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js
index 840d399140a26629f7d42a2dce81995ac1758d39..0c453f91c3e8e31847be4c6cca575257597a7650 100644
--- a/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js
+++ b/entity/Letter_entity/entityfields/downloadletterandcreateactivity/onActionProcess.js
@@ -6,12 +6,22 @@ import("system.vars");
 import("system.text");
 import("DocumentTemplate_lib");
 import("KeywordRegistry_basic");
+import("Placeholder_lib");
 
 var template = DocumentTemplate.getSelectedTemplate(vars.get("$field.DOCUMENT_TEMPLATE"), new FileUpload(vars.get("$field.bindata")));
 if (template)
 {
     var contactId = vars.get("$param.ContactId_param");
-    var content = template.getReplacedContentByContactId(contactId, true);
+    var additionalPlaceholders = null;
+    if (vars.exists("$param.AdditionalPlaceholders_param") && vars.get("$param.AdditionalPlaceholders_param"))
+    {
+        additionalPlaceholders = JSON.parse(vars.get("$param.AdditionalPlaceholders_param")).map(function (placeholder)
+        {
+            //assign the values from the JSON to a new Placeholder, so that the resulting object is an actual instance of Placeholder
+            return Object.assign(new Placeholder(), placeholder);
+        });
+    }
+    var content = template.setOptions({base64 : true}).getReplacedContentByContactId(contactId, additionalPlaceholders);
     if (template.type)
         neon.download(content, template.filename);
 
diff --git a/entity/ObjectTree_entity/recordcontainers/jdito/contentProcess.js b/entity/ObjectTree_entity/recordcontainers/jdito/contentProcess.js
index 55ac5773b3cb1302c26846d766e066c70d64222f..4ea71164c3cd8f2f93b39be55a3555cbf9b8090a 100644
--- a/entity/ObjectTree_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/ObjectTree_entity/recordcontainers/jdito/contentProcess.js
@@ -234,7 +234,7 @@ function _getEntryData(pObjectId, pDirection, pRelationType1, pRelationType2, pP
     if (pRelationType1 == undefined || pRelationType2 == undefined) 
         return [];
     
-    var [myNum, otherNum] = pDirection == "normal" ? [2, 1] : [1, 2];
+    var [myNum, otherNum] = pDirection == "normal" ? [1, 2] : [2, 1];
     
     onConditionForRelationTypeJoin = newWhere("AB_OBJECTRELATIONTYPEID = AB_OBJECTRELATIONTYPE" + myNum)
         .and("AB_OBJECTRELATION.AB_OBJECTRELATIONTYPE1", pRelationType1)
diff --git a/entity/Offer_entity/Offer_entity.aod b/entity/Offer_entity/Offer_entity.aod
index 11d49333e178a1925bef305a548c2f526aa61a7b..7459007391306a61a14ecf8965aec7edd05d2120 100644
--- a/entity/Offer_entity/Offer_entity.aod
+++ b/entity/Offer_entity/Offer_entity.aod
@@ -1027,6 +1027,16 @@
       <name>OFFER_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/offer_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -1265,6 +1275,15 @@
           <recordfield>OFFER.NET</recordfield>
           <aggregateType>SUM</aggregateType>
         </aggregateFieldDbMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Offer_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>OFFER.OFFER_ID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/Offer_entity/entityfields/offerreportdispatch/children/dispatchofferreport/onActionProcess.js b/entity/Offer_entity/entityfields/offerreportdispatch/children/dispatchofferreport/onActionProcess.js
index fbd11f7034742ee93fa02bf571013cf7cfcafe3a..a5b761ab29d8a43dfb5e9f3aa4a2b19a79bf057c 100644
--- a/entity/Offer_entity/entityfields/offerreportdispatch/children/dispatchofferreport/onActionProcess.js
+++ b/entity/Offer_entity/entityfields/offerreportdispatch/children/dispatchofferreport/onActionProcess.js
@@ -6,9 +6,11 @@ import("system.translate");
 import("Offer_lib");
 import("Email_lib");
 import("Sql_lib");
+import("MimeType_lib");
+import("Placeholder_lib");
 
-var offerReport = new Object();
-var attachmentArray = new Array();
+var offerReport = {};
+var attachmentArray = [];
 var notificationMsg = translate.text("The status of the offer was changed to \"Sent\".");
 var contactId = vars.get("$field.CONTACT_ID");
 var arrayReport = OfferUtils.buildOfferReport(vars.get("$field.OFFERID"));
@@ -17,12 +19,16 @@ var emailFilename = translate.text("Offerrequest");
 if (vars.get("$field.CONTACT_ID") == null || "") contactId = vars.get("$field.CONTACT_ORG_ID");
 
 offerReport.content = arrayReport[1];
-offerReport.contentType = "application/pdf";
+offerReport.contentType = MimeTypes.PDF();
 offerReport.filename = translate.text("Offer No.") + vars.get("$field.#CONTENTTITLE") + ".pdf";
 
 attachmentArray[0] = offerReport;
 
-EmailWritingUtils.sendReportAsMail(contactId, attachmentArray, "Offer", notificationMsg, emailFilename);
+var additionalPlaceholders = [
+    new Placeholder("offerCode", Placeholder.types.FIXEDVALUE, vars.get("$field.FullOfferCode"))
+];
+
+EmailWritingUtils.sendReportAsMail(contactId, attachmentArray, "Offer", notificationMsg, emailFilename, additionalPlaceholders);
 
 newWhere("OFFER.OFFERID", "$field.OFFERID")
     .updateData(true, "OFFER", ["STATUS"], null, [$KeywordRegistry.offerStatus$sent()]);
diff --git a/entity/Order_entity/Order_entity.aod b/entity/Order_entity/Order_entity.aod
index bf6651801aed2c5efdb408ce8a6c8fa9ed737556..7d0429a7cdd20cc0839dd75ea52e8c613c38d2a9 100644
--- a/entity/Order_entity/Order_entity.aod
+++ b/entity/Order_entity/Order_entity.aod
@@ -991,6 +991,16 @@
       <name>ORDER_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Order_entity/entityfields/order_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -1205,6 +1215,15 @@
           <name>ISOLANGUAGE.displayValue</name>
           <expression>%aditoprj%/entity/Order_entity/recordcontainers/db/recordfieldmappings/isolanguage.displayvalue/expression.js</expression>
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Order_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>SALESORDER.SALESORDERID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
     </dbRecordContainer>
     <indexRecordContainer>
diff --git a/entity/Organisation_entity/Organisation_entity.aod b/entity/Organisation_entity/Organisation_entity.aod
index 414ff2eb81e92fcd7606f0e8d6fe8696cb414819..192b93ca8611bc11017333d79470ec8ecbe56d5b 100644
--- a/entity/Organisation_entity/Organisation_entity.aod
+++ b/entity/Organisation_entity/Organisation_entity.aod
@@ -7,7 +7,7 @@
   <title>Company</title>
   <grantDeleteProcess>%aditoprj%/entity/Organisation_entity/grantDeleteProcess.js</grantDeleteProcess>
   <contentTitleProcess>%aditoprj%/entity/Organisation_entity/contentTitleProcess.js</contentTitleProcess>
-  <afterUiInit>%aditoprj%/entity/Organisation_entity/afterUiInit.js</afterUiInit>
+  <onInit>%aditoprj%/entity/Organisation_entity/onInit.js</onInit>
   <afterOperatingState>%aditoprj%/entity/Organisation_entity/afterOperatingState.js</afterOperatingState>
   <iconId>VAADIN:BUILDING</iconId>
   <imageProcess>%aditoprj%/entity/Organisation_entity/imageProcess.js</imageProcess>
@@ -788,7 +788,7 @@
       <title>Turnover Current Year</title>
       <contentType>NUMBER</contentType>
       <outputFormat>#,##0.00€</outputFormat>
-      <groupable v="true" />
+      <groupable v="false" />
       <valueProcess>%aditoprj%/entity/Organisation_entity/entityfields/turnovercurrentyear/valueProcess.js</valueProcess>
     </entityField>
     <entityField>
@@ -796,7 +796,7 @@
       <title>Turnover Last Year</title>
       <contentType>NUMBER</contentType>
       <outputFormat>#,##0.00€</outputFormat>
-      <groupable v="true" />
+      <groupable v="false" />
       <valueProcess>%aditoprj%/entity/Organisation_entity/entityfields/turnoverlastyear/valueProcess.js</valueProcess>
     </entityField>
     <entityField>
@@ -804,6 +804,7 @@
       <title>Turnover change</title>
       <colorProcess>%aditoprj%/entity/Organisation_entity/entityfields/turnoverpercentdiff/colorProcess.js</colorProcess>
       <contentType>TEXT</contentType>
+      <groupable v="false" />
       <valueProcess>%aditoprj%/entity/Organisation_entity/entityfields/turnoverpercentdiff/valueProcess.js</valueProcess>
     </entityField>
     <entityField>
@@ -1106,6 +1107,16 @@
       <name>ORGANISATION_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Organisation_entity/entityfields/organisation_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -1312,6 +1323,15 @@
           <name>STANDARD_ZIP.value</name>
           <recordfield>ADDRESS.ZIP</recordfield>
         </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>ORGANISATION.ORGANISATIONID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Organisation_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/Organisation_entity/afterUiInit.js b/entity/Organisation_entity/onInit.js
similarity index 89%
rename from entity/Organisation_entity/afterUiInit.js
rename to entity/Organisation_entity/onInit.js
index 669f54dbb747c656a7723b9795e3e10875eade5c..b9717583554415c62b48c4ad8304aceb87245938 100644
--- a/entity/Organisation_entity/afterUiInit.js
+++ b/entity/Organisation_entity/onInit.js
@@ -1,30 +1,30 @@
-import("Keyword_lib");
-import("KeywordRegistry_basic");
-import("system.neon");
-import("system.vars");
-import("Context_lib");
-import("Attribute_lib");
-
-var statusFilterElement = {
-        "type":"row",
-        "name":"STATUS",
-        "operator":"NOT_EQUAL",
-        "key":$KeywordRegistry.contactStatus$inactive(),
-        "contenttype": vars.get("$property.STATUS.contentType")
-};
-    
-statusFilterElement.value = KeywordUtils.getViewValue($KeywordRegistry.contactStatus(), statusFilterElement.key);
-    
-var filter = {
-        "type":"group",
-        "operator":"AND",
-        "childs": [statusFilterElement]
-};
-    
-filter = JSON.stringify(filter);
-neon.setFilter("#ENTITY", filter);
-
-if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-{
-    AttributeRelationUtils.presetMandatoryAttributes(ContextUtils.getCurrentContextId(), "Attributes");
-}
+import("Keyword_lib");
+import("KeywordRegistry_basic");
+import("system.neon");
+import("system.vars");
+import("Context_lib");
+import("Attribute_lib");
+
+var statusFilterElement = {
+        "type":"row",
+        "name":"STATUS",
+        "operator":"NOT_EQUAL",
+        "key":$KeywordRegistry.contactStatus$inactive(),
+        "contenttype": "TEXT"
+};
+    
+statusFilterElement.value = KeywordUtils.getViewValue($KeywordRegistry.contactStatus(), statusFilterElement.key);
+    
+var filter = {
+        "type":"group",
+        "operator":"AND",
+        "childs": [statusFilterElement]
+};
+    
+filter = JSON.stringify(filter);
+neon.setFilter("#ENTITY", filter);
+
+if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
+{
+    AttributeRelationUtils.presetMandatoryAttributes(ContextUtils.getCurrentContextId(), "Attributes");
+}
diff --git a/entity/PermissionCalendar_entity/PermissionCalendar_entity.aod b/entity/PermissionCalendar_entity/PermissionCalendar_entity.aod
index 8bd374fd3485951d6ff0cef39ff55d465a66f135..c2faec477ab09d9a7d1b57c5c8f74b8f4bf4fc19 100644
--- a/entity/PermissionCalendar_entity/PermissionCalendar_entity.aod
+++ b/entity/PermissionCalendar_entity/PermissionCalendar_entity.aod
@@ -90,20 +90,22 @@
       <description></description>
       <children>
         <entityActionField>
-          <name>addNewUserPermissionDealerAction</name>
-          <title>Add new User Permission</title>
-          <onActionProcess>%aditoprj%/entity/PermissionCalendar_entity/entityfields/addactions/children/addnewuserpermissiondealeraction/onActionProcess.js</onActionProcess>
+          <name>receiveNewUserPermissionDealerAction</name>
+          <title>Receive new User Permission</title>
+          <onActionProcess>%aditoprj%/entity/PermissionCalendar_entity/entityfields/addactions/children/receivenewuserpermissiondealeraction/onActionProcess.js</onActionProcess>
           <isMenuAction v="true" />
           <isObjectAction v="false" />
           <isSelectionAction v="false" />
+          <iconId>VAADIN:USER</iconId>
           <state>AUTO</state>
           <tooltip></tooltip>
         </entityActionField>
         <entityActionField>
-          <name>addNewDepartmentPermissionDealterAction</name>
-          <title>Add new Department Permission</title>
-          <onActionProcess>%aditoprj%/entity/PermissionCalendar_entity/entityfields/addactions/children/addnewdepartmentpermissiondealteraction/onActionProcess.js</onActionProcess>
+          <name>receiveNewDepartmentPermissionDealterAction</name>
+          <title>Receive new Department Permission</title>
+          <onActionProcess>%aditoprj%/entity/PermissionCalendar_entity/entityfields/addactions/children/receivenewdepartmentpermissiondealteraction/onActionProcess.js</onActionProcess>
           <isObjectAction v="false" />
+          <iconId>VAADIN:GROUP</iconId>
           <state>AUTO</state>
         </entityActionField>
       </children>
diff --git a/entity/PermissionCalendar_entity/entityfields/addactions/children/addnewdepartmentpermissiondealteraction/onActionProcess.js b/entity/PermissionCalendar_entity/entityfields/addactions/children/receivenewdepartmentpermissiondealteraction/onActionProcess.js
similarity index 100%
rename from entity/PermissionCalendar_entity/entityfields/addactions/children/addnewdepartmentpermissiondealteraction/onActionProcess.js
rename to entity/PermissionCalendar_entity/entityfields/addactions/children/receivenewdepartmentpermissiondealteraction/onActionProcess.js
diff --git a/entity/PermissionCalendar_entity/entityfields/addactions/children/addnewuserpermissiondealeraction/onActionProcess.js b/entity/PermissionCalendar_entity/entityfields/addactions/children/receivenewuserpermissiondealeraction/onActionProcess.js
similarity index 100%
rename from entity/PermissionCalendar_entity/entityfields/addactions/children/addnewuserpermissiondealeraction/onActionProcess.js
rename to entity/PermissionCalendar_entity/entityfields/addactions/children/receivenewuserpermissiondealeraction/onActionProcess.js
diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod
index 828766d541a77c594a9f9c4d3daea43416012465..0fd8e2ba840f0db515ebf0fa667d8ad933e05193 100644
--- a/entity/Person_entity/Person_entity.aod
+++ b/entity/Person_entity/Person_entity.aod
@@ -10,7 +10,7 @@
   </siblings>
   <grantDeleteProcess>%aditoprj%/entity/Person_entity/grantDeleteProcess.js</grantDeleteProcess>
   <contentTitleProcess>%aditoprj%/entity/Person_entity/contentTitleProcess.js</contentTitleProcess>
-  <afterUiInit>%aditoprj%/entity/Person_entity/afterUiInit.js</afterUiInit>
+  <onInit>%aditoprj%/entity/Person_entity/onInit.js</onInit>
   <onValidation>%aditoprj%/entity/Person_entity/onValidation.js</onValidation>
   <afterOperatingState>%aditoprj%/entity/Person_entity/afterOperatingState.js</afterOperatingState>
   <iconId>VAADIN:USERS</iconId>
@@ -192,7 +192,7 @@
           <name>ContactId_param</name>
           <valueProcess>%aditoprj%/entity/Person_entity/entityfields/communications/children/contactid_param/valueProcess.js</valueProcess>
           <expose v="false" />
-          <description>This parameter is used for specifing a related &amp;quot;CONTACTID&amp;quot; to a COMMUNICATION-entry. 
+          <description>This parameter is used for specifing a related &amp;quot;CONTACTID&amp;quot; to a COMMUNICATION-entry.
                         Usually this is used for filtering COMMUNICATION-entries by a specified contact or creating a new entry that is related to a contact.</description>
         </entityParameter>
         <entityParameter>
@@ -413,7 +413,7 @@
           <name>ContactId_param</name>
           <valueProcess>%aditoprj%/entity/Person_entity/entityfields/phonecommunications/children/contactid_param/valueProcess.js</valueProcess>
           <expose v="false" />
-          <description>This parameter is used for specifing a related &amp;quot;CONTACTID&amp;quot; to a COMMUNICATION-entry. 
+          <description>This parameter is used for specifing a related &amp;quot;CONTACTID&amp;quot; to a COMMUNICATION-entry.
                         Usually this is used for filtering COMMUNICATION-entries by a specified contact or creating a new entry that is related to a contact.</description>
         </entityParameter>
       </children>
@@ -431,7 +431,7 @@
           <name>ContactId_param</name>
           <valueProcess>%aditoprj%/entity/Person_entity/entityfields/emailcommunications/children/contactid_param/valueProcess.js</valueProcess>
           <expose v="false" />
-          <description>This parameter is used for specifing a related &amp;quot;CONTACTID&amp;quot; to a COMMUNICATION-entry. 
+          <description>This parameter is used for specifing a related &amp;quot;CONTACTID&amp;quot; to a COMMUNICATION-entry.
                         Usually this is used for filtering COMMUNICATION-entries by a specified contact or creating a new entry that is related to a contact.</description>
         </entityParameter>
       </children>
@@ -1270,6 +1270,16 @@
       <name>PERSON_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Person_entity/entityfields/person_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -1555,6 +1565,15 @@
           <name>CONTACTROLE.displayValue</name>
           <expression>%aditoprj%/entity/Person_entity/recordcontainers/db/recordfieldmappings/contactrole.displayvalue/expression.js</expression>
         </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>PERSON.PERSONID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Person_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/Person_entity/afterUiInit.js b/entity/Person_entity/onInit.js
similarity index 89%
rename from entity/Person_entity/afterUiInit.js
rename to entity/Person_entity/onInit.js
index e756cf590afbc22dfff0537787df1a139a3d47ff..1958e327f289481afe51088aa62d5d57af3a782f 100644
--- a/entity/Person_entity/afterUiInit.js
+++ b/entity/Person_entity/onInit.js
@@ -1,30 +1,30 @@
-import("Keyword_lib");
-import("KeywordRegistry_basic");
-import("system.neon");
-import("system.vars");
-import("Context_lib");
-import("Attribute_lib");
-
-var statusFilterElement = {
-        "type":"row",
-        "name":"STATUS",
-        "operator":"NOT_EQUAL",
-        "key":$KeywordRegistry.contactStatus$inactive(),
-        "contenttype": vars.get("$property.STATUS.contentType")
-};
-    
-statusFilterElement.value = KeywordUtils.getViewValue($KeywordRegistry.contactStatus(), statusFilterElement.key);
-    
-var filter = {
-        "type":"group",
-        "operator":"AND",
-        "childs": [statusFilterElement]
-};
-    
-filter = JSON.stringify(filter);
-neon.setFilter("#ENTITY", filter);   
-
-if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-{
-    AttributeRelationUtils.presetMandatoryAttributes(ContextUtils.getCurrentContextId(), "Attributes");
-}
+import("Keyword_lib");
+import("KeywordRegistry_basic");
+import("system.neon");
+import("system.vars");
+import("Context_lib");
+import("Attribute_lib");
+
+var statusFilterElement = {
+        "type":"row",
+        "name":"STATUS",
+        "operator":"NOT_EQUAL",
+        "key":$KeywordRegistry.contactStatus$inactive(),
+        "contenttype": "TEXT"
+};
+    
+statusFilterElement.value = KeywordUtils.getViewValue($KeywordRegistry.contactStatus(), statusFilterElement.key);
+    
+var filter = {
+        "type":"group",
+        "operator":"AND",
+        "childs": [statusFilterElement]
+};
+    
+filter = JSON.stringify(filter);
+neon.setFilter("#ENTITY", filter);   
+
+if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
+{
+    AttributeRelationUtils.presetMandatoryAttributes(ContextUtils.getCurrentContextId(), "Attributes");
+}
diff --git a/entity/Product_entity/Product_entity.aod b/entity/Product_entity/Product_entity.aod
index 54a47d4ae7e5fb27771c8cf09885b29d03fc50fd..5249b9cf120475c26b2fa149835abd91af6918c2 100644
--- a/entity/Product_entity/Product_entity.aod
+++ b/entity/Product_entity/Product_entity.aod
@@ -461,6 +461,16 @@
       <name>PRODUCT_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Product_entity/entityfields/product_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -585,6 +595,15 @@
           <isFilterable v="true" />
           <filtertype>EXTENDED</filtertype>
         </consumerMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Product_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>PRODUCT.PRODUCTID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/Salesproject_entity/Salesproject_entity.aod b/entity/Salesproject_entity/Salesproject_entity.aod
index 0c1444f2e900770553a72960461306354215d863..2c940e34bacc0d967faa57883035456b793503dc 100644
--- a/entity/Salesproject_entity/Salesproject_entity.aod
+++ b/entity/Salesproject_entity/Salesproject_entity.aod
@@ -627,7 +627,7 @@
     <entityField>
       <name>ClassificationResult</name>
       <title>Classification</title>
-      <groupable v="true" />
+      <groupable v="false" />
       <state>READONLY</state>
       <valueProcess>%aditoprj%/entity/Salesproject_entity/entityfields/classificationresult/valueProcess.js</valueProcess>
     </entityField>
@@ -753,6 +753,16 @@
       <name>SALESPROJECT_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Salesproject_entity/entityfields/salesproject_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -880,6 +890,15 @@
           <isFilterable v="true" />
           <isLookupFilter v="true" />
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Salesproject_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>SALESPROJECT.SALESPROJECTID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/SupportTicket_entity/SupportTicket_entity.aod b/entity/SupportTicket_entity/SupportTicket_entity.aod
index 8438598fe4cef2fb64e270de2534fb747a749e9c..ddaf1a5c7ab7000fd94f58b716a22e71487a8f83 100644
--- a/entity/SupportTicket_entity/SupportTicket_entity.aod
+++ b/entity/SupportTicket_entity/SupportTicket_entity.aod
@@ -399,6 +399,16 @@
       <name>SUPPORTTICKET_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/SupportTicket_entity/entityfields/supportticket_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -531,6 +541,15 @@
           <name>TASK_PARENT_CONTEXT.value</name>
           <recordfield>TASK.PARENT_CONTEXT</recordfield>
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/SupportTicket_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>TICKET.TICKETID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
     </dbRecordContainer>
   </recordContainers>
diff --git a/entity/Task_entity/Task_entity.aod b/entity/Task_entity/Task_entity.aod
index aa736a459ee93a5fe679f9fcf01cc8c1a86545a4..14cdb18785867088dbb7220fa1bb33afc7b479a3 100644
--- a/entity/Task_entity/Task_entity.aod
+++ b/entity/Task_entity/Task_entity.aod
@@ -6,7 +6,7 @@
   <title>Task</title>
   <grantDeleteProcess>%aditoprj%/entity/Task_entity/grantDeleteProcess.js</grantDeleteProcess>
   <contentTitleProcess>%aditoprj%/entity/Task_entity/contentTitleProcess.js</contentTitleProcess>
-  <afterUiInit>%aditoprj%/entity/Task_entity/afterUiInit.js</afterUiInit>
+  <onInit>%aditoprj%/entity/Task_entity/onInit.js</onInit>
   <onValidation>%aditoprj%/entity/Task_entity/onValidation.js</onValidation>
   <iconId>VAADIN:TASKS</iconId>
   <iconIdProcess>%aditoprj%/entity/Task_entity/iconIdProcess.js</iconIdProcess>
@@ -453,6 +453,16 @@
       <iconId>VAADIN:CURLY_BRACKETS</iconId>
       <stateProcess>%aditoprj%/entity/Task_entity/entityfields/openadminview/stateProcess.js</stateProcess>
     </entityActionField>
+    <entityField>
+      <name>COUNT</name>
+      <title>Count</title>
+      <contentType>NUMBER</contentType>
+    </entityField>
+    <entityAggregateField>
+      <name>COUNT_aggregate</name>
+      <parentField>COUNT</parentField>
+      <title>Count</title>
+    </entityAggregateField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -570,6 +580,15 @@
           <name>TYPE.value</name>
           <recordfield>TASK.KIND</recordfield>
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>COUNT.value</name>
+          <expression>%aditoprj%/entity/Task_entity/recordcontainers/db/recordfieldmappings/count.value/expression.js</expression>
+        </dbRecordFieldMapping>
+        <aggregateFieldDbMapping>
+          <name>COUNT_aggregate.value</name>
+          <recordfield>TASK.TASKID</recordfield>
+          <aggregateType>COUNT</aggregateType>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
     </dbRecordContainer>
   </recordContainers>
diff --git a/entity/Task_entity/afterUiInit.js b/entity/Task_entity/onInit.js
similarity index 93%
rename from entity/Task_entity/afterUiInit.js
rename to entity/Task_entity/onInit.js
index 566c37e5652d388bc77fea8c23183811a2da9f3c..0a610862cbb9ecae7e44e15eabbc31b0b20eceda 100644
--- a/entity/Task_entity/afterUiInit.js
+++ b/entity/Task_entity/onInit.js
@@ -17,7 +17,7 @@ else if (recordState != neon.OPERATINGSTATE_SEARCH)
         "name":"STATUS",
         "operator":"NOT_EQUAL",
         "key":$KeywordRegistry.taskStatus$ended(),
-        "contenttype": vars.get("$property.STATUS.contentType")
+        "contenttype": "TEXT"
     };
     statusFilterElement.value = KeywordUtils.getViewValue($KeywordRegistry.taskStatus(), statusFilterElement.key);
     
diff --git a/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod b/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
index 8af4e2662c3bff047edbda513cd485ad41cc2295..a7541f1ef80475ff626bbe90efc45fbd1a82dac1 100644
--- a/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
+++ b/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
@@ -7,7 +7,7 @@
   <grantCreateProcess>%aditoprj%/entity/WorkflowDefinition_entity/grantCreateProcess.js</grantCreateProcess>
   <grantDelete v="false" />
   <contentTitleProcess>%aditoprj%/entity/WorkflowDefinition_entity/contentTitleProcess.js</contentTitleProcess>
-  <afterUiInit>%aditoprj%/entity/WorkflowDefinition_entity/afterUiInit.js</afterUiInit>
+  <onInit>%aditoprj%/entity/WorkflowDefinition_entity/onInit.js</onInit>
   <iconId>VAADIN:DROP</iconId>
   <titlePlural>Workflow definitions</titlePlural>
   <recordContainer>jdito</recordContainer>
@@ -35,6 +35,7 @@
           <name>openModeler</name>
           <title>Open modeler</title>
           <onActionProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/tableactions/children/openmodeler/onActionProcess.js</onActionProcess>
+          <isObjectAction v="false" />
           <iconId>VAADIN:EXTERNAL_LINK</iconId>
           <stateProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/tableactions/children/openmodeler/stateProcess.js</stateProcess>
         </entityActionField>
@@ -42,6 +43,7 @@
           <name>createModel</name>
           <title>Create model</title>
           <onActionProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/tableactions/children/createmodel/onActionProcess.js</onActionProcess>
+          <isObjectAction v="false" />
           <iconId>NEON:PLUS</iconId>
         </entityActionField>
       </children>
@@ -49,11 +51,14 @@
     <entityField>
       <name>CATEGORY</name>
       <title>Category</title>
+      <consumer>CategoryKeyword</consumer>
+      <groupable v="true" />
     </entityField>
     <entityField>
       <name>ISACTIVE</name>
       <title>Active</title>
       <contentType>BOOLEAN</contentType>
+      <groupable v="true" />
       <dropDownProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/isactive/dropDownProcess.js</dropDownProcess>
       <stateProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/isactive/stateProcess.js</stateProcess>
     </entityField>
@@ -218,6 +223,20 @@
       <name>WORKFLOWDEFINITION_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/workflowdefinition_objecttype/valueProcess.js</valueProcess>
     </entityField>
+    <entityConsumer>
+      <name>CategoryKeyword</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>KeywordEntry_entity</entityName>
+        <fieldName>SpecificContainerKeywords</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>ContainerName_param</name>
+          <valueProcess>%aditoprj%/entity/WorkflowDefinition_entity/entityfields/categorykeyword/children/containername_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
   </entityFields>
   <recordContainers>
     <jDitoRecordContainer>
@@ -228,6 +247,7 @@
       <contentProcess>%aditoprj%/entity/WorkflowDefinition_entity/recordcontainers/jdito/contentProcess.js</contentProcess>
       <onInsert>%aditoprj%/entity/WorkflowDefinition_entity/recordcontainers/jdito/onInsert.js</onInsert>
       <onUpdate>%aditoprj%/entity/WorkflowDefinition_entity/recordcontainers/jdito/onUpdate.js</onUpdate>
+      <onDelete>%aditoprj%/entity/WorkflowDefinition_entity/recordcontainers/jdito/onDelete.js</onDelete>
       <recordFieldMappings>
         <jDitoRecordFieldMapping>
           <name>UID.value</name>
@@ -242,6 +262,9 @@
           <isFilterable v="true" />
           <isLookupFilter v="true" />
         </jDitoRecordFieldMapping>
+        <jDitoRecordFieldMapping>
+          <name>CATEGORY.displayValue</name>
+        </jDitoRecordFieldMapping>
         <jDitoRecordFieldMapping>
           <name>KEY.value</name>
           <isFilterable v="true" />
diff --git a/entity/WorkflowDefinition_entity/entityfields/categorykeyword/children/containername_param/valueProcess.js b/entity/WorkflowDefinition_entity/entityfields/categorykeyword/children/containername_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..d79eb290d58d4f19fbd534e91b252388749224ce
--- /dev/null
+++ b/entity/WorkflowDefinition_entity/entityfields/categorykeyword/children/containername_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.result");
+import("KeywordRegistry_basic");
+
+result.string($KeywordRegistry.workflowCategory());
\ No newline at end of file
diff --git a/entity/WorkflowDefinition_entity/afterUiInit.js b/entity/WorkflowDefinition_entity/onInit.js
similarity index 100%
rename from entity/WorkflowDefinition_entity/afterUiInit.js
rename to entity/WorkflowDefinition_entity/onInit.js
diff --git a/entity/WorkflowDefinition_entity/recordcontainers/jdito/contentProcess.js b/entity/WorkflowDefinition_entity/recordcontainers/jdito/contentProcess.js
index aff0261cf5187f58d2b66bafd7d223034036e2a4..bec4b9a0b8c4954217e7d33ed77af5640f95311f 100644
--- a/entity/WorkflowDefinition_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/WorkflowDefinition_entity/recordcontainers/jdito/contentProcess.js
@@ -5,6 +5,7 @@ import("system.result");
 import("Workflow_lib");
 import("system.workflow");
 import("JditoFilter_lib");
+import("KeywordData_lib");
 
 //immediately invoked function is used so that a return statement can be utilized to end the function at any point
 result.object((function ()
@@ -16,7 +17,9 @@ result.object((function ()
     var excludeVersion = vars.get("$param.CurrentVersion_param");
     var context = vars.get("$param.Context_param");
     var idvalues = vars.get("$local.idvalues");
-
+    
+    var categoryMap = KeywordData.getKeyIdMap($KeywordRegistry.workflowCategory());
+    
     var workflowDefs;
 
     if (idvalues)
@@ -48,6 +51,7 @@ result.object((function ()
             def.id,
             def.name,
             def.category,
+            categoryMap[def.category] || "",
             def.key,
             def.version,
             def.active,
@@ -73,14 +77,14 @@ result.object((function ()
     {
         filterFn = function (currDef)
         {
-            return newestVersions[currDef[3]] == currDef[4] && (possibleKeysMap ? possibleKeysMap[currDef[3]] : true);
+            return newestVersions[currDef[4]] == currDef[5] && (possibleKeysMap ? possibleKeysMap[currDef[4]] : true);
         };
     }
     else
     {
         filterFn = function (currDef)
         {
-            return excludeVersion != currDef[4];
+            return excludeVersion != currDef[5];
         };
     }
 
diff --git a/entity/WorkflowDefinition_entity/recordcontainers/jdito/onUpdate.js b/entity/WorkflowDefinition_entity/recordcontainers/jdito/onUpdate.js
index 2afd61402ee0fab203bf051660b1c227da1cdfdd..3dcde8317a8ad1ae4767f4e51f12535bb29d9656 100644
--- a/entity/WorkflowDefinition_entity/recordcontainers/jdito/onUpdate.js
+++ b/entity/WorkflowDefinition_entity/recordcontainers/jdito/onUpdate.js
@@ -4,11 +4,14 @@ import("system.workflow");
 import("Document_lib");
 
 var rowdata = vars.get("$local.rowdata");
+var changedFields = vars.get("$local.changed");
 
-if (vars.get("$local.changed").indexOf("ISACTIVE.value") !== -1)
+if (changedFields.includes("ISACTIVE.value"))
     workflow.setProcessActive(rowdata["UID.value"], rowdata["ISACTIVE.value"] == "true");
-    
 
+if (changedFields.includes("CATEGORY.value"))
+    workflow.setProcessDefinitionCategory(rowdata["UID.value"], rowdata["CATEGORY.value"]);
+    
 var upload = new FileUpload(vars.get("$field.FILEUPLOAD"));
 if (upload.isFilled())
 {
diff --git a/entity/WorkflowTask_entity/WorkflowTask_entity.aod b/entity/WorkflowTask_entity/WorkflowTask_entity.aod
index f5bcf9949894d5335e68613b990e62b9066e0208..3ffbe846c77cc3e4d64c7ed734ff2399dc30450a 100644
--- a/entity/WorkflowTask_entity/WorkflowTask_entity.aod
+++ b/entity/WorkflowTask_entity/WorkflowTask_entity.aod
@@ -27,6 +27,7 @@
     </entityField>
     <entityField>
       <name>FORMDEFINITION</name>
+      <valueProcess>%aditoprj%/entity/WorkflowTask_entity/entityfields/formdefinition/valueProcess.js</valueProcess>
     </entityField>
     <entityField>
       <name>FORMRESULT</name>
@@ -257,9 +258,6 @@
           <isFilterable v="true" />
           <isLookupFilter v="true" />
         </jDitoRecordFieldMapping>
-        <jDitoRecordFieldMapping>
-          <name>FORMDEFINITION.value</name>
-        </jDitoRecordFieldMapping>
         <jDitoRecordFieldMapping>
           <name>FORMRESULT.value</name>
         </jDitoRecordFieldMapping>
diff --git a/entity/WorkflowTask_entity/entityfields/formdefinition/valueProcess.js b/entity/WorkflowTask_entity/entityfields/formdefinition/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..8fc3f05f70c0f41c45cc8b15489f265bfd8695d4
--- /dev/null
+++ b/entity/WorkflowTask_entity/entityfields/formdefinition/valueProcess.js
@@ -0,0 +1,9 @@
+import("system.result");
+import("system.vars");
+import("system.workflow");
+import("system.neon");
+
+//the value of this field can be set by the onValueChange process of FORMRESULT
+
+if (vars.get("$this.value") == null)
+    result.string(workflow.getFormProperties(vars.get("$field.UID")));
\ No newline at end of file
diff --git a/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js b/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js
index de6e83f10c3755c6281daacaedff352aeb93ba55..ed15981f641e6ef0941c2d5298ba177b24c8a080 100644
--- a/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/WorkflowTask_entity/recordcontainers/jdito/contentProcess.js
@@ -96,7 +96,6 @@ result.object((function ()
             task.processDefinitionId,
             task.processInstanceId,
             Date.parse(task.createTime).toString(),
-            workflow.getFormProperties(task.id) || "",
             "",
             variables.USER_ID || "",
             task.description || "",
diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
index f32d5f97f0963a35286bac0842e7f823d580201a..ed12fc0f39983f65d9e03fa38e9411b86427147a 100644
--- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
+++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
@@ -6806,6 +6806,24 @@
     <entry>
       <key>Settings</key>
     </entry>
+    <entry>
+      <key>workflow notification</key>
+    </entry>
+    <entry>
+      <key>Permission received</key>
+    </entry>
+    <entry>
+      <key>leadimport notification</key>
+    </entry>
+    <entry>
+      <key>granted permission</key>
+    </entry>
+    <entry>
+      <key>bulk mail sent</key>
+    </entry>
+    <entry>
+      <key>download ready</key>
+    </entry>
     <entry>
       <key>No new recipients found that can be added to the bulk mail.</key>
     </entry>
@@ -6833,6 +6851,12 @@
     <entry>
       <key>send mail</key>
     </entry>
+    <entry>
+      <key>Add new Department Permission</key>
+    </entry>
+     <entry>
+      <key>Add new User Permission</key>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
   <sqlModels>
diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
index 7d8ec08a7b60354c748b9a25bfb6c35dd7a7c297..a4c956a47885f4d1a8c17b2e4c016cc676c2df32 100644
--- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
+++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
@@ -8187,7 +8187,6 @@ Bitte Datumseingabe prüfen</value>
     </entry>
     <entry>
       <key>Send email</key>
-      <value>E-Mail losschicken</value>
     </entry>
     <entry>
       <key>Activites</key>
@@ -8735,40 +8734,68 @@ Bitte Datumseingabe prüfen</value>
       <value>gültig ab (in </value>
     </entry>
     <entry>
-      <key>No new recipients found that can be added to the bulk mail.</key>
-      <value>Keine neuen Empfänger, die zur Serienmail hinzugefügt werden können, gefunden.</value>
+      <key>workflow notification</key>
     </entry>
     <entry>
-      <key>Add Recipients</key>
-      <value>Empfänger hinzufügen</value>
+      <key>Permission received</key>
+      <value>erhaltene Berechtigung</value>
     </entry>
     <entry>
-      <key>Add Participants</key>
-      <value>Teilnehmer hinzufügen</value>
+      <key>leadimport notification</key>
     </entry>
     <entry>
-      <key>Download letter and create Activity</key>
-      <value>Brief herunterladen und Aktivität erstellen</value>
+      <key>granted permission</key>
+      <value>vergebene Berechtigung</value>
     </entry>
     <entry>
-      <key>and open Report</key>
-      <value>und Report öffnen</value>
+      <key>bulk mail sent</key>
     </entry>
     <entry>
-      <key>export</key>
+      <key>download ready</key>
     </entry>
     <entry>
-      <key>export using the selected  template</key>
-      <value>Mit der ausgewählten Vorlage Exportieren</value>
+      <key>Receive new Department Permission</key>
+      <value>Neue Abteilungs-Berechtigung erhalten</value>
+    </entry>
+    <entry>
+      <key>Receive new User Permission</key>
+      <value>Neue Benutzer-Berechtigung erhalten</value>
+    </entry>
+    <entry>
+      <key>export</key>
     </entry>
     <entry>
       <key>No new recipients found that can be added to the serial letter.</key>
       <value>Keine neuen Empfänger, die zum  Serienbrief werden können, gefunden.</value>
     </entry>
+    <entry>
+      <key>No new recipients found that can be added to the bulk mail.</key>
+      <value>Keine neuen Empfänger, die zur Serienmail hinzugefügt werden können, gefunden.</value>
+    </entry>
+    <entry>
+      <key>export using the selected  template</key>
+      <value>Mit der ausgewählten Vorlage Exportieren</value>
+    </entry>
     <entry>
       <key>send mail</key>
       <value>E-Mail losschicken</value>
     </entry>
+    <entry>
+      <key>Download letter and create Activity</key>
+      <value>Brief herunterladen und Aktivität erstellen</value>
+    </entry>
+    <entry>
+      <key>Add Participants</key>
+      <value>Teilnehmer hinzufügen</value>
+    </entry>
+    <entry>
+      <key>and open Report</key>
+      <value>und Report öffnen</value>
+    </entry>
+    <entry>
+      <key>Add Recipients</key>
+      <value>Empfänger hinzufügen</value>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
 </language>
diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
index 40c367a50dbcf0c18340e45272f77ed124779931..f795919fd82d323b6293b5b6ada7effe00920d07 100644
--- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
+++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
@@ -6872,6 +6872,24 @@
     <entry>
       <key>Settings</key>
     </entry>
+    <entry>
+      <key>workflow notification</key>
+    </entry>
+    <entry>
+      <key>Permission received</key>
+    </entry>
+    <entry>
+      <key>leadimport notification</key>
+    </entry>
+    <entry>
+      <key>granted permission</key>
+    </entry>
+    <entry>
+      <key>bulk mail sent</key>
+    </entry>
+    <entry>
+      <key>download ready</key>
+    </entry>
     <entry>
       <key>No new recipients found that can be added to the bulk mail.</key>
     </entry>
@@ -6899,6 +6917,12 @@
     <entry>
       <key>send mail</key>
     </entry>
+    <entry>
+      <key>Receive new Department Permission</key>
+    </entry>
+    <entry>
+      <key>Receive new User Permission</key>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
 </language>
diff --git a/neonView/ActivityFilter_view/ActivityFilter_view.aod b/neonView/ActivityFilter_view/ActivityFilter_view.aod
index 09f94a720facdac4607c2410d50b3fe9ddcaf64f..0d59f1b7b3c98f9bf630fee21e641c2801b5022b 100644
--- a/neonView/ActivityFilter_view/ActivityFilter_view.aod
+++ b/neonView/ActivityFilter_view/ActivityFilter_view.aod
@@ -116,5 +116,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>fce2e978-e34d-4c6d-84f0-94d698ae793e</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/CampaignFilter_view/CampaignFilter_view.aod b/neonView/CampaignFilter_view/CampaignFilter_view.aod
index a30c1ab9f1f355ef861347d260fd2e120700499d..0dcb198305db9a4021ace200c99df40b0018904d 100644
--- a/neonView/CampaignFilter_view/CampaignFilter_view.aod
+++ b/neonView/CampaignFilter_view/CampaignFilter_view.aod
@@ -128,5 +128,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>945f1bdd-ae16-4f02-b3ec-d7bdd331adf0</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/ContractFilter_view/ContractFilter_view.aod b/neonView/ContractFilter_view/ContractFilter_view.aod
index f92d2bd17a33c1a20b623fd4e43c14114962124e..b43c2f7fa56d7f2d30204d9369376914532022b8 100644
--- a/neonView/ContractFilter_view/ContractFilter_view.aod
+++ b/neonView/ContractFilter_view/ContractFilter_view.aod
@@ -116,5 +116,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>5c0ec615-90ec-460b-b63f-bd4939ac3e09</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/OfferFilter_view/OfferFilter_view.aod b/neonView/OfferFilter_view/OfferFilter_view.aod
index 28fb45b5ae0dc0f8a90f1205e21d0d28f7c25652..0a1ab5740c5a8ae675bc91f798159175c3fdee75 100644
--- a/neonView/OfferFilter_view/OfferFilter_view.aod
+++ b/neonView/OfferFilter_view/OfferFilter_view.aod
@@ -136,5 +136,31 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChartCount</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>4bbc9650-47fd-4a59-8e1e-bb60ceb85795</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChartSum</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Total in euros</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>e5d14506-5205-43d0-89cb-416bf6debd25</name>
+          <entityField>NET</entityField>
+          <aggregateEntityField>NET_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/OrderFilter_view/OrderFilter_view.aod b/neonView/OrderFilter_view/OrderFilter_view.aod
index 6c1a61083eee585b71fe7f577ebac63b47d25263..8986ad83d38ead3ea35912d1be6ddfa5f3068bbc 100644
--- a/neonView/OrderFilter_view/OrderFilter_view.aod
+++ b/neonView/OrderFilter_view/OrderFilter_view.aod
@@ -120,5 +120,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>b4aa7cf1-5e25-4042-9430-b54a22dd83cf</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/OrganisationFilter_view/OrganisationFilter_view.aod b/neonView/OrganisationFilter_view/OrganisationFilter_view.aod
index 960c454e103af41d7e9cf5740ae51aec1b1047f5..1cc87b9732a33851587d07a0ca3950c4d1c8d8c1 100644
--- a/neonView/OrganisationFilter_view/OrganisationFilter_view.aod
+++ b/neonView/OrganisationFilter_view/OrganisationFilter_view.aod
@@ -134,5 +134,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>52be5c1a-4e19-4f03-862b-a9d68e15778f</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/PermissionCalendarFilterDrawer_view/PermissionCalendarFilterDrawer_view.aod b/neonView/PermissionCalendarFilterDrawer_view/PermissionCalendarFilterDrawer_view.aod
index 32b319f4445dd4838b972b11db7c6193c7833b35..bea5b5d3b4c83c14236e3e3ee1164389370c87fd 100644
--- a/neonView/PermissionCalendarFilterDrawer_view/PermissionCalendarFilterDrawer_view.aod
+++ b/neonView/PermissionCalendarFilterDrawer_view/PermissionCalendarFilterDrawer_view.aod
@@ -5,7 +5,7 @@
   <layout>
     <drawerLayout>
       <name>layout</name>
-      <layoutCaption>of other on this employee's calendar</layoutCaption>
+      <layoutCaption>Permission received</layoutCaption>
       <fixedDrawer v="true" />
     </drawerLayout>
   </layout>
diff --git a/neonView/PermissionCalendarFilterReverse_view/PermissionCalendarFilterReverse_view.aod b/neonView/PermissionCalendarFilterReverse_view/PermissionCalendarFilterReverse_view.aod
index df480a219c345fe0847a2ebdf5c5f62479108e60..ae077ac28d6a0d93a8073361d0467f7abc3a6478 100644
--- a/neonView/PermissionCalendarFilterReverse_view/PermissionCalendarFilterReverse_view.aod
+++ b/neonView/PermissionCalendarFilterReverse_view/PermissionCalendarFilterReverse_view.aod
@@ -7,12 +7,14 @@
   <layout>
     <drawerLayout>
       <name>layout</name>
-      <layoutCaption>of this employee on the calendar of others</layoutCaption>
+      <layoutCaption>granted permission</layoutCaption>
+      <fixedDrawer v="true" />
     </drawerLayout>
   </layout>
   <children>
     <tableViewTemplate>
       <name>PermissionCalendarFilterReverseTable</name>
+      <favoriteActionGroup1>AddReverseAction</favoriteActionGroup1>
       <entityField>#ENTITY</entityField>
       <isCreatable v="false" />
       <isDeletable v="false" />
diff --git a/neonView/PersonFilter_view/PersonFilter_view.aod b/neonView/PersonFilter_view/PersonFilter_view.aod
index 3de6433f11f0721a7a9d21644f7201c33dd0c364..8eaea8f8294ba09c4a94f70dc4b0930a20357b0c 100644
--- a/neonView/PersonFilter_view/PersonFilter_view.aod
+++ b/neonView/PersonFilter_view/PersonFilter_view.aod
@@ -148,5 +148,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>79379ca4-70f2-40c9-8af2-05cbe26e8916</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/ProductFilter_view/ProductFilter_view.aod b/neonView/ProductFilter_view/ProductFilter_view.aod
index 3f86ddd7ed38a5909124edfb0004546921b8305e..87133854a0bf04645764e64768e6037d069b48b9 100644
--- a/neonView/ProductFilter_view/ProductFilter_view.aod
+++ b/neonView/ProductFilter_view/ProductFilter_view.aod
@@ -117,5 +117,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>8e435e30-bd06-4172-81ea-4cd40cb835f2</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod b/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod
index 920128f5ff6cb8f4bb2f8378f524c6b4528e3240..6bfac93548e2b901c3d7952818fa6d21bb0c987a 100644
--- a/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod
+++ b/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod
@@ -136,5 +136,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>170e3be6-41e5-4e75-b772-a97312e83268</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/SupportTicketFilter_view/SupportTicketFilter_view.aod b/neonView/SupportTicketFilter_view/SupportTicketFilter_view.aod
index ed3af83d74e6237cd4298704707bde0e2f485502..f233e247a8ea243775ec164648f5d61952f791fd 100644
--- a/neonView/SupportTicketFilter_view/SupportTicketFilter_view.aod
+++ b/neonView/SupportTicketFilter_view/SupportTicketFilter_view.aod
@@ -139,5 +139,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>43e0d3fc-2556-4da9-985f-f46919755ebf</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/TaskFilter_view/TaskFilter_view.aod b/neonView/TaskFilter_view/TaskFilter_view.aod
index 83268457a49e851f0329c787d3b4e498adb9a620..e42baf0ab3dbc846a09889295e65fd2bf9e2df07 100644
--- a/neonView/TaskFilter_view/TaskFilter_view.aod
+++ b/neonView/TaskFilter_view/TaskFilter_view.aod
@@ -135,5 +135,18 @@
         </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
+    <dynamicMultiDataChartViewTemplate>
+      <name>DynamicMultiDataChart</name>
+      <chartType>COLUMN</chartType>
+      <yAxisLabel>Count</yAxisLabel>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>aad9359c-9d5c-480e-9671-68933a08d615</name>
+          <entityField>COUNT</entityField>
+          <aggregateEntityField>COUNT_aggregate</aggregateEntityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
   </children>
 </neonView>
diff --git a/neonView/WorkflowDefinitionFilter_view/WorkflowDefinitionFilter_view.aod b/neonView/WorkflowDefinitionFilter_view/WorkflowDefinitionFilter_view.aod
index a4e33a131b80ffae09321355f1d9a5f6e4d9f621..41ffef96290756599469bfd2da5878612c27a6d2 100644
--- a/neonView/WorkflowDefinitionFilter_view/WorkflowDefinitionFilter_view.aod
+++ b/neonView/WorkflowDefinitionFilter_view/WorkflowDefinitionFilter_view.aod
@@ -9,32 +9,6 @@
     </groupLayout>
   </layout>
   <children>
-    <tableViewTemplate>
-      <name>Table</name>
-      <favoriteActionGroup1>tableActions</favoriteActionGroup1>
-      <entityField>#ENTITY</entityField>
-      <linkedColumns>
-        <element>NAME</element>
-      </linkedColumns>
-      <columns>
-        <neonTableColumn>
-          <name>6a40b78d-422e-4b3f-9d94-c330cf51996d</name>
-          <entityField>NAME</entityField>
-        </neonTableColumn>
-        <neonTableColumn>
-          <name>5d90aabb-74a9-40f2-bb57-6bf9e5302ed3</name>
-          <entityField>CATEGORY</entityField>
-        </neonTableColumn>
-        <neonTableColumn>
-          <name>faf08eb7-7076-4872-975d-c38a399a1b98</name>
-          <entityField>VERSION</entityField>
-        </neonTableColumn>
-        <neonTableColumn>
-          <name>1e1ed75f-a1de-4abb-b81e-6033de520f32</name>
-          <entityField>ISACTIVE</entityField>
-        </neonTableColumn>
-      </columns>
-    </tableViewTemplate>
     <tilesViewTemplate>
       <name>Tiles</name>
       <iconField>DIAGRAM</iconField>
@@ -42,6 +16,7 @@
       <subtitleField>KEY</subtitleField>
       <descriptionField>DESCRIPTION</descriptionField>
       <infoTopField>VERSION_TITLE</infoTopField>
+      <infoBottomField>CATEGORY</infoBottomField>
       <favoriteActionGroup1>tableActions</favoriteActionGroup1>
       <entityField>#ENTITY</entityField>
       <isCreatable v="true" />
diff --git a/neonView/WorkflowDefinitionPreview_view/WorkflowDefinitionPreview_view.aod b/neonView/WorkflowDefinitionPreview_view/WorkflowDefinitionPreview_view.aod
index 0d2cd4622489b17425f3bea8fdd6e426d73e9186..a9c11e5e24128bb9893b34475596d7d4f7b81292 100644
--- a/neonView/WorkflowDefinitionPreview_view/WorkflowDefinitionPreview_view.aod
+++ b/neonView/WorkflowDefinitionPreview_view/WorkflowDefinitionPreview_view.aod
@@ -42,6 +42,10 @@
           <name>9ae7bada-afb2-48d4-9aa0-b2bd5bd17379</name>
           <entityField>ISACTIVE</entityField>
         </entityFieldLink>
+        <entityFieldLink>
+          <name>f5a0addd-becc-4c4f-b381-65612127acaf</name>
+          <entityField>CATEGORY</entityField>
+        </entityFieldLink>
         <entityFieldLink>
           <name>6b06cf99-37b1-4901-a502-81bb590faa92</name>
           <entityField>DESCRIPTION</entityField>
diff --git a/process/Address_lib/process.js b/process/Address_lib/process.js
index d68036c8e52c9e9d3b2248892b57a104eced03bb..ecd34ddbbcc7821e3781a340ba8e55588bfcb4ea 100644
--- a/process/Address_lib/process.js
+++ b/process/Address_lib/process.js
@@ -168,12 +168,12 @@ function fetchAddressData( pCondition, pConfig, AddressID, pPerson)
                 case Placeholder.types.SQLPART: //sql part
                     fields.push( pConfig[i].valueDefinition ); 
                     output.push([pos++, pConfig[i].type]);
-                    header.push( pConfig[i].placeholderName );
+                    header.push( pConfig[i].getFormattedName() );
                     break;
                 case Placeholder.types.SQLPARTFUNCTION: // adito SQL functions
                     fields.push("(" + pConfig[i].valueDefinition.call() + ")");
                     output.push([pos++, pConfig[i].type]);
-                    header.push( pConfig[i].placeholderName );
+                    header.push( pConfig[i].getFormattedName() );
                     break;
                 case Placeholder.types.ADDRESSFORMAT:
                     if ( posaddrfields == -1 )
@@ -184,7 +184,7 @@ function fetchAddressData( pCondition, pConfig, AddressID, pPerson)
                         pos += addrfields.length;								
                     }
                     output.push([posaddrfields, pConfig[i].type, pConfig[i].valueDefinition]);
-                    header.push( pConfig[i].placeholderName );
+                    header.push( pConfig[i].getFormattedName() );
                     break;
                     
                 case "afunction": // adito functions
@@ -192,7 +192,7 @@ function fetchAddressData( pCondition, pConfig, AddressID, pPerson)
                     {
                         fields.push( "'" + evalScript("Address_lib.fetchAddressData", vars.resolveVariables(pConfig[i].valueDefinition), {}, ["Attribute_lib", "Sql_lib", "Keyword_lib", "Person_lib"], true).replace(new RegExp("'","g"), "''") + "'" ); 
                         output.push([pos++, pConfig[i].type]);
-                        header.push( pConfig[i].placeholderName );
+                        header.push( pConfig[i].getFormattedName() );
                     }
                     catch( err )
                     {                      
@@ -209,7 +209,7 @@ function fetchAddressData( pCondition, pConfig, AddressID, pPerson)
                         configJSON.localVars]);
                                     
                     output.push([pos++, pConfig[i].type]);
-                    header.push( pConfig[i].placeholderName );                
+                    header.push( pConfig[i].getFormattedName() );                
                     break;
             }
         }
diff --git a/process/AttributeFilter_lib/process.js b/process/AttributeFilter_lib/process.js
index 5b093fee0e2d95cd7ccb60bf5851513fcc3f7e74..f64477390ffc247d5e6fd9768f2840dae133c1e1 100644
--- a/process/AttributeFilter_lib/process.js
+++ b/process/AttributeFilter_lib/process.js
@@ -1,3 +1,4 @@
+import("Util_lib");
 import("system.SQLTYPES");
 import("system.translate");
 import("Entity_lib");
diff --git a/process/Context_lib/process.js b/process/Context_lib/process.js
index 83ad817a1b9487b240e512d26d127e7f2b6a74e8..59bed651862041d08e72db34ad3256cab51d8acc 100644
--- a/process/Context_lib/process.js
+++ b/process/Context_lib/process.js
@@ -593,20 +593,6 @@ ContextUtils.getSelectMap  = function()
                             $KeywordRegistry.taskStatus$customerChecks(),
                         ])
                         .setCreationDateField("TASK.START_DATE")
-            ,"SupportTicket": ContextSelector.create("TICKET", "TICKETID", "TASK.SUBJECT")
-                        .setJoinExpression("left join TASK on TASK.TASKID = TICKET.TASK_ID left join TASKLINK on TASKLINK.TASK_ID = TASK.TASKID")
-                        .setCondition(newWhere("TICKET.TICKETTYPE", $KeywordRegistry.ticketType$supportTicket()))
-                        .setContactIdField("TASKLINK.OBJECT_ROWID")
-                        .setStateField("TASK.STATUS")
-                        .setActiveStates([
-                            $KeywordRegistry.taskStatus$new(),
-                            $KeywordRegistry.taskStatus$unassigned(),
-                            $KeywordRegistry.taskStatus$assigned(),
-                            $KeywordRegistry.taskStatus$inProgress(),
-                            $KeywordRegistry.taskStatus$waiting(),
-                            $KeywordRegistry.taskStatus$customerChecks(),
-                        ])
-                        .setCreationDateField("TASK.START_DATE")
             ,"BulkMail" : ContextSelector.create("BULKMAIL", "BULKMAILID", "NAME")
             ,"SerialLetter" : ContextSelector.create("SERIALLETTER", "SERIALLETTERID", "TITLE")
             ,"Leadimport": ContextSelector.create("LEADIMPORT", "LEADIMPORTID")
diff --git a/process/DocumentTemplate_lib/DocumentTemplate_lib.aod b/process/DocumentTemplate_lib/DocumentTemplate_lib.aod
index 9f4fede55f117c4fea142e84087e26eb4bd91be1..f7dede09487b8661444e1673ef88ecca8b415c21 100644
--- a/process/DocumentTemplate_lib/DocumentTemplate_lib.aod
+++ b/process/DocumentTemplate_lib/DocumentTemplate_lib.aod
@@ -2,6 +2,7 @@
 <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>DocumentTemplate_lib</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
+  <documentation>%aditoprj%/process/DocumentTemplate_lib/documentation.adoc</documentation>
   <process>%aditoprj%/process/DocumentTemplate_lib/process.js</process>
   <variants>
     <element>LIBRARY</element>
diff --git a/process/DocumentTemplate_lib/documentation.adoc b/process/DocumentTemplate_lib/documentation.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..547a9f00eb224a20d88876f161c2f94cc8088230
--- /dev/null
+++ b/process/DocumentTemplate_lib/documentation.adoc
@@ -0,0 +1,76 @@
+= DocumentTemplate
+
+This document explains the functions of the class `DocumentTemplate` and how to use it. Note that it does not cover every single method with the respective parameters in detail.
+
+== Introduction
+
+A DocumentTemplate is a template for generating individualized documents by filling the placeholders inside the template with data. It supports the following file types and formats:
+
+* txt
+* html
+* eml
+* odt
+* docx
+* docm
+* simple strings
+
+== Usage
+
+=== Creating a new DocumentTemplate instance
+
+The most basic way to create a DocumentTemplate is by simply using the constructor, for example:
+[source,js]
+----
+var myTemplate = new DocumentTemplate(myEncodedHtml, DocumentTemplate.types.HTML);
+----
+
+The parameters `pTemplateContent` and `pType` are mandatory, the others are not required for every use case. A new instance of DocumentTemplate can also be created by using these static functions for special situations:
+
+* *DocumentTemplate.fromUpload:* Constructs a template from the given FileUpload object.
+* *DocumentTemplate.loadTemplate:* Creates a template from a document stored in the database.
+
+=== Generating a document and filling placeholders
+
+Placeholders can be replaced by invoking the method `.getReplacedContent`. It only takes one parameter `pReplacements` which has to be an object with the placeholder as keys and the replacement data as values, like this:
+[source,js]
+----
+var replacements = {
+    "{@firstname@}" : "Joseph",
+    "{@lastname@}" : "Juster"
+};
+var myContent = myTemplate.getReplacedContent(replacements);
+----
+
+It's also possible to use contact data with the functions `.getReplacedContentByContactId` (for a single contactId) and `.getReplacedContentByContactIds` (for multiple contactIds at once). If these functions are used, all placeholders defined in the libraries `Placeholder_lib` and `CustomPlaceholder_lib` are available.
+To add extra placeholders that are not necessarily related to the contact, you can put them in the parameter `pAdditionalPlaceholders` which has to be an array of Placeholder objects. For placeholders unrelated to contact data, use these Placeholder types:
+
+* *FIXEDVALUE:* A fixed value that is stored inside the Placeholder object, useful for data that is already available when you define the placeholder (e. g. entity fields).
+* *CALLBACKFUNCTION:* A callback-function inside the Placeholder object that returns the replacement value, it will be called with the contactId as first argument. You can use this type to resolve the placeholder depending on the contactId or to avoid unnecessary code execution because the function will only be called if the placeholder is actually used inside the template.
+
+Here's an example for the usage of `pAdditionalPlaceholders`:
+[source,js]
+----
+var getProductCountFn = function (pContactId)
+{
+    ... //fancy code
+}
+var additionalPlaceholders = [
+    new Placeholder("offercode", Placeholder.types.FIXEDVALUE, vars.get("$field.FullOfferCode")),
+    new Placeholder("productCount", Placeholder.types.CALLBACKFUNCTION, getProductCountFn)
+];
+var myContent = myTemplate.getReplacedContentByContactId(vars.get("$field.CONTACTID"), additionalPlaceholders);
+----
+
+=== Document generation options
+
+Some aspects of the behavior of the document generation can be controlled by setting the `options` property of the DocumentTemplate with `.setOptions`. Available options differ depending on the DocumentTemplate type, that's why the options are wrapped inside an object. These options can currently be used:
+[%header,cols="1,3,2"]
+|===
+| Option | Description | Supported types
+| base64 | Controls if the replaced content will be base64-encoded | txt, html, eml
+| onlyBody | If set to true, only the body of an eml will be used as content | eml
+|===
+
+When a new DocumentTemplate is created, a default set of options will be loaded depending on the type.
+
+//TODO: explain subtemplates, serial letters, (bulk-)emails
\ No newline at end of file
diff --git a/process/DocumentTemplate_lib/process.js b/process/DocumentTemplate_lib/process.js
index ae3c193044abef89337c2be2e823dc4020ce1008..4ced5f9f03a66cdd93fd5b3836ab474107fa8017 100644
--- a/process/DocumentTemplate_lib/process.js
+++ b/process/DocumentTemplate_lib/process.js
@@ -29,14 +29,6 @@ import("Util_lib");
  * Object for working with document templates, holds the content and type of the template.
  * Provides functions to replace placeholders in the content.
  * 
- * @class
- */
-var DocumentTemplate = (function ()
-{
-
-/**
- * constructor for DocumentTemplate
- * 
  * @param {String} pTemplateContent content, as base64 string (except for DocumentTemplate.types.PLAIN, then it's a normal string)
  * @param {String} pType type of the template, use the DocumentTemplate.types constants here
  * @param {String} [pFilename=undefined] file name of the template 
@@ -44,19 +36,24 @@ var DocumentTemplate = (function ()
  * @param {String} [pTemplateId=undefined] Provide it, if you have it, because this enables the template to load attachments associated by this ID
  * @param {String} [pMimeType=undefined] mimetype of the content. Only an additional information. Not mandatory.
  */
-function DocumentTemplate(pTemplateContent, pType, pFilename, pResolveSubtemplates, pTemplateId, pMimeType)
+function DocumentTemplate (pTemplateContent, pType, pFilename, pResolveSubtemplates, pTemplateId, pMimeType)
 {
     this.content = pTemplateContent;
     this.type = pType;
+    this.options = DocumentTemplate.types.getDefaultTypeOptions(pType);
     this.filename = pFilename;
     this.templateId = pTemplateId;
     this.mimeType = pMimeType;
-    this._stringCache = null;
     this._attachmentCache = null;
-    this._subtemplatedContent = null;
+    this._subtemplateResolvedContent = null;
+    //cache used for .toString
+    this._stringCache = {
+        onlyContent : null,
+        withSubtemplatesResolved : null
+    };
     
     if (pResolveSubtemplates)
-        this._resolveEmbeddedTemplate();
+        this._resolveSubtemplates();
 }
 
 /**
@@ -64,18 +61,40 @@ function DocumentTemplate(pTemplateContent, pType, pFilename, pResolveSubtemplat
  */
 DocumentTemplate.prototype.toString = function (pWithSubtemplates)
 {    
-    if (this._stringCache == null)
+    var stringCachePosition = pWithSubtemplates ? "withSubtemplatesResolved" : "onlyContent";
+    if (this._stringCache[stringCachePosition] == null)
     {
-        var content = this._getTemplatedContent(pWithSubtemplates);
+        var content = pWithSubtemplates && this._subtemplateResolvedContent || this.content;
         if (this.type == DocumentTemplate.types.PLAIN)
-            this._stringCache = content;
+            this._stringCache[stringCachePosition] = content;
         else
-            this._stringCache = text.parseDocument(content);
+            this._stringCache[stringCachePosition] = text.parseDocument(content);
     }
-    return this._stringCache;
+    return this._stringCache[stringCachePosition];
 }
 
-DocumentTemplate.prototype._resolveEmbeddedTemplate = function ()
+/**
+ * Defines options for the DocumentTemplate, the given options will be appended to the existing options and options that 
+ * already exist will be overridden. The options that can be used may vary depending on the type of the DocumentTemplate, 
+ * that's why they are wrapped inside an object.
+ * 
+ * @param {Object} pOptions The options to set for the object. Some options only affect special types, for example:
+ *      <ul>
+ *          <li>base64 (boolean): If the replaced content should be base 64 encoded (does not work for docx and odt, these are always encoded)</li>
+ *          <li>onlyBody (boolean): If set to true, only use the body of an eml (option only for eml)</li>
+ *      </ul>
+ * @return {DocumentTemplate} current object
+ */
+DocumentTemplate.prototype.setOptions = function (pOptions)
+{
+    Object.assign(this.options, pOptions);
+    return this;
+}
+
+/**
+ * resolves sub-template placeholders
+ */
+DocumentTemplate.prototype._resolveSubtemplates = function ()
 {
     // currently we support only txt and html as others would need special caution.
     if (this.content != null && (this.type == DocumentTemplate.types.TXT || this.type == DocumentTemplate.types.HTML))
@@ -115,13 +134,6 @@ DocumentTemplate.prototype._resolveEmbeddedTemplate = function ()
     }
 }
 
-DocumentTemplate.prototype._getTemplatedContent = function (pWithSubtemplates) {
-    if (this._subtemplatedContent != null && pWithSubtemplates)
-        return this._subtemplatedContent;
-    else
-        return this.content;
-}
-
 /**
  * @return {DocumentTemmplate[]} if the templateId exists, it returns all attachments associated by the id as DocumentTemplate array else it just returns an empty array.
  */
@@ -223,7 +235,7 @@ DocumentTemplate.types = {
      * chooses the type depending on the extension in the metadata. If the extension doesn't work, try mimetype
      * @param {String[]} pBinaryMetadata the binary metadata from system.db
      */
-    fromBinaryMetadata: function(pBinaryMetadata)
+    fromBinaryMetadata : function (pBinaryMetadata)
     {
         let filename = pBinaryMetadata[db.BINARY_FILENAME].split(".");
         let type = DocumentTemplate.types.fromFileExtension(filename[filename.length - 1]);
@@ -231,6 +243,42 @@ DocumentTemplate.types = {
             type = DocumentTemplate.types.fromMimeType(pBinaryMetadata[db.BINARY_MIMETYPE]);
         
         return type;
+    },
+    /**
+     * Returns the default options for the given type.
+     * 
+     * @param {String} pType the type
+     * @return {Object} object containing the default options
+     */
+    getDefaultTypeOptions : function (pType)
+    {
+        switch (pType)
+        {
+            case this.EML:
+                return {
+                    base64 : false,
+                    onlyBody : false,
+                    placeholderRegExp : /\{\s*(=\r?\n)?@(.(?!{@)|(\r?\n))+?@\s*(=\r?\n)?\}/gi,
+                    parsePlaceholderFn : function (pPlaceholder)
+                    {
+                        return pPlaceholder.replace(/\s*(=\r?\n)?/, "");
+                    }
+                };
+            case this.TXT:
+            case this.HTML:
+                return {
+                    base64 : false
+                };
+            case this.DOCX:
+            case this.DOCM:
+                return {
+                    startDelimiter : "{@",
+                    endDelimiter : "@}"
+                };
+            case this.ODT:
+            default:
+                return {};
+        }
     }
 };
 
@@ -341,22 +389,19 @@ DocumentTemplate.getSelectedTemplate = function (pTemplateId, pDocumentUpload, p
  * replace function for the type.
  * 
  * @param {Object} pReplacements map, the structure is {placeholder : value}
- * @param {Boolean} pEncoded if the replaced content should be base64 encoded
- *                            (doesn't affect odt/docx)
- * @param {Boolean} [pEmlOnlyBody=false] if true for eml's only the body is parsed (e.g. for previews. Note that eml-bodies are not editable!)
  * 
  * @return {String} the replaced content
  */
-DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pEncoded, pEmlOnlyBody)
+DocumentTemplate.prototype.getReplacedContent = function (pReplacements)
 {
     // if there exists a _subtemplatedContent we use it because then I assume that the replacements are already based on content + subtemplates
-    var content = this._getTemplatedContent(true);
+    var content = this._subtemplateResolvedContent || this.content;
     
     switch (this.type)
     {
         case DocumentTemplate.types.EML:
             let emlContent
-            if (pEmlOnlyBody)
+            if (this.options.onlyBody)
             {
                 // get only body and treat it as html (next case)
                 var email = Email.fromRFC(content);
@@ -365,8 +410,8 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pEncode
             else
             {
                 emlContent = util.decodeBase64String(content);
-                emlContent = TemplateHelper._replaceText(emlContent, pReplacements, TemplateHelper._getSpecialRegexp(this));
-                if (pEncoded)
+                emlContent = this._replaceText(emlContent, pReplacements);
+                if (this.options.base64)
                     emlContent = util.encodeBase64String(emlContent);
                 return emlContent;
             }
@@ -376,18 +421,18 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pEncode
                 pReplacements[i] = text.text2html(pReplacements[i], false);
         case DocumentTemplate.types.TXT:
             let decodedContent = util.decodeBase64String(content);
-            let encodedContent = TemplateHelper._replaceText(decodedContent, pReplacements, TemplateHelper._getSpecialRegexp(this));
-            if (pEncoded)
+            let encodedContent = this._replaceText(decodedContent, pReplacements);
+            if (this.options.base64)
                 encodedContent = util.encodeBase64String(encodedContent);
             return encodedContent;
         case DocumentTemplate.types.ODT:
-            return TemplateHelper._getReplacedODT(this, pReplacements);
+            return this._getReplacedODT(pReplacements);
         case DocumentTemplate.types.DOCX:
         case DocumentTemplate.types.DOCM:
-            return TemplateHelper._getReplacedDOCX(this, pReplacements);
+            return this._getReplacedDOCX(pReplacements);
         case DocumentTemplate.types.PLAIN:
-            let plainText = TemplateHelper._replaceText(this.content, pReplacements, TemplateHelper._getSpecialRegexp(this));
-            if (pEncoded)
+            let plainText = this._replaceText(this.content, pReplacements);
+            if (this.options.base64)
                 plainText = util.encodeBase64String(plainText);
             return plainText;
         default:
@@ -397,11 +442,17 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pEncode
 
 /**
  * replaces the placeholders with data from one contact and returns the result
+ * 
+ * @param {String} pContactId contact id
+ * @param {Placeholder[]} pAdditionalPlaceholders Additional placeholders that should be used. You can use placeholders with the 
+ *      types FIXEDVALUE and CALLBACKFUNCTION if you want to calculate the replacement values yourself.
+ * 
+ * @return {String} replaced content
  */
-DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId, pEncoded, pEmlOnlyBody) 
+DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId, pAdditionalPlaceholders) 
 {
-    var replacements = TemplateHelper._getReplacementsByContactIds(this, [pContactId]); 
-    var content = this.getReplacedContent(replacements[pContactId], pEncoded, pEmlOnlyBody);
+    var replacements = this.getReplacementsByContactIds([pContactId], pAdditionalPlaceholders)[pContactId]; 
+    var content = this.getReplacedContent(replacements);
     
     return content;
 }
@@ -410,17 +461,18 @@ DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId,
  * replaces the placeholders with data from the contacts and returns the result
  * 
  * @param {Array} pContactIds contact ids
- * @param {boolean} pEncoded if the replaced content should be base64 encoded
+ * @param {Placeholder[]} pAdditionalPlaceholders Additional placeholders that should be used. You can use placeholders with the 
+ *      types FIXEDVALUE and CALLBACKFUNCTION if you want to calculate the replacement values yourself.
  * 
  * @return {Object} replaced content for every contactId
  */
-DocumentTemplate.prototype.getReplacedContentByContactIds = function (pContactIds, pEncoded) 
+DocumentTemplate.prototype.getReplacedContentByContactIds = function (pContactIds, pAdditionalPlaceholders) 
 {
-    var replacements = TemplateHelper._getReplacementsByContactIds(this, pContactIds);
+    var replacements = this.getReplacementsByContactIds(pContactIds, pAdditionalPlaceholders);
     var contents = {};
     for (let contactId in replacements)
     {
-        contents[contactId] = this.getReplacedContent(replacements[contactId], pEncoded);
+        contents[contactId] = this.getReplacedContent(replacements[contactId]);
     }
     return contents;
 }
@@ -432,6 +484,8 @@ DocumentTemplate.prototype.getReplacedContentByContactIds = function (pContactId
  * @param {Array} pContactIds contact ids
  * @param {Object[][][]} pTableData Table data for the document, as a three-dimensional array 
  *          of objects (dimensions are: document, table in that document, rows of the table). For the format, see example.
+ * @param {Placeholder[]} pAdditionalPlaceholders Additional placeholders that should be used. You can use placeholders with the 
+ *      types FIXEDVALUE and CALLBACKFUNCTION if you want to calculate the replacement values yourself.
  * 
  * @example 
  * var contacts = newSelect("FIRSTNAME, LASTNAME")
@@ -458,15 +512,16 @@ DocumentTemplate.prototype.getReplacedContentByContactIds = function (pContactId
  * 
  * @return {Object} the content of the replaced ODT
  */
-DocumentTemplate.prototype.getSerialLetterByContactIds = function (pContactIds, pTableData)
+DocumentTemplate.prototype.getSerialLetterByContactIds = function (pContactIds, pTableData, pAdditionalPlaceholders)
 {
     if (this.type == DocumentTemplate.types.ODT)
     {
-        let replacements = TemplateHelper._getReplacementsByContactIds(this, pContactIds);
-        let replaceArray = [];
-        for (let i = 0, l = pContactIds.length; i < l; i++)
-            replaceArray.push(replacements[pContactIds[i]]);
-        return TemplateHelper._getReplacedODT(this, replaceArray, pTableData);
+        let replacements = this.getReplacementsByContactIds(pContactIds, pAdditionalPlaceholders);
+        let replaceArray = pContactIds.map(function (contactId)
+        {
+            return replacements[contactId];
+        });
+        return this._getReplacedODT(replaceArray, pTableData);
     }
     
     question.showMessage(DocumentTemplate.getSerialLetterODTOnlyMessage(), question.INFORMATION, translate.text("Action not supported"))
@@ -482,15 +537,18 @@ DocumentTemplate.getSerialLetterODTOnlyMessage = function()
  * Replaces the placeholders with data from the contacts and returns the resulting Emails.
  * 
  * @param {Array} pContactIds contact ids
+ * @param {Placeholder[]} pAdditionalPlaceholders Additional placeholders that should be used. You can use placeholders with the 
+ *      types FIXEDVALUE and CALLBACKFUNCTION if you want to calculate the replacement values yourself.
  * 
  * @return {Object} Object containing the contact ids as keys and the corresponding Email
  *                   objects as values
  */
-DocumentTemplate.prototype.getReplacedEmailsByContactIds = function (pContactIds) 
+DocumentTemplate.prototype.getReplacedEmailsByContactIds = function (pContactIds, pAdditionalPlaceholders) 
 {
     var emailObjects = {};
     var isEML = this.type == DocumentTemplate.types.EML;
-    var emailContents = this.getReplacedContentByContactIds(pContactIds, isEML);
+    this.setOptions({base64 : isEML});
+    var emailContents = this.getReplacedContentByContactIds(pContactIds, pAdditionalPlaceholders);
     
     for (contactId in emailContents)
     {
@@ -514,15 +572,18 @@ DocumentTemplate.prototype.getReplacedEmailsByContactIds = function (pContactIds
 }
 
 /**
- * Provides functions for the DocumentTemplate object that aren't accessible from outside
+ * replaces placeholders in the given string
  */
-function TemplateHelper () {}
-TemplateHelper._replaceText = function (pText, pReplacements, pSpecialCharFilterRegexpPart)
+DocumentTemplate.prototype._replaceText = function (pText, pReplacements)
 {
-    if (pSpecialCharFilterRegexpPart == undefined) pSpecialCharFilterRegexpPart = "";
+    var placeholderRegExp = this.options.placeholderRegExp || PlaceholderUtils.getRegexpMatchAll();
+    var that = this;
     
-    pText = pText.replace(new RegExp(PlaceholderUtils.getRegexpMatchAll(pSpecialCharFilterRegexpPart), "gi"), function(pFound) {
-        let foundFiltered = pFound.replace(new RegExp(pSpecialCharFilterRegexpPart, "gi"),"");
+    pText = pText.replace(placeholderRegExp, function (pFound) 
+    {
+        let foundFiltered = typeof that.options.parsePlaceholderFn === "function"
+            ? that.options.parsePlaceholderFn(pFound)
+            : pFound;
         return pReplacements[foundFiltered] ? pReplacements[foundFiltered] : pFound;
     });
 
@@ -530,70 +591,89 @@ TemplateHelper._replaceText = function (pText, pReplacements, pSpecialCharFilter
 }
 
 /**
- * @param {DocumentTemplate} pTemplate
  * @param {String[]} pForcedPlaceholders these placeholders are always loaded
- * @return {Object[]} all placeholders needed in this template or null, if 
+ * @param {Placeholder[]} pAdditionalPlaceholders Additional placeholders that should be used. You can use placeholders with the 
+ *      types FIXEDVALUE and CALLBACKFUNCTION if you want to calculate the replacement values yourself.
+ * @return {Object[]} all placeholders needed in this template
  * @private
  */
-TemplateHelper._getRequiredPlaceholders = function (pTemplate, pForcedPlaceholders)
+DocumentTemplate.prototype._getRequiredPlaceholders = function (pForcedPlaceholders, pAdditionalPlaceholders)
 {    
-    var content = "";
-    content = pTemplate.toString(true);
-    
-    // get special regexp (e.g. to filter '=' in emls)
-    var filterRegexpPart = TemplateHelper._getSpecialRegexp(pTemplate);    
+    var content = this.toString(true);
     var placeholders = PlaceholderUtils.getPlaceholders();
+    if (pAdditionalPlaceholders)
+        placeholders = placeholders.concat(pAdditionalPlaceholders);
 
-    var placeholderCleanRegexp = new RegExp(filterRegexpPart, "gi");
-    
     // get all placeholders which matches the placeholder pattern
-    var foundPlaceholders = content.match(new RegExp(PlaceholderUtils.getRegexpMatchAll(TemplateHelper._getSpecialRegexp(pTemplate)), "gi"));
+    var foundPlaceholders = content.match(this.options.placeholderRegExp || PlaceholderUtils.getRegexpMatchAll());
     
     if (foundPlaceholders == null)
         foundPlaceholders = [];
     
     // clean placeholder from the spechial strings (e.g. to filter '=' in emls)
-    foundPlaceholders = foundPlaceholders.map(function(pFound) {
-        return pFound.replace(placeholderCleanRegexp,"");
-    });
+    if (typeof this.options.parsePlaceholderFn === "function")
+        foundPlaceholders = foundPlaceholders.map(this.options.parsePlaceholderFn);
 
     // filter the possible placeholders by all placeholders found
-    placeholders = placeholders.filter(function(pPlaceholder)
+    placeholders = placeholders.filter(function(placeholder)
     {
-        return foundPlaceholders.indexOf(pPlaceholder.placeholderName) != -1 || pForcedPlaceholders.indexOf(pPlaceholder.placeholderName) >= 0;
+        return foundPlaceholders.includes(placeholder.getFormattedName()) || pForcedPlaceholders.includes(placeholder.getFormattedName());
     });
     
     return placeholders;
 }
 
 /**
- * Builds an object with the placeholder data for multiple contacts
+ * Builds an object with the placeholder replacement data for multiple contacts
  * 
- * @param {DocumentTemplate} pTemplate document template
  * @param {Array} pContactIds contact ids
+ * @param {Placeholder[]} pAdditionalPlaceholders Additional placeholders that should be used. You can use placeholders with the 
+ *      types FIXEDVALUE and CALLBACKFUNCTION if you want to calculate the replacement values yourself.
  * 
  * @return {Object} Object containing the data. The structure is like {contactId : {placeholderName : replacementValue, ...}, ...}
- * 
- * @private
  */
-TemplateHelper._getReplacementsByContactIds = function (pTemplate, pContactIds)
+DocumentTemplate.prototype.getReplacementsByContactIds = function (pContactIds, pAdditionalPlaceholders)
 { 
-    var config = TemplateHelper._getRequiredPlaceholders(pTemplate, ["{@firstname@}", "{@lastname@}"]);
+    var placeholders = this._getRequiredPlaceholders(["{@firstname@}", "{@lastname@}"], pAdditionalPlaceholders);
+    var contactPlaceholders = [];
+    var additionalPlaceholders = {};
+    placeholders.forEach(function (placeholder)
+    {
+        switch (placeholder.type)
+        {
+            case Placeholder.types.ADDRESSFORMAT:
+            case Placeholder.types.SQLPART:
+            case Placeholder.types.SQLPARTFUNCTION:
+                contactPlaceholders.push(placeholder);
+                break;
+            case Placeholder.types.FIXEDVALUE:
+            case Placeholder.types.CALLBACKFUNCTION:
+                additionalPlaceholders[placeholder.getFormattedName()] = placeholder;
+        }
+    });
     var contactIdPlaceholder = new Placeholder("contactId", Placeholder.types.SQLPART, "CONTACT.CONTACTID");
-    config = [contactIdPlaceholder].concat(config);
-
-    var addressData = getAddressesData(pContactIds, config, EmployeeUtils.getCurrentContactId()); //TODO: add sender selection
+    contactPlaceholders = [contactIdPlaceholder].concat(contactPlaceholders);
+    
+    var addressData = getAddressesData(pContactIds, contactPlaceholders, EmployeeUtils.getCurrentContactId()); //TODO: add sender selection
     var replacements = {};
     var placeholderNames = addressData[0];
     var contactIdIndex = placeholderNames.indexOf(contactIdPlaceholder.toString());
     for (let i = 1; i < addressData.length; i++)
     {
         let contactId = addressData[i][contactIdIndex];
-        for (let ii = 0, ll = placeholderNames.length; ii < ll; ii++)
+        if (!(contactId in replacements))
+            replacements[contactId] = {};
+        placeholderNames.forEach(function (placeholderName, ii)
         {
-            if (!(contactId in replacements))
-                replacements[contactId] = {};
-            replacements[contactId][placeholderNames[ii]] = addressData[i][ii];
+            replacements[contactId][placeholderName] = addressData[i][ii];
+        });
+        for (let placeholderName in additionalPlaceholders)
+        {
+            var placeholder = additionalPlaceholders[placeholderName];
+            if (placeholder.type === Placeholder.types.FIXEDVALUE)
+                replacements[contactId][placeholderName] = placeholder.valueDefinition;
+            else if (placeholder.type === Placeholder.types.CALLBACKFUNCTION)
+                replacements[contactId][placeholderName] = placeholder.valueDefinition(contactId);
         }
     }
     return replacements;
@@ -602,7 +682,6 @@ TemplateHelper._getReplacementsByContactIds = function (pTemplate, pContactIds)
 /*
  * replaces a given Odt-File on the server and returns the replaced base64-file
  *
- * @param {DocumentTemplate} pTemplate document template
  * @param {Object} pReplacements map of placeholders and replacements
  * @param {Array} pTableData
  *
@@ -610,22 +689,32 @@ TemplateHelper._getReplacementsByContactIds = function (pTemplate, pContactIds)
  * 
  * @private
  */
-TemplateHelper._getReplacedODT = function (pTemplate, pReplacements, pTableData)
+DocumentTemplate.prototype._getReplacedODT = function (pReplacements, pTableData)
 {
-    var filename =  pTemplate.filename;
+    var filename =  this.filename;
     if (!filename)
         filename = "dummyname.odt";
     
+    var that = this;
+    
     //save the file on the server so it can be unzipped via pack.getFromZip
     var serverFilePath = vars.get("$sys.servertemp") + "/clientid_" + (vars.exists("$sys.clientid") ? vars.get("$sys.clientid") : 0)
         + "/" + util.getNewUUID() + "/" + filename.replace(/\\/g, "/");
     
-    fileIO.storeData(serverFilePath, pTemplate.content, util.DATA_BINARY, false);
-    if (!_replaceODTFile(pReplacements, serverFilePath, pTableData))
-        return null;
+    fileIO.storeData(serverFilePath, this.content, util.DATA_BINARY, false);
+    var replacedFileData = null;
+    try 
+    {
+        if (!_replaceODTFile(pReplacements, serverFilePath, pTableData))
+            return null;
 
-    var replacedFileData = fileIO.getData(serverFilePath, util.DATA_BINARY);
-    fileIO.remove(serverFilePath);
+        replacedFileData = fileIO.getData(serverFilePath, util.DATA_BINARY);
+        
+    }
+    finally 
+    {
+        fileIO.remove(serverFilePath);
+    }
 
     return replacedFileData;
     
@@ -643,7 +732,7 @@ TemplateHelper._getReplacedODT = function (pTemplate, pReplacements, pTableData)
         var senderRelId = EmployeeUtils.getCurrentContactId();
         if (senderRelId == null)
             return false;
-        if (pReplacements.length === undefined)
+        if (!Array.isArray(pReplacements))
             pReplacements = [pReplacements];
         if (!pTableData)
             pTableData = [];
@@ -697,7 +786,7 @@ TemplateHelper._getReplacedODT = function (pTemplate, pReplacements, pTableData)
                         for (let rowIndex = 0; rowIndex < tableData.length; rowIndex++)
                         {
                             let tableRowData = tableData[rowIndex];
-                            currentBody += TemplateHelper._replaceText(tableRow, tableRowData);
+                            currentBody += that._replaceText(tableRow, tableRowData);
                         }
                         currentBody += afterTable;
                     }
@@ -724,39 +813,25 @@ TemplateHelper._getReplacedODT = function (pTemplate, pReplacements, pTableData)
 /*
  * This function is used to replace placeholders via DocXTemplater
  * 
- * @param {DocumentTemplate} pTemplate document template
  * @param {Object} pReplacements - Must contain an object, which holds the placeholders
  * 
  * @return {String} returns the modified document in a BASE64 coded string
  * 
  * @private
  */
-TemplateHelper._getReplacedDOCX = function (pTemplate, pReplacements)
+DocumentTemplate.prototype._getReplacedDOCX = function (pReplacements)
 {
     var replacements = {};
+    var startDelimiter = this.options.startDelimiter;
+    var endDelimiter = this.options.endDelimiter;
     for (let placeholder in pReplacements)  //removes the prefix and postfix, the process needs it like this
-        replacements[placeholder.slice(2, -2)] = pReplacements[placeholder];
+        replacements[placeholder.slice(startDelimiter.length, -endDelimiter.length)] = pReplacements[placeholder];
 
-    var documentData = DocxtemplaterUtils.generateDocument(pTemplate.content, replacements, "{@", "@}");
+    var documentData = DocxtemplaterUtils.generateDocument(this.content, replacements, startDelimiter, endDelimiter);
     
     return documentData;
 }
 
-TemplateHelper._getSpecialRegexp = function (pTemplate)
-{
-    switch (pTemplate.type)
-    {
-        case DocumentTemplate.types.EML:
-            return "\\s*(=\\r?\\n)?";
-        default:
-            return "";
-    }
-}
-
-    return DocumentTemplate;
-
-})();
-
 /**
  * functions for working with letters (mails)
  */
diff --git a/process/DocxTemplater_lib/process.js b/process/DocxTemplater_lib/process.js
index e9cd6c748fa3f8ba17d1c5c13795ee659ab3459d..8306c0421438b2cdc1e8f38940979b25bb0ba41e 100644
--- a/process/DocxTemplater_lib/process.js
+++ b/process/DocxTemplater_lib/process.js
@@ -85,7 +85,7 @@ function _getAutoNewLineModule()
             if (value == null)
                 value = options.nullGetter(part);
             else
-                value = value.replace(/(\r\n)|(\n)|(\r)/g, "\n<w:br/>");
+                value = value.replace(/(\r\n)|(\n)|(\r)/g, "</w:t></w:r><w:r><w:br/></w:r><w:r><w:t xml:space=\"preserve\">");
 
             return {
                 value: value
diff --git a/process/Email_lib/process.js b/process/Email_lib/process.js
index d14798db16fadb33871b64b0a2dd879987fec383..94a4ab8ba9daa08c1021663cb1d6435a661e94c7 100644
--- a/process/Email_lib/process.js
+++ b/process/Email_lib/process.js
@@ -28,9 +28,10 @@ function EmailWritingUtils () {}
  * @param {Array} [pAttachments] attachments in a array (base64 encoded).
  * @param {String} pSubject an optional subject.
  * @param {String} [pEmailFilename] filename of the email.
+ * @param {Placeholder[]} [pAdditionalPlaceholders] additional placeholders
  * @return {Array} the eml document as array with [filename, base64]
  */
-EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId, pTemplateId, pRecipientContactId, pBindata, pAttachments, pSubject, pEmailFilename)
+EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId, pTemplateId, pRecipientContactId, pBindata, pAttachments, pSubject, pEmailFilename, pAdditionalPlaceholders)
 {
     if (pToRecipients && typeof(pToRecipients) == "string")
         pToRecipients = [pToRecipients];
@@ -39,7 +40,7 @@ EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId,
     
     if (pTemplateId || (pBindata.bindata != "" && pBindata.bindata != null))
     {
-        email = Email.fromTemplate(pTemplateId, pRecipientContactId, pBindata);
+        email = Email.fromTemplate(pTemplateId, pRecipientContactId, pBindata, pAdditionalPlaceholders);
         if (!email)
             email = new Email();
     }    
@@ -76,15 +77,17 @@ EmailWritingUtils.openMailTemplate = function (pToRecipients, pSenderContactId,
  * @param {String} pNotificationMsg message which will be shown after the operation is done.
  * @param {String} pComingFrom source from where you started (e.g. "Person", "Organisation" )
  * @param {String} pEmailFilename optional file name of the email.
+ * @param {String} [pAdditionalPlaceholders] additional placeholders for the email
  */
-EmailWritingUtils.openNewMail = function (pToContactId, pToEmailAddress, pComingFrom, pAttachmentArray, pNotificationMsg, pEmailFilename)
+EmailWritingUtils.openNewMail = function (pToContactId, pToEmailAddress, pComingFrom, pAttachmentArray, pNotificationMsg, pEmailFilename, pAdditionalPlaceholders)
 {
     var params = {
         "ContactId_param" : pToContactId,
         "Attachments_param" : JSON.stringify(pAttachmentArray),
         "ComingFrom_param" : pComingFrom,
         "NotificationMsg_param" : pNotificationMsg,
-        "EmailFilename" : pEmailFilename
+        "EmailFilename" : pEmailFilename,
+        "AdditionalPlaceholders_param" : JSON.stringify(pAdditionalPlaceholders)
     };
     
     if (pToEmailAddress)
@@ -107,14 +110,15 @@ EmailWritingUtils.getMailbridgeAddress = function ()
  * @param {Array} pReportArray array with reports.
  * @param {String} pNotificationMsg message which will be shown after the operation is done.
  * @param {String} pEmailFilename optional file name of the email.
+ * @param {String} [pAdditionalPlaceholders] additional placeholders for the email
  * Report have to be a object with these attrs: content (base64 encoded report), contentType (mimeType of the report), filename (complete filename with filending)
  */
-EmailWritingUtils.sendReportAsMail = function (pRecipient, pReportArray, pComingFrom, pNotificationMsg, pEmailFilename)
+EmailWritingUtils.sendReportAsMail = function (pRecipient, pReportArray, pComingFrom, pNotificationMsg, pEmailFilename, pAdditionalPlaceholders)
 {
     var pRecpientEmail = newSelect("COMMUNICATION.ADDR").from("COMMUNICATION")
     .where("COMMUNICATION.CONTACT_ID", pRecipient).and("COMMUNICATION.MEDIUM_ID", "COMMEMAIL").cell();
             
-    EmailWritingUtils.openNewMail(pRecipient, pRecpientEmail, pComingFrom, pReportArray, pNotificationMsg, pEmailFilename);
+    EmailWritingUtils.openNewMail(pRecipient, pRecpientEmail, pComingFrom, pReportArray, pNotificationMsg, pEmailFilename, pAdditionalPlaceholders);
 }
 
 /**
@@ -166,9 +170,10 @@ Email.fromRFC = function (pBase64RFC)
  * @param {String} [pTemplateId] UUID of the explicit template which shall used. (optional)
  * @param {String} [pContactId] (required)
  * @param {String} [pBindata] (required)
+ * @param {Placeholder[]} [pAdditionalPlaceholders] additional placeholders
  * @return {Email} a new Email object
  */
-Email.fromTemplate = function (pTemplateId, pContactId, pBindata)
+Email.fromTemplate = function (pTemplateId, pContactId, pBindata, pAdditionalPlaceholders)
 {
     var template;
     
@@ -184,7 +189,7 @@ Email.fromTemplate = function (pTemplateId, pContactId, pBindata)
             return null;
     }
     
-    return template.getReplacedEmailsByContactIds([pContactId])[pContactId];
+    return template.getReplacedEmailsByContactIds([pContactId], pAdditionalPlaceholders)[pContactId];
 }
 
 /**
diff --git a/process/ExportTemplate_lib/process.js b/process/ExportTemplate_lib/process.js
index 0272a91c61e87df64f2112201d4bc984e941bcd8..a8c09911551c8dfd933e082febebfac8d3a25dd3 100644
--- a/process/ExportTemplate_lib/process.js
+++ b/process/ExportTemplate_lib/process.js
@@ -71,7 +71,7 @@ ExportTemplateUtils.buildExport = function (pExportTemplateId, pSelection, pComi
     var affectedPlaceholders = [];
     for (var i = 0; i < fields.length; i++) {
             var placeholderField = placeholders.find(function(placeholder){
-                return placeholder.placeholderName == fields[i];
+                return placeholder.getFormattedName() == fields[i];
             })
             if(placeholderField)
                 affectedPlaceholders.push(placeholderField);
diff --git a/process/ImporterMappingFunctions_lib/process.js b/process/ImporterMappingFunctions_lib/process.js
index a5746a0276df1bc7963975598a51395c10e741b1..27a4b5725fbfc5be68e9d42c5a498c3d132d8a25 100644
--- a/process/ImporterMappingFunctions_lib/process.js
+++ b/process/ImporterMappingFunctions_lib/process.js
@@ -145,7 +145,7 @@ function iAttribute(pObject)
                 var parent = "NULL";
                 // select ab_attributeid from AB_ATTRIBUTE where ATTRIBUTE_NAME = 'Subordinate campaign of' and attribute_parent_id is null
                 id = newSelect(ab_attributeId, alias).from(ab_attribute).where(attribute_name, attributes[i])
-                        .and(attribute_parent_id + "is null").cell();
+                        .and(attribute_parent_id + " is null").cell();
             } 
             else 
             {
diff --git a/process/JditoFilter_lib/process.js b/process/JditoFilter_lib/process.js
index 9e6137b3ebbc088ec3a49495ac7a8b138cd5c7bd..d24d07552af5498326763f378b323980a41d0737 100644
--- a/process/JditoFilter_lib/process.js
+++ b/process/JditoFilter_lib/process.js
@@ -1,6 +1,7 @@
 import("system.tools");
 import("system.logging");
 import("Sql_lib");
+import("system.datetime");
 
 /**
  * object for filtering records
@@ -117,6 +118,8 @@ JditoFilter.prototype.checkRecord = function (pRow)
             case "TIMEFRAME_EQUAL":
             case "TIMEFRAME_COMING":
             case "TIMEFRAME_PAST":
+                var [start, end] = datetime.resolveRelativeDateExpression(pFilterValue);
+                return pRowValue >= start && pRowValue <= end;
         }
     }
 }
@@ -211,16 +214,163 @@ JditoFilterUtils.filterRecords = function (pColumns, pRecords, pFilter, pCustomC
  */
 JditoFilterUtils.getSqlCondition = function (pFilter, pTable, pTableAlias, pColumnOrFnMap)
 {
-    var condition = newWhere();
+    var filterTranslator = new FilterSqlTranslator(pFilter)
+        .table(pTable, pTableAlias);
     
-    var ignoreCase = JditoFilterUtils.isUserIgnoreCase();
-    
-    if (!pFilter)
+    if (pColumnOrFnMap)
+    {
+        for (let fieldName in pColumnOrFnMap)
+        {
+            var columnOrFn = pColumnOrFnMap[fieldName];
+            if (typeof columnOrFn === "function")
+                filterTranslator.addSpecialFieldConditionFn(fieldName, columnOrFn);
+            else
+                filterTranslator.addSqlFieldMapping(fieldName, columnOrFn);
+        }
+    }
+    return filterTranslator.getSqlCondition();
+}
+
+/**
+ * @return {boolean} the selectionIgnoreCase property of the current user, defaults to true
+ */
+JditoFilterUtils.isUserIgnoreCase = function ()
+{
+    var user = tools.getCurrentUser();
+    var ignoreCase = user ? user[tools.PARAMS][tools.SELECTION_IGNORECASE] : "";
+    return ignoreCase == "" || /true/i.test(ignoreCase);
+}
+
+/**
+ * Object for translating a filter object to a sql condition.
+ * 
+ * @param {Object} pFilter the filter object that should be used
+ * @param {String} pTable the database table to build the condition for
+ */
+function FilterSqlTranslator (pFilter, pTable)
+{
+    this._filter = null;
+    this.filter(pFilter);
+    this._table = pTable;
+    this._tableAlias = null;
+    this._dbAlias = null;
+    this._sqlFieldMappings = {};
+    this._fieldConditionFns = {};
+    this._ignoreCase = JditoFilterUtils.isUserIgnoreCase();
+}
+
+/**
+ * Sets the filter of the object
+ * 
+ * @param {Object} pFilter the filter object that should be used
+ * @return {FilterSqlTranslator} current object
+ */
+FilterSqlTranslator.prototype.filter = function (pFilter)
+{
+    if (pFilter)
+    {
+        if (typeof pFilter !== "object")
+            throw new TypeError("FilterSqlTranslator: Wrong type for the filter, expected 'object' but got '" + (typeof pFilter) + "'");
+        this._filter = pFilter.filter || pFilter;
+    }
+    return this;
+}
+
+/**
+ * Sets the filter of the object
+ * 
+ * @param {String} pFilter the filter object that should be used as JSON string
+ * @return {FilterSqlTranslator} current object
+ */
+FilterSqlTranslator.prototype.filterJSON = function (pFilter)
+{
+    return this.filter(JSON.parse(pFilter));
+}
+
+/**
+ * Sets the table of the object
+ * 
+ * @param {String} pTable the database table to build the condition for
+ * @param {String} [pTableAlias] the alias of the table
+ * @return {FilterSqlTranslator} current object
+ */
+FilterSqlTranslator.prototype.table = function (pTable, pTableAlias)
+{
+    this._table = pTable;
+    if (pTableAlias)
+        this._tableAlias = pTableAlias;
+    return this;
+}
+
+/**
+ * Adds a special database field mapping for the given field that will be used for the sql condition
+ * 
+ * @param {String} pFieldName the field name
+ * @param {String|String[]} pDBField the database field ("TABLE.COLUMN" or ["TABLE", "COLUMN", "alias"])
+ * @return {FilterSqlTranslator} current object
+ */
+FilterSqlTranslator.prototype.addSqlFieldMapping = function (pFieldName, pDBField)
+{
+    this._sqlFieldMappings[pFieldName] = pDBField;
+    return this;
+}
+
+/**
+ * Adds a special function for building the condition for the given field. The function must return a sql condition (SqlBuilder or String)
+ * 
+ * @param {String} pFieldName the field name
+ * @param {Function} pConditionFn a function that generates the condition
+ * @return {FilterSqlTranslator} current object
+ */
+FilterSqlTranslator.prototype.addSpecialFieldConditionFn = function (pFieldName, pConditionFn)
+{
+    this._fieldConditionFns[pFieldName] = pConditionFn;
+    return this;
+}
+
+/**
+ * Sets the database alias
+ * 
+ * @param {String} pAlias the alias to be used
+ * @return {FilterSqlTranslator} current object
+ */
+FilterSqlTranslator.prototype.dbAlias = function (pAlias)
+{
+    this._dbAlias = pAlias;
+    return this;
+}
+
+/**
+ * Changes whether the condition should be case-insensitive for text
+ * 
+ * @param {boolean} [pIgnoreCase=true] if it should be case-insensitive
+ * @return {FilterSqlTranslator} current object
+ */
+FilterSqlTranslator.prototype.ignoreCase = function (pIgnoreCase)
+{
+    //"", 0 , false -> false, everything else is considered true
+    this._ignoreCase = pIgnoreCase != false;
+    return this;
+}
+
+/**
+ * Builds the sql condition from the filter
+ * 
+ * @return {SqlBuilder} the sql condition
+ */
+FilterSqlTranslator.prototype.getSqlCondition = function ()
+{
+    var condition = new SqlBuilder(this._dbAlias).where();
+    if (!this._filter)
         return condition;
-    if (!pColumnOrFnMap)
-        pColumnOrFnMap = {};
     
-    _addCondition.call(condition, pFilter, pFilter.operator);
+    var table = this._table;
+    var tableAlias = this._tableAlias;
+    var ignoreCase = this._ignoreCase;
+    var sqlFieldMappings = this._sqlFieldMappings;
+    var fieldConditionFns = this._fieldConditionFns;
+    
+    _addCondition.call(condition, this._filter, this._filter.operator);
     
     return condition;
     
@@ -230,47 +380,61 @@ JditoFilterUtils.getSqlCondition = function (pFilter, pTable, pTableAlias, pColu
     {
         if (pFilter.type == "row")
         {
-            if (pFilter.name in pColumnOrFnMap)
+            var sqlField, condition;
+            var filterValue = (pFilter.key || pFilter.value);
+            if (pFilter.name in fieldConditionFns)
             {
-                pFilter.name = pColumnOrFnMap[pFilter.name];
+                var conditionFn = fieldConditionFns[pFilter.name];
+                
+                condition = conditionFn.call(null, filterValue, pFilter.operator);
+                if (pOperator == "AND")
+                    this.andIfSet(condition);
+                else if (pOperator == "OR")
+                    this.orIfSet(condition);
+                
+                return;
+            }
+            
+            if (pFilter.name in sqlFieldMappings)
+            {
+                sqlField = sqlFieldMappings[sqlField];
                 
                 //possibility to explicitly set the value to null/false so that the field is ignored
-                if (pFilter.name === null || pFilter.name === false)
+                if (sqlField === null || sqlField === false)
                     return;
             }
-            else if (pTable && pTableAlias)
-                pFilter.name = [pTable, pFilter.name, pTableAlias];
-            else if (pTable)
-                pFilter.name = pTable + "." + pFilter.name;
-            
-            pFilter.value = (pFilter.key || pFilter.value);
+            else if (table && tableAlias)
+                sqlField = [table, pFilter.name, tableAlias];
+            else if (table)
+                sqlField = table + "." + pFilter.name;
             
-            var condition;
-            if (typeof(pFilter.name) === "function")
+            var generatedCondition = _getCondition(filterValue, pFilter.operator, sqlField);
+            if (generatedCondition instanceof SqlBuilder || typeof generatedCondition === "string")
             {
-                condition = pFilter.name.call(null, pFilter.value, pFilter.operator);
                 if (pOperator == "AND")
-                    this.andIfSet(condition);
+                    this.andIfSet(generatedCondition);
                 else if (pOperator == "OR")
-                    this.orIfSet(condition);
+                    this.orIfSet(generatedCondition);
             }
             else
             {
-                let isStringType, filterValue;
-                [condition, filterValue, isStringType] = _getCondition(pFilter.value, pFilter.operator);
+                var isStringType = pFilter.contenttype != "NUMBER" 
+                    && pFilter.contenttype != "DATE" 
+                    && pFilter.contenttype != "BOOLEAN";
+                [condition, filterValue] = generatedCondition;
                 if (isStringType && ignoreCase)
                     condition = condition.replace("#", "UPPER(#)").replace("?", "UPPER(?)");
-                
+
                 if (pOperator == "AND")
-                    this.andIfSet(pFilter.name, filterValue, condition);
+                    this.andIfSet(sqlField, filterValue, condition);
                 else if (pOperator == "OR")
-                    this.orIfSet(pFilter.name, filterValue, condition);
+                    this.orIfSet(sqlField, filterValue, condition);
             }
         }
         else if (pFilter.type == "group")
         {
-            let subCondition = newWhere();
-            let operator = pFilter.operator;
+            var subCondition = newWhere();
+            var operator = pFilter.operator;
             pFilter.childs.forEach(function (cond)
             {
                 _addCondition.call(subCondition, cond, operator);
@@ -282,45 +446,41 @@ JditoFilterUtils.getSqlCondition = function (pFilter, pTable, pTableAlias, pColu
         }
     }
     
-    //returns [condition, value with wildcards, is a string type] depending on the operator
-    function _getCondition (pValue, pOperator)
+    //returns [condition, value with wildcards] depending on the operator
+    function _getCondition (pValue, pOperator, pField)
     {
         switch (pOperator)
         {
             case "CONTAINS":
-                return [SqlBuilder.LIKE(), "%" + pValue + "%", true];
+                return [SqlBuilder.LIKE(), "%" + pValue + "%"];
             case "CONTAINSNOT":
-                return [SqlBuilder.NOT_LIKE(), "%" + pValue + "%", true];
+                return [SqlBuilder.NOT_LIKE(), "%" + pValue + "%"];
             case "STARTSWITH":
-                return [SqlBuilder.LIKE(), pValue + "%", true];
+                return [SqlBuilder.LIKE(), pValue + "%"];
             case "ENDSWITH":
-                return [SqlBuilder.LIKE(), "%" + pValue, true];
+                return [SqlBuilder.LIKE(), "%" + pValue];
             case "EQUAL":
-                return [SqlBuilder.EQUAL(), pValue, true];
+                return [SqlBuilder.EQUAL(), pValue];
             case "NOT_EQUAL":
-                return [SqlBuilder.NOT_EQUAL(), pValue, true];
+                return [SqlBuilder.NOT_EQUAL(), pValue];
             case "LESS":
-                return [SqlBuilder.LESS(), pValue, false];
+                return [SqlBuilder.LESS(), pValue];
             case "LESS_OR_EQUAL":
-                return [SqlBuilder.LESS_OR_EQUAL(), pValue, false];
+                return [SqlBuilder.LESS_OR_EQUAL(), pValue];
             case "GREATER":
-                return [SqlBuilder.GREATER(), pValue, false];
+                return [SqlBuilder.GREATER(), pValue];
             case "GREATER_OR_EQUAL":
-                return [SqlBuilder.GREATER_OR_EQUAL(), pValue, false];
+                return [SqlBuilder.GREATER_OR_EQUAL(), pValue];
             case "ISNULL":
-                return ["# is null", pValue, false];
+                return pField + " is null";
             case "ISNOTNULL":
-                return ["# is not null", pValue, false];
+                return pField + " is not null";
+            case "TIMEFRAME_EQUAL":
+            case "TIMEFRAME_COMING":
+            case "TIMEFRAME_PAST":
+                var [start, end] = datetime.resolveRelativeDateExpression(pValue);
+                return newWhere(pField, start, SqlBuilder.GREATER_OR_EQUAL())
+                    .and(pField, end, SqlBuilder.LESS_OR_EQUAL());
         }
     }
-}
-
-/**
- * @return {boolean} the selectionIgnoreCase property of the current user, defaults to true
- */
-JditoFilterUtils.isUserIgnoreCase = function ()
-{
-    var user = tools.getCurrentUser();
-    var ignoreCase = user ? user[tools.PARAMS][tools.SELECTION_IGNORECASE] : "";
-    return ignoreCase == "" || /true/i.test(ignoreCase);
-}
+}
\ No newline at end of file
diff --git a/process/KeywordRegistry_basic/process.js b/process/KeywordRegistry_basic/process.js
index b53349181660fe4f0829d5fa6f8b7e03e755f735..2ae7c40b6e90dc3d207d4441cbeb3abeadfd128c 100644
--- a/process/KeywordRegistry_basic/process.js
+++ b/process/KeywordRegistry_basic/process.js
@@ -284,4 +284,6 @@ $KeywordRegistry.visitPlanEntryStatus$Visitreportcreated = function(){return $Ke
 
 $KeywordRegistry.visitRecommendationPrioSource = function(){return $KeywordRegistry._autoPad("VisitRecommendationPrioSource");};
 $KeywordRegistry.visitRecommendationPrioSource$visitFrequency = function(){return $KeywordRegistry._autoPad("VISITFREQUENCY");};
-$KeywordRegistry.visitRecommendationPrioSource$manual = function(){return $KeywordRegistry._autoPad("MANUAL");};
\ No newline at end of file
+$KeywordRegistry.visitRecommendationPrioSource$manual = function(){return $KeywordRegistry._autoPad("MANUAL");};
+
+$KeywordRegistry.workflowCategory = function(){return "WorkflowCategory";};
\ No newline at end of file
diff --git a/process/Placeholder_lib/process.js b/process/Placeholder_lib/process.js
index d6028a429c4158197cedfdc5f11e8f9ffe68c5e6..4f271fa114efc53ff3bb909ea0d4692436e8cead 100644
--- a/process/Placeholder_lib/process.js
+++ b/process/Placeholder_lib/process.js
@@ -68,7 +68,7 @@ PlaceholderUtils.getPlaceholders = function (pLocale, pIsExportTemplateField)
                 if(placeholders[i]["target"] != "RECIPIENT"){
                     placeholders.splice(i, 1);
                     i--}
-                else if(placeholders[i]["placeholderName"] == "{@letterSalutation@}"){
+                else if(placeholders[i].getFormattedName() == "{@letterSalutation@}"){
                     placeholders.splice(i, 1);
                      i--}
             }
@@ -106,11 +106,12 @@ PlaceholderUtils.getPlaceholders = function (pLocale, pIsExportTemplateField)
 
 /**
  * Returns the placeholder with the required prefix and postfix added.
- * This function defines the format for placeholders.
+ * 
+ * @deprecated
  */
 PlaceholderUtils.formatPlaceholder = function (pPlaceholder)
 {
-    return "{@" + pPlaceholder + "@}";
+    return Placeholder.getDefaultStartDelimiter() + pPlaceholder + Placeholder.getDefaultEndDelimiter();
 }
 
 /**
@@ -120,14 +121,9 @@ PlaceholderUtils.formatPlaceholder = function (pPlaceholder)
  *  return "my special replacement"
  * });
  */
-PlaceholderUtils.getRegexpMatchAll = function (pSpecialCharFilterRegexpPart)
+PlaceholderUtils.getRegexpMatchAll = function ()
 {
-    if (pSpecialCharFilterRegexpPart == undefined)
-    {
-        pSpecialCharFilterRegexpPart = "";
-    }
-    
-    return "{" + pSpecialCharFilterRegexpPart + "@(.(?!{@)|(\\r?\\n))+?@" + pSpecialCharFilterRegexpPart + "}";
+    return /\{@(.(?!{@)|(\r?\n))+?@\}/gi;
 }
 
 /**
@@ -141,16 +137,42 @@ PlaceholderUtils.getRegexpMatchAll = function (pSpecialCharFilterRegexpPart)
  */
 function Placeholder (pName, pType, pValueDef, pTarget, pTitle) 
 {
-    this.placeholderName = PlaceholderUtils.formatPlaceholder(pName);
+    this.startDelimiter = Placeholder.getDefaultStartDelimiter();
+    this.endDelimiter = Placeholder.getDefaultEndDelimiter();
+    this.placeholderName = pName;
     this.type = pType;
     this.target = pTarget || Placeholder.targets.RECIPIENT;
     this.valueDefinition = pValueDef;
     this.title = pTitle;
 }
 
+/**
+ * Returns the default placeholder start delimiter
+ */
+Placeholder.getDefaultStartDelimiter = function ()
+{
+    return "{@";
+}
+
+/**
+ * Returns the default placeholder end delimiter
+ */
+Placeholder.getDefaultEndDelimiter = function ()
+{
+    return "@}";
+}
+
+/**
+ * Returns the placeholderName with startDelimiter and endDelimiter added
+ */
+Placeholder.prototype.getFormattedName = function ()
+{
+    return this.startDelimiter + this.placeholderName + this.endDelimiter;
+}
+
 Placeholder.prototype.toString = function ()
 {
-    return this.placeholderName;
+    return this.getFormattedName();
 }
 
 /**
@@ -170,7 +192,15 @@ Placeholder.types = {
     /**
      * function that returns a sub-sql
      */
-    SQLPARTFUNCTION : "SQLPARTFUNCTION"
+    SQLPARTFUNCTION : "SQLPARTFUNCTION",
+    /**
+     * a predefined value, useful for own implementations of special placeholders
+     */
+    FIXEDVALUE : "FIXEDVALUE",
+    /**
+     * functions that returns the value for the placeholder
+     */
+    CALLBACKFUNCTION : "CALLBACKFUNCTION"
 };
 
 /**