diff --git a/.liquibase/Data_alias/basic/2019.1.4/AttributeKeyword.xml b/.liquibase/Data_alias/basic/2019.1.4/AttributeKeyword.xml
index dba5cdc84a7f3fc3ad29b646e6a42ed5e781cdc7..9ff598e1434a61a29de0ad379cf9c9858dee7096 100644
--- a/.liquibase/Data_alias/basic/2019.1.4/AttributeKeyword.xml
+++ b/.liquibase/Data_alias/basic/2019.1.4/AttributeKeyword.xml
@@ -5,6 +5,7 @@
             <column name="DROPDOWNDEFINITION" type="VARCHAR(80)"/>
             <column name="ATTRIBUTE_INFO" type="NCLOB"/>
             <column name="SORTING" type="INTEGER"/>
+            <column name="DROPDOWNFILTER" type="NVARCHAR(512)"/>
 	</addColumn>
 	<addColumn tableName="AB_ATTRIBUTERELATION">
             <column name="INT_VALUE" type="INTEGER"/>
diff --git a/aliasDefinition/Data_alias/Data_alias.aod b/aliasDefinition/Data_alias/Data_alias.aod
index 6e195ac3cb4317a4be191efdac7ac6d5973e6ba9..a3feff6d5a00f34ad0a89bd000ae8d182b062067 100644
--- a/aliasDefinition/Data_alias/Data_alias.aod
+++ b/aliasDefinition/Data_alias/Data_alias.aod
@@ -5700,6 +5700,20 @@
                   </customBooleanProperty>
                 </customProperties>
               </entityFieldDb>
+              <entityFieldDb>
+                <name>DROPDOWNFILTER</name>
+                <dbName></dbName>
+                <primaryKey v="false" />
+                <columnType v="12" />
+                <size v="512" />
+                <scale v="0" />
+                <notNull v="false" />
+                <isUnique v="false" />
+                <index v="false" />
+                <documentation></documentation>
+                <title></title>
+                <description></description>
+              </entityFieldDb>
             </entityFields>
           </entityDb>
           <entityDb>
diff --git a/entity/Activity_entity/Activity_entity.aod b/entity/Activity_entity/Activity_entity.aod
index b8c9b45e40a40d95acda8de2cd0e60232d3f8e61..5f23c46537951e40ba3bff13bca090f9af6ffdd6 100644
--- a/entity/Activity_entity/Activity_entity.aod
+++ b/entity/Activity_entity/Activity_entity.aod
@@ -18,6 +18,7 @@
       <consumer>KeywordDirections</consumer>
       <groupable v="true" />
       <mandatory v="true" />
+      <valueProcess>%aditoprj%/entity/Activity_entity/entityfields/direction/valueProcess.js</valueProcess>
       <displayValueProcess>%aditoprj%/entity/Activity_entity/entityfields/direction/displayValueProcess.js</displayValueProcess>
     </entityField>
     <entityField>
@@ -467,11 +468,16 @@
       <name>PresetDocuments_param</name>
       <expose v="true" />
     </entityParameter>
+    <entityParameter>
+      <name>Direction_param</name>
+      <expose v="true" />
+    </entityParameter>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
       <name>db</name>
       <alias>Data_alias</alias>
+      <maximumDbRows v="10000" />
       <conditionProcess>%aditoprj%/entity/Activity_entity/recordcontainers/db/conditionProcess.js</conditionProcess>
       <orderClauseProcess>%aditoprj%/entity/Activity_entity/recordcontainers/db/orderClauseProcess.js</orderClauseProcess>
       <onDBInsert>%aditoprj%/entity/Activity_entity/recordcontainers/db/onDBInsert.js</onDBInsert>
diff --git a/entity/Activity_entity/entityfields/direction/valueProcess.js b/entity/Activity_entity/entityfields/direction/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..e219a5baf3adfbaf2d1706cbf721703e81e93a7a
--- /dev/null
+++ b/entity/Activity_entity/entityfields/direction/valueProcess.js
@@ -0,0 +1,6 @@
+import("system.neon");
+import("system.vars");
+import("system.result");
+
+if (vars.get("$this.value") == null && vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.exists("$param.Direction_param"))
+    result.string(vars.get("$param.Direction_param"));
\ No newline at end of file
diff --git a/entity/Address_entity/Address_entity.aod b/entity/Address_entity/Address_entity.aod
index e6628408551b8c1281803c8523fcef6d2be2026b..ec9bd9ac4585868981f9c82dcd4c3ddf50171f48 100644
--- a/entity/Address_entity/Address_entity.aod
+++ b/entity/Address_entity/Address_entity.aod
@@ -12,7 +12,6 @@
     <entityField>
       <name>ADDRESS</name>
       <title>Street</title>
-      <consumer>StreetValidation</consumer>
       <mandatoryProcess>%aditoprj%/entity/Address_entity/entityfields/address/mandatoryProcess.js</mandatoryProcess>
       <textInputAllowed v="true" />
       <valueProcess>%aditoprj%/entity/Address_entity/entityfields/address/valueProcess.js</valueProcess>
@@ -48,7 +47,6 @@
     <entityField>
       <name>CITY</name>
       <title>City</title>
-      <consumer>CityValidation</consumer>
       <mandatoryProcess>%aditoprj%/entity/Address_entity/entityfields/city/mandatoryProcess.js</mandatoryProcess>
       <textInputAllowed v="true" />
       <valueProcess>%aditoprj%/entity/Address_entity/entityfields/city/valueProcess.js</valueProcess>
@@ -86,7 +84,6 @@
     <entityField>
       <name>ZIP</name>
       <title>Postcode</title>
-      <consumer>ZipValidation</consumer>
       <mandatoryProcess>%aditoprj%/entity/Address_entity/entityfields/zip/mandatoryProcess.js</mandatoryProcess>
       <textInputAllowed v="true" />
       <valueProcess>%aditoprj%/entity/Address_entity/entityfields/zip/valueProcess.js</valueProcess>
diff --git a/entity/Address_entity/entityfields/address/displayValueProcess.js b/entity/Address_entity/entityfields/address/displayValueProcess.js
index 10012b6d85bef52b735c75233b6149f866b3c12a..18985f7a004b046c160746de13e8970eb6c87ece 100644
--- a/entity/Address_entity/entityfields/address/displayValueProcess.js
+++ b/entity/Address_entity/entityfields/address/displayValueProcess.js
@@ -2,4 +2,5 @@ import("system.vars");
 import("system.result");
 
 // Needed for instant refresh if set by neon.setFieldValue
-result.string(vars.get("$field.ADDRESS"));
\ No newline at end of file
+// use the code if address webservice is active
+//result.string(vars.get("$field.ADDRESS"));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/address/onValueChange.js b/entity/Address_entity/entityfields/address/onValueChange.js
index c19e660f1099559c1b027aba2317e52eee3e6495..abec5ca7ea53495f6a64fbb7eee7ed6fa3f53b25 100644
--- a/entity/Address_entity/entityfields/address/onValueChange.js
+++ b/entity/Address_entity/entityfields/address/onValueChange.js
@@ -1,4 +1,5 @@
 import("system.vars");
 import("WsValidation_lib");
 
-WsValidationUtils.setAddressFields(vars.get("$local.value"));
\ No newline at end of file
+// use the code if address webservice is active
+//WsValidationUtils.setAddressFields(vars.get("$local.value"));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/address/valueProcess.js b/entity/Address_entity/entityfields/address/valueProcess.js
index e5e514c90862ca236702c6dabc10e44ddaa4d1e5..2c9d496185be419f31c762709ca97d83a1ae4bd4 100644
--- a/entity/Address_entity/entityfields/address/valueProcess.js
+++ b/entity/Address_entity/entityfields/address/valueProcess.js
@@ -2,4 +2,5 @@ import("system.result");
 import("WsValidation_lib");
 import("system.vars");
 
-result.string(WsValidationUtils.valueFromJSON(vars.get("$this.value")));
\ No newline at end of file
+// use the code if address webservice is active
+//result.string(WsValidationUtils.valueFromJSON(vars.get("$this.value")));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/city/displayValueProcess.js b/entity/Address_entity/entityfields/city/displayValueProcess.js
index 60c162e2025d8c553422a6e077c591dd837187cb..0738ded17951195fb9050da641ec78c256a3ee38 100644
--- a/entity/Address_entity/entityfields/city/displayValueProcess.js
+++ b/entity/Address_entity/entityfields/city/displayValueProcess.js
@@ -2,4 +2,5 @@ import("system.vars");
 import("system.result");
 
 // Needed for instant refresh if set by neon.setFieldValue
-result.string(vars.get("$field.CITY"));
\ No newline at end of file
+// use the code if address webservice is active
+//result.string(vars.get("$field.CITY"));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/city/onValueChange.js b/entity/Address_entity/entityfields/city/onValueChange.js
index c19e660f1099559c1b027aba2317e52eee3e6495..abec5ca7ea53495f6a64fbb7eee7ed6fa3f53b25 100644
--- a/entity/Address_entity/entityfields/city/onValueChange.js
+++ b/entity/Address_entity/entityfields/city/onValueChange.js
@@ -1,4 +1,5 @@
 import("system.vars");
 import("WsValidation_lib");
 
-WsValidationUtils.setAddressFields(vars.get("$local.value"));
\ No newline at end of file
+// use the code if address webservice is active
+//WsValidationUtils.setAddressFields(vars.get("$local.value"));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/city/valueProcess.js b/entity/Address_entity/entityfields/city/valueProcess.js
index e5e514c90862ca236702c6dabc10e44ddaa4d1e5..2c9d496185be419f31c762709ca97d83a1ae4bd4 100644
--- a/entity/Address_entity/entityfields/city/valueProcess.js
+++ b/entity/Address_entity/entityfields/city/valueProcess.js
@@ -2,4 +2,5 @@ import("system.result");
 import("WsValidation_lib");
 import("system.vars");
 
-result.string(WsValidationUtils.valueFromJSON(vars.get("$this.value")));
\ No newline at end of file
+// use the code if address webservice is active
+//result.string(WsValidationUtils.valueFromJSON(vars.get("$this.value")));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/zip/displayValueProcess.js b/entity/Address_entity/entityfields/zip/displayValueProcess.js
index bb62a2e6ba7cd75da9a04529fe0b98b4e0f0b13f..219ae2ffc092fe47ebcd3b427c2c4f28052cd0d4 100644
--- a/entity/Address_entity/entityfields/zip/displayValueProcess.js
+++ b/entity/Address_entity/entityfields/zip/displayValueProcess.js
@@ -2,4 +2,5 @@ import("system.vars");
 import("system.result");
 
 // Needed for instant refresh if set by neon.setFieldValue
-result.string(vars.get("$field.ZIP"));
\ No newline at end of file
+// use the code if address webservice is active
+//result.string(vars.get("$field.ZIP"));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/zip/onValueChange.js b/entity/Address_entity/entityfields/zip/onValueChange.js
index c19e660f1099559c1b027aba2317e52eee3e6495..abec5ca7ea53495f6a64fbb7eee7ed6fa3f53b25 100644
--- a/entity/Address_entity/entityfields/zip/onValueChange.js
+++ b/entity/Address_entity/entityfields/zip/onValueChange.js
@@ -1,4 +1,5 @@
 import("system.vars");
 import("WsValidation_lib");
 
-WsValidationUtils.setAddressFields(vars.get("$local.value"));
\ No newline at end of file
+// use the code if address webservice is active
+//WsValidationUtils.setAddressFields(vars.get("$local.value"));
\ No newline at end of file
diff --git a/entity/Address_entity/entityfields/zip/valueProcess.js b/entity/Address_entity/entityfields/zip/valueProcess.js
index 86705dc47362b571c2cfb30d66c8fd05f3f08ef4..92c7fae75dc7a1b51668e4685fe75ed5d197a85b 100644
--- a/entity/Address_entity/entityfields/zip/valueProcess.js
+++ b/entity/Address_entity/entityfields/zip/valueProcess.js
@@ -2,4 +2,5 @@ import("system.vars");
 import("system.result");
 import("WsValidation_lib");
 
-result.string(WsValidationUtils.valueFromJSON(vars.get("$this.value")));
\ No newline at end of file
+// use the code if address webservice is active
+//result.string(WsValidationUtils.valueFromJSON(vars.get("$this.value")));
\ No newline at end of file
diff --git a/entity/Appointment_entity/entityfields/begin/valueProcess.js b/entity/Appointment_entity/entityfields/begin/valueProcess.js
index 0ec0da52b21a9bb3169b5447365dda3006449bfb..f87cdc03567024fded757914d9ee6b1587f2a258 100644
--- a/entity/Appointment_entity/entityfields/begin/valueProcess.js
+++ b/entity/Appointment_entity/entityfields/begin/valueProcess.js
@@ -1,3 +1,4 @@
+import("system.logging");
 import("system.neon");
 import("system.vars");
 import("system.calendars");
@@ -10,6 +11,8 @@ if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.exists("$para
 {
     var event = JSON.parse(vars.getString("$param.Entry_param"));
 
-    if(event[calendars.DTSTART])
+    if(vars.get("$this.value"))
+        result.string(vars.get("$this.value"));
+    else if(event[calendars.DTSTART])
         result.string(event[calendars.DTSTART]);
 }
\ No newline at end of file
diff --git a/entity/Appointment_entity/entityfields/deleteseries/stateProcess.js b/entity/Appointment_entity/entityfields/deleteseries/stateProcess.js
index cafd855df058e4a32622c8959d810159887d4cdf..b32031361cda543dc371943b8db3ba13d92aa3d6 100644
--- a/entity/Appointment_entity/entityfields/deleteseries/stateProcess.js
+++ b/entity/Appointment_entity/entityfields/deleteseries/stateProcess.js
@@ -1,23 +1,23 @@
-import("system.logging");
-import("system.tools");
-import("system.vars");
-import("system.result");
-import("system.calendars");
-import("system.neon");
-import("system.text");
-
-
-var event = JSON.parse(vars.getString("$param.Entry_param"));
-
-if(event) //event not empty
-{
-    var orgaCn = event[calendars.ORGANIZER2]["cn"];
-    var currentUserTitle = vars.getString("$sys.user");
-    
-    if(event[calendars.RECURRENCEID] && ((orgaCn == currentUserTitle) || calendars.getBackendType() == calendars.BACKEND_EXCHANGEWS)) //serientermin und currentUser der TerminOwner
-            result.object(neon.COMPONENTSTATE_AUTO);
-        else
-            result.object(neon.COMPONENTSTATE_INVISIBLE);
-}
-else
+import("system.logging");
+import("system.tools");
+import("system.vars");
+import("system.result");
+import("system.calendars");
+import("system.neon");
+import("system.text");
+
+
+var event = JSON.parse(vars.getString("$param.Entry_param"));
+
+if(event) //event not empty
+{
+    var orgaCn = event[calendars.ORGANIZER2]["cn"];
+    var currentUserTitle = vars.getString("$sys.user");
+    
+    if(event[calendars.RECURRENCEID] && ((orgaCn == currentUserTitle)))//) || calendars.getBackendType() == calendars.BACKEND_EXCHANGEWS)) //serientermin und currentUser der TerminOwner
+            result.object(neon.COMPONENTSTATE_AUTO);
+        else
+            result.object(neon.COMPONENTSTATE_INVISIBLE);
+}
+else
     result.object(neon.COMPONENTSTATE_AUTO);
\ No newline at end of file
diff --git a/entity/Appointment_entity/entityfields/end/valueProcess.js b/entity/Appointment_entity/entityfields/end/valueProcess.js
index 1276bc19ec272188393c5485613b2fbb779fc5de..284d2d66518b86d3727a04d3ab07ebe1ba250662 100644
--- a/entity/Appointment_entity/entityfields/end/valueProcess.js
+++ b/entity/Appointment_entity/entityfields/end/valueProcess.js
@@ -1,15 +1,17 @@
-import("system.neon");
-import("system.vars");
-import("system.calendars");
-import("system.result");
-
-/**
- * Following if() is only for passing param-parts from "new Appointment"-Dialog to AppointmentEditViewTemplate
- */
-if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.exists("$param.Entry_param"))
-{
-    var event = JSON.parse(vars.getString("$param.Entry_param"));
-
-    if(event[calendars.DTEND])
-        result.string(event[calendars.DTEND]);
+import("system.neon");
+import("system.vars");
+import("system.calendars");
+import("system.result");
+
+/**
+ * Following if() is only for passing param-parts from "new Appointment"-Dialog to AppointmentEditViewTemplate
+ */
+if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.exists("$param.Entry_param"))
+{
+    var event = JSON.parse(vars.getString("$param.Entry_param"));
+
+    if(vars.get("$this.value"))
+        result.string(vars.get("$this.value"));
+    else if(event[calendars.DTEND])
+        result.string(event[calendars.DTEND]);
 }
\ No newline at end of file
diff --git a/entity/Attribute_entity/Attribute_entity.aod b/entity/Attribute_entity/Attribute_entity.aod
index 6dbc75f24c8a2c42ac787b0ab19c10ee498a9f0e..8ea004bc50a01695f2cb4e130c793c61aeb8bfb1 100644
--- a/entity/Attribute_entity/Attribute_entity.aod
+++ b/entity/Attribute_entity/Attribute_entity.aod
@@ -331,6 +331,11 @@
       <iconId>VAADIN:CURLY_BRACKETS</iconId>
       <stateProcess>%aditoprj%/entity/Attribute_entity/entityfields/openadminview/stateProcess.js</stateProcess>
     </entityActionField>
+    <entityField>
+      <name>DROPDOWNFILTER</name>
+      <title>Filter</title>
+      <contentType>FILTER_TREE</contentType>
+    </entityField>
   </entityFields>
   <recordContainers>
     <jDitoRecordContainer>
@@ -361,6 +366,9 @@
         <jDitoRecordFieldMapping>
           <name>DROPDOWNDEFINITION.value</name>
         </jDitoRecordFieldMapping>
+        <jDitoRecordFieldMapping>
+          <name>DROPDOWNFILTER.value</name>
+        </jDitoRecordFieldMapping>
         <jDitoRecordFieldMapping>
           <name>SORTING.value</name>
         </jDitoRecordFieldMapping>
diff --git a/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js b/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js
index 26dccfdc9956c9f8d85820185957af2e8e031ff5..016b432ba387c332027c8d13771fd7d000c805b0 100644
--- a/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js
@@ -15,7 +15,7 @@ var parentType = vars.exists("$param.AttrParentType_param") && vars.get("$param.
 var fetchUsages = true;
 var translateName = false;
 
-var sqlSelect = "select AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME, ATTRIBUTE_ACTIVE, DROPDOWNDEFINITION, SORTING, ATTRIBUTE_TYPE, " 
+var sqlSelect = "select AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME, ATTRIBUTE_ACTIVE, DROPDOWNDEFINITION, DROPDOWNFILTER, SORTING, ATTRIBUTE_TYPE, " 
     + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.attributeType(), "ATTRIBUTE_TYPE") //3
     + ", '', '', '' from AB_ATTRIBUTE"; 
 
@@ -152,15 +152,15 @@ function _buildAttributeTable (pAttributes, pUsages)
     for (let i in rows)
     {
         let rowData = rows[i].data;
-        if (pUsages && rowData[6].trim() != $AttributeTypes.COMBOVALUE && i in pUsages)
+        if (pUsages && rowData[7].trim() != $AttributeTypes.COMBOVALUE && i in pUsages)
         {
-            rowData[8] = pUsages[i].map(function (usage)
+            rowData[9] = pUsages[i].map(function (usage)
             {
                 return translate.text(usage);
             }).join(", ");
         }
-        rowData[9] = _getFullName(rowData[1]); //parent full name
-        rowData[10] = _getFullName(rowData[0], displaySimpleName);
+        rowData[10] = _getFullName(rowData[1]); //parent full name
+        rowData[11] = _getFullName(rowData[0], displaySimpleName);
         sortedArray[rows[i].index] = rowData;
     }
     
diff --git a/entity/Attribute_entity/recordcontainers/jdito/onInsert.js b/entity/Attribute_entity/recordcontainers/jdito/onInsert.js
index 5001a6ab2c5289932e32c56bf7843efa09a2a8dc..e44ad6dacc4be5f21442e178e609cedfa32ffff8 100644
--- a/entity/Attribute_entity/recordcontainers/jdito/onInsert.js
+++ b/entity/Attribute_entity/recordcontainers/jdito/onInsert.js
@@ -1,24 +1,26 @@
-import("system.db");
-import("system.vars");
-
-var rowdata = vars.get("$local.rowdata");
-var columns = [
-    "AB_ATTRIBUTEID",
-    "ATTRIBUTE_ACTIVE",
-    "ATTRIBUTE_NAME",
-    "ATTRIBUTE_PARENT_ID",
-    "ATTRIBUTE_TYPE",
-    "DROPDOWNDEFINITION",
-    "SORTING"
-];
-var values = [
-    rowdata["UID.value"],
-    rowdata["ATTRIBUTE_ACTIVE.value"] || "",
-    rowdata["ATTRIBUTE_NAME.value"] || "",
-    rowdata["ATTRIBUTE_PARENT_ID.value"] || "",
-    rowdata["ATTRIBUTE_TYPE.value"] || "",
-    rowdata["DROPDOWNDEFINITION.value"] || "",
-    rowdata["SORTING.value"] || ""
-];
-
+import("system.db");
+import("system.vars");
+
+var rowdata = vars.get("$local.rowdata");
+var columns = [
+    "AB_ATTRIBUTEID",
+    "ATTRIBUTE_ACTIVE",
+    "ATTRIBUTE_NAME",
+    "ATTRIBUTE_PARENT_ID",
+    "ATTRIBUTE_TYPE",
+    "DROPDOWNDEFINITION",
+    "DROPDOWNFILTER",
+    "SORTING"
+];
+var values = [
+    rowdata["UID.value"],
+    rowdata["ATTRIBUTE_ACTIVE.value"] || "",
+    rowdata["ATTRIBUTE_NAME.value"] || "",
+    rowdata["ATTRIBUTE_PARENT_ID.value"] || "",
+    rowdata["ATTRIBUTE_TYPE.value"] || "",
+    rowdata["DROPDOWNDEFINITION.value"] || "",
+    rowdata["DROPDOWNFILTER.value"] || "",
+    rowdata["SORTING.value"] || ""
+];
+
 db.insertData("AB_ATTRIBUTE", columns, null, values);
\ No newline at end of file
diff --git a/entity/Attribute_entity/recordcontainers/jdito/onUpdate.js b/entity/Attribute_entity/recordcontainers/jdito/onUpdate.js
index 12855e6b9b1d12e65051d9b40dddae43b221f4d5..12ab6ce802c360e2ca62e9ce4ac7f26e6f6e2b74 100644
--- a/entity/Attribute_entity/recordcontainers/jdito/onUpdate.js
+++ b/entity/Attribute_entity/recordcontainers/jdito/onUpdate.js
@@ -1,24 +1,26 @@
-import("Sql_lib");
-import("system.db");
-import("system.vars");
-
-var rowdata = vars.get("$local.rowdata");
-var columns = [
-    "ATTRIBUTE_ACTIVE",
-    "ATTRIBUTE_NAME",
-    "ATTRIBUTE_PARENT_ID",
-    "ATTRIBUTE_TYPE",
-    "DROPDOWNDEFINITION",
-    "SORTING"
-];
-var values = [
-    rowdata["ATTRIBUTE_ACTIVE.value"] || "",
-    rowdata["ATTRIBUTE_NAME.value"] || "",
-    rowdata["ATTRIBUTE_PARENT_ID.value"] || "",
-    rowdata["ATTRIBUTE_TYPE.value"] || "",
-    rowdata["DROPDOWNDEFINITION.value"] || "",
-    rowdata["SORTING.value"] || ""
-];
-
-db.updateData("AB_ATTRIBUTE", columns, null, values, 
+import("Sql_lib");
+import("system.db");
+import("system.vars");
+
+var rowdata = vars.get("$local.rowdata");
+var columns = [
+    "ATTRIBUTE_ACTIVE",
+    "ATTRIBUTE_NAME",
+    "ATTRIBUTE_PARENT_ID",
+    "ATTRIBUTE_TYPE",
+    "DROPDOWNDEFINITION",
+    "DROPDOWNFILTER",
+    "SORTING"
+];
+var values = [
+    rowdata["ATTRIBUTE_ACTIVE.value"] || "",
+    rowdata["ATTRIBUTE_NAME.value"] || "",
+    rowdata["ATTRIBUTE_PARENT_ID.value"] || "",
+    rowdata["ATTRIBUTE_TYPE.value"] || "",
+    rowdata["DROPDOWNDEFINITION.value"] || "",
+    rowdata["DROPDOWNFILTER.value"] || "",
+    rowdata["SORTING.value"] || ""
+];
+
+db.updateData("AB_ATTRIBUTE", columns, null, values, 
     SqlCondition.equals("AB_ATTRIBUTE.AB_ATTRIBUTEID", vars.get("$field.UID"), "1=2"));
\ No newline at end of file
diff --git a/entity/BulkMailChart_entity/recordcontainers/jdito/contentProcess.js b/entity/BulkMailChart_entity/recordcontainers/jdito/contentProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..0869420384ccec1e8f1d42e8c2658734e3e3df7c
--- /dev/null
+++ b/entity/BulkMailChart_entity/recordcontainers/jdito/contentProcess.js
@@ -0,0 +1,16 @@
+import("system.db");
+import("system.result");
+import("Sql_lib");
+import("Keyword_lib");
+import("KeywordRegistry_basic");
+import("system.vars");
+
+var bulkMailId = vars.get("$param.BulkMailId_param");
+
+var query = SqlBuilder.begin()
+    .select(["STATUS", "STATUS", KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.bulkMailRecipientStatus(), "STATUS"), "count(STATUS)"])
+    .from("BULKMAILRECIPIENT")
+    .where(SqlCondition.begin().andPrepare("BULKMAILRECIPIENT.BULKMAIL_ID", bulkMailId))
+    .groupBy("STATUS");
+
+result.object(db.table(query.build()));
\ No newline at end of file
diff --git a/entity/BulkMailStatusChart_entity/BulkMailStatusChart_entity.aod b/entity/BulkMailStatusChart_entity/BulkMailStatusChart_entity.aod
new file mode 100644
index 0000000000000000000000000000000000000000..0c0b218c5fab7dd9f6e4a0298bce8d70ba0078c8
--- /dev/null
+++ b/entity/BulkMailStatusChart_entity/BulkMailStatusChart_entity.aod
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.10" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.10">
+  <name>BulkMailStatusChart_entity</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <title>Recipient status</title>
+  <titlePlural>Recipient status</titlePlural>
+  <recordContainer>jdito</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+    </entityProvider>
+    <entityField>
+      <name>X</name>
+      <title>Recipients</title>
+    </entityField>
+    <entityField>
+      <name>Y</name>
+    </entityField>
+    <entityParameter>
+      <name>BulkMailId_param</name>
+      <expose v="true" />
+      <mandatory v="true" />
+    </entityParameter>
+    <entityField>
+      <name>UID</name>
+    </entityField>
+    <entityProvider>
+      <name>RecipientStatusChart</name>
+      <dependencies>
+        <entityDependency>
+          <name>e2d96467-ec53-424b-b78c-c97c2db2bb8a</name>
+          <entityName>BulkMail_entity</entityName>
+          <fieldName>RecipientStatusChart</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+    </entityProvider>
+  </entityFields>
+  <recordContainers>
+    <jDitoRecordContainer>
+      <name>jdito</name>
+      <jDitoRecordAlias>Data_alias</jDitoRecordAlias>
+      <contentProcess>%aditoprj%/entity/BulkMailStatusChart_entity/recordcontainers/jdito/contentProcess.js</contentProcess>
+      <recordFieldMappings>
+        <jDitoRecordFieldMapping>
+          <name>UID.value</name>
+        </jDitoRecordFieldMapping>
+        <jDitoRecordFieldMapping>
+          <name>X.value</name>
+        </jDitoRecordFieldMapping>
+        <jDitoRecordFieldMapping>
+          <name>X.displayValue</name>
+        </jDitoRecordFieldMapping>
+        <jDitoRecordFieldMapping>
+          <name>Y.value</name>
+        </jDitoRecordFieldMapping>
+      </recordFieldMappings>
+    </jDitoRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/BulkMailStatusChart_entity/recordcontainers/jdito/contentProcess.js b/entity/BulkMailStatusChart_entity/recordcontainers/jdito/contentProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..0869420384ccec1e8f1d42e8c2658734e3e3df7c
--- /dev/null
+++ b/entity/BulkMailStatusChart_entity/recordcontainers/jdito/contentProcess.js
@@ -0,0 +1,16 @@
+import("system.db");
+import("system.result");
+import("Sql_lib");
+import("Keyword_lib");
+import("KeywordRegistry_basic");
+import("system.vars");
+
+var bulkMailId = vars.get("$param.BulkMailId_param");
+
+var query = SqlBuilder.begin()
+    .select(["STATUS", "STATUS", KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.bulkMailRecipientStatus(), "STATUS"), "count(STATUS)"])
+    .from("BULKMAILRECIPIENT")
+    .where(SqlCondition.begin().andPrepare("BULKMAILRECIPIENT.BULKMAIL_ID", bulkMailId))
+    .groupBy("STATUS");
+
+result.object(db.table(query.build()));
\ No newline at end of file
diff --git a/entity/BulkMail_entity/BulkMail_entity.aod b/entity/BulkMail_entity/BulkMail_entity.aod
index 04cb781052806175e74ca8bd4c0a07f8af6ebe5c..74c3e84fb824e7dc5aed402646e584b712db7510 100644
--- a/entity/BulkMail_entity/BulkMail_entity.aod
+++ b/entity/BulkMail_entity/BulkMail_entity.aod
@@ -94,6 +94,7 @@
       <onActionProcess>%aditoprj%/entity/BulkMail_entity/entityfields/sendmail/onActionProcess.js</onActionProcess>
       <iconId>VAADIN:PAPERPLANE</iconId>
       <stateProcess>%aditoprj%/entity/BulkMail_entity/entityfields/sendmail/stateProcess.js</stateProcess>
+      <tooltipProcess>%aditoprj%/entity/BulkMail_entity/entityfields/sendmail/tooltipProcess.js</tooltipProcess>
     </entityActionField>
     <entityField>
       <name>ICON</name>
@@ -158,6 +159,33 @@
         </entityParameter>
       </children>
     </entityConsumer>
+    <entityField>
+      <name>CREATEACTIVITIES</name>
+      <title>Create activities</title>
+      <contentType>BOOLEAN</contentType>
+      <dropDownProcess>%aditoprj%/entity/BulkMail_entity/entityfields/createactivities/dropDownProcess.js</dropDownProcess>
+      <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/createactivities/valueProcess.js</valueProcess>
+    </entityField>
+    <entityConsumer>
+      <name>RecipientStatusChart</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>BulkMailStatusChart_entity</entityName>
+        <fieldName>RecipientStatusChart</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>BulkMailId_param</name>
+          <valueProcess>%aditoprj%/entity/BulkMail_entity/entityfields/recipientstatuschart/children/bulkmailid_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityActionField>
+      <name>testMail</name>
+      <title>Test email</title>
+      <onActionProcess>%aditoprj%/entity/BulkMail_entity/entityfields/testmail/onActionProcess.js</onActionProcess>
+      <iconId>VAADIN:CLIPBOARD_CHECK</iconId>
+    </entityActionField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
diff --git a/entity/BulkMail_entity/entityfields/content/displayValueProcess.js b/entity/BulkMail_entity/entityfields/content/displayValueProcess.js
index 15c8c8a5835c2d7f3e7540aa4d4d0be4f74e4669..33b1e10e22e8eb98f9041122f0f668c05200ccc5 100644
--- a/entity/BulkMail_entity/entityfields/content/displayValueProcess.js
+++ b/entity/BulkMail_entity/entityfields/content/displayValueProcess.js
@@ -12,8 +12,8 @@ if (vars.get("$sys.viewmode") == neon.FRAME_VIEWMODE_DATASET)
     var template = BulkMailUtils.getBulkMailTemplate(vars.get("$field.BULKMAILID"), vars.get("$field.DOCUMENTTEMPLATE_ID"));
     
     var contactId = EmployeeUtils.getCurrentContactId();
-    var preview = template.getReplacedEmailsByContactIds([contactId]);
+    var preview = template.getReplacedContentByContactId(contactId);
 
-    result.string(preview[contactId].body);
+    result.string(preview);
 }
 
diff --git a/entity/BulkMail_entity/entityfields/content/valueProcess.js b/entity/BulkMail_entity/entityfields/content/valueProcess.js
index 7abb9759cf4b8f7cfc718bdc8b234d2f526c63ea..b19a5392e33ff17995b855aaeb30f11b542ee0c4 100644
--- a/entity/BulkMail_entity/entityfields/content/valueProcess.js
+++ b/entity/BulkMail_entity/entityfields/content/valueProcess.js
@@ -7,7 +7,7 @@ import("system.db");
 import("DocumentTemplate_lib");
 import("Bulkmail_lib");
 
-if (vars.get("$this.value") == null)
+if (vars.get("$this.value") == null && vars.get("$sys.viewmode") == neon.FRAME_VIEWMODE_DATASET)
 {
     var upload = vars.get("$field.BINDATA");
     var template;
@@ -22,7 +22,7 @@ if (vars.get("$this.value") == null)
     {
         template = BulkMailUtils.getBulkMailTemplate(vars.get("$field.BULKMAILID"), vars.get("$field.DOCUMENTTEMPLATE_ID"));
     }
-    var content = template.getReplacedContent({}, true);
+    var content = template.getReplacedContent({});
 
     result.string(content);
 }
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/createactivities/dropDownProcess.js b/entity/BulkMail_entity/entityfields/createactivities/dropDownProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..3373b8a886df7267c9205c206442cb2e091128fb
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/createactivities/dropDownProcess.js
@@ -0,0 +1,7 @@
+import("system.translate");
+import("system.result");
+
+result.object([
+    ["1", translate.text("Yes")],
+    ["0", translate.text("No")]
+]);
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/createactivities/valueProcess.js b/entity/BulkMail_entity/entityfields/createactivities/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..72e22f0a52f1d6439b67df5abc59a66280df8fd4
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/createactivities/valueProcess.js
@@ -0,0 +1,6 @@
+import("system.neon");
+import("system.vars");
+import("system.result");
+
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$this.value") == null)
+    result.string("1");
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/recipientstatuschart/children/bulkmailid_param/valueProcess.js b/entity/BulkMail_entity/entityfields/recipientstatuschart/children/bulkmailid_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a12b8389ba83e397d6b9ae10eb59989a25590fe
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/recipientstatuschart/children/bulkmailid_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$field.BULKMAILID"));
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/sender/onValidation.js b/entity/BulkMail_entity/entityfields/sender/onValidation.js
index 429ec70614bd74bcba194b44a61640f3b7a2e779..36c5491ee5aa2ddf06932ee751e0f7740ad24547 100644
--- a/entity/BulkMail_entity/entityfields/sender/onValidation.js
+++ b/entity/BulkMail_entity/entityfields/sender/onValidation.js
@@ -1,3 +1,4 @@
+import("system.vars");
 import("system.result");
 import("Communication_lib");
 import("Entity_lib");
diff --git a/entity/BulkMail_entity/entityfields/sendmail/onActionProcess.js b/entity/BulkMail_entity/entityfields/sendmail/onActionProcess.js
index 84cc2e975ffd32302521043c2342a774b0a927cf..4a316db7db175aae1530bb366fe02086d1702f45 100644
--- a/entity/BulkMail_entity/entityfields/sendmail/onActionProcess.js
+++ b/entity/BulkMail_entity/entityfields/sendmail/onActionProcess.js
@@ -1,3 +1,5 @@
+import("system.translate");
+import("system.question");
 import("Sql_lib");
 import("system.neon");
 import("system.vars");
@@ -5,7 +7,11 @@ import("Bulkmail_lib");
 import("system.db");
 import("KeywordRegistry_basic");
 
-db.updateData("BULKMAIL", ["STATUS"], null, [$KeywordRegistry.bulkMailStatus$beingSent()], 
-    SqlCondition.equals("BULKMAIL.BULKMAILID", vars.get("$field.BULKMAILID"), "1=2"));
-neon.refreshAll();
-BulkMailUtils.sendBulkMailOnServer(vars.get("$field.BULKMAILID"));
\ No newline at end of file
+var send = question.askYesNo(translate.text("Bulk mail"), translate.text("Should the mail be sent now?"), false);
+if (send)
+{
+    db.updateData("BULKMAIL", ["STATUS"], null, [$KeywordRegistry.bulkMailStatus$beingSent()], 
+        SqlCondition.equals("BULKMAIL.BULKMAILID", vars.get("$field.BULKMAILID"), "1=2"));
+    neon.refreshAll();
+    BulkMailUtils.sendBulkMailOnServer(vars.get("$field.BULKMAILID"));
+}
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/sendmail/tooltipProcess.js b/entity/BulkMail_entity/entityfields/sendmail/tooltipProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..264f6bfd16f8e4e181b4088811117bf017025771
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/sendmail/tooltipProcess.js
@@ -0,0 +1,4 @@
+import("system.translate");
+import("system.result");
+
+result.string(translate.text("Send"));
\ No newline at end of file
diff --git a/entity/BulkMail_entity/entityfields/testmail/onActionProcess.js b/entity/BulkMail_entity/entityfields/testmail/onActionProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..9dcf990316b9b824b8377fc6f18a362be936f684
--- /dev/null
+++ b/entity/BulkMail_entity/entityfields/testmail/onActionProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("Bulkmail_lib");
+
+BulkMailUtils.sendBulkMailOnServer(vars.get("$field.BULKMAILID"));
\ No newline at end of file
diff --git a/entity/ClassificationAdmin_entity/ClassificationAdmin_entity.aod b/entity/ClassificationAdmin_entity/ClassificationAdmin_entity.aod
index e357c82de6f0ac692987fb1a41db11eea32d6c24..752f40d13e406aa9d5422c9c1c547c4428318f7e 100644
--- a/entity/ClassificationAdmin_entity/ClassificationAdmin_entity.aod
+++ b/entity/ClassificationAdmin_entity/ClassificationAdmin_entity.aod
@@ -6,6 +6,7 @@
   <title>Classification</title>
   <grantDeleteProcess>%aditoprj%/entity/ClassificationAdmin_entity/grantDeleteProcess.js</grantDeleteProcess>
   <contentTitleProcess>%aditoprj%/entity/ClassificationAdmin_entity/contentTitleProcess.js</contentTitleProcess>
+  <iconId>VAADIN:LIST_OL</iconId>
   <titlePlural>Classifications</titlePlural>
   <recordContainer>jdito</recordContainer>
   <entityFields>
diff --git a/entity/DuplicateScan_entity/DuplicateScan_entity.aod b/entity/DuplicateScan_entity/DuplicateScan_entity.aod
index 74e964fd18e7c2fe99950c2ba386daceb52b5a28..a0f3f3e1d7cb7c084f4c97aff148c67eb23bce74 100644
--- a/entity/DuplicateScan_entity/DuplicateScan_entity.aod
+++ b/entity/DuplicateScan_entity/DuplicateScan_entity.aod
@@ -3,6 +3,7 @@
   <name>DuplicateScan_entity</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <title>Duplicatescan</title>
+  <iconId>VAADIN:DATABASE</iconId>
   <recordContainer>DBRecordContainer</recordContainer>
   <entityFields>
     <entityProvider>
diff --git a/entity/Email_entity/recordcontainers/jdito/onInsert.js b/entity/Email_entity/recordcontainers/jdito/onInsert.js
index d0a851b561749859c1d3facc086380da8aa2c3de..0d1bbaf89d697443184dda23614a52ca5bdb2cb8 100644
--- a/entity/Email_entity/recordcontainers/jdito/onInsert.js
+++ b/entity/Email_entity/recordcontainers/jdito/onInsert.js
@@ -3,6 +3,7 @@ import("system.neon");
 import("Employee_lib");
 import("system.vars");
 import("Email_lib");
+import("Contact_lib");
 
 var contactId = vars.get("$param.ContactId_param");
 var eml = EmailWritingUtils.openMailTemplate(
@@ -11,9 +12,3 @@ var eml = EmailWritingUtils.openMailTemplate(
     vars.get("$field.DOCUMENT_TEMPLATE"), 
     contactId
 );
-
-var links = [];
-if (contactId)
-    links.push(["Person", contactId]); //TODO: dynamic
-
-ActivityUtils.createNewActivity(null, links, null, null, [eml]);
\ No newline at end of file
diff --git a/entity/Employee_entity/entityfields/email_address/dropDownProcess.js b/entity/Employee_entity/entityfields/email_address/dropDownProcess.js
index da419b6e5ea563cb1659058ed6999d65218ce082..1e6f7e670fc70b7c1fcdd6f78318b624d9c9cf07 100644
--- a/entity/Employee_entity/entityfields/email_address/dropDownProcess.js
+++ b/entity/Employee_entity/entityfields/email_address/dropDownProcess.js
@@ -1,26 +1,26 @@
-import("Communication_lib");
-import("system.neon");
-import("system.vars");
-import("system.db");
-import("system.result");
-import("Sql_lib");
-
-var contactId = vars.get("$field.CONTACT_ID");
-if (contactId)
-{
-    var sql = SqlCondition.begin()
-        .andPrepare("COMMUNICATION.CONTACT_ID", contactId)
-        .and("COMMUNICATION.MEDIUM_ID in ('" + CommUtil.getMediumIdsByCategory("EMAIL").join("', '") + "')")
-        .buildSql("select ADDR, ADDR from COMMUNICATION");
-    
-    var addresses = db.table(sql);
-    
-    //include the currently set email address
-    var currentAddress = vars.get("$field.EMAIL_ADDRESS");
-    if (currentAddress && !addresses.some(function (row) {return row[0] == currentAddress;}))
-    {
-        addresses.push([currentAddress, currentAddress]);
-    }   
-    
-    result.object(addresses);
+import("Communication_lib");
+import("system.neon");
+import("system.vars");
+import("system.db");
+import("system.result");
+import("Sql_lib");
+
+var contactId = vars.get("$field.CONTACT_ID");
+if (contactId && (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT || vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW))
+{
+    var sql = SqlCondition.begin()
+        .andPrepare("COMMUNICATION.CONTACT_ID", contactId)
+        .and("COMMUNICATION.MEDIUM_ID in ('" + CommUtil.getMediumIdsByCategory("EMAIL").join("', '") + "')")
+        .buildSql("select ADDR, ADDR from COMMUNICATION");
+    
+    var addresses = db.table(sql);
+    
+    //include the currently set email address
+    var currentAddress = vars.get("$field.EMAIL_ADDRESS");
+    if (currentAddress && !addresses.some(function (row) {return row[0] == currentAddress;}))
+    {
+        addresses.push([currentAddress, currentAddress]);
+    }   
+    
+    result.object(addresses);
 }
\ No newline at end of file
diff --git a/entity/Employee_entity/recordcontainers/jdito/contentProcess.js b/entity/Employee_entity/recordcontainers/jdito/contentProcess.js
index 175260510da1e538cf01076746572566e3373f11..61bf29a24123620584dc00946b74a781d10b7f47 100644
--- a/entity/Employee_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/Employee_entity/recordcontainers/jdito/contentProcess.js
@@ -1,3 +1,5 @@
+import("Sql_lib");
+import("system.db");
 import("Attribute_lib");
 import("system.vars");
 import("system.result");
@@ -18,8 +20,11 @@ else
     users = tools.getUsersByAttribute(tools.ISACTIVE, values, tools.PROFILE_FULL);
 }
 
+var contactIds = [];
 users = users.map(function (user)
 {
+    contactIds.push(user[tools.PARAMS][tools.CONTACTID]);
+    
     return [
         user[tools.NAME],
         user[tools.TITLE],
@@ -29,13 +34,28 @@ users = users.map(function (user)
         user[tools.PARAMS][tools.EMAIL],
         user[tools.PARAMS][tools.EMAIL],
         user[tools.DESCRIPTION],
-        user[tools.PARAMS][tools.CONTACTID],
-        ContactUtils.getTitleByContactId(user[tools.PARAMS][tools.CONTACTID]), //TODO: get the names more efficiently
+        user[tools.PARAMS][tools.CONTACTID], //8
+        null,                                //9
         user[tools.PARAMS].department,
         ""
     ];
 });
 
+var renderer = new ContactTitleRenderer(Contact.createWithColumnPreset(), ContactTitleRenderer.OPTIONS.NoOption);
+var selectExpression = renderer.asSql();
+
+var names = db.table(SqlCondition.begin()
+    .andIn("CONTACT.CONTACTID", contactIds)
+    .buildSql("select CONTACTID, " + selectExpression + " from CONTACT \n\
+        left join PERSON on (PERSON.PERSONID = CONTACT.PERSON_ID)")
+);
+var nameMap = {};
+for (let i = 0, l = names.length; i < l; i++)
+    nameMap[names[i][0]] = names[i][1];
+
+for (let i = 0, l = users.length; i < l; i++)
+    users[i][9] = nameMap[users[i][8]] || "";
+
 var filter = vars.get("$local.filter"); 
 
 //TODO: this is a workaround that filters the records manually, it should be possible to filter the users with a tools.* method
diff --git a/entity/LetterRecipient_entity/LetterRecipient_entity.aod b/entity/LetterRecipient_entity/LetterRecipient_entity.aod
index 492db4ac95e2c09229f8337f6aeeab2aac09c4a7..eb34d0f56486a42e1d2abafbb9bd1cf5c72bfa4e 100644
--- a/entity/LetterRecipient_entity/LetterRecipient_entity.aod
+++ b/entity/LetterRecipient_entity/LetterRecipient_entity.aod
@@ -87,6 +87,10 @@
         </entityActionField>
       </children>
     </entityActionGroup>
+    <entityField>
+      <name>ADDRESS_ID</name>
+      <title>Address</title>
+    </entityField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -159,6 +163,14 @@
           <name>TARGETCONTEXT.value</name>
           <expression>%aditoprj%/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/targetcontext.value/expression.js</expression>
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>ADDRESS_ID.displayValue</name>
+          <expression>%aditoprj%/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/address_id.displayvalue/expression.js</expression>
+        </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>ADDRESS_ID.value</name>
+          <recordfield>CONTACT.ADDRESS_ID</recordfield>
+        </dbRecordFieldMapping>
       </recordFieldMappings>
     </dbRecordContainer>
   </recordContainers>
diff --git a/entity/LetterRecipient_entity/recordcontainers/db/fromClauseProcess.js b/entity/LetterRecipient_entity/recordcontainers/db/fromClauseProcess.js
index 7abfb0194a42a66eabe85346e22719f5e071f9c7..a1d94b7c23a149a7209785683f84aca4253e5710 100644
--- a/entity/LetterRecipient_entity/recordcontainers/db/fromClauseProcess.js
+++ b/entity/LetterRecipient_entity/recordcontainers/db/fromClauseProcess.js
@@ -2,4 +2,5 @@ import("system.result");
 
 result.string("LETTERRECIPIENT join CONTACT on LETTERRECIPIENT.CONTACT_ID = CONTACT.CONTACTID \
     left join PERSON on CONTACT.PERSON_ID = PERSON.PERSONID \
-    left join ORGANISATION on CONTACT.ORGANISATION_ID = ORGANISATION.ORGANISATIONID");
\ No newline at end of file
+    left join ORGANISATION on CONTACT.ORGANISATION_ID = ORGANISATION.ORGANISATIONID \
+    left join ADDRESS on (ADDRESS.ADDRESSID = CONTACT.ADDRESS_ID)");
\ No newline at end of file
diff --git a/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/address_id.displayvalue/expression.js b/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/address_id.displayvalue/expression.js
new file mode 100644
index 0000000000000000000000000000000000000000..beac43f3d912a8f81208580f156bb766178124f7
--- /dev/null
+++ b/entity/LetterRecipient_entity/recordcontainers/db/recordfieldmappings/address_id.displayvalue/expression.js
@@ -0,0 +1,5 @@
+import("PostalAddress_lib");
+import("system.result");
+
+var res = AddressUtils.formatOnelineSql();
+result.string(res);
\ No newline at end of file
diff --git a/entity/Letter_entity/recordcontainers/jdito/onInsert.js b/entity/Letter_entity/recordcontainers/jdito/onInsert.js
index c2f5bcbd5112cb76c57d5be90df26a6f3d947931..1248954c4ed301dc2822e207a534f449dba7e9b5 100644
--- a/entity/Letter_entity/recordcontainers/jdito/onInsert.js
+++ b/entity/Letter_entity/recordcontainers/jdito/onInsert.js
@@ -1,15 +1,20 @@
+import("Contact_lib");
 import("ActivityTask_lib");
 import("system.neon");
 import("system.vars");
 import("DocumentTemplate_lib");
+import("KeywordRegistry_basic");
 
 var template = DocumentTemplate.loadTemplate(vars.get("$field.DOCUMENT_TEMPLATE"));
 var contactId = vars.get("$param.ContactId_param");
-var content = template.getReplacedContentByContactId(contactId);
+var content = template.getReplacedContentByContactId(contactId, true);
 neon.download(content, template.filename);
 
 var links = [];
 if (contactId)
-    links.push(["Person", contactId]); //TODO: dynamic
+{
+    let context = ContactUtils.getContextByContactId(contactId);
+    links.push([context, contactId]);
+}
 
-ActivityUtils.createNewActivity(null, links, null, null, [[template.filename, content, false]]);
+ActivityUtils.createNewActivity(null, links, null, null, [[template.filename, content, false]], $KeywordRegistry.activityDirection$outgoing());
diff --git a/entity/ObjectRelationType_entity/ObjectRelationType_entity.aod b/entity/ObjectRelationType_entity/ObjectRelationType_entity.aod
index b99283f7f80a053827d38444754406e242d15e30..696d07ca489a8b84343a3999459a9fe43303362d 100644
--- a/entity/ObjectRelationType_entity/ObjectRelationType_entity.aod
+++ b/entity/ObjectRelationType_entity/ObjectRelationType_entity.aod
@@ -7,6 +7,7 @@
   <grantUpdateProcess>%aditoprj%/entity/ObjectRelationType_entity/grantUpdateProcess.js</grantUpdateProcess>
   <grantDeleteProcess>%aditoprj%/entity/ObjectRelationType_entity/grantDeleteProcess.js</grantDeleteProcess>
   <contentTitleProcess>%aditoprj%/entity/ObjectRelationType_entity/contentTitleProcess.js</contentTitleProcess>
+  <iconId>VAADIN:SPLIT</iconId>
   <titlePlural>Relation types</titlePlural>
   <recordContainer>jdito</recordContainer>
   <entityFields>
diff --git a/entity/Organisation_entity/Organisation_entity.aod b/entity/Organisation_entity/Organisation_entity.aod
index b6e7883a6b4d38d3067bd334425ee84fde61b196..9ef1193c6003969ad128dff7831b03d6c0033d38 100644
--- a/entity/Organisation_entity/Organisation_entity.aod
+++ b/entity/Organisation_entity/Organisation_entity.aod
@@ -767,6 +767,7 @@
           <isObjectAction v="false" />
           <isSelectionAction v="true" />
           <iconId>VAADIN:AT</iconId>
+          <tooltipProcess>%aditoprj%/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js</tooltipProcess>
         </entityActionField>
         <entityActionField>
           <name>addToSerialLetter</name>
@@ -774,6 +775,7 @@
           <isObjectAction v="false" />
           <isSelectionAction v="true" />
           <iconId>VAADIN:ENVELOPES</iconId>
+          <tooltipProcess>%aditoprj%/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js</tooltipProcess>
         </entityActionField>
       </children>
     </entityActionGroup>
@@ -1083,7 +1085,7 @@
         <indexRecordFieldMapping>
           <name>NAME.value</name>
           <indexFieldType>PROPER_NAME</indexFieldType>
-          <isKeyword v="true" />
+          <isBoosted v="true" />
         </indexRecordFieldMapping>
         <indexRecordFieldMapping>
           <name>ORGANISATIONID.value</name>
diff --git a/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js b/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..76c0ea1a0d6fa4b8dadbd4eca545c544935d477b
--- /dev/null
+++ b/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js
@@ -0,0 +1,4 @@
+import("system.translate");
+import("system.result");
+
+result.string(translate.text("Add the selection to a bulk mail"));
\ No newline at end of file
diff --git a/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js b/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..d00822c123e56419934a9e98a623e3863e7a83ed
--- /dev/null
+++ b/entity/Organisation_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js
@@ -0,0 +1,4 @@
+import("system.translate");
+import("system.result");
+
+result.string(translate.text("Add the selection to a serial letter"));
\ No newline at end of file
diff --git a/entity/PermissionAction_entity/PermissionAction_entity.aod b/entity/PermissionAction_entity/PermissionAction_entity.aod
new file mode 100644
index 0000000000000000000000000000000000000000..cd867971b4e9eb6bf463622825c4af3c58ac8cac
--- /dev/null
+++ b/entity/PermissionAction_entity/PermissionAction_entity.aod
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.10" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.10">
+  <name>PermissionAction_entity</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <title>Action</title>
+  <titlePlural>Actions</titlePlural>
+  <recordContainer>jDito</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+    </entityProvider>
+    <entityField>
+      <name>ACTION</name>
+      <title>Action</title>
+      <dropDownProcess>%aditoprj%/entity/PermissionAction_entity/entityfields/action/dropDownProcess.js</dropDownProcess>
+      <stateProcess>%aditoprj%/entity/PermissionAction_entity/entityfields/action/stateProcess.js</stateProcess>
+      <displayValueProcess>%aditoprj%/entity/PermissionAction_entity/entityfields/action/displayValueProcess.js</displayValueProcess>
+    </entityField>
+    <entityField>
+      <name>UID</name>
+    </entityField>
+    <entityProvider>
+      <name>PermissionActions</name>
+      <recordContainer>jDito</recordContainer>
+      <dependencies>
+        <entityDependency>
+          <name>c92e552c-6d88-4fe1-918f-1a9a71ea28ad</name>
+          <entityName>PermissionDetail_entity</entityName>
+          <fieldName>PermissionActions</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+    </entityProvider>
+    <entityConsumer>
+      <name>PermissionDetails</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>PermissionDetail_entity</entityName>
+        <fieldName>Permissions</fieldName>
+      </dependency>
+    </entityConsumer>
+    <entityParameter>
+      <name>PermissionId_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityParameter>
+      <name>AccessType_param</name>
+      <expose v="true" />
+    </entityParameter>
+  </entityFields>
+  <recordContainers>
+    <jDitoRecordContainer>
+      <name>jDito</name>
+      <jDitoRecordAlias>_____SYSTEMALIAS</jDitoRecordAlias>
+      <contentProcess>%aditoprj%/entity/PermissionAction_entity/recordcontainers/jdito/contentProcess.js</contentProcess>
+      <onInsert>%aditoprj%/entity/PermissionAction_entity/recordcontainers/jdito/onInsert.js</onInsert>
+      <onUpdate>%aditoprj%/entity/PermissionAction_entity/recordcontainers/jdito/onUpdate.js</onUpdate>
+      <onDelete>%aditoprj%/entity/PermissionAction_entity/recordcontainers/jdito/onDelete.js</onDelete>
+      <recordFieldMappings>
+        <jDitoRecordFieldMapping>
+          <name>UID.value</name>
+        </jDitoRecordFieldMapping>
+        <jDitoRecordFieldMapping>
+          <name>ACTION.value</name>
+        </jDitoRecordFieldMapping>
+        <jDitoRecordFieldMapping>
+          <name>ACTION.displayValue</name>
+        </jDitoRecordFieldMapping>
+      </recordFieldMappings>
+    </jDitoRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/PermissionAction_entity/entityfields/action/displayValueProcess.js b/entity/PermissionAction_entity/entityfields/action/displayValueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..65a3ad0b2b9e511648cf581003a9061e05a1c8ad
--- /dev/null
+++ b/entity/PermissionAction_entity/entityfields/action/displayValueProcess.js
@@ -0,0 +1,6 @@
+import("system.result");
+import("system.vars");
+
+var action = vars.get("$field.ACTION");
+
+result.string(action);
\ No newline at end of file
diff --git a/entity/PermissionAction_entity/entityfields/action/dropDownProcess.js b/entity/PermissionAction_entity/entityfields/action/dropDownProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..371de4f973263f8e8f350776ff042bf5390c5877
--- /dev/null
+++ b/entity/PermissionAction_entity/entityfields/action/dropDownProcess.js
@@ -0,0 +1,95 @@
+import("system.vars");
+import("system.result");
+
+var accesstype = vars.get("$param.AccessType_param");
+var actions = [];
+
+switch (accesstype) {
+    case "E":
+        actions = [
+            ["view", "view"],
+            ["create", "create"]
+            ]
+        break;
+    case "R":
+        actions = [
+            ["read", "read"],
+            ["update", "update"],
+            ["delete", "delete"]
+            ]
+        break;
+    case "F":
+        actions = [
+            ["read", "read"],
+            ["update", "update"]
+            ]
+}
+
+result.object(actions);
+
+
+//#############################################################################
+//################only show actions which are not yet in the DB################
+//##########################not done yet#######################################
+//#############################################################################
+//import("system.logging");
+//import("Permission_lib");
+//import("system.vars");
+//import("system.result");
+//
+//var permisson = vars.get("$param.PermissionId_param");
+//var actionIdsInDb = PermissionUtil.getPermissionAction(permisson);
+//var actionsInDb = [];
+//for each (var actionId in actionIdsInDb) {
+//    actionsInDb.push(PermissionUtil.resolvePermissionActionId(actionId));
+//}
+//
+//var entityActions = ["view", "create"];
+//var recordActions = ["read", "update", "delete"];
+//var fieldActions = ["read", "update"];
+//var diff;
+//
+//var accesstype = vars.get("$param.AccessType_param");
+//var actions = [];
+//
+//switch (accesstype) {
+//    case "E":
+//        diff = arrDiff(actionsInDb, entityActions);
+//        break;
+//    case "R":
+//        diff = arrDiff(actionsInDb, recordActions);
+//        break;
+//    case "F":
+//        diff = arrDiff(actionsInDb, fieldActions);
+//        break;
+//}
+//
+//for each (let entry in diff) {
+//    actions.push([entry, entry]);
+//}
+//
+//result.object(actions);
+//
+//// arrDiff calculates different elements of two arrays and returns them as array, otherwise empty array
+//function arrDiff (arr1, arr2) {
+//    var helperArr = [], diff = [];
+//
+//    for (let i = 0; i < arr1.length; i++) {
+//        helperArr[arr1[i]] = true;
+//    }
+//
+//    for (let i = 0; i < arr2.length; i++) {
+//        if (helperArr[arr2[i]]) {
+//            delete helperArr[arr2[i]];
+//        } 
+//        else {
+//            helperArr[arr2[i]] = true;
+//        }
+//    }
+//
+//    for (var k in helperArr) {
+//        diff.push(k);
+//    }
+//
+//    return diff;
+//}
\ No newline at end of file
diff --git a/entity/PermissionAction_entity/entityfields/action/stateProcess.js b/entity/PermissionAction_entity/entityfields/action/stateProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..b4084caba76a70eeb1b82b8f65a214904cb98d16
--- /dev/null
+++ b/entity/PermissionAction_entity/entityfields/action/stateProcess.js
@@ -0,0 +1,9 @@
+import("system.vars");
+import("system.result");
+import("system.neon");
+
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW || vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT) {
+    result.string(neon.COMPONENTSTATE_EDITABLE);
+} else {
+    result.string(neon.COMPONENTSTATE_READONLY);
+}
diff --git a/entity/PermissionAction_entity/recordcontainers/jdito/contentProcess.js b/entity/PermissionAction_entity/recordcontainers/jdito/contentProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..e3af7028be1e1b0648f1c4a92b35b7e382118ff1
--- /dev/null
+++ b/entity/PermissionAction_entity/recordcontainers/jdito/contentProcess.js
@@ -0,0 +1,18 @@
+import("system.logging");
+import("system.result");
+import("system.vars");
+import("system.tools");
+import("Permission_lib");
+
+var actions = [];
+var permissionId = vars.exists("$param.PermissionId_param") && vars.get("$param.PermissionId_param");
+
+if (permissionId && PermissionUtil.existsPermission(permissionId))
+{
+    var permActions = PermissionUtil.getPermissionAction(permissionId);
+    for each (var permActionId in permActions) {
+        actions.push([permActionId[0], PermissionUtil.resolvePermissionActionId(permActionId), PermissionUtil.resolvePermissionActionId(permActionId)]);    
+    }
+
+    result.object(actions);
+}
\ No newline at end of file
diff --git a/entity/PermissionAction_entity/recordcontainers/jdito/onDelete.js b/entity/PermissionAction_entity/recordcontainers/jdito/onDelete.js
new file mode 100644
index 0000000000000000000000000000000000000000..69b743814c1db71967e744c83ca9b55fa011f84d
--- /dev/null
+++ b/entity/PermissionAction_entity/recordcontainers/jdito/onDelete.js
@@ -0,0 +1,5 @@
+import("system.vars");
+import("Permission_lib");
+
+var action = vars.get("$local.uid");
+PermissionUtil.deletePermissionAction(action);
\ No newline at end of file
diff --git a/entity/PermissionAction_entity/recordcontainers/jdito/onInsert.js b/entity/PermissionAction_entity/recordcontainers/jdito/onInsert.js
new file mode 100644
index 0000000000000000000000000000000000000000..f7e1c66e82ec846dd37c2b2c5510c1a4642421cf
--- /dev/null
+++ b/entity/PermissionAction_entity/recordcontainers/jdito/onInsert.js
@@ -0,0 +1,16 @@
+import("system.logging");
+import("system.db");
+import("system.tools");
+import("system.result");
+import("system.vars");
+import("Permission_lib");
+
+var alias = "_____SYSTEMALIAS";
+var permissionId = vars.exists("$param.PermissionId_param") && vars.get("$param.PermissionId_param");
+
+if (permissionId) {
+    var newAction = vars.get("$local.rowdata")["ACTION.value"];
+    PermissionUtil.insertNewPermissionAction(permissionId, newAction, vars.get("$field.UID"));
+}
+
+tools.clearPermissionCache();
\ No newline at end of file
diff --git a/entity/PermissionAction_entity/recordcontainers/jdito/onUpdate.js b/entity/PermissionAction_entity/recordcontainers/jdito/onUpdate.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d5e623b7c990ff901bcfc65cbae34e86b2b65a8
--- /dev/null
+++ b/entity/PermissionAction_entity/recordcontainers/jdito/onUpdate.js
@@ -0,0 +1,13 @@
+import("system.tools");
+import("system.result");
+import("system.vars");
+import("Permission_lib");
+
+var col = "ACTION";
+var table = "ASYS_PERMISSIONACTION";
+var permissionId = vars.exists("$param.PermissionId_param") && vars.get("$param.PermissionId_param");
+
+if (permissionId && PermissionUtil.existsPermission(permissionId)) {
+    var newAction = vars.get("$local.rowdata")["ACTION.value"];
+    PermissionUtil.updateIfDiff(vars.get("$field.UID"), newAction, col, table);
+}
\ No newline at end of file
diff --git a/entity/PermissionDetail_entity/PermissionDetail_entity.aod b/entity/PermissionDetail_entity/PermissionDetail_entity.aod
index 805cd843553b44db1fa41862d00a6f860b38af7c..bcacf9e74ba1b543ba42c577e3d76d5e7cf475e4 100644
--- a/entity/PermissionDetail_entity/PermissionDetail_entity.aod
+++ b/entity/PermissionDetail_entity/PermissionDetail_entity.aod
@@ -24,7 +24,8 @@
     <entityField>
       <name>ACTION</name>
       <title>Action</title>
-      <mandatory v="true" />
+      <mandatory v="false" />
+      <state>INVISIBLE</state>
     </entityField>
     <entityField>
       <name>ROLE</name>
@@ -101,6 +102,12 @@
           <fieldName>PermissionDetails</fieldName>
           <isConsumer v="false" />
         </entityDependency>
+        <entityDependency>
+          <name>62a56e76-d049-4c53-a439-79261a8058e1</name>
+          <entityName>PermissionAction_entity</entityName>
+          <fieldName>PermissionDetails</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
       </dependencies>
     </entityProvider>
     <entityParameter>
@@ -165,6 +172,24 @@
         </entityParameter>
       </children>
     </entityConsumer>
+    <entityConsumer>
+      <name>PermissionActions</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>PermissionAction_entity</entityName>
+        <fieldName>PermissionActions</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>PermissionId_param</name>
+          <valueProcess>%aditoprj%/entity/PermissionDetail_entity/entityfields/permissionactions/children/permissionid_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>AccessType_param</name>
+          <valueProcess>%aditoprj%/entity/PermissionDetail_entity/entityfields/permissionactions/children/accesstype_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
   </entityFields>
   <recordContainers>
     <jDitoRecordContainer>
diff --git a/entity/PermissionDetail_entity/entityfields/condition/stateProcess.js b/entity/PermissionDetail_entity/entityfields/condition/stateProcess.js
index 71fd7034f822385b31ede8fc4d755ce78aa56a1b..419962f904c9cd0a047f5c53832be8154b966e77 100644
--- a/entity/PermissionDetail_entity/entityfields/condition/stateProcess.js
+++ b/entity/PermissionDetail_entity/entityfields/condition/stateProcess.js
@@ -3,7 +3,7 @@ import("system.result");
 import("system.neon");
 
 if(vars.get("$field.ACCESSTYPE") == "E") {
-    result.string(neon.COMPONENTSTATE_DISABLED);
+    result.string(neon.COMPONENTSTATE_INVISIBLE);
 } else {
     if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW || vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT) {
         result.string(neon.COMPONENTSTATE_EDITABLE);
diff --git a/entity/PermissionDetail_entity/entityfields/condition/valueProcess.js b/entity/PermissionDetail_entity/entityfields/condition/valueProcess.js
index 1c44df7a4b437ff59294457d7198174510327b28..63d2b62fa7a27a2855ee7dd5967859f8049da68e 100644
--- a/entity/PermissionDetail_entity/entityfields/condition/valueProcess.js
+++ b/entity/PermissionDetail_entity/entityfields/condition/valueProcess.js
@@ -1,4 +1,3 @@
-import("system.logging");
 import("system.neon");
 import("system.vars");
 import("system.result");
diff --git a/entity/PermissionDetail_entity/entityfields/permissionactions/children/accesstype_param/valueProcess.js b/entity/PermissionDetail_entity/entityfields/permissionactions/children/accesstype_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..530d2556d48deea69763a157ea7713b4dc0b233f
--- /dev/null
+++ b/entity/PermissionDetail_entity/entityfields/permissionactions/children/accesstype_param/valueProcess.js
@@ -0,0 +1,3 @@
+import("system.vars");
+import("system.result");
+result.string(vars.get("$field.ACCESSTYPE"));
\ No newline at end of file
diff --git a/entity/PermissionDetail_entity/entityfields/permissionactions/children/permissionid_param/valueProcess.js b/entity/PermissionDetail_entity/entityfields/permissionactions/children/permissionid_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f2dea6db775c3e184ecfe8b4937e583ad91ec39
--- /dev/null
+++ b/entity/PermissionDetail_entity/entityfields/permissionactions/children/permissionid_param/valueProcess.js
@@ -0,0 +1,17 @@
+import("system.vars");
+import("system.result");
+import("Permission_lib");
+
+var entity = vars.get("$field.ENTITY");
+var cond = vars.get("$field.CONDITION");
+var noCond = "{\"entity\":\"" + entity + "\",\"filter\":{\"type\":\"group\",\"operator\":\"AND\",\"childs\":[]}}";
+var permSetId = PermissionUtil.getPermissionSet(vars.get("$field.ROLE"), vars.get("$field.ENTITY"), vars.get("$field.ACCESSTYPE"));
+
+if (permSetId != "" && (cond == "" || cond == noCond)) {
+    var rootPermId = PermissionUtil.getDefaultPermission(permSetId);
+    if (rootPermId != "") {
+        result.string(rootPermId);
+    }
+} else {
+    result.string(vars.get("$field.UID"));
+}
\ No newline at end of file
diff --git a/entity/PermissionDetail_entity/recordcontainers/jdito/onInsert.js b/entity/PermissionDetail_entity/recordcontainers/jdito/onInsert.js
index 043cefec525b2ba9304aaeb29f8dd1d87c953bd2..df2a2545e7f02a5b61ab2de2d49a6e8da67488d2 100644
--- a/entity/PermissionDetail_entity/recordcontainers/jdito/onInsert.js
+++ b/entity/PermissionDetail_entity/recordcontainers/jdito/onInsert.js
@@ -1,4 +1,3 @@
-import("system.logging");
 import("Permission_lib");
 import("system.neon");
 import("system.util");
@@ -9,26 +8,20 @@ import("Permission_lib");
 import("Entity_lib");
 
 var alias = "_____SYSTEMALIAS";
+var tablename = "ASYS_PERMISSION";
 var sqlExt = "";
-var permissionid = util.getNewUUID();
+var permissionid = vars.get("$field.UID");
 var role = vars.get("$field.ROLE");
 var entity = vars.get("$field.ENTITY");
 var field = vars.get("$field.FIELD");
 var accesstype = vars.get("$field.ACCESSTYPE").trim();
 var condtype = vars.get("$field.CONDTYPE").trim();
 var condition = vars.get("$field.CONDITION");
-var action = vars.get("$field.ACTION");
 
-if (checkInput([role, entity, accesstype, condtype, action])) {
-    if (checkInput([field]))
-        sqlExt += " and FIELD_ID = '" + field + "'";
-    else if (action.includes("view") || action.includes("create"))
-        sqlExt += " and ACCESSTYPE = 'E'";
-    else 
-        sqlExt += " and ACCESSTYPE = 'R'";
-
-    var sqlStr = "select ASYS_PERMISSIONSETID from ASYS_PERMISSIONSET where ENTITY_ID = '" + entity + "' and ROLE_ID = '" + role + "'" + sqlExt;
-    var permissionsetid = db.cell(sqlStr, alias);
+if (checkInput([role, entity, accesstype, condtype])) {
+    
+    // permission set
+    var permissionsetid = PermissionUtil.getPermissionSet(role, entity, accesstype, field);
     
     if (permissionsetid == "") {
         // no fitting permissionset found - insert new permissionset
@@ -38,35 +31,22 @@ if (checkInput([role, entity, accesstype, condtype, action])) {
         } else {
             rootpermissionset = PermissionUtil.getRootPermissionSet(role, entity);
         }
-        permissionsetid = PermissionUtil.insertNewPermissionSet(rootpermissionset, entity, role, field, accesstype)
+        permissionsetid = PermissionUtil.insertNewPermissionSet(rootpermissionset, entity, role, field, accesstype);
     }
-
-    // deletes permissions with CONDTYPE = 'false' - condtype=false if a permission is used to display that a entity has no permissions
-    var childPermissions = PermissionUtil.getAllChildPermissions(permissionsetid);
-    for each (var permid in childPermissions) {
-        if (PermissionUtil.getCondType(permid) == "false") {
-            let table = "ASYS_PERMISSION";
-            let cond = " ASYS_PERMISSIONID = '" + permid + "'";
-            db.deleteData(table, cond, alias); // delete permission with cond type = false
-        }
-    }
-
-    // check if a new permissions is needed or an existing one can be used
-    var existingPermId = permExists(role, entity, field, accesstype, condtype, condition);
-    if (existingPermId != "") {
-        // update
-        permissionid = existingPermId;
+    
+    // permission
+    var existingPerm = PermissionUtil.getPermission(role, entity, field, accesstype, condition);
+    if (existingPerm == "") {
+        // no existing perm found -> insert
+        PermissionUtil.insertNewPermission(permissionsetid, condition, condtype, permissionid);
     } else {
-        // permission doesnt exist -> insert new permission
-        // new permissionid is needed to link actions to the permission in the next step
-        permissionid = PermissionUtil.insertNewPermission(permissionsetid, condition, condtype)
+        // existing perm found -> update
+        PermissionUtil.updateIfDiff(existingPerm, permissionsetid, "ASYS_PERMISSIONSET_ID", tablename);
+        PermissionUtil.updateIfDiff(existingPerm, condition, "COND", tablename);
+        PermissionUtil.updateIfDiff(existingPerm, "true", "CONDTYPE", tablename);
     }
     
-    // insert new permissionaction    
-    var actionNew = action.split(",");
-    for each (let permaction in actionNew) {
-        PermissionUtil.insertNewPermissionAction(permissionid, permaction);
-    }
+    // permission action gets created in PermissionAction_entity
     
     tools.clearPermissionCache();
 }
@@ -80,23 +60,51 @@ function checkInput(pInputArr) {
     return true;
 }
 
-// returns permissionid of the permission with fitting parameters, otherwise returns empty string
-function permExists(pRole, pEntity, pField, pAccesstype, pCondtype, pCondition) {
-    var sqlStr = "";
-    var sqlExt = "";
-    
-    if (checkInput([pCondition])) {
-        sqlExt += " and COND like '%" + pCondition + "%'";
-    }
-    
-    if (checkInput([pField])) {
-        sqlExt += " and FIELD_ID = '" + pField + "'";
-    }
-    
-    sqlStr = "select ASYS_PERMISSION.ASYS_PERMISSIONID from ASYS_PERMISSIONSET"
-    + " join ASYS_PERMISSION on ASYS_PERMISSION.ASYS_PERMISSIONSET_ID = ASYS_PERMISSIONSET.ASYS_PERMISSIONSETID"
-    + " where ENTITY_ID = '" + pEntity + "' and ROLE_ID = '" + pRole + "'"
-    + " and ACCESSTYPE = '" + pAccesstype + "' and CONDTYPE = '" + pCondtype + "'" + sqlExt;
-    var permId = db.cell(sqlStr, alias);
-    return permId;
-}
\ No newline at end of file
+//
+//    // deletes permissions with CONDTYPE = 'false' - condtype=false if a permission is used to display that a entity has no permissions
+//    var childPermissions = PermissionUtil.getAllChildPermissions(permissionsetid);
+//    for each (var permid in childPermissions) {
+//        if (PermissionUtil.getCondType(permid) == "false") {
+//            PermissionUtil.deletePermission(permid);
+//        }
+//    }
+//
+//    // check if a new permissions is needed or an existing one can be used
+//    var existingPermId = permExists(role, entity, field, accesstype, condtype, condition);
+//    if (existingPermId != "") {
+//        // update
+//        permissionid = existingPermId;
+//    } else {
+//        // permission doesnt exist -> insert new permission
+//        // new permissionid is needed to link actions to the permission in the next step
+//        logging.log("onInsert cond: " + condition);
+//        permissionid = PermissionUtil.insertNewPermission(permissionsetid, condition, condtype)
+//    }
+//    
+//    // insert new permissionaction    
+//    var actionNew = action.split(",");
+//    for each (let permaction in actionNew) {
+//        PermissionUtil.insertNewPermissionAction(permissionid, permaction);
+//    }
+//    
+//
+//// returns permissionid of the permission with fitting parameters, otherwise returns empty string
+//function permExists(pRole, pEntity, pField, pAccesstype, pCondtype, pCondition) {
+//    var sqlStr = "";
+//    var sqlExt = "";
+//    
+//    if (checkInput([pCondition])) {
+//        sqlExt += " and cast(COND as varchar(999) = '" + pCondition + "'";
+//    }
+//    
+//    if (checkInput([pField])) {
+//        sqlExt += " and FIELD_ID = '" + pField + "'";
+//    }
+//    
+//    sqlStr = "select ASYS_PERMISSION.ASYS_PERMISSIONID from ASYS_PERMISSIONSET"
+//    + " join ASYS_PERMISSION on ASYS_PERMISSION.ASYS_PERMISSIONSET_ID = ASYS_PERMISSIONSET.ASYS_PERMISSIONSETID"
+//    + " where ENTITY_ID = '" + pEntity + "' and ROLE_ID = '" + pRole + "'"
+//    + " and ACCESSTYPE = '" + pAccesstype + "' and CONDTYPE = '" + pCondtype + "'" + sqlExt;
+//    var permId = db.cell(sqlStr, alias);
+//    return permId;
+//}
\ No newline at end of file
diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod
index 431f0aa75908bf318db844cb218bcb83182f170e..f637a79ed63fca53f5efd66008441ef0beca7bf2 100644
--- a/entity/Person_entity/Person_entity.aod
+++ b/entity/Person_entity/Person_entity.aod
@@ -832,6 +832,7 @@ Usually this is used for filtering COMMUNICATION-entries by a specified contact
           <isObjectAction v="false" />
           <isSelectionAction v="true" />
           <iconId>VAADIN:AT</iconId>
+          <tooltipProcess>%aditoprj%/entity/Person_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js</tooltipProcess>
         </entityActionField>
         <entityActionField>
           <name>addToSerialLetter</name>
@@ -840,6 +841,7 @@ Usually this is used for filtering COMMUNICATION-entries by a specified contact
           <isObjectAction v="false" />
           <isSelectionAction v="true" />
           <iconId>VAADIN:ENVELOPES</iconId>
+          <tooltipProcess>%aditoprj%/entity/Person_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js</tooltipProcess>
         </entityActionField>
       </children>
     </entityActionGroup>
@@ -1164,12 +1166,12 @@ Usually this is used for filtering COMMUNICATION-entries by a specified contact
         <indexRecordFieldMapping>
           <name>FIRSTNAME.value</name>
           <indexFieldType>PHONETIC_NAME</indexFieldType>
-          <isKeyword v="true" />
+          <isBoosted v="true" />
         </indexRecordFieldMapping>
         <indexRecordFieldMapping>
           <name>LASTNAME.value</name>
           <indexFieldType>PHONETIC_NAME</indexFieldType>
-          <isKeyword v="true" />
+          <isBoosted v="true" />
         </indexRecordFieldMapping>
         <indexRecordFieldMapping>
           <name>SALUTATION.value</name>
diff --git a/entity/Person_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js b/entity/Person_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..81d6fafaa074b4e9a0a599fa3ee245d63f9bd42b
--- /dev/null
+++ b/entity/Person_entity/entityfields/campaignactiongroup/children/addtobulkmailfromtable/tooltipProcess.js
@@ -0,0 +1,4 @@
+import("system.translate");
+import("system.result");
+
+result.string(translate.text("Adds the selection to a bulk mail"));
\ No newline at end of file
diff --git a/entity/Person_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js b/entity/Person_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..a8ad9436e617cbbbf896c21479e267e5c16374d3
--- /dev/null
+++ b/entity/Person_entity/entityfields/campaignactiongroup/children/addtoserialletter/tooltipProcess.js
@@ -0,0 +1,4 @@
+import("system.translate");
+import("system.result");
+
+result.string(translate.text("Adds the selection to a serial letter"));
\ No newline at end of file
diff --git a/entity/SerialLetter_entity/SerialLetter_entity.aod b/entity/SerialLetter_entity/SerialLetter_entity.aod
index 425c91fd3f5c075431ef55681bd699ee5965372e..e495082159a746f52d5a5b64d8cb5bf661ecf009 100644
--- a/entity/SerialLetter_entity/SerialLetter_entity.aod
+++ b/entity/SerialLetter_entity/SerialLetter_entity.aod
@@ -86,6 +86,13 @@
         </entityParameter>
       </children>
     </entityConsumer>
+    <entityActionField>
+      <name>openAdminView</name>
+      <title>Open admin view</title>
+      <onActionProcess>%aditoprj%/entity/SerialLetter_entity/entityfields/openadminview/onActionProcess.js</onActionProcess>
+      <iconId>VAADIN:CURLY_BRACKETS</iconId>
+      <stateProcess>%aditoprj%/entity/SerialLetter_entity/entityfields/openadminview/stateProcess.js</stateProcess>
+    </entityActionField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
diff --git a/entity/SerialLetter_entity/entityfields/openadminview/onActionProcess.js b/entity/SerialLetter_entity/entityfields/openadminview/onActionProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..3987f54cc36d46bc92fb70806d7481b80104cf6f
--- /dev/null
+++ b/entity/SerialLetter_entity/entityfields/openadminview/onActionProcess.js
@@ -0,0 +1,6 @@
+import("system.vars");
+import("Context_lib");
+
+AdminViewUtils.open("SERIALLETTERID", [
+    ["DOCUMENTTEMPLATE_ID", vars.get("$field.DOCUMENTTEMPLATE_ID")]
+]);
\ No newline at end of file
diff --git a/entity/SerialLetter_entity/entityfields/openadminview/stateProcess.js b/entity/SerialLetter_entity/entityfields/openadminview/stateProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..38f2298db7304b4d44a15fbad7f720558c02da99
--- /dev/null
+++ b/entity/SerialLetter_entity/entityfields/openadminview/stateProcess.js
@@ -0,0 +1,4 @@
+import("Context_lib");
+import("system.result");
+
+result.string(AdminViewUtils.getActionState());
\ No newline at end of file
diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
index b968e1938ebc128ec5adf60af07e7b816c8bf7aa..daaf0d800bf5b41cca7a4fe3d61fb8439690b08f 100644
--- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
+++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
@@ -4826,6 +4826,15 @@
     </entry>
     <entry>
       <key>Shows the organisations turnover and forecast</key>
+    </entry>
+     <entry>
+      <key>Should the mail be sent now?</key>
+    </entry>
+    <entry>
+      <key>Add the selection to a bulk mail</key>
+    </entry>
+    <entry>
+      <key>Add the selection to a serial letter</key>
     </entry>
     <entry>
       <key>Campaign management</key>
diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
index 6899a2ffe2bdf4f930a516633587c3c71aa4dfe0..edadaa90ae275927dfc01db96713731d7b8c1739 100644
--- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
+++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
@@ -14,6 +14,10 @@
       <key>Data Privacy</key>
       <value>Datenschutz</value>
     </entry>
+    <entry>
+      <key>Add the selection to a bulk mail</key>
+      <value>Fügt die Auswahl einer Serienmail hinzu</value>
+    </entry>
     <entry>
       <key>Number of activities</key>
       <value>Anzahl Aktivitäten</value>
@@ -54,6 +58,10 @@
       <key>MAX</key>
       <value>maximal</value>
     </entry>
+    <entry>
+      <key>Create activities</key>
+      <value>Aktivitäten erstellen</value>
+    </entry>
     <entry>
       <key>NONE</key>
       <value>keine</value>
@@ -66,6 +74,10 @@
       <key>NORMAL</key>
       <value>normal</value>
     </entry>
+    <entry>
+      <key>Add the selection to a serial letter</key>
+      <value>Fügt die Auswahl einem Serienbrief hinzu</value>
+    </entry>
     <entry>
       <key>HIGH</key>
       <value>hoch</value>
@@ -82,6 +94,10 @@
       <key>Categorization</key>
       <value>Kategorisierung</value>
     </entry>
+    <entry>
+      <key>Should the mail be sent now?</key>
+      <value>Soll die Mail jetzt versendet werden?</value>
+    </entry>
     <entry>
       <key>Names</key>
       <value>Namen</value>
diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
index 0e79331dfa21ce6d685c2c8eba187a21685b1ba7..df438a57a3f2a32e7238544b6cd85712859a2214 100644
--- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
+++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
@@ -4879,6 +4879,15 @@
     <entry>
       <key>Campaign management</key>
     </entry>
+    <entry>
+      <key>Should the mail be sent now?</key>
+    </entry>
+    <entry>
+      <key>Add the selection to a bulk mail</key>
+    </entry>
+    <entry>
+      <key>Add the selection to a serial letter</key>
+    </entry>
     <entry>
       <key>Campaign costs</key>
     </entry>
diff --git a/neonContext/BulkMailStatusChart/BulkMailStatusChart.aod b/neonContext/BulkMailStatusChart/BulkMailStatusChart.aod
new file mode 100644
index 0000000000000000000000000000000000000000..da6eee86883a6fd594f8c90e0284a354782b6519
--- /dev/null
+++ b/neonContext/BulkMailStatusChart/BulkMailStatusChart.aod
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.0">
+  <name>BulkMailStatusChart</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <entity>BulkMailStatusChart_entity</entity>
+  <references>
+    <neonViewReference>
+      <name>403b6458-f106-436c-abf7-5620ecb42eae</name>
+      <view>BulkMailStatusChart_view</view>
+    </neonViewReference>
+  </references>
+</neonContext>
diff --git a/neonContext/PermissionAction/PermissionAction.aod b/neonContext/PermissionAction/PermissionAction.aod
new file mode 100644
index 0000000000000000000000000000000000000000..d59ee2df144a9e3cff48b0f6a69a2063c6ab5a71
--- /dev/null
+++ b/neonContext/PermissionAction/PermissionAction.aod
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.0">
+  <name>PermissionAction</name>
+  <title>Permission Action</title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <entity>PermissionAction_entity</entity>
+  <references>
+    <neonViewReference>
+      <name>e2098ef8-52da-4a97-abf9-e313be9ba43f</name>
+      <view>PermissionActionEdit_view</view>
+    </neonViewReference>
+    <neonViewReference>
+      <name>2d27ce8b-7676-4db8-9644-006b2d83d61f</name>
+      <view>PermissionActionFilter_view</view>
+    </neonViewReference>
+  </references>
+</neonContext>
diff --git a/neonView/AttributeEdit_view/AttributeEdit_view.aod b/neonView/AttributeEdit_view/AttributeEdit_view.aod
index 23e61f9a3bb5587fd5baa5691f00ca4eaa2f6424..22e0de724ed6fcd70dd5ef7a4ea07dad3b81f8f0 100644
--- a/neonView/AttributeEdit_view/AttributeEdit_view.aod
+++ b/neonView/AttributeEdit_view/AttributeEdit_view.aod
@@ -1,49 +1,55 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.2">
-  <name>AttributeEdit_view</name>
-  <majorModelMode>DISTRIBUTED</majorModelMode>
-  <isSmall v="true" />
-  <layout>
-    <noneLayout>
-      <name>layout</name>
-    </noneLayout>
-  </layout>
-  <children>
-    <genericViewTemplate>
-      <name>Edit</name>
-      <editMode v="true" />
-      <entityField>#ENTITY</entityField>
-      <fields>
-        <entityFieldLink>
-          <name>2d269ed7-a664-40c3-aadb-f274f7c00a66</name>
-          <entityField>ATTRIBUTE_PARENT_ID</entityField>
-        </entityFieldLink>
-        <entityFieldLink>
-          <name>0c6cd7c6-cced-4719-b0c5-08f8e3d13f2f</name>
-          <entityField>ATTRIBUTE_NAME</entityField>
-        </entityFieldLink>
-        <entityFieldLink>
-          <name>8cbc6049-2530-4960-b45f-830f3220889e</name>
-          <entityField>ATTRIBUTE_TYPE</entityField>
-        </entityFieldLink>
-        <entityFieldLink>
-          <name>529f9734-182e-46f3-ad89-14dc5656f307</name>
-          <entityField>DROPDOWNDEFINITION</entityField>
-        </entityFieldLink>
-        <entityFieldLink>
-          <name>d26696ac-199c-45f0-9147-b75dee3f4b65</name>
-          <entityField>ATTRIBUTE_ACTIVE</entityField>
-        </entityFieldLink>
-        <entityFieldLink>
-          <name>c8a5f45e-8092-45f4-ac22-681700447235</name>
-          <entityField>ATTRIBUTE_LEVEL</entityField>
-        </entityFieldLink>
-      </fields>
-    </genericViewTemplate>
-    <neonViewReference>
-      <name>8387ef27-9565-400f-a0d5-ef1d2019b722</name>
-      <entityField>AttributeUsages</entityField>
-      <view>AttributeUsageMultiEdit_view</view>
-    </neonViewReference>
-  </children>
-</neonView>
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.2">
+  <name>AttributeEdit_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <isSmall v="true" />
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <genericViewTemplate>
+      <name>Edit</name>
+      <editMode v="true" />
+      <entityField>#ENTITY</entityField>
+      <fields>
+        <entityFieldLink>
+          <name>2d269ed7-a664-40c3-aadb-f274f7c00a66</name>
+          <entityField>ATTRIBUTE_PARENT_ID</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>0c6cd7c6-cced-4719-b0c5-08f8e3d13f2f</name>
+          <entityField>ATTRIBUTE_NAME</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>8cbc6049-2530-4960-b45f-830f3220889e</name>
+          <entityField>ATTRIBUTE_TYPE</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>529f9734-182e-46f3-ad89-14dc5656f307</name>
+          <entityField>DROPDOWNDEFINITION</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>d26696ac-199c-45f0-9147-b75dee3f4b65</name>
+          <entityField>ATTRIBUTE_ACTIVE</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>c8a5f45e-8092-45f4-ac22-681700447235</name>
+          <entityField>ATTRIBUTE_LEVEL</entityField>
+        </entityFieldLink>
+      </fields>
+    </genericViewTemplate>
+    <neonViewReference>
+      <name>8387ef27-9565-400f-a0d5-ef1d2019b722</name>
+      <entityField>AttributeUsages</entityField>
+      <view>AttributeUsageMultiEdit_view</view>
+    </neonViewReference>
+    <filterTreeViewTemplate>
+      <name>FilterTree</name>
+      <entityNameField>DROPDOWNDEFINITION</entityNameField>
+      <filterField>DROPDOWNFILTER</filterField>
+      <entityField>#ENTITY</entityField>
+    </filterTreeViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/BulkMailEdit_view/BulkMailEdit_view.aod b/neonView/BulkMailEdit_view/BulkMailEdit_view.aod
index a827d94cd307211099ee8fab33220fd2a878760a..c0f679557d36cc1bea56e1d31bf8d995b10af86d 100644
--- a/neonView/BulkMailEdit_view/BulkMailEdit_view.aod
+++ b/neonView/BulkMailEdit_view/BulkMailEdit_view.aod
@@ -37,6 +37,10 @@
           <name>e4ec09c2-3815-4a3b-bce8-c12d5b919b04</name>
           <entityField>SENDER</entityField>
         </entityFieldLink>
+        <entityFieldLink>
+          <name>d9b91083-948e-4a0f-a29c-4962ddd78b41</name>
+          <entityField>CREATEACTIVITIES</entityField>
+        </entityFieldLink>
         <entityFieldLink>
           <name>0a67f430-dbcd-4605-b626-ee6d715ab248</name>
           <entityField>content</entityField>
diff --git a/neonView/BulkMailPreview_view/BulkMailPreview_view.aod b/neonView/BulkMailPreview_view/BulkMailPreview_view.aod
index f6f68c3a24cb687ac356f5612219f51a9e7b07af..bd3f635140211001485e5f0458d86cf2620525b6 100644
--- a/neonView/BulkMailPreview_view/BulkMailPreview_view.aod
+++ b/neonView/BulkMailPreview_view/BulkMailPreview_view.aod
@@ -6,6 +6,7 @@
     <headerFooterLayout>
       <name>layout</name>
       <header>Card</header>
+      <footer>6def3a7a-c9a0-4f2d-a36f-e53a631d8261</footer>
     </headerFooterLayout>
   </layout>
   <children>
@@ -14,6 +15,7 @@
       <iconField>ICON</iconField>
       <titleField>NAME</titleField>
       <descriptionField>STATUS</descriptionField>
+      <favoriteAction1>sendMail</favoriteAction1>
       <entityField>#ENTITY</entityField>
     </cardViewTemplate>
     <genericViewTemplate>
@@ -41,7 +43,16 @@
           <name>8bb72d39-3348-4bd6-b57d-f7f5ae573e73</name>
           <entityField>DESCRIPTION</entityField>
         </entityFieldLink>
+        <entityFieldLink>
+          <name>514d0861-ad00-4d32-9c56-6be0443e03e3</name>
+          <entityField>CREATEACTIVITIES</entityField>
+        </entityFieldLink>
       </fields>
     </genericViewTemplate>
+    <neonViewReference>
+      <name>6def3a7a-c9a0-4f2d-a36f-e53a631d8261</name>
+      <entityField>RecipientStatusChart</entityField>
+      <view>BulkMailStatusChart_view</view>
+    </neonViewReference>
   </children>
 </neonView>
diff --git a/neonView/BulkMailStatusChart_view/BulkMailStatusChart_view.aod b/neonView/BulkMailStatusChart_view/BulkMailStatusChart_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..efd092ba46067e5b1ef4fbff2ee1cbc12b40a05f
--- /dev/null
+++ b/neonView/BulkMailStatusChart_view/BulkMailStatusChart_view.aod
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.2">
+  <name>BulkMailStatusChart_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <singleDataChartViewTemplate>
+      <name>SingleDataChart</name>
+      <chartType>PIE</chartType>
+      <xAxis>X</xAxis>
+      <yAxis>Y</yAxis>
+      <entityField>#ENTITY</entityField>
+      <title>Recipients</title>
+    </singleDataChartViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/LetterRecipientFilter_view/LetterRecipientFilter_view.aod b/neonView/LetterRecipientFilter_view/LetterRecipientFilter_view.aod
index 3a4c82e844a79145303b58c6ab4b98548d22bb4b..5d453c6f013ee1d445b54ff640597acc5a066aa8 100644
--- a/neonView/LetterRecipientFilter_view/LetterRecipientFilter_view.aod
+++ b/neonView/LetterRecipientFilter_view/LetterRecipientFilter_view.aod
@@ -24,6 +24,10 @@
           <name>037e6bac-1e49-4c89-ae72-a5c64b9261d0</name>
           <entityField>CONTACT_ID</entityField>
         </neonTableColumn>
+        <neonTableColumn>
+          <name>e4e4ac89-100c-4fb8-b365-3e8f909ca526</name>
+          <entityField>ADDRESS_ID</entityField>
+        </neonTableColumn>
       </columns>
     </tableViewTemplate>
   </children>
diff --git a/neonView/PermissionActionEdit_view/PermissionActionEdit_view.aod b/neonView/PermissionActionEdit_view/PermissionActionEdit_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..9a9c84f8257b9f369d7c8455519121792ffe4f1e
--- /dev/null
+++ b/neonView/PermissionActionEdit_view/PermissionActionEdit_view.aod
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.2">
+  <name>PermissionActionEdit_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <genericMultipleViewTemplate>
+      <name>GenericMultiple</name>
+      <entityField>#ENTITY</entityField>
+      <title>Action</title>
+      <columns>
+        <neonTableColumn>
+          <name>0272107d-c34c-40e7-974e-5a63d2239fdb</name>
+          <entityField>ACTION</entityField>
+        </neonTableColumn>
+      </columns>
+    </genericMultipleViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/PermissionActionFilter_view/PermissionActionFilter_view.aod b/neonView/PermissionActionFilter_view/PermissionActionFilter_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..3bbf8059184dc70dc4053b1c43338fc19f829655
--- /dev/null
+++ b/neonView/PermissionActionFilter_view/PermissionActionFilter_view.aod
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.2" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.2">
+  <name>PermissionActionFilter_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <tableViewTemplate>
+      <name>Table</name>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonTableColumn>
+          <name>87d9c672-bce9-489a-b0cd-f8fcd2e4cdfd</name>
+          <entityField>ACTION</entityField>
+        </neonTableColumn>
+      </columns>
+    </tableViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/PermissionDetailEdit_view/PermissionDetailEdit_view.aod b/neonView/PermissionDetailEdit_view/PermissionDetailEdit_view.aod
index 8ef8579b7a1540329efda5245002705fd31b22ff..5a86fdf6d84f791ab91f4abd6c7269a73bd5eca4 100644
--- a/neonView/PermissionDetailEdit_view/PermissionDetailEdit_view.aod
+++ b/neonView/PermissionDetailEdit_view/PermissionDetailEdit_view.aod
@@ -4,9 +4,9 @@
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <isSmall v="true" />
   <layout>
-    <boxLayout>
+    <noneLayout>
       <name>layout</name>
-    </boxLayout>
+    </noneLayout>
   </layout>
   <children>
     <genericViewTemplate>
@@ -40,5 +40,10 @@
         </entityFieldLink>
       </fields>
     </genericViewTemplate>
+    <neonViewReference>
+      <name>bde148a0-e0ba-45e1-9402-f2855fd2ec4a</name>
+      <entityField>PermissionActions</entityField>
+      <view>PermissionActionEdit_view</view>
+    </neonViewReference>
   </children>
 </neonView>
diff --git a/neonView/PermissionDetailPreview_view/PermissionDetailPreview_view.aod b/neonView/PermissionDetailPreview_view/PermissionDetailPreview_view.aod
index 5ebbf66f77e25fcb516748764f0e687e3f9cd596..4a5ae421786a728f041aad983d1c0fa6871bb9a3 100644
--- a/neonView/PermissionDetailPreview_view/PermissionDetailPreview_view.aod
+++ b/neonView/PermissionDetailPreview_view/PermissionDetailPreview_view.aod
@@ -3,9 +3,9 @@
   <name>PermissionDetailPreview_view</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <layout>
-    <boxLayout>
+    <noneLayout>
       <name>layout</name>
-    </boxLayout>
+    </noneLayout>
   </layout>
   <children>
     <cardViewTemplate>
@@ -29,5 +29,10 @@
         </entityFieldLink>
       </fields>
     </genericViewTemplate>
+    <neonViewReference>
+      <name>b9e52e84-8ed8-4fe1-a938-6c6ff399c418</name>
+      <entityField>PermissionActions</entityField>
+      <view>PermissionActionFilter_view</view>
+    </neonViewReference>
   </children>
 </neonView>
diff --git a/neonView/PersonSimpleList_view/PersonSimpleList_view.aod b/neonView/PersonSimpleList_view/PersonSimpleList_view.aod
index cb5d4798dc7ea26426387fd7ffbed1dea0bac76e..5d4f929a7d3784339ef8901b6c9a7f5065f4a0cb 100644
--- a/neonView/PersonSimpleList_view/PersonSimpleList_view.aod
+++ b/neonView/PersonSimpleList_view/PersonSimpleList_view.aod
@@ -46,6 +46,18 @@
           <name>60cb743a-7a1f-4faa-92d6-780bd2ad0564</name>
           <entityField>STANDARD_PHONE_COMMUNICATION</entityField>
         </neonTableColumn>
+        <neonTableColumn>
+          <name>f3afd575-7a44-44c0-8d8c-7b8b20382b39</name>
+          <entityField>DEPARTMENT</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>07400a08-4dad-4c04-9349-e2e94f58bfec</name>
+          <entityField>CONTACTROLE</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>6ae815ae-117b-4349-8a8b-f63a404e9a05</name>
+          <entityField>POSITION</entityField>
+        </neonTableColumn>
       </columns>
     </tableViewTemplate>
   </children>
diff --git a/process/ActivityTask_lib/process.js b/process/ActivityTask_lib/process.js
index 75016636d736e311046824bb2dd988f7de58b6a9..dc1ac9e9af178f5464b81d1bd86f3fa4eab8807d 100644
--- a/process/ActivityTask_lib/process.js
+++ b/process/ActivityTask_lib/process.js
@@ -138,9 +138,9 @@ ActivityUtils.insertDocuments = function (pActivityId, pDocuments)
 /**
  * Create a new activity
  */
-ActivityUtils.createNewActivity = function(pRowId, pAdditionalLinks, pParentContext, pParentId, pDocuments)
+ActivityUtils.createNewActivity = function(pRowId, pAdditionalLinks, pParentContext, pParentId, pDocuments, pDirection)
 {
-    _ActivityTaskUtils._createNew("Activity", pRowId, pAdditionalLinks, pParentContext, pParentId, null, pDocuments)
+    _ActivityTaskUtils._createNew("Activity", pRowId, pAdditionalLinks, pParentContext, pParentId, null, pDocuments, pDirection)
 }
 
 /*
@@ -246,7 +246,7 @@ function _ActivityTaskUtils() {}
  * Create a new task
  * @ignore
  */
-_ActivityTaskUtils._createNew = function(pContext, pRowId, pAdditionalLinks, pParentContext, pParentId, pParams, pDocuments)
+_ActivityTaskUtils._createNew = function(pContext, pRowId, pAdditionalLinks, pParentContext, pParentId, pParams, pDocuments, pDirection)
 {
     if (pAdditionalLinks == undefined)
         pAdditionalLinks = [];
@@ -274,6 +274,10 @@ _ActivityTaskUtils._createNew = function(pContext, pRowId, pAdditionalLinks, pPa
     
     if (pDocuments)
         params["PresetDocuments_param"] = JSON.stringify(pDocuments);
+    
+    if (pDirection)
+        params["Direction_param"] = pDirection;
+    
     neon.openContext(pContext, null, null, neon.OPERATINGSTATE_NEW, params);
 }
 
diff --git a/process/Attribute_lib/process.js b/process/Attribute_lib/process.js
index 3236ea76d543e02a6e4c148dca4b539816eb0b14..5a9235fa19681fc63304cc64136b2809685f9ff5 100644
--- a/process/Attribute_lib/process.js
+++ b/process/Attribute_lib/process.js
@@ -1,5 +1,4 @@
 import("KeywordData_lib");
-import("KeywordData_lib");
 import("Context_lib");
 import("system.util");
 import("system.datetime");
@@ -7,6 +6,8 @@ import("system.translate");
 import("system.neon");
 import("system.vars");
 import("system.db");
+import("system.project");
+import("system.entities");
 import("Sql_lib");
 import("Keyword_lib");
 
@@ -116,7 +117,6 @@ AttributeUtil.getPossibleListValues = function (pAttributeId, pAttributeType, pI
             ["0", translate.text("No")]
             ];
     }
-    //TODO this is a workaround for keywords, when it's possible to use the consumer remove this
     else if (attrType == $AttributeTypes.KEYWORD.toString())
     {
         var attrKeywordSelect = "select DROPDOWNDEFINITION from AB_ATTRIBUTE";
@@ -129,13 +129,24 @@ AttributeUtil.getPossibleListValues = function (pAttributeId, pAttributeType, pI
     }
     else if (attrType == $AttributeTypes.OBJECTSELECTION)
     {
-        var module = db.cell(SqlCondition.begin()
+        var [module, filter] = db.array(db.ROW, SqlCondition.begin()
             .andPrepare("AB_ATTRIBUTE.AB_ATTRIBUTEID", attributeId)
-            .buildSql("select DROPDOWNDEFINITION from AB_ATTRIBUTE")
+            .buildSql("select DROPDOWNDEFINITION, DROPDOWNFILTER from AB_ATTRIBUTE")
             );
         var objects = [];
-        objects = db.table(ContextUtils.getContextDataSql(module));
-
+        if (module)
+        {
+            var uid = "#UID";
+            var title = "#CONTENTTITLE";
+            var config = entities.createConfigForLoadingRows()
+                .entity(module)
+                .fields([uid, title]);
+            if (filter)
+                config.filter(filter);
+            var rows = entities.getRows(config);
+            for (let i = 0, l = rows.length; i < l; i++)
+                objects.push([rows[i][uid], rows[i][title]])
+        }
         return objects;
     }
     else
@@ -746,11 +757,30 @@ $AttributeTypes.OBJECTSELECTION = {
     databaseField : "ID_VALUE",
     getViewValue : function (pValue, pModule)
         {
-            return db.cell(ContextUtils.getNameSql(pModule, pValue));
+            if (pValue)
+            {
+                var title = "#CONTENTTITLE";
+                var config = entities.createConfigForLoadingRows()
+                    .entity(pModule)
+                    .fields([title])
+                    .uid(pValue);
+                var rows = entities.getRow(config);
+                pValue = rows ? rows[title] : pValue;
+            }
+            return pValue;
         },
     getDropDownDefinitions : function ()
         {
-            return ContextUtils.getContexts(true);
+            var dropDownList = [];
+            //TODO filter entities
+            project.getDataModels(project.DATAMODEL_KIND_ENTITY).forEach(
+                function (entity)
+                {
+                    if (entity[1])
+                        dropDownList.push([entity[0], translate.text(entity[1])]);
+                }
+            );
+            return dropDownList;
         }
 };
 
@@ -814,7 +844,7 @@ AttributeTypeUtil.getDatabaseField = function (pAttributeType)
 
 AttributeTypeUtil.getAttributeViewValue = function (pAttributeType, pValue, pKeyword)
 {
-    if (pAttributeType in $AttributeTypes && "getViewValue" in $AttributeTypes[pAttributeType])
+    if (pAttributeType in $AttributeTypes && $AttributeTypes[pAttributeType].getViewValue)
         return $AttributeTypes[pAttributeType].getViewValue(pValue, pKeyword);
     return pValue;
 }
diff --git a/process/Bulkmail_lib/process.js b/process/Bulkmail_lib/process.js
index f262b0fc0ca14ccf163379f82aeb043945bbb8af..d143652488115d6ebd2f2bc51e718b0ff6b75721 100644
--- a/process/Bulkmail_lib/process.js
+++ b/process/Bulkmail_lib/process.js
@@ -22,16 +22,18 @@ function BulkMailUtils () {}
  * Executes a process to send bulk mails on the server and creates a notification when finished.
  * 
  * @param {String} pBulkMailId id of the bulk mail
+ * @param {Array} [pRecipients=bulkMailRecipients] overwrite the recipients (e.g. for testing)
  * @param {String} [pUser=currentUser] User that will get the notification, if null (not undefined!), no notification
  *                                      will be created.
  */
-BulkMailUtils.sendBulkMailOnServer = function (pBulkMailId, pUser)
+BulkMailUtils.sendBulkMailOnServer = function (pBulkMailId, pRecipients, pUser)
 {
     if (pUser === undefined)
         pUser = EmployeeUtils.getCurrentUserId();
     process.execute("sendBulkMail_serverProcess", 
         {
             bulkMailId : pBulkMailId,
+            recipients : JSON.stringify(pRecipients),
             user : pUser || ""
         }
     );
@@ -42,10 +44,11 @@ BulkMailUtils.sendBulkMailOnServer = function (pBulkMailId, pUser)
  * can take some time to execute, use BulkMailUtils.sendBulkMailOnServer instead.
  * 
  * @param {String} pBulkMailId id of the bulk mail 
+ * @param {Array} [pRecipients=bulkMailRecipients] overwrite the recipients (e.g. for testing)
  * 
  * @return {Object} count of sucessful and failed mails 
  */
-BulkMailUtils.sendBulkMail = function (pBulkMailId)
+BulkMailUtils.sendBulkMail = function (pBulkMailId, pRecipients)
 {
     var [templateId, subject, emailSender] = db.array(db.ROW, SqlCondition.begin()
         .andPrepare("BULKMAIL.BULKMAILID", pBulkMailId)
diff --git a/process/DocumentTemplate_lib/process.js b/process/DocumentTemplate_lib/process.js
index d43a480aa427019e311a21da0bc6f64ff6acc992..6327fbf8a15ca61cd53c30328ae2c8004713724a 100644
--- a/process/DocumentTemplate_lib/process.js
+++ b/process/DocumentTemplate_lib/process.js
@@ -150,11 +150,12 @@ DocumentTemplate.prototype._getRequiredPlaceholders = function ()
  * replace function for the type.
  * 
  * @param {Object} pReplacements map, the structure is {placeholder : value}
- * @param {boolean} pDecoded if the replaced content should be not base64 encoded
+ * @param {boolean} pEncoded if the replaced content should be base64 encoded
+ *                            (doesn't affect odt/docx)
  * 
  * @return {String} the replaced content
  */
-DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pDecoded)
+DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pEncoded)
 {
     switch (this.type)
     {
@@ -164,17 +165,23 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pDecode
         case DocumentTemplate.types.TXT:
             let decodedContent = util.decodeBase64String(this.content);
             let encodedContent = DocumentTemplate._replaceText(decodedContent, pReplacements);
-            if (!pDecoded)
+            if (pEncoded)
                 encodedContent = util.encodeBase64String(encodedContent);
             return encodedContent;
         case DocumentTemplate.types.EML:
-            return this._getReplacedEML(pReplacements);
+            let content = this._getReplacedEML(pReplacements);
+            if (pEncoded)
+                content = util.encodeBase64String(content);
+            return content;
         case DocumentTemplate.types.ODT:
             return this._getReplacedODT(pReplacements);
         case DocumentTemplate.types.DOCX:
             return this._getReplacedDOCX(pReplacements);
         case DocumentTemplate.types.PLAIN:
-            return DocumentTemplate._replaceText(this.content, pReplacements);
+            let plainText = DocumentTemplate._replaceText(this.content, pReplacements);
+            if (pEncoded)
+                plainText = util.encodeBase64String(plainText);
+            return plainText;
         default:
             return null;
     }
@@ -183,10 +190,10 @@ DocumentTemplate.prototype.getReplacedContent = function (pReplacements, pDecode
 /**
  * replaces the placeholders with data from one contact and returns the result
  */
-DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId) 
+DocumentTemplate.prototype.getReplacedContentByContactId = function (pContactId, pEncoded) 
 {
     var replacements = this._getReplacementsByContactIds([pContactId]); 
-    var content = this.getReplacedContent(replacements[pContactId]);
+    var content = this.getReplacedContent(replacements[pContactId], pEncoded);
     
     return content;
 }
@@ -195,16 +202,17 @@ 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
  * 
  * @return {Object} replaced content for every contactId
  */
-DocumentTemplate.prototype.getReplacedContentByContactIds = function (pContactIds) 
+DocumentTemplate.prototype.getReplacedContentByContactIds = function (pContactIds, pEncoded) 
 {
     var replacements = this._getReplacementsByContactIds(pContactIds);
     var contents = {};
     for (let contactId in replacements)
     {
-        contents[contactId] = this.getReplacedContent(replacements[contactId]);
+        contents[contactId] = this.getReplacedContent(replacements[contactId], pEncoded);
     }
     return contents;
 }
@@ -275,7 +283,7 @@ DocumentTemplate.prototype.getReplacedEmailsByContactIds = function (pContactIds
         }
         else
         {
-            let body = this.getReplacedContent(replacements[contactId], true);
+            let body = this.getReplacedContent(replacements[contactId]);
             if (this.type == DocumentTemplate.types.TXT || this.type == DocumentTemplate.types.PLAIN)
                 body = text.text2html(body, false);
             emailObj[contactId] = new Email(null, null, null, body);
diff --git a/process/Email_lib/process.js b/process/Email_lib/process.js
index 8de0df67a0fd66b5f9a2d3ded4084895dc138bc6..bdaf02a758707629a40926757f069a3338674fe9 100644
--- a/process/Email_lib/process.js
+++ b/process/Email_lib/process.js
@@ -210,7 +210,7 @@ Email.prototype.getEML = function()
  * 
  * @return {boolean} true, if the mail was sent sucessfully
  */
-Email.prototype.send = function ()
+Email.prototype.send = function (pUser)
 {
     var ENCODING = "UTF-8";
     var mailId;
@@ -227,7 +227,10 @@ Email.prototype.send = function ()
             util.sleep(1500);
             mailId = mail.newMail();
         }
-
+        
+        if (this.sender)
+            mail.setSender(mailId, this.sender);
+        
         if (this.toRecipients.length)
             mail.addRecipients(mailId, mail.RECIPIENT_TO, this.toRecipients);
 
@@ -245,8 +248,7 @@ Email.prototype.send = function ()
         else
             mail.addText(mailId, "", "text/html", ENCODING, null);
     
-        mail.sendMail(mailId);
-        return true;
+        return mail.sendMailAs(pUser || "mailbridge", mailId) > 0;
     }
     catch (ex)
     {
diff --git a/process/Permission_lib/process.js b/process/Permission_lib/process.js
index 689c3577f4200a347625f62998acd1ccc3305026..bec5de949e05a8cad27e1e644de9705220b7630b 100644
--- a/process/Permission_lib/process.js
+++ b/process/Permission_lib/process.js
@@ -301,6 +301,28 @@ PermissionUtil.getPermissionAction = function(pPermId) {
     return db.table(sqlStr, alias);
 }
 
+/**
+ * Gets the permission set id of a given role-entity-accesstype-combination.
+ * 
+ * @param {String} pRole the name of the role
+ * 
+ * @param {String} pEntity the name of the entity
+ * 
+ * @param {String} pAccessType the name of the access type (E,R,F)
+ * 
+ * @param {String} pField the name of the field
+ * 
+ * @result {String} returns the id of the matching permission set. The result can never be null.
+ */
+PermissionUtil.getPermissionSet = function(pRole, pEntity, pAccessType, pField) {
+    var sqlStr = "select ASYS_PERMISSIONSETID from ASYS_PERMISSIONSET"
+    + " where ROLE_ID = '" + pRole + "' and ENTITY_ID = '" + pEntity + "' and ACCESSTYPE = '" + pAccessType + "'";
+    if (pField != null && pField != "" && pField != undefined) {
+        sqlStr += " and FIELD_ID = '" + pField + "'";
+    }
+    return db.cell(sqlStr, alias);
+}
+
 /**
  * Gets the root permission set of a entity-role-combination.
  * 
@@ -412,15 +434,22 @@ PermissionUtil.insertNewPermissionSet = function(pParentPermSet, pEntity, pRole,
  * 
  * @param {String} pCondType The Condition Type of the permission, should nearly always be "true"
  * 
+ * @param {String} pPermId The id of the new permission (can be empty/null)
+ * 
  * @result {Integer} returns the id of the inserted permission
  */
-PermissionUtil.insertNewPermission = function(pParentPermSet, pCond, pCondType) {
+PermissionUtil.insertNewPermission = function(pParentPermSet, pCond, pCondType, pPermId) {
     var table = "ASYS_PERMISSION";
     var cols = db.getColumns(table, alias);
-    var permid = util.getNewUUID(); 
-    var vals = [permid, pParentPermSet, pCond, pCondType];
+    var permId;
+    if (pPermId != null && pPermId != "" && pPermId != undefined) {
+        permId = pPermId;
+    } else {
+        permId = util.getNewUUID(); 
+    }
+    var vals = [permId, pParentPermSet, pCond, pCondType];
     db.insertData(table, cols, null, vals, alias);  
-    return permid;
+    return permId;
 }
 
 /**
@@ -430,30 +459,138 @@ PermissionUtil.insertNewPermission = function(pParentPermSet, pCond, pCondType)
  * 
  * @param {String} pAction Action (view, create,...), mandatory
  * 
- * @result {Integer} returns the id of the inserted permission action
+ * @param {String} pActionId The id of the new permission action
+ * 
+ * @result {Integer} returns the id of the inserted permission action, returns null if insert was not possible
  */
-PermissionUtil.insertNewPermissionAction = function(pParentPerm, pAction) {
+PermissionUtil.insertNewPermissionAction = function(pParentPerm, pAction, pActionId) {
     var table = "ASYS_PERMISSIONACTION";
     var cols = db.getColumns(table, alias);
-    var permactionid = util.getNewUUID();
-    var vals = [pAction, permactionid, pParentPerm];
-    db.insertData(table, cols, null, vals, alias);
-    return permactionid;
+    var permactionid;
+    
+    var actions = PermissionUtil.getPermissionAction(pParentPerm);
+    var sqlStr = "select ACCESSTYPE from ASYS_PERMISSIONSET where ASYS_PERMISSIONSETID = '" + PermissionUtil.getParentPermissionSet(pParentPerm) + "'";
+    var accesstype = db.cell(sqlStr, alias);
+    var insertIsAllowed = true;
+    
+    switch (accesstype) {
+        case "R":
+            if (actions.length >= 3) {
+                insertIsAllowed = false;
+            }
+            break;
+        default:
+            if (actions.length >= 2) {
+                insertIsAllowed = false;        
+            }
+            break;
+    }
+    
+    if (insertIsAllowed) {
+        sqlStr = "select ASYS_PERMISSIONACTIONID from ASYS_PERMISSIONACTION where ASYS_PERMISSIONACTIONID = '" + pActionId + "'"; // if same id is already in db -> create new UID
+
+        if (pActionId != null & pActionId != "" && pActionId != undefined && db.cell(sqlStr, alias) == "") {
+            permactionid = pActionId;
+        } else {
+            permactionid = util.getNewUUID();
+        }
+        var vals = [pAction, permactionid, pParentPerm];
+        db.insertData(table, cols, null, vals, alias);
+        return permactionid;
+    }
+    return null;
 }
 
 /**
- * Returns the cond type of a permission.
- * 
- * @param {String} pPerm The permission, mandatory
- * 
- * @result {Integer} returns the cond type of a permission
- */
+     * Returns the cond type of a permission.
+     * 
+     * @param {String} pPerm The permission, mandatory
+     * 
+     * @result {Integer} returns the cond type of a permission
+     */
 PermissionUtil.getCondType = function(pPerm) {
     var table = "ASYS_PERMISSION";
     var sqlStr = "select CONDTYPE from " + table + " where ASYS_PERMISSIONID = '" + pPerm + "'";
     return db.cell(sqlStr, alias);
 }
 
+/**
+     * Returns true if the permission exists, otherwise false.
+     * 
+     * @param {String} pPermId The permission id
+     * 
+     * @result {Boolean} true if permission exists, otherwise false
+     */
+PermissionUtil.existsPermission = function(pPermId) {
+    var table = "ASYS_PERMISSION";
+    var sqlStr = "select COUNT(*) from " + table + " where ASYS_PERMISSIONID = '" + pPermId + "'";
+    if (db.cell(sqlStr, alias) != "0") {
+        return true;
+    }
+    return false;
+}
+
+/**
+     * Returns permissionid of the permission with fitting parameters, otherwise returns empty string
+     * 
+     * @param {String} pRole Name of the role
+     * 
+     * @param {String} pEntity Name of the entity
+     * 
+     * @param {String} pField Name of the field
+     * 
+     * @param {String} pAccesstype Accesstype (E,F,R)
+     * 
+     * @param {String} pCondition The condition (Filter in JSON-format)
+     * 
+     * @param {String} pCondtype Type of the condition (true/false)
+     * 
+     * @result {String} Returns the id of the permission with fitting parameters, otherwise returns empty string, can never be null
+     *
+     */
+PermissionUtil.getPermission = function(pRole, pEntity, pField, pAccesstype, pCondition, pCondtype) {
+    var sqlStr = "";
+    var sqlExt = "";
+    var noCond = "{\"entity\":\"" + pEntity + "\",\"filter\":{\"type\":\"group\",\"operator\":\"AND\",\"childs\":[]}}";
+    
+    if (checkInput([pCondition])) {
+        if (pCondition == noCond) {
+            sqlExt += " and (COND like '%" + pCondition + "%' or COND is null)";
+        } else {
+            sqlExt += " and COND like '%" + pCondition + "%'";
+        }
+    }
+    
+    if (checkInput([pField])) {
+        sqlExt += " and FIELD_ID = '" + pField + "'";
+    }
+    
+    if (checkInput([pCondtype])) {
+        sqlExt += " and CONDTYPE = '" + pCondtype + "'";
+    }
+    
+    sqlStr = "select ASYS_PERMISSION.ASYS_PERMISSIONID from ASYS_PERMISSIONSET"
+    + " join ASYS_PERMISSION on ASYS_PERMISSION.ASYS_PERMISSIONSET_ID = ASYS_PERMISSIONSET.ASYS_PERMISSIONSETID"
+    + " where ENTITY_ID = '" + pEntity + "' and ROLE_ID = '" + pRole + "'"
+    + " and ACCESSTYPE = '" + pAccesstype + "'" + sqlExt;
+    var permId = db.cell(sqlStr, alias);
+    return permId;
+}
+
+/**
+     * Deletes a permission action from ASYS_PERMISSIONACTION.
+     * 
+     * @param {String} pPermActionId The permission action id which should be deleted, mandatory
+     * 
+     * @result {Integer} returns the number of deleted records
+     */
+PermissionUtil.deletePermissionAction = function(pPermActionId) {
+    var table = "ASYS_PERMISSIONACTION";
+    var cond = " ASYS_PERMISSIONACTIONID = '" + pPermActionId + "'";
+    return db.deleteData(table, cond, alias);
+}
+
+
 // arrDiff calculates different elements of two arrays and returns them as array, otherwise empty array
 function arrDiff (arr1, arr2) {
     var helperArr = [], diff = [];
@@ -476,4 +613,13 @@ function arrDiff (arr1, arr2) {
     }
 
     return diff;
+}
+
+// checks input array if each element is a valid input, returns true if valid, otherwise false
+function checkInput(pInputArr) {
+    for each (var input in pInputArr) {
+        if (input == undefined || input == null || input == "")
+            return false;
+    }
+    return true;
 }
\ No newline at end of file
diff --git a/process/sendBulkMail_serverProcess/process.js b/process/sendBulkMail_serverProcess/process.js
index 68c0371b37a3721cd13e0aef3113a8e170034ecd..89c76bc2898eecb6a7e6772566e775a8e3eed78c 100644
--- a/process/sendBulkMail_serverProcess/process.js
+++ b/process/sendBulkMail_serverProcess/process.js
@@ -10,7 +10,8 @@ import("system.notification");
 var startTime = datetime.date();
 var bulkMailId = vars.get("$local.bulkMailId");
 var user = vars.get("$local.user");
-var res = BulkMailUtils.sendBulkMail(bulkMailId);
+var recipients = JSON.parse(vars.get("$local.recipients"));
+var res = BulkMailUtils.sendBulkMail(bulkMailId, recipients);
 
 if (user)
 {