diff --git a/.liquibase/Data_alias/basic/2020.1.1/changelog.xml b/.liquibase/Data_alias/basic/2020.1.1/changelog.xml
index 7070cb88cfdc67dbb126680500fad85499f40887..f5686ce22ccea6e17c577957774efd2009a0dd7f 100644
--- a/.liquibase/Data_alias/basic/2020.1.1/changelog.xml
+++ b/.liquibase/Data_alias/basic/2020.1.1/changelog.xml
@@ -2,5 +2,4 @@
 <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
     <include relativeToChangelogFile="true" file="AlterTablesToDatetime.xml"/>
-    <include relativeToChangelogFile="true" file="Notification/changelog.xml"/>
 </databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2020.1.1/Notification/changelog.xml b/.liquibase/Data_alias/basic/2020.1.2/Notification/changelog.xml
similarity index 100%
rename from .liquibase/Data_alias/basic/2020.1.1/Notification/changelog.xml
rename to .liquibase/Data_alias/basic/2020.1.2/Notification/changelog.xml
diff --git a/.liquibase/Data_alias/basic/2020.1.1/Notification/init_NotificationType.xml b/.liquibase/Data_alias/basic/2020.1.2/Notification/init_NotificationType.xml
similarity index 100%
rename from .liquibase/Data_alias/basic/2020.1.1/Notification/init_NotificationType.xml
rename to .liquibase/Data_alias/basic/2020.1.2/Notification/init_NotificationType.xml
diff --git a/.liquibase/Data_alias/basic/2020.1.1/Notification/insert_NotificationState.xml b/.liquibase/Data_alias/basic/2020.1.2/Notification/insert_NotificationState.xml
similarity index 100%
rename from .liquibase/Data_alias/basic/2020.1.1/Notification/insert_NotificationState.xml
rename to .liquibase/Data_alias/basic/2020.1.2/Notification/insert_NotificationState.xml
diff --git a/.liquibase/Data_alias/basic/2020.1.2/changelog.xml b/.liquibase/Data_alias/basic/2020.1.2/changelog.xml
index 7696526b5b01d5485e47a5a69bbade95aa0c6317..1f2c05d8e7b344c7cbe3cd689c4b0c526cd8e56b 100644
--- a/.liquibase/Data_alias/basic/2020.1.2/changelog.xml
+++ b/.liquibase/Data_alias/basic/2020.1.2/changelog.xml
@@ -2,7 +2,8 @@
 <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
     <include file="AlterDatatypeOfKeyColumnsToChar/changelog.xml" relativeToChangelogFile="true"/>
-    <include file="VisitPlanEntry/rename_VisitPlanEntry_ORGANISATION_ID.xml" relativeToChangelogFile="true"/>
-    <include file="AddNullableToDateNew.xml" relativeToChangelogFile="true" />
+    <include file="AddNullableToDateNew.xml" relativeToChangelogFile="true" />    
+    <include file="insert_workflowCategory_keyword.xml" relativeToChangelogFile="true"/>
+    <include file="Notification/changelog.xml" relativeToChangelogFile="true" />
     <include file="AlterButtonLabelTitles/AlterButtonLabelTitles.xml" relativeToChangelogFile="true" />
 </databaseChangeLog>
diff --git a/.liquibase/Data_alias/basic/2020.1.2/insert_workflowCategory_keyword.xml b/.liquibase/Data_alias/basic/2020.1.2/insert_workflowCategory_keyword.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a4bbbd1638f60b4023e3ccab49955e358c011ba9
--- /dev/null
+++ b/.liquibase/Data_alias/basic/2020.1.2/insert_workflowCategory_keyword.xml
@@ -0,0 +1,24 @@
+<?xml version="1.1" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd">
+    <changeSet author="s.listl" id="38b13161-5163-48d9-9791-f9c7027cac62">
+        <insert tableName="AB_KEYWORD_ENTRY">
+            <column name="AB_KEYWORD_ENTRYID" value="f241b36a-c2fe-40be-9e2e-8293c700d096"/>
+            <column name="KEYID" value="WORKFLOWCATEGORYMARKETING"/>
+            <column name="TITLE" value="Marketing"/>
+            <column name="CONTAINER" value="WorkflowCategory"/>
+            <column name="SORTING" valueNumeric="1"/>
+            <column name="ISACTIVE" valueNumeric="1"/>
+            <column name="ISESSENTIAL" valueNumeric="0"/>
+        </insert>
+        <insert tableName="AB_KEYWORD_ENTRY">
+            <column name="AB_KEYWORD_ENTRYID" value="00a72718-554e-46ab-b83c-fb9b81be4be6"/>
+            <column name="KEYID" value="WORKFLOWCATEGORYRELEASE"/>
+            <column name="TITLE" value="Release"/>
+            <column name="CONTAINER" value="WorkflowCategory"/>
+            <column name="SORTING" valueNumeric="2"/>
+            <column name="ISACTIVE" valueNumeric="1"/>
+            <column name="ISESSENTIAL" valueNumeric="0"/>
+        </insert>
+    </changeSet>
+</databaseChangeLog>
diff --git a/.liquibase/Data_alias/changelog.xml b/.liquibase/Data_alias/changelog.xml
index a8cc53b406959a8797b32a02af71dd93e1576384..415dcce4162c36e2f1c7945a6082d40e3968a5b1 100644
--- a/.liquibase/Data_alias/changelog.xml
+++ b/.liquibase/Data_alias/changelog.xml
@@ -14,7 +14,7 @@
     <include relativeToChangelogFile="true" file="basic/2020.1.0/changelog.xml"/>
     <include relativeToChangelogFile="true" file="basic/2020.1.1/changelog.xml"/>
     <include relativeToChangelogFile="true" file="basic/2020.1.2/changelog.xml"/>
-    
+
     <!--enable this only when you definetly want to overwrite the existing data with demo records:--> 
     <!--<include relativeToChangelogFile="true" file="basic/_demoData/changelog.xml" context="example"/>-->
 </databaseChangeLog>
\ No newline at end of file
diff --git a/entity/Address_entity/Address_entity.aod b/entity/Address_entity/Address_entity.aod
index a8fab2595e8795a739e854e715f1669bbd0477ac..0b6f95c995e62e440e543f9a9839fd760bf4a6c3 100644
--- a/entity/Address_entity/Address_entity.aod
+++ b/entity/Address_entity/Address_entity.aod
@@ -15,8 +15,6 @@
       <mandatoryProcess>%aditoprj%/entity/Address_entity/entityfields/address/mandatoryProcess.js</mandatoryProcess>
       <textInputAllowed v="true" />
       <stateProcess>%aditoprj%/entity/Address_entity/entityfields/address/stateProcess.js</stateProcess>
-      <valueProcess>%aditoprj%/entity/Address_entity/entityfields/address/valueProcess.js</valueProcess>
-      <displayValueProcess>%aditoprj%/entity/Address_entity/entityfields/address/displayValueProcess.js</displayValueProcess>
       <onValueChange>%aditoprj%/entity/Address_entity/entityfields/address/onValueChange.js</onValueChange>
       <onValueChangeTypes>
         <element>MASK</element>
diff --git a/entity/Address_entity/entityfields/address/displayValueProcess.js b/entity/Address_entity/entityfields/address/displayValueProcess.js
deleted file mode 100644
index 18985f7a004b046c160746de13e8970eb6c87ece..0000000000000000000000000000000000000000
--- a/entity/Address_entity/entityfields/address/displayValueProcess.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import("system.vars");
-import("system.result");
-
-// Needed for instant refresh if set by neon.setFieldValue
-// 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/valueProcess.js b/entity/Address_entity/entityfields/address/valueProcess.js
deleted file mode 100644
index 2c9d496185be419f31c762709ca97d83a1ae4bd4..0000000000000000000000000000000000000000
--- a/entity/Address_entity/entityfields/address/valueProcess.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import("system.result");
-import("WsValidation_lib");
-import("system.vars");
-
-// 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/address_ws/valueProcess.js b/entity/Address_entity/entityfields/address_ws/valueProcess.js
index 5ccdf5a99f70f8b801158a56c1fa7b8136854130..2c7449d49d0036b67e5de71b0a7d7cf9b75876a9 100644
--- a/entity/Address_entity/entityfields/address_ws/valueProcess.js
+++ b/entity/Address_entity/entityfields/address_ws/valueProcess.js
@@ -1,3 +1,5 @@
+import("system.vars");
 import("WsValidation_lib");
 
-WsValidationFieldUtils.wsValueProcess(WsValidationType.get().TYPE_STREET_NOMINATIM, "$field.ADDRESS");
\ No newline at end of file
+if(!vars.get("$this.value"))
+    WsValidationFieldUtils.wsValueProcess(WsValidationType.get().TYPE_STREET_NOMINATIM, "$field.ADDRESS");
\ No newline at end of file
diff --git a/entity/Email_entity/Email_entity.aod b/entity/Email_entity/Email_entity.aod
index f3a15f3c8ad189a57e5dd9c9b3167d59a5043bed..b14e753e4e989ccf0645d68cb7bca2f6cca765c4 100644
--- a/entity/Email_entity/Email_entity.aod
+++ b/entity/Email_entity/Email_entity.aod
@@ -119,7 +119,7 @@
     </entityParameter>
     <entityActionField>
       <name>sendMail</name>
-      <title>send mail</title>
+      <title>{SEND_MAIL}</title>
       <onActionProcess>%aditoprj%/entity/Email_entity/entityfields/sendmail/onActionProcess.js</onActionProcess>
       <iconId>VAADIN:AT</iconId>
       <stateProcess>%aditoprj%/entity/Email_entity/entityfields/sendmail/stateProcess.js</stateProcess>
diff --git a/entity/Employee_entity/entityfields/contact_id/onValueChange.js b/entity/Employee_entity/entityfields/contact_id/onValueChange.js
index d469435d5c78d77ed6371942df1cb330d36389d3..4a1dbe67e5fb2353cd24c297f9ca0c1eb08e9304 100644
--- a/entity/Employee_entity/entityfields/contact_id/onValueChange.js
+++ b/entity/Employee_entity/entityfields/contact_id/onValueChange.js
@@ -22,7 +22,7 @@ if ((vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW || vars.get("$sys.r
     neon.setFieldValues({
         "$field.FIRSTNAME" : name[0] || "",
         "$field.LASTNAME" : name[1] || "",
-        "$field.EMAIL_ADDRESS" : name[2] || "",
+        "$field.EMAIL_ADDRESS" : name[2] || vars.get("$field.EMAIL_ADDRESS") || "",
         "$field.TITLE" : username
     });
 }
\ 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 99e97c2dddc0cae705cdc328a215b226a386f227..559a598b48b1f347bf21ee32e097eacc741b1083 100644
--- a/entity/Employee_entity/entityfields/email_address/dropDownProcess.js
+++ b/entity/Employee_entity/entityfields/email_address/dropDownProcess.js
@@ -6,7 +6,7 @@ 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))
+if (contactId)
 {
     var addresses = newSelect("ADDR, ADDR")
                 .from("COMMUNICATION")
diff --git a/entity/Notification_entity/Notification_entity.aod b/entity/Notification_entity/Notification_entity.aod
index 3f08a4f669f0e68b3182f2d392daab2235930c23..50b11b29d038dfbffc77b87f3ba92e06474cc9d8 100644
--- a/entity/Notification_entity/Notification_entity.aod
+++ b/entity/Notification_entity/Notification_entity.aod
@@ -34,7 +34,7 @@
     </entityField>
     <entityField>
       <name>CAPTION</name>
-      <title>title</title>
+      <title>Title</title>
     </entityField>
     <entityField>
       <name>CREATEDATE</name>
@@ -45,7 +45,7 @@
     </entityField>
     <entityField>
       <name>DESCRIPTION</name>
-      <title>description</title>
+      <title>Description</title>
     </entityField>
     <entityField>
       <name>FORCEDPRIORITY</name>
@@ -124,7 +124,7 @@
     </entityActionGroup>
     <entityField>
       <name>RESOLVEDPRIORITY</name>
-      <title>priority</title>
+      <title>Priority</title>
       <consumer>PrioKeywords</consumer>
       <textInputAllowed v="false" />
     </entityField>
diff --git a/entity/Offer_entity/Offer_entity.aod b/entity/Offer_entity/Offer_entity.aod
index ef4dc76656ae23282b3d30e6b56db39c4c223e06..8d82f2247f9b980096ecc6f120a15f4711a76e6a 100644
--- a/entity/Offer_entity/Offer_entity.aod
+++ b/entity/Offer_entity/Offer_entity.aod
@@ -1023,6 +1023,7 @@
     <entityAggregateField>
       <name>NET_aggregate</name>
       <parentField>NET</parentField>
+      <title>Sum</title>
     </entityAggregateField>
     <entityField>
       <name>OFFER_OBJECTTYPE</name>
@@ -1038,6 +1039,15 @@
       <parentField>COUNT</parentField>
       <title>Count</title>
     </entityAggregateField>
+    <entityAggregateField>
+      <name>PROBABILITY_aggregate</name>
+      <parentField>PROBABILITY</parentField>
+      <title>Ø Probability</title>
+    </entityAggregateField>
+    <entityProvider>
+      <name>OfferAggregates</name>
+      <useAggregates v="true" />
+    </entityProvider>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -1285,6 +1295,10 @@
           <recordfield>OFFER.OFFER_ID</recordfield>
           <aggregateType>COUNT</aggregateType>
         </aggregateFieldDbMapping>
+        <aggregateFieldDbMapping>
+          <name>PROBABILITY_aggregate.value</name>
+          <expression>%aditoprj%/entity/Offer_entity/recordcontainers/db/recordfieldmappings/probability_aggregate.value/expression.js</expression>
+        </aggregateFieldDbMapping>
       </recordFieldMappings>
       <filterExtensions>
         <filterExtensionSet>
diff --git a/entity/Offer_entity/recordcontainers/db/recordfieldmappings/probability_aggregate.value/expression.js b/entity/Offer_entity/recordcontainers/db/recordfieldmappings/probability_aggregate.value/expression.js
new file mode 100644
index 0000000000000000000000000000000000000000..25f76f180180bfc8602cee9566751078ba280678
--- /dev/null
+++ b/entity/Offer_entity/recordcontainers/db/recordfieldmappings/probability_aggregate.value/expression.js
@@ -0,0 +1,6 @@
+import("system.SQLTYPES");
+import("system.result");
+import("Sql_lib");
+
+var helper = new SqlMaskingUtils();
+result.string("AVG("+ helper.cast("OFFER.PROBABILITY", SQLTYPES.INTEGER)  + ")");
\ No newline at end of file
diff --git a/entity/Salesproject_entity/Salesproject_entity.aod b/entity/Salesproject_entity/Salesproject_entity.aod
index 2c5b4e88d58f9275bb82fbb89150e513362331bf..5aee7c68558f7368b7a933c7d6390839203a5716 100644
--- a/entity/Salesproject_entity/Salesproject_entity.aod
+++ b/entity/Salesproject_entity/Salesproject_entity.aod
@@ -750,6 +750,13 @@
       <iconId>VAADIN:PLAY</iconId>
       <stateProcess>%aditoprj%/entity/Salesproject_entity/entityfields/startworkflow/stateProcess.js</stateProcess>
     </entityActionField>
+    <entityField>
+      <name>PROBABILITY_AI</name>
+      <title>Probability AI</title>
+      <state>READONLY</state>
+      <stateProcess>%aditoprj%/entity/Salesproject_entity/entityfields/probability_ai/stateProcess.js</stateProcess>
+      <valueProcess>%aditoprj%/entity/Salesproject_entity/entityfields/probability_ai/valueProcess.js</valueProcess>
+    </entityField>
     <entityField>
       <name>SALESPROJECT_OBJECTTYPE</name>
       <valueProcess>%aditoprj%/entity/Salesproject_entity/entityfields/salesproject_objecttype/valueProcess.js</valueProcess>
diff --git a/entity/Salesproject_entity/entityfields/probability_ai/stateProcess.js b/entity/Salesproject_entity/entityfields/probability_ai/stateProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..fd3f09b8d62446c4e3946a0ece4b428e7f8ca48b
--- /dev/null
+++ b/entity/Salesproject_entity/entityfields/probability_ai/stateProcess.js
@@ -0,0 +1,7 @@
+import("system.result");
+import("system.project");
+
+if(!JSON.parse(project.getPreferenceValue("custom.ai.salesprojectProbability", "false")))
+{
+    result.string("INVISIBLE");
+}
\ No newline at end of file
diff --git a/entity/Salesproject_entity/entityfields/probability_ai/valueProcess.js b/entity/Salesproject_entity/entityfields/probability_ai/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..844f60472a79f7551370dc0bf2ad0c3607eeed43
--- /dev/null
+++ b/entity/Salesproject_entity/entityfields/probability_ai/valueProcess.js
@@ -0,0 +1,16 @@
+import("system.vars");
+import("system.logging");
+import("system.result");
+import("AISalesproject_lib");
+import("system.project");
+
+if(JSON.parse(project.getPreferenceValue("custom.ai.salesprojectProbability", "false")))
+{
+    result.string(AISalesprojectUtil.classify(vars.getString("$field.SALESPROJECTID"), 
+                                          vars.getString("$field.CONTACT_ID"), 
+                                          vars.getString("$field.PHASE"), 
+                                          vars.getString("$field.STATUS"), 
+                                          vars.getString("$field.VOLUME"),
+                                          vars.getString("$field.PROBABILITY"))); 
+ 
+}
\ No newline at end of file
diff --git a/entity/WorkflowStartConfig_entity/imageProcess.js b/entity/WorkflowStartConfig_entity/imageProcess.js
index 34147b89bd271ec01be2bb3fa1c6eb055186963f..8b918cbc285c80f90e305b0b2aee6655949db65f 100644
--- a/entity/WorkflowStartConfig_entity/imageProcess.js
+++ b/entity/WorkflowStartConfig_entity/imageProcess.js
@@ -2,5 +2,5 @@ import("system.result");
 import("system.vars");
 import("system.project");
 
-var contextModel = project.getDataModel(project.DATAMODEL_KIND_CONTEXT, vars.get("$field.OBJECT_TYPE"));
+var contextModel = vars.get("$field.OBJECT_TYPE") && project.getDataModel(project.DATAMODEL_KIND_CONTEXT, vars.get("$field.OBJECT_TYPE"));
 result.string(contextModel ? contextModel[5] : "");
\ No newline at end of file
diff --git a/entity/WorkflowTask_entity/WorkflowTask_entity.aod b/entity/WorkflowTask_entity/WorkflowTask_entity.aod
index 3ffbe846c77cc3e4d64c7ed734ff2399dc30450a..938fbcdc991e33b51be6bc7134499438ac1fbabd 100644
--- a/entity/WorkflowTask_entity/WorkflowTask_entity.aod
+++ b/entity/WorkflowTask_entity/WorkflowTask_entity.aod
@@ -31,6 +31,7 @@
     </entityField>
     <entityField>
       <name>FORMRESULT</name>
+      <onValueChange>%aditoprj%/entity/WorkflowTask_entity/entityfields/formresult/onValueChange.js</onValueChange>
     </entityField>
     <entityField>
       <name>NAME</name>
diff --git a/entity/WorkflowTask_entity/entityfields/formresult/onValueChange.js b/entity/WorkflowTask_entity/entityfields/formresult/onValueChange.js
new file mode 100644
index 0000000000000000000000000000000000000000..249aba04bbb279e4e8ae4dc4f7164fbeee463fe5
--- /dev/null
+++ b/entity/WorkflowTask_entity/entityfields/formresult/onValueChange.js
@@ -0,0 +1,25 @@
+import("system.result");
+import("system.vars");
+import("system.workflow");
+import("system.neon");
+
+var taskId = vars.get("$field.UID");
+var newResult = vars.get("$local.value");
+var oldResult = vars.get("$field.FORMRESULT");
+
+if (newResult && newResult !== oldResult)
+{
+    /*
+     * fieldListeners = all fields that are used inside a visibility expression
+     * -> if one of these fields is changed, set the new FORMDEFINITION
+     */
+    var fieldListeners = JSON.parse(workflow.getFormFieldListeners(taskId));
+    newResult = newResult ? JSON.parse(newResult) : {};
+    oldResult = oldResult ? JSON.parse(oldResult) : {};
+    var isRefreshRequired = fieldListeners.some(function (fieldId)
+    {
+        return newResult[fieldId] !== oldResult[fieldId];
+    });
+    if (isRefreshRequired)
+        neon.setFieldValue("$field.FORMDEFINITION", workflow.getFormProperties(taskId, newResult));
+}
diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
index d339195f21f074660303e10b1a80ce278c3bb123..fdd95ea3c05aaba3655b1a0c2acf0b42faf21c30 100644
--- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
+++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
@@ -6872,9 +6872,24 @@
     <entry>
       <key>Workflow Model</key>
     </entry>
+    <entry>
+      <key>{SENT_MAIL}</key>
+    </entry>
     <entry>
       <key>The Sales Project can only be filled when a company has been specified</key>
     </entry>
+    <entry>
+      <key>The workflow could not be deployed</key>
+    </entry>
+    <entry>
+      <key>Workflow deploy failed</key>
+    </entry>
+    <entry>
+      <key>Ø Probability</key>
+    </entry>
+    <entry>
+      <key>Probability AI</key>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
   <sqlModels>
diff --git a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
index a132152c5028d6e84f533b84d53bb64e431762fa..a073f74c706b90066d7b2ba6a1dbe829150d7dbf 100644
--- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
+++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
@@ -6,6 +6,10 @@
   <country></country>
   <variant></variant>
   <keyValueMap>
+    <entry>
+      <key>Probability AI</key>
+      <value>Wahrscheinlichkeit KI</value>
+    </entry>
     <entry>
       <key>Settings</key>
       <value>Einstellungen</value>
@@ -32,6 +36,7 @@
     </entry>
     <entry>
       <key>Finished</key>
+      <value>Abgeschlossen</value>
     </entry>
     <entry>
       <key>Show my organisations</key>
@@ -3529,6 +3534,10 @@
       <key>Gambia</key>
       <value>Gambia</value>
     </entry>
+    <entry>
+      <key>Ø Probability</key>
+      <value>Ø Wahrscheinlichkeit</value>
+    </entry>
     <entry>
       <key>Qatar</key>
       <value>Katar</value>
@@ -8743,15 +8752,12 @@ Bitte Datumseingabe prüfen</value>
     </entry>
     <entry>
       <key>leadimport notification</key>
-      <value>Leadimport Benachrichtigung</value>
     </entry>
     <entry>
       <key>bulk mail sent</key>
-      <value>Serienmail versendet</value>
     </entry>
     <entry>
       <key>download ready</key>
-      <value>Download bereit</value>
     </entry>
     <entry>
       <key>No new recipients found that can be added to the bulk mail.</key>
@@ -8761,19 +8767,10 @@ Bitte Datumseingabe prüfen</value>
       <key>Permission received</key>
       <value>erhaltene Berechtigung</value>
     </entry>
-    <entry>
-      <key>leadimport notification</key>
-    </entry>
     <entry>
       <key>granted permission</key>
       <value>vergebene Berechtigung</value>
     </entry>
-    <entry>
-      <key>bulk mail sent</key>
-    </entry>
-    <entry>
-      <key>download ready</key>
-    </entry>
     <entry>
       <key>Receive new Department Permission</key>
       <value>Neue Abteilungs-Berechtigung erhalten</value>
@@ -8789,10 +8786,6 @@ Bitte Datumseingabe prüfen</value>
       <key>No new recipients found that can be added to the serial letter.</key>
       <value>Keine neuen Empfänger, die zum  Serienbrief werden können, gefunden.</value>
     </entry>
-    <entry>
-      <key>No new recipients found that can be added to the bulk mail.</key>
-      <value>Keine neuen Empfänger, die zur Serienmail hinzugefügt werden können, gefunden.</value>
-    </entry>
     <entry>
       <key>export using the selected  template</key>
       <value>Mit der ausgewählten Vorlage Exportieren</value>
@@ -8807,6 +8800,16 @@ Bitte Datumseingabe prüfen</value>
     <entry>
       <key>Workflow Model</key>
     </entry>
+    <entry>
+      <key>{SEND_MAIL}</key>
+      <value>Email versenden</value>
+    </entry>
+    <entry>
+      <key>The workflow could not be deployed</key>
+    </entry>
+    <entry>
+      <key>Workflow deploy failed</key>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
 </language>
diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
index dd32b2a7b3caf16d762271d43e41d228628bf79d..e3bcf535ebd4754b2d7709f21d52dba8b8f7a216 100644
--- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
+++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
@@ -2661,6 +2661,9 @@
     <entry>
       <key>Locked</key>
     </entry>
+    <entry>
+      <key>Ø Probability</key>
+    </entry>
     <entry>
       <key>Timetracking Id</key>
     </entry>
@@ -6941,6 +6944,19 @@
     <entry>
       <key>The Sales Project can only be filled when a company has been specified</key>
     </entry>
+    <entry>
+      <key>{SEND_MAIL}</key>
+      <value>Send mail</value>
+    </entry>
+    <entry>
+      <key>The workflow could not be deployed</key>
+    </entry>
+    <entry>
+      <key>Workflow deploy failed</key>
+    </entry>
+    <entry>
+      <key>Probability AI</key>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
 </language>
diff --git a/neonContext/Offer/Offer.aod b/neonContext/Offer/Offer.aod
index 2a823d8bf9e71c15d73fdddddfde09bb4b38834d..e8a6d8d34e56933b89b40bd124432ff6e1a89d0c 100644
--- a/neonContext/Offer/Offer.aod
+++ b/neonContext/Offer/Offer.aod
@@ -8,6 +8,7 @@
   <filterView>OfferFilter_view</filterView>
   <editView>OfferEdit_view</editView>
   <previewView>OfferPreview_view</previewView>
+  <previewMultipleView>OfferPreviewMultiple_view</previewMultipleView>
   <lookupView>OfferFilter_view</lookupView>
   <entity>Offer_entity</entity>
   <references>
@@ -39,5 +40,9 @@
       <name>02938f44-bc24-4542-916b-8db5d1976b40</name>
       <view>OfferReport_view</view>
     </neonViewReference>
+    <neonViewReference>
+      <name>136dceaa-0eca-452a-9757-132fd54e8c55</name>
+      <view>OfferPreviewMultiple_view</view>
+    </neonViewReference>
   </references>
 </neonContext>
diff --git a/neonView/OfferPreviewMultiple_view/OfferPreviewMultiple_view.aod b/neonView/OfferPreviewMultiple_view/OfferPreviewMultiple_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..d9949333d93de78c8373d7cbe77aa29d49b867d6
--- /dev/null
+++ b/neonView/OfferPreviewMultiple_view/OfferPreviewMultiple_view.aod
@@ -0,0 +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.6" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.6">
+  <name>OfferPreviewMultiple_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <headerFooterLayout>
+      <name>layout</name>
+      <footer>Scorecard</footer>
+    </headerFooterLayout>
+  </layout>
+  <children>
+    <dynamicMultiDataChartViewTemplate>
+      <name>OfferChart</name>
+      <chartType>BAR</chartType>
+      <shareParent v="false" />
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonDynamicMultiDataChartColumn>
+          <name>53b01786-bb5d-41f2-8c30-36bff460b82b</name>
+          <entityField>NET</entityField>
+        </neonDynamicMultiDataChartColumn>
+      </columns>
+    </dynamicMultiDataChartViewTemplate>
+    <treeTableViewTemplate>
+      <name>StatusTreeTable</name>
+      <defaultGroupFields>
+        <element>STATUS</element>
+      </defaultGroupFields>
+      <hideActions v="true" />
+      <entityField>#ENTITY</entityField>
+      <linkedColumns />
+      <columns>
+        <neonTreeTableColumn>
+          <name>5cd9839b-0dea-44e8-9e2f-8f75a7e9cb16</name>
+          <entityField>NET</entityField>
+          <aggregateEntityField>NET_aggregate</aggregateEntityField>
+        </neonTreeTableColumn>
+      </columns>
+    </treeTableViewTemplate>
+    <scoreCardViewTemplate>
+      <name>AggregatedValues</name>
+      <entityField>OfferAggregates</entityField>
+      <fields>
+        <entityFieldLink>
+          <name>71cd7dd5-c142-4b4c-8a6b-ca5ed8acf92e</name>
+          <entityField>NET_aggregate</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>e76a8a8c-529a-457f-bb23-4dcef79f6f0f</name>
+          <entityField>PROBABILITY_aggregate</entityField>
+        </entityFieldLink>
+      </fields>
+    </scoreCardViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/OrderDetail_view/OrderDetail_view.aod b/neonView/OrderDetail_view/OrderDetail_view.aod
index 9e876a6e5cb22b37ad233e3c14ab8c25073b2169..6e749e3cfbd8e9a0e2e9b348b4c8186d45aae1ec 100644
--- a/neonView/OrderDetail_view/OrderDetail_view.aod
+++ b/neonView/OrderDetail_view/OrderDetail_view.aod
@@ -1,7 +1,7 @@
 <?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.6" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.6">
   <name>OrderDetail_view</name>
-  <title>Texts</title>
+  <title>Cover letter</title>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <layout>
     <noneLayout>
diff --git a/neonView/OrderMain_view/OrderMain_view.aod b/neonView/OrderMain_view/OrderMain_view.aod
index b76b54dcaaff68957fa6d0c26f48d5a57a2f9c02..428d0c02e07af523318e7f24d35f87230edab64f 100644
--- a/neonView/OrderMain_view/OrderMain_view.aod
+++ b/neonView/OrderMain_view/OrderMain_view.aod
@@ -29,16 +29,16 @@
       <entityField>#ENTITY</entityField>
       <view>OrderDetail_view</view>
     </neonViewReference>
-    <neonViewReference>
-      <name>b3014999-da86-45ae-86ae-feb738d62906</name>
-      <entityField>Documents</entityField>
-      <view>DocumentFilter_view</view>
-    </neonViewReference>
     <neonViewReference>
       <name>7ec102f5-fb45-44a7-9bbf-0eba7f1536d7</name>
       <entityField>Activities</entityField>
       <view>ActivityFilter_view</view>
     </neonViewReference>
+    <neonViewReference>
+      <name>b3014999-da86-45ae-86ae-feb738d62906</name>
+      <entityField>Documents</entityField>
+      <view>DocumentFilter_view</view>
+    </neonViewReference>
     <neonViewReference>
       <name>351a9b5d-a050-4fb9-b3e4-402dcd84b331</name>
       <entityField>Tasks</entityField>
diff --git a/neonView/OrderitemFilter_view/OrderitemFilter_view.aod b/neonView/OrderitemFilter_view/OrderitemFilter_view.aod
index 5879614ec37bdf2d2ec54e12e0dbf57a17d05042..4c6e8a7eac674bd309fbe4aefe1f9bda7c40bba0 100644
--- a/neonView/OrderitemFilter_view/OrderitemFilter_view.aod
+++ b/neonView/OrderitemFilter_view/OrderitemFilter_view.aod
@@ -31,6 +31,10 @@
           <name>a8dcb2bb-bb09-4a6e-b0f0-1b4d1111eb22</name>
           <entityField>UNIT</entityField>
         </neonTableColumn>
+        <neonTableColumn>
+          <name>bfd34c94-1a5f-4caf-ae6e-2c09375c023c</name>
+          <entityField>VAT</entityField>
+        </neonTableColumn>
         <neonTableColumn>
           <name>33ef0703-d4ea-4187-b555-648a1733ee99</name>
           <entityField>PRICE</entityField>
@@ -39,22 +43,18 @@
           <name>61a39c6b-f7dd-487c-bc5f-c2e95376ec37</name>
           <entityField>DISCOUNT</entityField>
         </neonTableColumn>
-        <neonTableColumn>
-          <name>bfd34c94-1a5f-4caf-ae6e-2c09375c023c</name>
-          <entityField>VAT</entityField>
-        </neonTableColumn>
         <neonTableColumn>
           <name>89fd18d0-f6ee-4323-9277-464dee6da625</name>
           <entityField>OPTIONAL</entityField>
         </neonTableColumn>
-        <neonTableColumn>
-          <name>03a15cab-67d9-4e9d-b911-0d5599c87671</name>
-          <entityField>INFO</entityField>
-        </neonTableColumn>
         <neonTableColumn>
           <name>eecc066d-e380-4fe7-9e9b-99d80842981d</name>
           <entityField>TotalPrice</entityField>
         </neonTableColumn>
+        <neonTableColumn>
+          <name>03a15cab-67d9-4e9d-b911-0d5599c87671</name>
+          <entityField>INFO</entityField>
+        </neonTableColumn>
       </columns>
     </tableViewTemplate>
     <treeTableViewTemplate>
@@ -77,6 +77,10 @@
           <name>4998fc65-67b7-465d-9891-808dcf0fe080</name>
           <entityField>UNIT</entityField>
         </neonTreeTableColumn>
+        <neonTreeTableColumn>
+          <name>e545cb87-e4a5-4154-89b1-1f88a6d59fde</name>
+          <entityField>VAT</entityField>
+        </neonTreeTableColumn>
         <neonTreeTableColumn>
           <name>b4470ca6-89e8-421b-bb91-7d32f9c48aa2</name>
           <entityField>PRICE</entityField>
@@ -85,22 +89,18 @@
           <name>0c533079-4b39-4412-8de5-086bf7a08706</name>
           <entityField>DISCOUNT</entityField>
         </neonTreeTableColumn>
-        <neonTreeTableColumn>
-          <name>e545cb87-e4a5-4154-89b1-1f88a6d59fde</name>
-          <entityField>VAT</entityField>
-        </neonTreeTableColumn>
         <neonTreeTableColumn>
           <name>9ac44050-ea77-43d2-b0fe-f7ca411b91e7</name>
           <entityField>OPTIONAL</entityField>
         </neonTreeTableColumn>
-        <neonTreeTableColumn>
-          <name>4d4f204a-1c2b-4587-93b9-df03f31da38e</name>
-          <entityField>INFO</entityField>
-        </neonTreeTableColumn>
         <neonTreeTableColumn>
           <name>c44b5bc2-4283-4dca-bd20-bd048e05fe45</name>
           <entityField>TotalPrice</entityField>
         </neonTreeTableColumn>
+        <neonTreeTableColumn>
+          <name>4d4f204a-1c2b-4587-93b9-df03f31da38e</name>
+          <entityField>INFO</entityField>
+        </neonTreeTableColumn>
       </columns>
     </treeTableViewTemplate>
   </children>
diff --git a/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod b/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod
index 6bfac93548e2b901c3d7952818fa6d21bb0c987a..de645d22f05545f6870869c4347a29066cb23d4c 100644
--- a/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod
+++ b/neonView/SalesprojectFilter_view/SalesprojectFilter_view.aod
@@ -77,6 +77,10 @@
           <name>9f6b967e-5140-420f-84ca-2273920221bd</name>
           <entityField>PROJECTTITLE</entityField>
         </neonTableColumn>
+        <neonTableColumn>
+          <name>20f132ef-161e-4b84-b6ae-1f4daf016d16</name>
+          <entityField>PROBABILITY_AI</entityField>
+        </neonTableColumn>
         <neonTableColumn>
           <name>fec843c3-f7c0-42c7-8295-50386651edb2</name>
           <entityField>STARTDATE</entityField>
diff --git a/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod b/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod
index da9674dd3bde6002522eb4afdc065c6293b21a02..dbf8adad5727fdd82cff1371702bd42bd82a794e 100644
--- a/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod
+++ b/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod
@@ -65,6 +65,10 @@
           <name>0ba7dcb5-9606-4d74-8455-3423a16fd98a</name>
           <entityField>PROBABILITY</entityField>
         </entityFieldLink>
+        <entityFieldLink>
+          <name>bee2acfb-20ac-485e-be6c-c9c6a25e6013</name>
+          <entityField>PROBABILITY_AI</entityField>
+        </entityFieldLink>
         <entityFieldLink>
           <name>950d21a3-c0f9-4df5-9810-fa027a6fdb4a</name>
           <entityField>VOLUME</entityField>
diff --git a/neonView/WorkflowStartConfigFilter_view/WorkflowStartConfigFilter_view.aod b/neonView/WorkflowStartConfigFilter_view/WorkflowStartConfigFilter_view.aod
index 9c98d1fe51548d2c24a3f1e415cf83a1de05e69d..cdac1faccf7f16acf27044fd57f434dea9502e3c 100644
--- a/neonView/WorkflowStartConfigFilter_view/WorkflowStartConfigFilter_view.aod
+++ b/neonView/WorkflowStartConfigFilter_view/WorkflowStartConfigFilter_view.aod
@@ -3,9 +3,9 @@
   <name>WorkflowStartConfigFilter_view</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <layout>
-    <groupLayout>
+    <boxLayout>
       <name>layout</name>
-    </groupLayout>
+    </boxLayout>
   </layout>
   <children>
     <tableViewTemplate>
@@ -24,19 +24,5 @@
         </neonTableColumn>
       </columns>
     </tableViewTemplate>
-    <treeTableViewTemplate>
-      <name>Treetable</name>
-      <entityField>#ENTITY</entityField>
-      <columns>
-        <neonTreeTableColumn>
-          <name>4874074f-80af-4e99-8449-2a4dc4428360</name>
-          <entityField>OBJECT_TYPE</entityField>
-        </neonTreeTableColumn>
-        <neonTreeTableColumn>
-          <name>d479a082-ea95-40c6-81a2-9318fcf9ce98</name>
-          <entityField>TRIGGER_EVENT</entityField>
-        </neonTreeTableColumn>
-      </columns>
-    </treeTableViewTemplate>
   </children>
 </neonView>
diff --git a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod
index 2c486ae8a6b6c5f2b17883cfe535de5f164d468e..5a3ae3b71b41c6205c08d1b791638ac250219ccc 100644
--- a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod
+++ b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod
@@ -102,6 +102,11 @@
       <description></description>
       <property>http://localhost:8080/flowable-modeler/</property>
     </customStringProperty>
+    <customBooleanProperty>
+      <name>ai.salesprojectProbability</name>
+      <description></description>
+      <property v="false" />
+    </customBooleanProperty>
   </customProperties>
   <customConfigProperties>
     <customBooleanProperty>
diff --git a/process/AISalesproject_lib/AISalesproject_lib.aod b/process/AISalesproject_lib/AISalesproject_lib.aod
new file mode 100644
index 0000000000000000000000000000000000000000..13b8a275db57d71b190f905695f39072a7756756
--- /dev/null
+++ b/process/AISalesproject_lib/AISalesproject_lib.aod
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1">
+  <name>AISalesproject_lib</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <process>%aditoprj%/process/AISalesproject_lib/process.js</process>
+  <alias>Data_alias</alias>
+  <variants>
+    <element>LIBRARY</element>
+  </variants>
+</process>
diff --git a/process/AISalesproject_lib/process.js b/process/AISalesproject_lib/process.js
new file mode 100644
index 0000000000000000000000000000000000000000..c1a63392f2bfc2786c2e3e79c4f38146e11f990d
--- /dev/null
+++ b/process/AISalesproject_lib/process.js
@@ -0,0 +1,210 @@
+import("AttributeRegistry_basic");
+import("KeywordRegistry_basic");
+import("Sql_lib");
+import("system.logging");
+import("system.db");
+import("system.result");
+import("system.vars");
+import("Keyword_lib");
+import("AI_lib");
+import("AISalesproject_lib");
+import("Attribute_lib");
+import("system.entities");
+import("DataCaching_lib");
+
+/**
+ * Provides static methods for artificial intelligence.<br>
+ * <b>Do not create an instance of this!</b>
+ * 
+ * @class
+ */
+function AISalesprojectUtil(){}
+
+
+AISalesprojectUtil.getTrainedModel = function()
+{
+    var cache = new CachedData("SalesprojectNBData", false);
+    return cache.load(function (pTranslationNecessary, pLocale){
+        var data = AISalesprojectUtil.train();
+        return data;
+    });
+};
+
+
+AISalesprojectUtil.train = function ()
+{
+    //Trainingdata  
+    var data = new NBDataSet();
+    
+    var loadConfig = entities.createConfigForLoadingRows()
+        .entity("Salesproject_entity")
+        .fields(["#UID", "CONTACT_ID", "PHASE", "STATUS", "VOLUME", "PROBABILITY"]);
+
+    var spRecords = entities.getRows(loadConfig).map(function (spRow)
+    {
+        if(spRow["STATUS"] == $KeywordRegistry.salesprojectState$lost() || spRow["STATUS"] == $KeywordRegistry.salesprojectState$order())
+        {
+            var attributes = [];
+            attributes.push(spRow["PHASE"]) //PHASE
+            if(spRow["VOLUME"] != null && parseFloat(spRow["VOLUME"]) > 0)
+                attributes.push(AISalesprojectUtil.getVolumeClassification(parseFloat(spRow["VOLUME"]))); //VOLUME
+            if(spRow["PROBABILITY"] != null)
+                attributes.push(AISalesprojectUtil.getProbabilityValue(spRow["PROBABILITY"])); //PROBABILITY
+            var sectorSP = new AttributeRelationQuery(spRow["CONTACT_ID"], $AttributeRegistry.industry()).getSingleAttributeValue();
+            if(sectorSP != null)
+                attributes.push(sectorSP); //Sector       
+            var doc = new NBDocument(spRow["#UID"], attributes);
+            
+            //Classification
+            
+            //Department
+            var department = AISalesprojectUtil.getClassificationValues("SALESPROJ", "Salesproject", spRow["#UID"], "ScoreDepartment");
+            if(department)
+                attributes.push(department);
+            
+            //Standard
+            var standard = AISalesprojectUtil.getClassificationValues("SALESPROJ", "Salesproject", spRow["#UID"], "ScoreStandard");
+            if(standard)
+                attributes.push(standard);
+
+            //Users
+            var users = AISalesprojectUtil.getClassificationValues("SALESPROJ", "Salesproject", spRow["#UID"], "ScoreUsers");
+            if(users)
+                attributes.push(users);
+
+
+            var loadCompConfig = entities.createConfigForLoadingRows()
+                .entity("Competition_entity")
+                .provider("Links")
+                .addParameter("ObjectType_param", "Salesproject")
+                .addParameter("ObjectRowId_param", spRow["#UID"])
+                .fields(["ORGANISATION_NAME"]);
+
+            var compRecords = entities.getRows(loadCompConfig).map(function (compRow)
+            {
+                doc.add(compRow["ORGANISATION_NAME"]); //competitors
+            });
+
+            data.add(spRow["STATUS"], [doc]); // train model with lost and order salesprojects    
+            //logging.log("data:");
+            //logging.log(JSON.stringify(doc));
+        }
+        
+    });
+
+    // an optimisation for working with small vocabularies
+    var options = {
+        applyInverse: true
+    };
+
+    // create a classifier
+    var classifier = new NBClassifier(options);
+
+    // train the classifier
+    classifier.train(data);
+
+    //logging.log('Classifier trained.');
+    //logging.log(JSON.stringify(classifier));
+    return JSON.stringify(classifier);
+
+};
+
+AISalesprojectUtil.classify = function (pSalesprojectId, pContactId, pPhase, pStatus, pVolume, pProb)
+{
+    
+    if(pSalesprojectId == null || pContactId == null)
+        return "--";
+    var testAttributes = [];   
+    testAttributes.push(pPhase) //PHASE
+    if(pVolume != null && parseFloat(pVolume) > 0)
+        testAttributes.push(AISalesprojectUtil.getVolumeClassification(parseFloat(pVolume))); //VOLUME
+    if(pProb != null)
+        testAttributes.push(AISalesprojectUtil.getProbabilityValue(pProb)); //PROBABILITY
+    if(pContactId != null) 
+    {
+        var sectorSP = new AttributeRelationQuery(pContactId, $AttributeRegistry.industry()).getSingleAttributeValue();
+        if(sectorSP != null)
+            testAttributes.push(sectorSP); //Sector    
+    }
+    
+    //Classification
+    
+    //Department
+    var department = AISalesprojectUtil.getClassificationValues("SALESPROJ", "Salesproject", pSalesprojectId, "ScoreDepartment");
+    if(department)
+        testAttributes.push(department);
+          
+    //Standard      
+    var standard = AISalesprojectUtil.getClassificationValues("SALESPROJ", "Salesproject", pSalesprojectId, "ScoreStandard");
+    if(standard)
+        testAttributes.push(standard);
+
+    //Users
+    var users = AISalesprojectUtil.getClassificationValues("SALESPROJ", "Salesproject", pSalesprojectId, "ScoreUsers");
+    if(users)
+        testAttributes.push(users);    
+    
+    var loadCompConfig = entities.createConfigForLoadingRows()
+        .entity("Competition_entity")
+        .provider("Links")
+        .addParameter("ObjectType_param", "Salesproject")
+        .addParameter("ObjectRowId_param", pSalesprojectId)
+        .fields(["ORGANISATION_NAME"]);
+
+    var compRecords = entities.getRows(loadCompConfig).map(function (compRow) 
+    {
+        testAttributes.push(compRow["ORGANISATION_NAME"]); //competitors
+    });
+    
+    //logging.log("testdata");
+    //logging.log(JSON.stringify(testAttributes));
+    
+    var model = AISalesprojectUtil.getTrainedModel();
+    var classifier = new NBClassifier(JSON.parse(model));
+    
+    // test the classifier on a new test object
+    var testDoc = new NBDocument(pSalesprojectId, testAttributes);
+    var classifyResult = classifier.classify(testDoc);
+    //logging.log("result");
+    //logging.log(JSON.stringify(classifyResult));
+    if(classifyResult.probability == null || isNaN(classifyResult.probability))
+        return "--";
+    else
+        return Math.round(parseFloat((classifyResult.probability) * 100)) + "% / " + KeywordUtils.getViewValue($KeywordRegistry.salesprojectState(), classifyResult.category);   
+};
+
+AISalesprojectUtil.getVolumeClassification = function (pVolume)
+{
+    if(pVolume < 100000) 
+        return "low";
+    else if(pVolume >= 100000 && pVolume < 250000)
+        return "middle";
+    else
+        return "high";
+};
+
+AISalesprojectUtil.getProbabilityValue = function (pProbId)
+{
+    if(pProbId == "SALPROJPROB0" || pProbId == "SALPROJPROB25") 
+        return "negative";
+    else if(pProbId == "SALPROJPROB50")
+        return "neutral";
+    else if(pProbId == "SALPROJPROB75" || pProbId == "SALPROJPROB100")
+        return "positive";
+    return "";
+};
+
+AISalesprojectUtil.getClassificationValues = function (pClassificationType, pObjectType, pObjectRowid, pScoreType)
+{
+    var value = newSelect("TITLE")
+        .from("CLASSIFICATIONTYPE")
+        .leftJoin("CLASSIFICATION", newWhere("CLASSIFICATIONTYPEID = CLASSIFICATIONTYPE_ID")
+            .and("CLASSIFICATION.OBJECT_TYPE", pObjectType)
+            .and("CLASSIFICATION.OBJECT_ROWID", pObjectRowid))
+        .leftJoin("CLASSIFICATIONSCORE", "CLASSIFICATIONSCORE_ID = CLASSIFICATIONSCOREID")
+        .where("CLASSIFICATIONTYPE.CLASSIFICATIONTYPE", pClassificationType)
+        .andIfSet("CLASSIFICATIONTYPE.SCORETYPE", pScoreType)
+        .cell()
+
+    return value;
+};
diff --git a/process/AI_lib/AI_lib.aod b/process/AI_lib/AI_lib.aod
new file mode 100644
index 0000000000000000000000000000000000000000..153e8fc6b66bfd5d8016c8a0a22521c04ad0e209
--- /dev/null
+++ b/process/AI_lib/AI_lib.aod
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1">
+  <name>AI_lib</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <process>%aditoprj%/process/AI_lib/process.js</process>
+  <variants>
+    <element>LIBRARY</element>
+  </variants>
+</process>
diff --git a/process/AI_lib/process.js b/process/AI_lib/process.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0f8c0f06354aee7dd7718887cafa97f7f92b2d6
--- /dev/null
+++ b/process/AI_lib/process.js
@@ -0,0 +1,219 @@
+import("system.logging");
+import("system.vars");
+import("AI_lib");
+
+/**
+ * Provides static methods for artificial intelligence.<br>
+ * <b>Do not create an instance of this!</b>
+ * 
+ * @class
+ */
+function AIUtil(){}
+
+
+function NBClassifier(options) {
+  options = options || {};
+  this.applyInverse = options.applyInverse || false;
+  this.probabilityThreshold = options.probabilityThreshold || 0.5;
+  this.defaultCategory = options.defaultCategory || null;
+  this.tokens = options.tokens || {};
+  this.categoryCounts = options.categoryCounts || {};
+  this.probabilities = options.probabilities || {};
+}
+
+
+NBClassifier.prototype = {
+  train: function (trainingSet) {
+    var categories = Object.keys(trainingSet.categorizedItems);
+    var i = 0, j = 0, k = 0, category = "";
+    // Iterate over each category in the training set
+    for (i = 0; i < categories.length; i++) {
+      category = categories[i];
+      var subSet = trainingSet.categorizedItems[category];
+      this.categoryCounts[category] = subSet.length;
+      // Iterate over each data item in the category
+      for (j = 0; j < subSet.length; j++) {
+        var item = subSet[j];
+        // for each token in the data item, increment the token:category counter
+        var tokenlist = item.tokens;
+        for (k = 0; k < tokenlist.length; k++) {
+          var token = tokenlist[k];
+          if (!this.tokens[token]) {
+            this.tokens[token] = {};
+          }
+          if (!this.tokens[token][category]) {
+            this.tokens[token][category] = 1;
+          } else {
+            this.tokens[token][category] = 1 + this.tokens[token][category];
+          }
+        }
+      }
+    }
+    //After counting occurences of tokens, calculate probabilities.
+    for (i = 0; i < categories.length; i++) {
+      category = categories[i];
+      for (k in this.tokens) {
+        if (this.tokens.hasOwnProperty(k)) {
+          var count = this.tokens[k][category] || 0;
+          var total = this.categoryCounts[category];
+          var percentage = count / total;
+          if (!this.probabilities[category]) {
+            this.probabilities[category] = {};
+          }
+          this.probabilities[category][k] = percentage;
+        }
+      }
+    }
+  },
+
+  validate: function (testSet) {
+    var total = 0;
+    var correctGuesses = 0;
+    var wrongGuesses = 0;
+    var wrongCategories = {};
+    var wrongItems = [];
+    var categories = testSet.categorizedItems;
+    var category;
+    for (category in categories) {
+      validateCategory(category);
+    }
+
+    function validateCategory(category) {
+      if (categories.hasOwnProperty(category)) {
+        var items = categories[category];
+        var item;
+        for (item in items) {
+          if (items.hasOwnProperty(item)) {
+            total += 1;
+            item = items[item];
+            var result1 = this.classify(item);
+            // if certainty is below probabilityThreshold, go with the default
+            if (result1.probability <= this.probabilityThreshold) {
+              result1.category = this.defaultCategory || result1.category;
+            }
+            if (result1.category === category) {
+              correctGuesses++;
+            } else {
+              wrongCategories[result1.category] = (wrongCategories[result1.category]) ? wrongCategories[result1.category]++ : 1;
+              wrongItems.push(item.id);
+              wrongGuesses++;
+            }
+          }
+        }
+      }
+    }
+
+    return {
+      'total': total,
+      'correct': correctGuesses,
+      'wrong': wrongGuesses,
+      'accuracy': (correctGuesses / (correctGuesses + wrongGuesses)),
+      'wrongCategories': wrongCategories,
+      'wrongItems': wrongItems
+    };
+  },
+
+  classify: function (item) {
+    // for each category
+    var category;
+    var learnedProbabilities = this.probabilities;
+    var itemProbabilities = {};
+    var itemTokens = item.tokens;
+    for (category in learnedProbabilities) {
+      if (learnedProbabilities.hasOwnProperty(category)) {
+        itemProbabilities[category] = 1;
+        var t;
+        var probs = learnedProbabilities[category];
+        for (t in probs) {
+          // iterate over the tokens
+          if (probs.hasOwnProperty(t)) {
+            // and take the product of all probabilities
+            if (itemTokens.indexOf(t) !== -1) {
+              itemProbabilities[category] = itemProbabilities[category] * probs[t];
+            } else if (this.applyInverse) {
+              itemProbabilities[category] = itemProbabilities[category] * (1 - probs[t]);
+            }
+          }
+        }
+      }
+    }
+
+    // Pick the highest two probabilities
+    function compareCategories(a, b) {
+      if (a.probability > b.probability) {
+        return -1;
+      }
+      if (a.probability < b.probability) {
+        return 1;
+      }
+      return 0;
+    }
+
+    var categoryScores = [];
+    var sumOfProbabilities = 0;
+    var k;
+    for (k in itemProbabilities) {
+      if (itemProbabilities.hasOwnProperty(k)) {
+        categoryScores.push({
+          category: k,
+          probability: itemProbabilities[k]
+        });
+        sumOfProbabilities += itemProbabilities[k];
+      }
+    }
+    categoryScores = categoryScores.sort(compareCategories);
+
+    var firstPlace = categoryScores[0];
+    var secondPlace = categoryScores[1];
+    var timesMoreLikely = firstPlace.probability / secondPlace.probability;
+    var probability = firstPlace.probability / sumOfProbabilities;
+
+    return ({
+      'category': firstPlace.category,
+      'probability': probability,
+      'timesMoreLikely': timesMoreLikely,
+      'secondCategory': secondPlace.category,
+      'probabilities': categoryScores
+    });
+  }
+};
+
+
+function NBDataSet() {
+  this.categorizedItems = {};
+}
+
+NBDataSet.prototype = {
+  add: function (label, items) {
+    var originalItems = this.categorizedItems[label] ||  [];
+    this.categorizedItems[label] = originalItems.concat(items);
+  }
+};
+
+
+
+function NBDocument(id, tokens) {
+  if (!id) {
+    logging.log('Document(id, tokens) requires an id string');
+  }
+  this.id = id;
+  this.tokens = tokens || [];
+}
+
+NBDocument.prototype = {
+  add: function (token, factor) {
+    if(factor == undefined)
+        factor = 1
+    if (Array.isArray(token)) { // array of tokens
+      for (var i = 0; i < token.length; i++) {
+        this.add(token[i], factor);
+      }
+      return;
+    }
+    if (typeof token === 'string') {
+        for (var j = 0; j < factor; j++) {
+            this.tokens.push(token);
+        }
+    }
+  }
+};
\ No newline at end of file
diff --git a/process/AttributeRegistry_basic/process.js b/process/AttributeRegistry_basic/process.js
index cacb5a18c5652984a98533ed93ff819bc030ed6e..0d5b68b1c70a1889289312420d1b8902818b0866 100644
--- a/process/AttributeRegistry_basic/process.js
+++ b/process/AttributeRegistry_basic/process.js
@@ -18,6 +18,7 @@ $AttributeRegistry.targetGroup$competitior = function(){return "1d30d0ab-6103-49
 $AttributeRegistry.departments = function(){return "87d4ff5b-0ab6-4534-be26-76c6ef486072";};
 $AttributeRegistry.salesprojectType = function(){return "fd3963bc-8e60-411a-9911-b97eb73e5cf7";};
 $AttributeRegistry.responsibleADsupervisor = function(){return "c0b26482-c0aa-413d-a9c3-f44c56bd04a9";};
+$AttributeRegistry.industry = function(){return "7e9927a4-41e4-426f-bddd-c3e9ee3b093e";};
 
 $AttributeRegistry.visitPlanFrequency = function(){return "547b8b9d-88ba-4590-9e01-34d2a58116cc";};
 $AttributeRegistry.visitPlanFrequency$monthly = function(){return "8c100817-1d2b-4fc7-8fdd-fd0370e19385";};
diff --git a/process/KeywordRegistry_basic/process.js b/process/KeywordRegistry_basic/process.js
index b4d74a2a8f0cb51a439f5c8991d3d1e54a77602b..04e469c42da0bb82885071aec0350704dc6d59bc 100644
--- a/process/KeywordRegistry_basic/process.js
+++ b/process/KeywordRegistry_basic/process.js
@@ -21,6 +21,11 @@ $KeywordRegistry._autoPad = function(pKey){return (pKey + "
 
 $KeywordRegistry.attributeType = function(){return "AttributeType";};
 $KeywordRegistry.keywordAttributeType = function(){return "KeywordAttributeType";};
+$KeywordRegistry.keywordAttributeType$char = function(){return "CHAR";};
+$KeywordRegistry.keywordAttributeType$number = function(){return "NUMBER";};
+$KeywordRegistry.keywordAttributeType$bool = function(){return "BOOLEAN";};
+$KeywordRegistry.keywordAttributeType$longChar = function(){return "LONGCHAR";};
+
 $KeywordRegistry.contractPayment = function(){return "ContractPayment";};
 
 $KeywordRegistry.contractStatus = function(){return "ContractStatus";};