diff --git a/entity/Appointment_entity/Appointment_entity.aod b/entity/Appointment_entity/Appointment_entity.aod
index d2e1ef75a8f1596e6efed00651911617de158eed..404193668657a52c874035b82c351e95ce13806b 100644
--- a/entity/Appointment_entity/Appointment_entity.aod
+++ b/entity/Appointment_entity/Appointment_entity.aod
@@ -115,16 +115,11 @@
     </entityField>
     <entityField>
       <name>UID</name>
+      <valueProcess>%aditoprj%/entity/Appointment_entity/entityfields/uid/valueProcess.js</valueProcess>
     </entityField>
     <entityField>
       <name>ATTENDEESLENGTH</name>
     </entityField>
-    <entityField>
-      <name>LINKOBJECT</name>
-      <title>Linkobject</title>
-      <consumer>Objects</consumer>
-      <linkedContext>Object</linkedContext>
-    </entityField>
     <entityField>
       <name>ICON</name>
     </entityField>
@@ -187,12 +182,6 @@
         </entityParameter>
       </children>
     </entityConsumer>
-    <entityField>
-      <name>LINKTYPE</name>
-      <title>Linktype</title>
-      <consumer>Contexts</consumer>
-      <linkedContext>Context</linkedContext>
-    </entityField>
   </entityFields>
   <recordContainers>
     <jDitoRecordContainer>
diff --git a/entity/Appointment_entity/entityfields/uid/valueProcess.js b/entity/Appointment_entity/entityfields/uid/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..85c485a5e49ef24d8752fb4bc217ed12223c1ca3
--- /dev/null
+++ b/entity/Appointment_entity/entityfields/uid/valueProcess.js
@@ -0,0 +1,8 @@
+import("system.vars");
+import("system.result");
+import("system.util");
+
+if(!(vars.get("$field.UID")))
+    result.string(util.getNewUUID());
+else
+    result.string(vars.get("$field.UID"));
\ No newline at end of file
diff --git a/entity/AttributeRelation_entity/entityfields/attributerelation_value/displayValueProcess.js b/entity/AttributeRelation_entity/entityfields/attributerelation_value/displayValueProcess.js
index d335cd62e77addfc931bed30ac991706c5750333..a740c792ce459f70fa42d619de7ef61148d5e405 100644
--- a/entity/AttributeRelation_entity/entityfields/attributerelation_value/displayValueProcess.js
+++ b/entity/AttributeRelation_entity/entityfields/attributerelation_value/displayValueProcess.js
@@ -2,10 +2,10 @@ import("system.db");
 import("system.result");
 import("system.vars");
 import("Attribute_lib");
-import("Sql_lib");
 
-var attributeId = vars.get("$field.AB_ATTRIBUTE_ID");
-var attrType = AttributeHandler.begin(attributeId).getAttributeType();
+var attrType = AttributeHandler.begin(vars.get("$field.AB_ATTRIBUTE_ID")).getAttributeType();
 
 if (attrType == $AttributeTypes.COMBO)
-    result.string(AttributeUtil.getSimpleAttributeName(vars.get("$field.ID_VALUE")));  
\ No newline at end of file
+    result.string(AttributeUtil.getSimpleAttributeName(vars.get("$field.ID_VALUE")));
+else
+    result.string(vars.get("$field.ATTRIBUTERELATION_VALUE"));
diff --git a/entity/AttributeRelation_entity/entityfields/attributerelation_value/possibleItemsProcess.js b/entity/AttributeRelation_entity/entityfields/attributerelation_value/possibleItemsProcess.js
index 6aff0255e3f9b244d81ed6168501b93dde182fb4..41294703389058f527824cabc768946894055718 100644
--- a/entity/AttributeRelation_entity/entityfields/attributerelation_value/possibleItemsProcess.js
+++ b/entity/AttributeRelation_entity/entityfields/attributerelation_value/possibleItemsProcess.js
@@ -14,6 +14,5 @@ if (attrType == $AttributeTypes.COMBO)
         .andPrepare("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.COMBOVALUE)
         .buildSql("select AB_ATTRIBUTEID, ATTRIBUTE_NAME from AB_ATTRIBUTE");
     var valueList = db.table(valueSql);
-    
     result.object(valueList);
-}    
\ No newline at end of file
+}
diff --git a/entity/AttributeRelation_entity/entityfields/attributerelation_value/valueProcess.js b/entity/AttributeRelation_entity/entityfields/attributerelation_value/valueProcess.js
index 33a878bf683706d59c2a7658f97f66223ebc6fbf..737c6e3a51228fc8f0e69135a0c87bd2e46cdbfe 100644
--- a/entity/AttributeRelation_entity/entityfields/attributerelation_value/valueProcess.js
+++ b/entity/AttributeRelation_entity/entityfields/attributerelation_value/valueProcess.js
@@ -8,19 +8,19 @@ if (attrType != null) //load the value from the correct field for the type
 {
     switch (attrType)
     {
-        case $AttributeTypes.TEXT:
+        case $AttributeTypes.TEXT.toString():
             result.string(vars.get("$field.CHAR_VALUE"));
             break;    
-        case $AttributeTypes.DATE:
+        case $AttributeTypes.DATE.toString():
             result.string(vars.get("$field.DATE_VALUE"));
             break;
-        case $AttributeTypes.NUMBER:
+        case $AttributeTypes.NUMBER.toString():
             result.string(vars.get("$field.NUMBER_VALUE"));
             break;
-        case $AttributeTypes.BOOLEAN:
+        case $AttributeTypes.BOOLEAN.toString():
             result.string(vars.get("$field.BOOL_VALUE"));
             break;
-        case $AttributeTypes.COMBO:
+        case $AttributeTypes.COMBO.toString():
             result.string(vars.get("$field.ID_VALUE"));
             break;            
     }
diff --git a/entity/Attribute_entity/Attribute_entity.aod b/entity/Attribute_entity/Attribute_entity.aod
index 3032d15a7f9cfa12ed50a252ae4551ceadb4e0da..19200a77d9fa5e23d745fab789b98709c7f8c658 100644
--- a/entity/Attribute_entity/Attribute_entity.aod
+++ b/entity/Attribute_entity/Attribute_entity.aod
@@ -23,6 +23,7 @@
       <title>Type</title>
       <consumer>KeywordAttributeType</consumer>
       <mandatory v="true" />
+      <stateProcess>%aditoprj%/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js</stateProcess>
       <valueProcess>%aditoprj%/entity/Attribute_entity/entityfields/attribute_type/valueProcess.js</valueProcess>
       <displayValueProcess>%aditoprj%/entity/Attribute_entity/entityfields/attribute_type/displayValueProcess.js</displayValueProcess>
     </entityField>
diff --git a/entity/Attribute_entity/entityfields/attribute_name/displayValueProcess.js b/entity/Attribute_entity/entityfields/attribute_name/displayValueProcess.js
index 12344946d51439c11673fdbf76838b2594bf37b1..bb5f44d124ef66e4da13d4e661679b6e1b003a11 100644
--- a/entity/Attribute_entity/entityfields/attribute_name/displayValueProcess.js
+++ b/entity/Attribute_entity/entityfields/attribute_name/displayValueProcess.js
@@ -2,4 +2,4 @@ import("system.vars");
 import("system.result");
 import("Attribute_lib");
 
-result.string(AttributeUtil.getFullAttributeName(vars.get("$field.AB_ATTRIBUTEID")));
\ No newline at end of file
+result.string(AttributeUtil.getFullAttributeName(vars.get("$field.AB_ATTRIBUTEID")));
diff --git a/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js b/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..b768fb2fba7336e45a6e5c99d6224d9e623d4e5b
--- /dev/null
+++ b/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js
@@ -0,0 +1,12 @@
+import("system.db");
+import("system.neon");
+import("system.result");
+import("system.vars");
+import("Attribute_lib");
+
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$field.ATTRIBUTE_PARENT_ID") != "")
+{
+    var type = AttributeHandler.begin(vars.get("$field.ATTRIBUTE_PARENT_ID")).getAttributeType();
+    if (type == $AttributeTypes.COMBO)
+        result.string(neon.COMPONENTSTATE_INVISIBLE);
+}
\ No newline at end of file
diff --git a/entity/Attribute_entity/recordcontainers/db/conditionProcess.js b/entity/Attribute_entity/recordcontainers/db/conditionProcess.js
index 1a5a7ef8aa7f0828ba0791f1ea8a2acd3e99f354..bdd0ea7449ed0bd35470a8ac8dffb388034951c6 100644
--- a/entity/Attribute_entity/recordcontainers/db/conditionProcess.js
+++ b/entity/Attribute_entity/recordcontainers/db/conditionProcess.js
@@ -7,24 +7,8 @@ import("Attribute_lib");
 var condition = "AB_ATTRIBUTE.ATTRIBUTE_TYPE = '" + $AttributeTypes.GROUP + "'";
 
 if (vars.exists("$param.attrParentId_param") && vars.get("$param.attrParentId_param"))
-    condition = "AB_ATTRIBUTE.AB_ATTRIBUTEID in ('" + getAllChildren(vars.getString("$param.attrParentId_param")).join("','") + "')";
+    condition = "AB_ATTRIBUTE.AB_ATTRIBUTEID in ('" + AttributeUtil.getAllChildren(vars.getString("$param.attrParentId_param")).join("','") + "')";
 else if (vars.get("$param.attrParentId_param") !== "")
     condition = "";
 
 result.string(condition);
-
-function getAllChildren (pAttributeId)
-{
-    var childIds = [];
-    var attributes= [pAttributeId];
-    while (attributes.length > 0)
-    {
-        attributes = db.array(db.COLUMN, SqlCondition.begin()
-            .and("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID in ('" + attributes.join("','") + "')")
-            .buildSql("select AB_ATTRIBUTEID from AB_ATTRIBUTE")
-        );
-        if (attributes.length > 0)
-            childIds = childIds.concat(attributes);
-    }
-    return childIds;
-}
diff --git a/entity/Attribute_entity/recordcontainers/db/onDBDelete.js b/entity/Attribute_entity/recordcontainers/db/onDBDelete.js
index 504e2d5e4f82c9ccbdeb7b380f546003c3f5f9a8..7d1eb8b477436101b8cacb2fa7aa00241708adae 100644
--- a/entity/Attribute_entity/recordcontainers/db/onDBDelete.js
+++ b/entity/Attribute_entity/recordcontainers/db/onDBDelete.js
@@ -1,11 +1,29 @@
 import("system.vars");
 import("system.db");
 import("Sql_lib");
+import("Attribute_lib");
 
 var attributeId = vars.get("$field.AB_ATTRIBUTEID");
-var usageCondition = SqlCondition.begin()
-    .andPrepare("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID", attributeId)
+
+var childIds = AttributeUtil.getAllChildren(attributeId).concat(attributeId);
+
+var condition = SqlCondition.begin()
+    .and("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID in ('" + childIds.join("','") + "')")
     .build();
 
 //delete all entries in AB_ATTRIBUTEUSAGE belonging to the attribute to avoid unrelated entries
-db.deleteData("AB_ATTRIBUTEUSAGE", usageCondition);
\ No newline at end of file
+db.deleteData("AB_ATTRIBUTEUSAGE", condition);
+
+condition = SqlCondition.begin()
+    .and("AB_ATTRIBUTERELATION.AB_ATTRIBUTE_ID in ('" + childIds.join("','") + "')")
+    .build();
+
+//delete all entries in AB_ATTRIBUTERELATION for the attributes
+db.deleteData("AB_ATTRIBUTERELATION", condition);
+
+condition = SqlCondition.begin()
+    .and("AB_ATTRIBUTE.AB_ATTRIBUTEID in ('" + childIds.join("','") + "')")
+    .build();
+
+//delete all attribute children
+db.deleteData("AB_ATTRIBUTE", condition);
diff --git a/entity/Contract_entity/entityfields/contractcode_display_fieldgroup/valueProcess.js b/entity/Contract_entity/entityfields/contractcode_display_fieldgroup/valueProcess.js
index 3b3d5b96c09bae19240fbc0866f31943de579664..279ddaaf279e54233680dea48d9937503f0d530b 100644
--- a/entity/Contract_entity/entityfields/contractcode_display_fieldgroup/valueProcess.js
+++ b/entity/Contract_entity/entityfields/contractcode_display_fieldgroup/valueProcess.js
@@ -1,8 +1,9 @@
+import("system.translate");
 import("system.vars");
 import("system.result");
 import("Keyword_lib");
 
-var cType = vars.get("$field.CONTRACTTYPE");
-var cCode = vars.get("$field.CONTRACTCODE");
+var contractType = KeywordUtils.getViewValue($KeywordRegistry.get.ContractType, vars.get("$field.CONTRACTTYPE"));
+var contractCode = vars.get("$field.CONTRACTCODE");
 
-result.string(KeywordUtils.getViewValue($KeywordRegistry.get.ContractType, cType) + " " + cCode);
\ No newline at end of file
+result.string((contractType || translate.text("Contract")) + " " + contractCode);
\ No newline at end of file
diff --git a/entity/Document_entity/Document_entity.aod b/entity/Document_entity/Document_entity.aod
index fdd488929f2c9efe1a5c92d4203b7dda93896f4d..a2760d94b9e9fa63f40d7530dc57c8ca2fc7a793 100644
--- a/entity/Document_entity/Document_entity.aod
+++ b/entity/Document_entity/Document_entity.aod
@@ -62,6 +62,7 @@
           <fieldType>ACTION</fieldType>
           <onActionProcess>%aditoprj%/entity/Document_entity/entityfields/document_actions/children/downloadfilesaction/onActionProcess.js</onActionProcess>
           <isObjectAction v="false" />
+          <isSelectionAction v="true" />
           <iconId>VAADIN:DOWNLOAD</iconId>
         </entityActionField>
       </children>
diff --git a/entity/Offer_entity/Offer_entity.aod b/entity/Offer_entity/Offer_entity.aod
index 2297b80962e45811beb9c262263d9d95d4f110c0..cba3010100ed198c433c1a2f516d8a2bd7e7ed8c 100644
--- a/entity/Offer_entity/Offer_entity.aod
+++ b/entity/Offer_entity/Offer_entity.aod
@@ -15,6 +15,8 @@
       <name>CURRENCY</name>
       <title>Currency</title>
       <consumer>KeywordCurrencies</consumer>
+      <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/currency/valueProcess.js</valueProcess>
+      <displayValueProcess>%aditoprj%/entity/Offer_entity/entityfields/currency/displayValueProcess.js</displayValueProcess>
     </entityField>
     <entityField>
       <name>OFFERCODE</name>
@@ -87,6 +89,7 @@
       <name>HEADER</name>
       <title>Cover letter</title>
       <contentType>HTML</contentType>
+      <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/header/valueProcess.js</valueProcess>
     </entityField>
     <entityConsumer>
       <name>Offeritems</name>
@@ -181,12 +184,14 @@
       <title>Language</title>
       <consumer>Languages</consumer>
       <mandatory v="true" />
+      <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/language/valueProcess.js</valueProcess>
+      <displayValueProcess>%aditoprj%/entity/Offer_entity/entityfields/language/displayValueProcess.js</displayValueProcess>
     </entityField>
     <entityActionField>
-      <name>newOffer</name>
+      <name>copyOffer</name>
       <fieldType>ACTION</fieldType>
       <title>Copy offer</title>
-      <onActionProcess>%aditoprj%/entity/Offer_entity/entityfields/newoffer/onActionProcess.js</onActionProcess>
+      <onActionProcess>%aditoprj%/entity/Offer_entity/entityfields/copyoffer/onActionProcess.js</onActionProcess>
     </entityActionField>
     <entityField>
       <name>VERSNR</name>
@@ -198,6 +203,7 @@
     <entityField>
       <name>OFFER_ID</name>
       <documentation>%aditoprj%/entity/Offer_entity/entityfields/offer_id/documentation.adoc</documentation>
+      <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/offer_id/valueProcess.js</valueProcess>
     </entityField>
     <entityFieldGroup>
       <name>OfferCode_VersNr_fieldgroup</name>
@@ -229,10 +235,10 @@
       <description>PARAMETER</description>
     </entityParameter>
     <entityActionField>
-      <name>offerReport</name>
+      <name>printOffer</name>
       <fieldType>ACTION</fieldType>
-      <title>Offer report</title>
-      <onActionProcess>%aditoprj%/entity/Offer_entity/entityfields/offerreport/onActionProcess.js</onActionProcess>
+      <title>Print Offer</title>
+      <onActionProcess>%aditoprj%/entity/Offer_entity/entityfields/printoffer/onActionProcess.js</onActionProcess>
     </entityActionField>
     <entityField>
       <name>CONTACT_ORG_ID</name>
@@ -313,6 +319,8 @@
       <title>Address</title>
       <description></description>
       <contentType>LONG_TEXT</contentType>
+      <mandatory v="true" />
+      <valueProcess>%aditoprj%/entity/Offer_entity/entityfields/address/valueProcess.js</valueProcess>
     </entityField>
     <entityField>
       <name>ChosenAddress</name>
@@ -395,6 +403,77 @@
       <onActionProcess>%aditoprj%/entity/Offer_entity/entityfields/newactivity/onActionProcess.js</onActionProcess>
       <iconId>NEON:HISTORY</iconId>
     </entityActionField>
+    <entityProvider>
+      <name>ContactOffers</name>
+      <fieldType>DEPENDENCY_IN</fieldType>
+      <dependencies>
+        <entityDependency>
+          <name>5c9720b5-1288-4a30-88fd-6dcff6359083</name>
+          <entityName>Person_entity</entityName>
+          <fieldName>Offers</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+      <children>
+        <entityParameter>
+          <name>ContactId_param</name>
+          <expose v="true" />
+        </entityParameter>
+        <entityParameter>
+          <name>SalesprojectId_param</name>
+          <expose v="true" />
+        </entityParameter>
+      </children>
+    </entityProvider>
+    <entityParameter>
+      <name>OfferCurrency_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferLanguage_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferHeader_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferOriginal_Id_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferAddress_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferCode_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>OfferVersnr_param</name>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <description>PARAMETER</description>
+    </entityParameter>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
@@ -403,6 +482,7 @@
       <maximumDbRows v="0" />
       <fromClauseProcess>%aditoprj%/entity/Offer_entity/recordcontainers/db/fromClauseProcess.js</fromClauseProcess>
       <conditionProcess>%aditoprj%/entity/Offer_entity/recordcontainers/db/conditionProcess.js</conditionProcess>
+      <onDBInsert>%aditoprj%/entity/Offer_entity/recordcontainers/db/onDBInsert.js</onDBInsert>
       <onDBDelete>%aditoprj%/entity/Offer_entity/recordcontainers/db/onDBDelete.js</onDBDelete>
       <linkInformation>
         <linkInformation>
diff --git a/entity/Offer_entity/entityfields/address/valueProcess.js b/entity/Offer_entity/entityfields/address/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..160f9518edab8b5ed593d921661aada906512ee4
--- /dev/null
+++ b/entity/Offer_entity/entityfields/address/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.result");
+import("system.vars");
+
+if (vars.exists("$param.OfferAddress_param")) 
+{
+    result.string(vars.get("$param.OfferAddress_param"));
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/copyoffer/onActionProcess.js b/entity/Offer_entity/entityfields/copyoffer/onActionProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..4957b1ff844fb074b3ffd05533d1e75377f5b96d
--- /dev/null
+++ b/entity/Offer_entity/entityfields/copyoffer/onActionProcess.js
@@ -0,0 +1,12 @@
+import("system.vars");
+import("system.neon");
+import("Offer_lib");
+
+var contactId = vars.getString("$field.CONTACT_ID");
+var currency = vars.getString("$field.CURRENCY");
+var language = vars.getString("$field.LANGUAGE");
+var header = vars.getString("$field.HEADER");
+var offerId = vars.getString("$field.OFFERID");
+
+OfferUtils.copyOffer(offerId, contactId, language, currency, header);
+    
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/currency/displayValueProcess.js b/entity/Offer_entity/entityfields/currency/displayValueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..251895de0caa384e595ac12282df6a3955093b04
--- /dev/null
+++ b/entity/Offer_entity/entityfields/currency/displayValueProcess.js
@@ -0,0 +1,9 @@
+import("system.result");
+import("system.vars");
+import("Keyword_lib");
+
+if (vars.exists("$param.OfferCurrency_param") && vars.get("$param.OfferCurrency_param")) 
+{
+    var currency = KeywordUtils.getViewValue($KeywordRegistry.get.Currency, vars.get("$param.OfferCurrency_param"));
+    result.string(currency);
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/currency/valueProcess.js b/entity/Offer_entity/entityfields/currency/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..636be1adc9a7505eea4d957860d46a81856f5a93
--- /dev/null
+++ b/entity/Offer_entity/entityfields/currency/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.result");
+import("system.vars");
+
+if (vars.exists("$param.OfferCurrency_param") && vars.get("$param.OfferCurrency_param")) 
+{
+    result.string(vars.get("$param.OfferCurrency_param"));
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/header/valueProcess.js b/entity/Offer_entity/entityfields/header/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..c1dd2bbc6e368ccd25f363f47e8e86f6abceaa55
--- /dev/null
+++ b/entity/Offer_entity/entityfields/header/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.result");
+import("system.vars");
+
+if (vars.exists("$param.OfferHeader_param") && vars.get("$param.OfferHeader_param")) 
+{
+    result.string(vars.get("$param.OfferHeader_param"));
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/language/displayValueProcess.js b/entity/Offer_entity/entityfields/language/displayValueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..987df7556fbe55afa0152a52e1e8d4c766b4ce39
--- /dev/null
+++ b/entity/Offer_entity/entityfields/language/displayValueProcess.js
@@ -0,0 +1,15 @@
+import("system.db");
+import("system.translate");
+import("system.result");
+import("system.vars");
+import("Sql_lib");
+
+if (vars.exists("$param.OfferLanguage_param") && vars.get("$param.OfferLanguage_param")) 
+{
+    var iso3 = vars.get("$param.OfferLanguage_param");
+    var latinName = db.cell(SqlCondition.begin()
+        .andPrepare("AB_LANGUAGE.ISO3", iso3)
+        .buildSql("select NAME_LATIN from AB_LANGUAGE", "1=0"));
+    latinName = translate.text(latinName);
+    result.string(latinName);
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/language/valueProcess.js b/entity/Offer_entity/entityfields/language/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..4fc924e18219f6a6b30f4b3ebb8ffb22d8ed3cb0
--- /dev/null
+++ b/entity/Offer_entity/entityfields/language/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.result");
+import("system.vars");
+
+if (vars.exists("$param.OfferLanguage_param") && vars.get("$param.OfferLanguage_param")) 
+{
+    result.string(vars.get("$param.OfferLanguage_param"));
+}
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/newoffer/onActionProcess.js b/entity/Offer_entity/entityfields/newoffer/onActionProcess.js
deleted file mode 100644
index 1991c7036f76bc53bdb6c9ce2b6abe508001a7a1..0000000000000000000000000000000000000000
--- a/entity/Offer_entity/entityfields/newoffer/onActionProcess.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import("system.vars");
-import("system.neon");
-import("Util_lib");
-import("Neon_lib");
-import("Offer_lib");
-
-var InputMapping = {
-    
-    "OFFER": {
-            condition: "OFFERID = '" + vars.get("$field.OFFERID") + "'"
-            , ValueMapping: {
-                            "OFFER_ID": ""
-                            , "OFFERCODE":  OfferUtils.getNextOfferNumber()
-                            , "VERSNR": "1"
-                        }
-            , SubModules:{
-                "OFFERITEM": {
-                    condition: "OFFER_ID = '" + vars.get("$field.OFFERID") + "' order by ITEMSORT" 
-            }
-        }
-    }
-}
-
-var ModulesMapping = CopyModuleUtils.copyModule(InputMapping);
-
-CopyModuleUtils.openNewModules("Offer", ModulesMapping);
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js b/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js
index 0a83f6827223845ef954c036bf5d99866118fe5e..add48fbf11814bdf125f71afc331b9957afa4172 100644
--- a/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js
+++ b/entity/Offer_entity/entityfields/newofferversion/onActionProcess.js
@@ -1,26 +1,16 @@
 import("system.vars");
 import("system.neon");
-import("Util_lib");
-import("Neon_lib");
 import("Offer_lib");
 
-var InputMapping = {
-    
-    "OFFER": {
-            condition: "OFFERID = '" + vars.get("$field.OFFERID") + "'"
-            , ValueMapping: {
-                            "OFFER_ID": vars.get("$field.OFFERID")
-                            , "OFFERCODE":  vars.get("$field.OFFERCODE")
-                            , "VERSNR":  OfferUtils.getNextOfferVersionNumber(vars.get("$field.OFFERCODE"))
-                        }
-            , SubModules:{
-                "OFFERITEM": {
-                    condition: "OFFER_ID = '" + vars.get("$field.OFFERID") + "' order by ITEMSORT" 
-            }
-        }
-    }
+var params = {
+    "ContactId_param" : vars.get("$field.CONTACT_ID"),
+    "SalesprojectId_param" : vars.get("$field.SALESPROJECT_ID"),
+    "OfferLanguage_param" : vars.get("$field.LANGUAGE"),
+    "OfferOriginal_Id_param" : vars.get("$field.OFFERID"),
+    "OfferCode_param" : vars.get("$field.OFFERCODE"),
+    "OfferVersnr_param" : OfferUtils.getNextOfferVersionNumber(vars.get("$field.OFFERCODE")),
+    "OfferCurrency_param" : vars.get("$field.CURRENCY"),
+    "OfferAddress_param" : vars.get("$field.ADDRESS"),
+    "OfferHeader_param" : vars.get("$field.HEADER")
 }
-
-var ModulesMapping = CopyModuleUtils.copyModule(InputMapping);
-
-CopyModuleUtils.openNewModules("Offer", ModulesMapping);
\ No newline at end of file
+neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params);
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/offer_id/valueProcess.js b/entity/Offer_entity/entityfields/offer_id/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/entity/Offer_entity/entityfields/offercode/onValidation.js b/entity/Offer_entity/entityfields/offercode/onValidation.js
index de949a3e766bbf81de26ee22689c4808a7faae44..3b9c0b76f65fa2b8ae4026d17b1e78d5197d919f 100644
--- a/entity/Offer_entity/entityfields/offercode/onValidation.js
+++ b/entity/Offer_entity/entityfields/offercode/onValidation.js
@@ -6,7 +6,8 @@ import("Salesproject_lib");
 import("Util_lib");
 import("Entity_lib");
 
-if( vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW
+    && !vars.exists("$param.OfferCode_param")
     && !OfferUtils.validateOfferNumber(ProcessHandlingUtils.getOnValidationValue(vars.get("$field.OFFERCODE"))) )
 {
     vars.set( "$field.OFFERCODE", OfferUtils.getNextOfferNumber().toString() );
diff --git a/entity/Offer_entity/entityfields/offercode/valueProcess.js b/entity/Offer_entity/entityfields/offercode/valueProcess.js
index 933257e8cc871bfd2d5cb0be92049e55ea93a2b8..502b44731b281c7fc79094de58242869d07e423d 100644
--- a/entity/Offer_entity/entityfields/offercode/valueProcess.js
+++ b/entity/Offer_entity/entityfields/offercode/valueProcess.js
@@ -4,6 +4,9 @@ import("system.neon");
 import("Offer_lib");
 
 if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-{    
-    result.string(OfferUtils.getNextOfferNumber());
+{
+    if (vars.exists("$param.OfferCode_param") && vars.get("$param.OfferCode_param"))
+        result.string(vars.get("$param.OfferCode_param"));
+    else
+        result.string(OfferUtils.getNextOfferNumber());
 }
\ No newline at end of file
diff --git a/entity/Offer_entity/entityfields/offerreport/onActionProcess.js b/entity/Offer_entity/entityfields/printoffer/onActionProcess.js
similarity index 100%
rename from entity/Offer_entity/entityfields/offerreport/onActionProcess.js
rename to entity/Offer_entity/entityfields/printoffer/onActionProcess.js
diff --git a/entity/Offer_entity/entityfields/versnr/valueProcess.js b/entity/Offer_entity/entityfields/versnr/valueProcess.js
index f3ad73d05605a0009779e02d2767edba66fe2189..5d3797b77b0fc1e83590585de35fa636da9962aa 100644
--- a/entity/Offer_entity/entityfields/versnr/valueProcess.js
+++ b/entity/Offer_entity/entityfields/versnr/valueProcess.js
@@ -5,5 +5,8 @@ import("Offer_lib");
 
 if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
 {
-    result.string( "1" );
+    if (vars.exists("$param.OfferVersnr_param") && vars.get("$param.OfferVersnr_param"))
+        result.string(vars.get("$param.OfferVersnr_param"));
+    else
+        result.string( "1" );
 }
\ No newline at end of file
diff --git a/entity/Offer_entity/recordcontainers/db/conditionProcess.js b/entity/Offer_entity/recordcontainers/db/conditionProcess.js
index 46b77172c421062e7a3ca794200ae6c992f04147..58347450b6f13af8e510f022630d36b1dfac80ea 100644
--- a/entity/Offer_entity/recordcontainers/db/conditionProcess.js
+++ b/entity/Offer_entity/recordcontainers/db/conditionProcess.js
@@ -4,6 +4,7 @@ import("Sql_lib");
 
 var cond = new SqlCondition();
 cond.andPrepareVars("OFFER.SALESPROJECT_ID", "$param.SalesprojectId_param");
+cond.andPrepareVars("OFFER.CONTACT_ID", "$param.ContactId_param");
 
 //TODO: use a preparedCondition when available #1030812 #1034026
 result.string(db.translateCondition(cond.build("1 = 1")));
\ No newline at end of file
diff --git a/entity/Offer_entity/recordcontainers/db/onDBInsert.js b/entity/Offer_entity/recordcontainers/db/onDBInsert.js
new file mode 100644
index 0000000000000000000000000000000000000000..6b3c4033a05890bdd874ce4fa610333b06fdc538
--- /dev/null
+++ b/entity/Offer_entity/recordcontainers/db/onDBInsert.js
@@ -0,0 +1,6 @@
+import("system.neon");
+import("system.vars");
+import("Offer_lib");
+
+if (vars.get("$sys.operatingstate") == neon.OPERATINGSTATE_NEW && vars.exists("$param.OfferOriginal_Id_param"))
+    OfferUtils.copyOfferItems(vars.getString("$param.OfferOriginal_Id_param"), vars.get("$field.OFFERID"));
diff --git a/entity/Order_entity/entityfields/currency/displayValueProcess.js b/entity/Order_entity/entityfields/currency/displayValueProcess.js
index 6be00b937833451cf3146a6c30d09c46980cf840..2519786ebebdab4dd7112825bf47108ea7110ead 100644
--- a/entity/Order_entity/entityfields/currency/displayValueProcess.js
+++ b/entity/Order_entity/entityfields/currency/displayValueProcess.js
@@ -1,5 +1,3 @@
-import("system.db");
-import("system.translate");
 import("system.result");
 import("system.vars");
 import("Keyword_lib");
diff --git a/entity/Orderitem_entity/Orderitem_entity.aod b/entity/Orderitem_entity/Orderitem_entity.aod
index 9162c9654de9ae11fc8509b929d8f764d7497db5..c479324ec12198fed69af55498a8f6bc10d18342 100644
--- a/entity/Orderitem_entity/Orderitem_entity.aod
+++ b/entity/Orderitem_entity/Orderitem_entity.aod
@@ -235,10 +235,6 @@
           <name>ASSIGNEDTO.value</name>
           <recordfield>SALESORDERITEM.ASSIGNEDTO</recordfield>
         </dbRecordFieldMapping>
-        <dbRecordFieldMapping>
-          <name>DESCRIPTION.value</name>
-          <recordfield>SALESORDERITEM.DESCRIPTION</recordfield>
-        </dbRecordFieldMapping>
         <dbRecordFieldMapping>
           <name>DISCOUNT.value</name>
           <recordfield>SALESORDERITEM.DISCOUNT</recordfield>
@@ -303,6 +299,10 @@
           <name>PRODUCT_ID.displayValue</name>
           <expression>%aditoprj%/entity/Orderitem_entity/recordcontainers/db/recordfieldmappings/product_id.displayvalue/expression.js</expression>
         </dbRecordFieldMapping>
+        <dbRecordFieldMapping>
+          <name>INFO.value</name>
+          <recordfield>SALESORDERITEM.INFO</recordfield>
+        </dbRecordFieldMapping>
       </recordFieldMappings>
     </dbRecordContainer>
   </recordContainers>
diff --git a/entity/Organisation_entity/Organisation_entity.aod b/entity/Organisation_entity/Organisation_entity.aod
index 7692f06dc4e5c53e9b9a9ba09eaf29c2d6e36c29..844a65942f92a6089f1c7a5197d1065a0a1311d1 100644
--- a/entity/Organisation_entity/Organisation_entity.aod
+++ b/entity/Organisation_entity/Organisation_entity.aod
@@ -405,6 +405,7 @@
         <entityParameter>
           <name>objectRowId_param</name>
           <code>%aditoprj%/entity/Organisation_entity/entityfields/attributes/children/objectrowid_param/code.js</code>
+          <expose v="true" />
           <triggerRecalculation v="true" />
         </entityParameter>
         <entityParameter>
diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod
index c7f4fd219afb5c37341a0bf6d75f657fd5a50bf2..a23bb04ef680c78a634a70268b6fad524d821b53 100644
--- a/entity/Person_entity/Person_entity.aod
+++ b/entity/Person_entity/Person_entity.aod
@@ -4,6 +4,7 @@
   <title>Contact</title>
   <description>former Pers</description>
   <majorModelMode>DISTRIBUTED</majorModelMode>
+  <documentation>%aditoprj%/entity/Person_entity/documentation.adoc</documentation>
   <iconId>VAADIN:USERS</iconId>
   <imageProcess>%aditoprj%/entity/Person_entity/imageProcess.js</imageProcess>
   <titleProcess>%aditoprj%/entity/Person_entity/titleProcess.js</titleProcess>
@@ -522,6 +523,22 @@ Usually this is used for filtering COMMUNICATION-entries by a specified contact
         <fieldName>LanguagesISO3Code</fieldName>
       </dependency>
     </entityConsumer>
+    <entityConsumer>
+      <name>Offers</name>
+      <title>Offer</title>
+      <fieldType>DEPENDENCY_OUT</fieldType>
+      <dependency>
+        <name>dependency</name>
+        <entityName>Offer_entity</entityName>
+        <fieldName>ContactOffers</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>ContactId_param</name>
+          <code>%aditoprj%/entity/Person_entity/entityfields/offers/children/contactid_param/code.js</code>
+        </entityParameter>
+      </children>
+    </entityConsumer>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
diff --git a/entity/Person_entity/documentation.adoc b/entity/Person_entity/documentation.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/entity/Person_entity/entityfields/offers/children/contactid_param/code.js b/entity/Person_entity/entityfields/offers/children/contactid_param/code.js
new file mode 100644
index 0000000000000000000000000000000000000000..ed4a4f567aa9d494002b914426589ea37bc56682
--- /dev/null
+++ b/entity/Person_entity/entityfields/offers/children/contactid_param/code.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$field.CONTACTID"));
\ No newline at end of file
diff --git a/entity/Productprice_entity/Productprice_entity.aod b/entity/Productprice_entity/Productprice_entity.aod
index 7037175d27761a49a0684cc7a3ef38103cdd38e2..18bb74b1c7ea3631d0c071fd7a576f6202bfa501 100644
--- a/entity/Productprice_entity/Productprice_entity.aod
+++ b/entity/Productprice_entity/Productprice_entity.aod
@@ -60,6 +60,7 @@
       <contentType>DATE</contentType>
       <resolution>DAY</resolution>
       <mandatory v="true" />
+      <valueProcess>%aditoprj%/entity/Productprice_entity/entityfields/valid_from/valueProcess.js</valueProcess>
       <onValidation>%aditoprj%/entity/Productprice_entity/entityfields/valid_from/onValidation.js</onValidation>
     </entityField>
     <entityField>
diff --git a/entity/Productprice_entity/entityfields/valid_from/valueProcess.js b/entity/Productprice_entity/entityfields/valid_from/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a5ac41f637617745a3985ec17bd66594133db52
--- /dev/null
+++ b/entity/Productprice_entity/entityfields/valid_from/valueProcess.js
@@ -0,0 +1,11 @@
+import("system.result");
+import("system.vars");
+import("system.neon");
+import("Date_lib");
+
+if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$this.value") == "")
+{
+    result.string(DateUtils.getTodayUTC());
+}
+else
+    result.string(vars.get("$this.value"));
\ No newline at end of file
diff --git a/entity/SalesprojectForecast_entity/recordcontainers/db/onDBUpdate.js b/entity/SalesprojectForecast_entity/recordcontainers/db/onDBUpdate.js
index f165ed8fa18606a2080496441041fe5a39a06d59..ee62dca4c5b6641758a1ce2856db770d63641278 100644
--- a/entity/SalesprojectForecast_entity/recordcontainers/db/onDBUpdate.js
+++ b/entity/SalesprojectForecast_entity/recordcontainers/db/onDBUpdate.js
@@ -1,3 +1,3 @@
 import("Salesproject_lib");
 
-notifyToUpdateForecast()
\ No newline at end of file
+Salesproject.notifyToUpdateForecast()
\ No newline at end of file
diff --git a/entity/SalesprojectSource_entity/SalesprojectSource_entity.aod b/entity/SalesprojectSource_entity/SalesprojectSource_entity.aod
index 53a24c81a9974cb37bf7621b9067231ad163fccb..63774cba86c602cea3ea1ac99c03442e4d7b5433 100644
--- a/entity/SalesprojectSource_entity/SalesprojectSource_entity.aod
+++ b/entity/SalesprojectSource_entity/SalesprojectSource_entity.aod
@@ -1,7 +1,7 @@
 <?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.2.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.2.0">
   <name>SalesprojectSource_entity</name>
-  <title>Source</title>
+  <title>Touchpoint</title>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <recordContainer>db</recordContainer>
   <entityFields>
@@ -54,7 +54,7 @@
     </entityField>
     <entityField>
       <name>SOURCE</name>
-      <title>Source</title>
+      <title>Touchpoint</title>
       <consumer>KeywordSources</consumer>
     </entityField>
     <entityConsumer>
diff --git a/entity/Salesproject_entity/Salesproject_entity.aod b/entity/Salesproject_entity/Salesproject_entity.aod
index 93027687026652ae17e3034af4d629ac96fbf99b..dddedee3f57491eaa507b1233f036cfe38a6b023 100644
--- a/entity/Salesproject_entity/Salesproject_entity.aod
+++ b/entity/Salesproject_entity/Salesproject_entity.aod
@@ -111,7 +111,7 @@
     </entityField>
     <entityConsumer>
       <name>SalesprojectSources</name>
-      <title>Source</title>
+      <title>Touchpoints</title>
       <fieldType>DEPENDENCY_OUT</fieldType>
       <dependency>
         <name>dependency</name>
@@ -311,6 +311,7 @@
       <description>the total hours of all time trackings related to the salesproject</description>
       <state>READONLY</state>
       <valueProcess>%aditoprj%/entity/Salesproject_entity/entityfields/timetrackingsum/valueProcess.js</valueProcess>
+      <displayValueProcess>%aditoprj%/entity/Salesproject_entity/entityfields/timetrackingsum/displayValueProcess.js</displayValueProcess>
     </entityField>
     <entityField>
       <name>IMAGE</name>
@@ -394,6 +395,13 @@
       <onActionProcess>%aditoprj%/entity/Salesproject_entity/entityfields/newactivity/onActionProcess.js</onActionProcess>
       <iconId>NEON:HISTORY</iconId>
     </entityActionField>
+    <entityField>
+      <name>DAYS_NOTACTIVE</name>
+      <title>Days inactive</title>
+      <contentType>NUMBER</contentType>
+      <state>READONLY</state>
+      <valueProcess>%aditoprj%/entity/Salesproject_entity/entityfields/days_notactive/valueProcess.js</valueProcess>
+    </entityField>
   </entityFields>
   <recordContainers>
     <dbRecordContainer>
diff --git a/neonContext/Salesproject/documentation.adoc b/entity/Salesproject_entity/documentation.adoc
similarity index 100%
rename from neonContext/Salesproject/documentation.adoc
rename to entity/Salesproject_entity/documentation.adoc
diff --git a/entity/Salesproject_entity/entityfields/days_notactive/valueProcess.js b/entity/Salesproject_entity/entityfields/days_notactive/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..cddfb6d43c94f74e66d49f9444cbaf03415b07d2
--- /dev/null
+++ b/entity/Salesproject_entity/entityfields/days_notactive/valueProcess.js
@@ -0,0 +1,11 @@
+import("system.translate");
+import("system.result");
+import("system.vars");
+import("Activity_lib");
+import("Date_lib");
+
+var entryDate = ActivityUtils.getLastActivityDate(vars.get("$field.SALESPROJECTID"));
+var daysPassed = DateUtils.getDayDifference(entryDate);
+
+if (daysPassed != null)
+    result.string(daysPassed);
\ No newline at end of file
diff --git a/entity/Salesproject_entity/entityfields/timetrackingsum/displayValueProcess.js b/entity/Salesproject_entity/entityfields/timetrackingsum/displayValueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..bfe42a40a4a4811369dc8073130dc00b96032782
--- /dev/null
+++ b/entity/Salesproject_entity/entityfields/timetrackingsum/displayValueProcess.js
@@ -0,0 +1,5 @@
+import("system.vars");
+import("system.result");
+import("Timetracking_lib");
+
+result.string(Timetracking.minutesToReadableHour(parseInt(vars.getString("$field.TIMETRACKINGSUM"))));
\ No newline at end of file
diff --git a/entity/Salesproject_entity/entityfields/timetrackingsum/valueProcess.js b/entity/Salesproject_entity/entityfields/timetrackingsum/valueProcess.js
index e3ef6877942e157abdbd49460716516416b058d0..83c88895a0224ff240ea0dfbaf5b68249efffe8d 100644
--- a/entity/Salesproject_entity/entityfields/timetrackingsum/valueProcess.js
+++ b/entity/Salesproject_entity/entityfields/timetrackingsum/valueProcess.js
@@ -1,10 +1,5 @@
-import("system.text");
-import("system.translate");
-import("system.result");
-import("system.vars");
-import("Timetracking_lib");
-
-var hrs = Timetracking.getTotalTrackingTime(vars.getString("$field.SALESPROJECTID")) / 60;
-hrs = text.formatDouble(hrs, "0.00");
-
-result.string(hrs + " " + translate.text("hrs"));
\ No newline at end of file
+import("system.vars");
+import("system.result");
+import("Timetracking_lib");
+
+result.string(Timetracking.getTotalTrackingTime(vars.getString("$field.SALESPROJECTID")));
\ No newline at end of file
diff --git a/entity/Salesproject_entity/recordcontainers/db/onDBUpdate.js b/entity/Salesproject_entity/recordcontainers/db/onDBUpdate.js
index c5ae703c9e1ee768bc4f56bfcbdc6290871d04f6..222926e7c12d2e84a2f409dd5b6698a8bbbf4c87 100644
--- a/entity/Salesproject_entity/recordcontainers/db/onDBUpdate.js
+++ b/entity/Salesproject_entity/recordcontainers/db/onDBUpdate.js
@@ -15,7 +15,7 @@ vars.get("$local.changed").forEach(function(fieldName) {
             fieldVar = "$field.STATE";
             break;
     }
-        
+
     if (typeValue) {
         Salesproject.insertMilestone(vars.getString("$field.SALESPROJECTID"), typeValue, vars.getString(fieldVar), true);
     }
diff --git a/entity/Timetracking_entity/Timetracking_entity.aod b/entity/Timetracking_entity/Timetracking_entity.aod
index 4bdee59f79a0d7ca91293f99c44eb094b05b6259..8e52105f68d966cf5b7d9f7dc22db12a9c829bed 100644
--- a/entity/Timetracking_entity/Timetracking_entity.aod
+++ b/entity/Timetracking_entity/Timetracking_entity.aod
@@ -15,8 +15,10 @@
     </entityField>
     <entityField>
       <name>MINUTES</name>
-      <title>Minutes</title>
+      <title>Time</title>
+      <contentType>NUMBER</contentType>
       <mandatory v="true" />
+      <displayValueProcess>%aditoprj%/entity/Timetracking_entity/entityfields/minutes/displayValueProcess.js</displayValueProcess>
     </entityField>
     <entityField>
       <name>OBJECT_ID</name>
diff --git a/entity/Timetracking_entity/entityfields/minutes/displayValueProcess.js b/entity/Timetracking_entity/entityfields/minutes/displayValueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..326c2a9f306a8a9356e4f895c630ace18a27a91f
--- /dev/null
+++ b/entity/Timetracking_entity/entityfields/minutes/displayValueProcess.js
@@ -0,0 +1,5 @@
+import("system.vars");
+import("system.result");
+import("Timetracking_lib");
+
+result.string(Timetracking.minutesToReadableHour(parseInt(vars.getString("$field.MINUTES"))));
\ No newline at end of file
diff --git a/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js b/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js
index 5953c631790c0ce6159a487fbed9642f5f47a103..74fa0b796d49d26a64f3dc1afebdec42fa58ec9d 100644
--- a/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js
@@ -5,7 +5,8 @@ import("system.db");
 import("system.result");
 import("system.translate");
 import("Data_lib");
-
+import("Keyword_lib");
+import("Money_lib");
 
 var turnoverCategory = translate.text('Turnover');
 var forecastCategory = translate.text('Forecast');
@@ -13,6 +14,13 @@ var forecastCategory = translate.text('Forecast');
 // load data
 var sumOfMonthTurnover = db.table("select year(SALESORDERDATE) yearNum, month(SALESORDERDATE) monthNum, sum(NET + VAT) from SALESORDER group by year(SALESORDERDATE), month(SALESORDERDATE) order by yearNum, monthNum");
 var sumOfMonthForecast = db.table("select year(DATE_START) yearNum, month(DATE_START) monthNum, sum(VOLUME * 1000) from SALESPROJECT_FORECAST group by year(DATE_START), month(DATE_START) order by yearNum, monthNum");
+var sumOfMonthProductsTurnover = db.table("select year(SALESORDERDATE) yearNum, month(SALESORDERDATE) monthNum, SALESORDERITEM.DISCOUNT, SALESORDERITEM.VAT, SALESORDERITEM.PRICE, sum(SALESORDERITEM.QUANTITY), SALESORDERITEM.GROUPCODEID, (" + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.get.ProductGroupcode, "SALESORDERITEM.GROUPCODEID") + ") \n\
+                                            from SALESORDER \n\
+                                            join SALESORDERITEM on SALESORDERITEM.SALESORDER_ID = SALESORDER.SALESORDERID \n\
+                                            where SALESORDERITEM.OPTIONAL <> 1 \n\
+                                            group by year(SALESORDERDATE), month(SALESORDERDATE), SALESORDERITEM.GROUPCODEID, SALESORDERITEM.DISCOUNT, SALESORDERITEM.VAT, SALESORDERITEM.PRICE \n\
+                                            order by yearNum, monthNum");                  //           V--V--> there is no VAT/Discount in forecasts  V-----> forecasts are grouped by grupcode and have always quantity 1
+var sumOfMonthProductsForecast = db.table("select year(DATE_START) yearNum, month(DATE_START) monthNum, 0, 0, sum(VOLUME * 1000),                      1, GROUPCODE, (" + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.get.ProductGroupcode, "GROUPCODE") + ") from SALESPROJECT_FORECAST group by year(DATE_START), month(DATE_START), GROUPCODE order by yearNum, monthNum");
 
 // build chartData
 var rootNode = "";
@@ -25,33 +33,35 @@ var yearCountToShow = parseInt(vars.get("$param.YearCountToShow_param"));
 
 for (let i = 0; i < yearCountToShow; i++)
 {
-    // TODO: currently years are hardcoded.
     var year = i + maxYear - yearCountToShow + 1;
     
-    var TurnoverYearSum = 0;
-    var ForecastYearSum = 0;
+    var turnoverYearSum = 0;
+    var forecastYearSum = 0;
     
     // filter data by current year
-    var TurnoverYearData = sumOfMonthTurnover.filter(function(row)
+    var turnoverYearData = sumOfMonthTurnover.filter(function(row)
     {
-        return row[0] == year
+        return row[0] == year;
     });
     
-    var ForecastYearData = sumOfMonthForecast.filter(function(row)
+    var forecastYearData = sumOfMonthForecast.filter(function(row)
     {
-        return row[0] == year
+        return row[0] == year;
     });
     
     for (let i = 1; i <= 12; i++) 
     { 
         // add months
-        TurnoverYearSum += _addMonth(year, i, TurnoverYearData, turnoverCategory);
-        ForecastYearSum += _addMonth(year, i, ForecastYearData, forecastCategory);
+        turnoverYearSum += _addMonth(year, i, turnoverYearData, turnoverCategory);
+        forecastYearSum += _addMonth(year, i, forecastYearData, forecastCategory);
+        
+        _addProducts(year, i, sumOfMonthProductsTurnover, turnoverCategory);
+        _addProducts(year, i, sumOfMonthProductsForecast, forecastCategory);
     }
     
     // add year nodes
-    chartData.add(turnoverCategory + year, rootNode, [turnoverCategory, year.toString(), TurnoverYearSum]);
-    chartData.add(forecastCategory + year, rootNode, [forecastCategory, year.toString(), ForecastYearSum]);
+    chartData.add(turnoverCategory + year, rootNode, [turnoverCategory, year.toString(), turnoverYearSum]);
+    chartData.add(forecastCategory + year, rootNode, [forecastCategory, year.toString(), forecastYearSum]);
 
 }
 
@@ -87,4 +97,40 @@ function _addMonth(pYear, pMonth, pData, pCategory)
     // add month node
     chartData.add(pCategory + pYear + pMonth, pCategory + pYear, [pCategory, monthDate, monthValue]);
     return yearSum;
-}
\ No newline at end of file
+}
+
+function _addProducts(pYear, pMonth, pData, pCategory)
+{
+    var groupcodeSums = {};
+    
+    for (let i = 0; i < pData.length; i++) 
+    { 
+        if (pData[i][0] == pYear && pData[i][1] == pMonth)
+        {
+            var groupCode = pData[i][6];
+            if (groupCode != undefined)
+            {
+                if (groupcodeSums[groupCode] == undefined)
+                {
+                    groupcodeSums[groupCode] = {
+                        sum: 0,
+                        name: pData[i][7]
+                    }
+                }
+                
+                pData[i][2] = pData[i][2] || 0;
+                pData[i][3] = pData[i][3] || 0;
+                pData[i][4] = pData[i][4] || 0;
+                pData[i][5] = pData[i][5] || 0;
+
+                groupcodeSums[groupCode]["sum"] += MoneyUtils.getGross(parseFloat(pData[i][3]), parseFloat(pData[i][4]), parseFloat(pData[i][5]), parseFloat(pData[i][2]));
+            }
+        }
+    }
+    
+    for (let groupcode in groupcodeSums) 
+    {
+        if (groupcodeSums[groupcode]["sum"])
+            chartData.add(pCategory + pYear + pMonth + groupcode, pCategory + pYear + pMonth, [pCategory, groupcodeSums[groupcode]["name"], groupcodeSums[groupcode]["sum"]]);
+    }
+}
diff --git a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
index 2e8efe2be5fecf6e058410ebe85732907514a80b..8caf6fac2ab14bb213f36e8f62b22eb30574d62f 100644
--- a/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
+++ b/language/_____LANGUAGE_EXTRA/_____LANGUAGE_EXTRA.aod
@@ -2346,6 +2346,33 @@
     <entry>
       <key>Level</key>
     </entry>
+    <entry>
+      <key>Print Offer</key>
+    </entry>
+    <entry>
+      <key>Touchpoints</key>
+    </entry>
+    <entry>
+      <key>Day</key>
+    </entry>
+    <entry>
+      <key>Days</key>
+    </entry>
+    <entry>
+      <key>Days inactive</key>
+    </entry>
+    <entry>
+      <key>Touchpoint</key>
+    </entry>
+    <entry>
+      <key>Combobox Value</key>
+    </entry>
+    <entry>
+      <key>relations</key>
+    </entry>
+    <entry>
+      <key>Time</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 ffe27c577a316c2ca4ac5122cd26811e3ad99ce6..0969f6e7d8cc4b87a87542cd85f3a584e99622a8 100644
--- a/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
+++ b/language/_____LANGUAGE_de/_____LANGUAGE_de.aod
@@ -14,6 +14,10 @@
       <key>Turnover</key>
       <value>Umsatz</value>
     </entry>
+    <entry>
+      <key>Days</key>
+      <value>Tage</value>
+    </entry>
     <entry>
       <key>E-Mail</key>
       <value>E-Mail</value>
@@ -78,6 +82,10 @@
       <key>${SALESPROJECT_MEMBER}</key>
       <value>Projektteam</value>
     </entry>
+    <entry>
+      <key>Days inactive</key>
+      <value>Tage inaktiv</value>
+    </entry>
     <entry>
       <key>Active</key>
       <value>Aktiv</value>
@@ -309,6 +317,10 @@
     <entry>
       <key>Internal (2)</key>
     </entry>
+    <entry>
+      <key>Touchpoints</key>
+      <value>Kontaktpunkte</value>
+    </entry>
     <entry>
       <key>Company Addresses</key>
       <value>Firmenadressen</value>
@@ -752,6 +764,10 @@
       <key>Show open salesprojects</key>
       <value>Offene Vertriebsprojekte anzeigen</value>
     </entry>
+    <entry>
+      <key>Day</key>
+      <value>Tag</value>
+    </entry>
     <entry>
       <key>Receipt number</key>
       <value>Belegnummer</value>
@@ -1047,6 +1063,10 @@
       <key>My Activities</key>
       <value>Meine Aktivitäten</value>
     </entry>
+    <entry>
+      <key>Combobox Value</key>
+      <value>Combobox-Wert</value>
+    </entry>
     <entry>
       <key>Salesprojects</key>
       <value>Vertriebsprojekte</value>
@@ -2414,6 +2434,10 @@
     <entry>
       <key>${GENDER_OTHER}</key>
     </entry>
+    <entry>
+      <key>Touchpoint</key>
+      <value>Kontaktpunkt</value>
+    </entry>
     <entry>
       <key>Turkey</key>
     </entry>
@@ -2624,6 +2648,7 @@
     </entry>
     <entry>
       <key>Checkbox</key>
+      <value></value>
     </entry>
     <entry>
       <key>Numeric value</key>
@@ -2645,6 +2670,7 @@
     </entry>
     <entry>
       <key>${NUMBER}</key>
+      <value>Zahl</value>
     </entry>
     <entry>
       <key>Name \&amp;quot;%0\&amp;quot; already used for container \&amp;quot;%1\&amp;quot;</key>
@@ -2704,6 +2730,17 @@
     <entry>
       <key>Level</key>
     </entry>
+    <entry>
+      <key>Print Offer</key>
+      <value>Angebot drucken</value>
+    </entry>
+    <entry>
+      <key>relations</key>
+    </entry>
+    <entry>
+      <key>Time</key>
+      <value>Zeit</value>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
 </language>
diff --git a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
index 1e68696cfb16f1159c185d3d650cafaeb5e35c3f..fd662446d3a6dfb7a7c49144c1a5b90ac6466440 100644
--- a/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
+++ b/language/_____LANGUAGE_en/_____LANGUAGE_en.aod
@@ -55,6 +55,9 @@
     <entry>
       <key>Information</key>
     </entry>
+    <entry>
+      <key>Print Offer</key>
+    </entry>
     <entry>
       <key>Language</key>
     </entry>
@@ -2370,6 +2373,30 @@
     <entry>
       <key>Level</key>
     </entry>
+    <entry>
+      <key>Touchpoint</key>
+    </entry>
+    <entry>
+      <key>Touchpoints</key>
+    </entry>
+    <entry>
+      <key>Day</key>
+    </entry>
+    <entry>
+      <key>Days</key>
+    </entry>
+    <entry>
+      <key>Days inactive</key>
+    </entry>
+    <entry>
+      <key>Combobox Value</key>
+    </entry>
+    <entry>
+      <key>relations</key>
+    </entry>
+    <entry>
+      <key>Time</key>
+    </entry>
   </keyValueMap>
   <font name="Dialog" style="0" size="11" />
 </language>
diff --git a/neonContext/Salesproject/Salesproject.aod b/neonContext/Salesproject/Salesproject.aod
index cf828aac4f6e718b1539118fa6804a5faac30b2d..0d925d49efa8aeaf7421bd5b6fee7b5673f5d789 100644
--- a/neonContext/Salesproject/Salesproject.aod
+++ b/neonContext/Salesproject/Salesproject.aod
@@ -3,7 +3,6 @@
   <name>Salesproject</name>
   <title>Salesproject</title>
   <majorModelMode>DISTRIBUTED</majorModelMode>
-  <documentation>%aditoprj%/neonContext/Salesproject/documentation.adoc</documentation>
   <mainview>SalesprojectMain_view</mainview>
   <filterview>SalesprojectFilter_view</filterview>
   <editview>SalesprojectEdit_view</editview>
diff --git a/neonView/AppointmentEdit_view/AppointmentEdit_view.aod b/neonView/AppointmentEdit_view/AppointmentEdit_view.aod
index 68581d6336cf998f5963361f1f428d10b09a002b..81d642c40d54f51d68ef3246add18df5e97f9d6a 100644
--- a/neonView/AppointmentEdit_view/AppointmentEdit_view.aod
+++ b/neonView/AppointmentEdit_view/AppointmentEdit_view.aod
@@ -30,8 +30,6 @@
       <masterBeginField>MASTERBEGIN</masterBeginField>
       <masterEndField>MASTEREND</masterEndField>
       <reminderField>REMINDER</reminderField>
-      <appointmentLinkField>LINKS</appointmentLinkField>
-      <appointmentLinkTypeField>LINKTYPE</appointmentLinkTypeField>
       <entityField>#ENTITY</entityField>
     </appointmentEditViewTemplate>
     <neonViewReference>
diff --git a/neonView/AppointmentLinkFilter_view/AppointmentLinkFilter_view.aod b/neonView/AppointmentLinkFilter_view/AppointmentLinkFilter_view.aod
index 28572813858612fe1b31d76dffa1ec8adac5320b..0e6f03ca25af5f1f5f76bd87009bc68a788c48c1 100644
--- a/neonView/AppointmentLinkFilter_view/AppointmentLinkFilter_view.aod
+++ b/neonView/AppointmentLinkFilter_view/AppointmentLinkFilter_view.aod
@@ -1,6 +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.0.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.0.1">
   <name>AppointmentLinkFilter_view</name>
+  <title>relations</title>
   <majorModelMode>DISTRIBUTED</majorModelMode>
   <layout>
     <boxLayout>
@@ -10,8 +11,10 @@
   <children>
     <tableViewTemplate>
       <name>Links</name>
+      <showHeader v="true" />
       <autoNewRow v="true" />
       <entityField>#ENTITY</entityField>
+      <title>relations</title>
       <columns>
         <neonTableColumn>
           <name>17c0a8a9-354c-4095-a5d4-5c2613c897a3</name>
diff --git a/neonView/AttributePreview_view/AttributePreview_view.aod b/neonView/AttributePreview_view/AttributePreview_view.aod
index 59adbab341fa443a18be81de0097635898b4fc31..f3e5d5fa9e51b0d3fedf0e8f0b07f37f8c561472 100644
--- a/neonView/AttributePreview_view/AttributePreview_view.aod
+++ b/neonView/AttributePreview_view/AttributePreview_view.aod
@@ -20,6 +20,10 @@
       <entityField>#ENTITY</entityField>
       <title></title>
       <fields>
+        <entityFieldLink>
+          <name>5f20a5d4-0343-4b8c-92bf-15eeb2483ba9</name>
+          <entityField>ATTRIBUTE_PARENT_ID</entityField>
+        </entityFieldLink>
         <entityFieldLink>
           <name>e00bfeb1-7003-4d5a-b71a-c6921e255c9d</name>
           <entityField>ATTRIBUTE_ACTIVE</entityField>
diff --git a/neonView/OfferMain_view/OfferMain_view.aod b/neonView/OfferMain_view/OfferMain_view.aod
index 01fc943f6aabc0eef9a44669332c76c760b0756c..96e53e98805a3dc2c0a049a9c7e8f1c9482925bf 100644
--- a/neonView/OfferMain_view/OfferMain_view.aod
+++ b/neonView/OfferMain_view/OfferMain_view.aod
@@ -14,6 +14,11 @@
       <entityField>#ENTITY</entityField>
       <view>OfferPreview_view</view>
     </neonViewReference>
+    <neonViewReference>
+      <name>da7c8cef-a4f0-4614-a330-d81221abe566</name>
+      <entityField>Offeritems</entityField>
+      <view>OfferitemFilter_view</view>
+    </neonViewReference>
     <neonViewReference>
       <name>a3702740-418d-40d5-9415-788542c14abb</name>
       <entityField>Activities</entityField>
@@ -24,11 +29,6 @@
       <entityField>#ENTITY</entityField>
       <view>OfferDetail_view</view>
     </neonViewReference>
-    <neonViewReference>
-      <name>da7c8cef-a4f0-4614-a330-d81221abe566</name>
-      <entityField>Offeritems</entityField>
-      <view>OfferitemFilter_view</view>
-    </neonViewReference>
     <neonViewReference>
       <name>e96f2fec-1a98-4380-895a-82ab78ba408a</name>
       <entityField>Documents</entityField>
diff --git a/neonView/PersonMain_view/PersonMain_view.aod b/neonView/PersonMain_view/PersonMain_view.aod
index 5cf87beba03510c471fa28c577e490feaacdfed3..c1585cf24ddda592508fed29d38aaf9d469926d1 100644
--- a/neonView/PersonMain_view/PersonMain_view.aod
+++ b/neonView/PersonMain_view/PersonMain_view.aod
@@ -24,6 +24,11 @@
       <entityField>Documents</entityField>
       <view>DocumentFilter_view</view>
     </neonViewReference>
+    <neonViewReference>
+      <name>0cb8f431-0377-45cb-a41b-a5716efb0fd0</name>
+      <entityField>Offers</entityField>
+      <view>OfferFilter_view</view>
+    </neonViewReference>
     <neonViewReference>
       <name>ec344a07-7b82-4c54-b06b-30ac5b8599f9</name>
       <entityField>Contracts</entityField>
diff --git a/neonView/ProductpriceEdit_view/ProductpriceEdit_view.aod b/neonView/ProductpriceEdit_view/ProductpriceEdit_view.aod
index 4e378bfd4da1e655a215ec14f72ecbeb9d22859c..867fcfc0b4a69b217396e3a4e219d7f8eabc65ab 100644
--- a/neonView/ProductpriceEdit_view/ProductpriceEdit_view.aod
+++ b/neonView/ProductpriceEdit_view/ProductpriceEdit_view.aod
@@ -18,6 +18,10 @@
           <name>e2afee84-173b-430a-8e29-1fd16d33dd69</name>
           <entityField>PRICELIST</entityField>
         </entityFieldLink>
+        <entityFieldLink>
+          <name>21c8be49-ee64-4d9c-a8b0-eb44575cfd01</name>
+          <entityField>PRODUCT_ID</entityField>
+        </entityFieldLink>
         <entityFieldLink>
           <name>fa21fa53-ac64-44b1-a5d1-8a1af16590fe</name>
           <entityField>VALID_FROM</entityField>
@@ -46,10 +50,6 @@
           <name>ca06ebcb-abf5-4606-98cd-fd54dccce6d0</name>
           <entityField>CURRENCY</entityField>
         </entityFieldLink>
-        <entityFieldLink>
-          <name>21c8be49-ee64-4d9c-a8b0-eb44575cfd01</name>
-          <entityField>PRODUCT_ID</entityField>
-        </entityFieldLink>
       </fields>
     </genericViewTemplate>
   </children>
diff --git a/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod b/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod
index e0bc20e97a1fcf618f7bc89005c47ade6ac496d0..b36c8a2373c0003b4582c199462fffc280b5873f 100644
--- a/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod
+++ b/neonView/SalesprojectPreview_view/SalesprojectPreview_view.aod
@@ -76,5 +76,15 @@
       <entityField>MainDocuments</entityField>
       <view>DocumentList_view</view>
     </neonViewReference>
+    <scoreCardViewTemplate>
+      <name>SalesprojectScore_template</name>
+      <entityField>#ENTITY</entityField>
+      <fields>
+        <entityFieldLink>
+          <name>79490331-6be4-422f-9450-da0db56f0654</name>
+          <entityField>DAYS_NOTACTIVE</entityField>
+        </entityFieldLink>
+      </fields>
+    </scoreCardViewTemplate>
   </children>
 </neonView>
diff --git a/others/guide/HowToDataLib.adoc b/others/guide/HowToDataLib.adoc
index b331b7eb20e5498b7591e27f8bf1c4fdb4a16aba..f16c4f8b74628f20c0a95c2799a747a8e7eb6cf0 100644
--- a/others/guide/HowToDataLib.adoc
+++ b/others/guide/HowToDataLib.adoc
@@ -36,7 +36,7 @@ var myDescriptiveNameOfTheTree = new DataTree(alias);
 // or
 var myDescriptiveNameOfTheTree = DataTree.begin(alias);
 ----
-* use the object, add conditions
+* use the object, add conditions with add(uid, parent, itemArray)
 [source,javascript]
 ----
 var myTree = myDescriptiveNameOfTheTree.add("1", "myRoot", ["itemId1", "value"])
@@ -44,7 +44,7 @@ var myTree = myDescriptiveNameOfTheTree.add("1", "myRoot", ["itemId1", "value"])
                           .add("3", "2", ["itemId3", "value"])
                           .add("4", "2", ["itemId4", "value"])
                           .add("5", "4", ["itemId5", "value"])
-                          .add("5", "3", ["itemId5", "value"])  // Now you added id "5" a seccond time.
+                          .add("5", "3", ["itemId5", "value"])  // Now you added id "5" a second time, overrides previous entry with id 5
                           .getTreeObject();
 
 var myArray = myDescriptiveNameOfTheTree.toArray();
@@ -92,7 +92,7 @@ var myTree = myDescriptiveName.add("1", "myRoot", ["itemId1", "value"])
 Note that if you add an item two times, only the data-array of the second item is used! It will overwrite the data from the first one!
 
 == When to use which ==
-If you only need a array with parent - child - structure e.g. for the treetable or charts, use
+If you only need an array with parent - child - structure e.g. for the treetable or charts, use
 ReferencingData
 
 If you need a tree object for your logic, use DataTree.
\ No newline at end of file
diff --git a/others/guide/HowToSqlConditionLib.adoc b/others/guide/HowToSqlConditionLib.adoc
index 82f29b1b846b875aee80c5eaa7052726dd50c010..51e953b5a3c983c2ce0a3ac82c36f998d48e95ce 100644
--- a/others/guide/HowToSqlConditionLib.adoc
+++ b/others/guide/HowToSqlConditionLib.adoc
@@ -29,8 +29,8 @@ var myDescriptiveNameOfTheCondition = SqlCondition.begin(alias);
 * use the object, add conditions
 [source,javascript]
 ----
-myDescriptiveNameOfTheCondition.orPrepare("PERSON.FIRSTNAME", "Bob")
-                               .orPrepare("PERSON.LASTNAME", "Meier");
+myDescriptiveNameOfTheCondition.orPrepare("PERSON.FIRSTNAME", "Bob") 
+                               .orPrepare("PERSON.LASTNAME", "Meier"); // orPrepare explained in "available methods" below
 ----
 * You can also use table aliases, if you provide the table, column and alias as array.
   The table name has to be provided for loading the data types but the alias is built into the sql.
@@ -82,11 +82,11 @@ The field name needs to be given with
 Or if you use only COLUMNNAME, you have to provide the fieldType.
 
 But keep in mind: Other than the original adito db. functions this lib caches the field types automatically (for the livetime of an SqlCondition Object).
-So most times it is save to use the first method. Even in loops or if you use the same Column several times.
+So most times it is save to use the first method. Even in loops or if you use the same column several times.
 
 [source,javascript]
 ----
-myDescriptiveNameOfTheCondition.orPrepared("PERSON.FIRSTNAME", 'Bob', "#<?");
+myDescriptiveNameOfTheCondition.orPrepared("PERSON.FIRSTNAME", 'Bob', "#<?"); // #(field) < ?(value)
 ----
 
 === andPreparedVars / orPreparedVars ===
@@ -126,7 +126,7 @@ var myConditionSql = myDescriptiveNameOfTheCondition.toWhereString("1=0");
 ----
 
 === preparedValues ===
-This is no method but a membervariable.
+This is no method but a member variable.
 It contains the array with the prepared values.
 
 [source,javascript]
diff --git a/others/guide/PersonOrganisationContact.adoc b/others/guide/PersonOrganisationContact.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..7d7a1b33f971b107ef28b8f4a6a5885a9e10a3f5
--- /dev/null
+++ b/others/guide/PersonOrganisationContact.adoc
@@ -0,0 +1,39 @@
+Person, Organisation, Contact
+=============================
+:toc2: left
+:numbered:
+
+== Differences to old Adito ==
+
+The old Adito basic had:
+
+- Pers
+- Org
+- Relation
+
+They are not gone, just renamed:
+
+- Pers = Person
+- Org = Organisation
+- Relation = Contact
+
+TODO: doku erweitern
+erson, Organisation, Contact
+===========================================
+:toc2: left
+:numbered:
+
+== Differences to old Adito ==
+
+The old Adito basic had:
+
+- Pers
+- Org
+- Relation
+
+They are not gone, just renamed:
+
+- Pers = Person
+- Org = Organisation
+- Relation = Contact
+
diff --git a/others/guide/ProviderConsumerParameter.adoc b/others/guide/ProviderConsumerParameter.adoc
index 67b427e998091baebd9d482c2de581b3d20d2dea..ee9ff59bc7d051dc069cd0ba1a409887036f8f8c 100644
--- a/others/guide/ProviderConsumerParameter.adoc
+++ b/others/guide/ProviderConsumerParameter.adoc
@@ -25,7 +25,7 @@ If you connect to *EmailCommunications* you get *only the Email* communication t
 If you connect to *PhoneCommunications* you get *only the Phone* communication type of a contact.
 
 *Important:*
-*Do not always create a new provider when connecting a new entity. Maybe u can use an already existing provider.*
+*Do not always create a new provider when connecting a new entity. Maybe you can use an already existing provider.*
 *Try to reuse providers if you need similar data for two dependencies*
 
 === Consumer ===
diff --git a/others/guide/TargetContext.adoc b/others/guide/TargetContext.adoc
index 89155b20aa2879693555d901cf1f6f5445f002ab..1d466a0da9c53953491cf301711f745d6d8478e4 100644
--- a/others/guide/TargetContext.adoc
+++ b/others/guide/TargetContext.adoc
@@ -16,4 +16,4 @@ It is configured by two properties of the providers.
 * targetContextField
 * targetIdField
 
-You can provide an entity-field for each of them which contain the contextId (currently the contextName 13.02.2019) and the rowId (UID) which should be used to open the preview or main view.
\ No newline at end of file
+You can provide an entity-field for each of them which contains the contextId (currently the contextName 13.02.2019) and the rowId (UID) which should be used to open the preview or main view.
\ No newline at end of file
diff --git a/others/guide/how to copy objects with subitems.adoc b/others/guide/how to copy objects with subitems.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..63f85af69459e163f28844400e364f42d7ca8023
--- /dev/null
+++ b/others/guide/how to copy objects with subitems.adoc	
@@ -0,0 +1,100 @@
+How to make an action for copying modules
+=========================================
+:toc2: left
+:numbered:
+
+== What this guide is for ==
+You want to create an action or process that should copy a module with
+related sub-items.
+(for example: Offer + OfferItems, Order + OrderItems)
+
+== How to do it ==
+There are two possibilities when it comes to creating a new dataset based on another one:
+
+* Save it directly and open the created dataset in show-mode
+* Open it in new-mode so that the user can make changes first or cancel the action
+
+=== Save it directly ===
+This is relatively easy to do with the functions in the Neon_lib.
+At first you have make the copy with the method "CopyModuleUtils.copyModule". It requires an InputMapping object that
+defines the structure of the module. For example:
+
+[source, javascript]
+----
+var InputMapping = {
+    "OFFER": {
+            condition: "OFFERID = '" + vars.get("$field.OFFERID") + "'"
+            , ValueMapping: {
+                            "OFFER_ID": ""
+                            , "OFFERCODE":  OfferUtils.getNextOfferNumber()
+                            , "VERSNR": "1"
+                        }
+            , SubModules:{
+                "OFFERITEM": {
+                    condition: "OFFER_ID = '" + vars.get("$field.OFFERID") + "' order by ITEMSORT" 
+            }
+        }
+    }
+}
+----
+
+The root element of the object (in this case 'OFFER') defines what module is copied, the condition is used to select the specific dataset.
+'ValueMapping' should be used when some fields need new values (for example the offercode should not be the same as in the copied object).
+You can also set 'SubModules' in order to copy sub-elements like offerItems.
+Now you just have to use the following code:
+
+[source, javascript]
+----
+var ModulesMapping = CopyModuleUtils.copyModule(InputMapping);
+
+CopyModuleUtils.openNewModules("Offer", ModulesMapping);
+----
+
+The first line copies the module and the second line opens the newly created dataset.
+
+=== Open it in new-mode first ===
+For this case it needs a few more steps. For values that should be preset in the edit view, you will need to create
+parameters in the entity for every one (set them exposed, triggerRecalculation and not mandatory). After that you have to use these parameters in the valueProcess of the fields
+they should fill. 
+The next step is to create an action that opens the context in new-mode. That could look like this:
+
+[source, javascript]
+----
+var params = {
+    "ContactId_param" : vars.get("$field.CONTACT_ID"),
+    "SalesprojectId_param" : vars.get("$field.SALESPROJECT_ID"),
+    "OfferLanguage_param" : vars.get("$field.LANGUAGE"),
+    "OfferOriginal_Id_param" : vars.get("$field.OFFERID"),
+    "OfferCode_param" : vars.get("$field.OFFERCODE"),
+    "OfferVersnr_param" : OfferUtils.getNextOfferVersionNumber(vars.get("$field.OFFERCODE")),
+    "OfferCurrency_param" : vars.get("$field.CURRENCY"),
+    "OfferAddress_param" : vars.get("$field.ADDRESS"),
+    "OfferHeader_param" : vars.get("$field.HEADER")
+}
+neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params);
+----
+
+Important: There has to be one parameter for the id, so that sub-items can be copied (see the following).
+
+Now we can preset values of the module, but what about related things like offerItems?
+For that we use the same function as in the section above. Because the offerItems should only be copied to the new offer when the user
+saved it, this has to be done in the onInsert-process of the recordcontainer.
+
+[source, javascript]
+----
+if (vars.get("$sys.operatingstate") == neon.OPERATINGSTATE_NEW && vars.exists("$param.OfferOriginal_Id_param"))
+{
+    var InputMapping = {
+        "OFFERITEM": {
+            condition: "OFFER_ID = '" + vars.getString("$param.OfferOriginal_Id_param") + "' order by ITEMSORT",
+            ValueMapping: {
+                "OFFER_ID" : vars.get("$field.OFFERID")
+            }
+        }
+    };
+    CopyModuleUtils.copyModule(InputMapping);
+}
+----
+
+The offer is already created, so that only offerItem is needed in the 'InputMapping'. The 'condition' should use the id of the offer
+that is copied and in 'ValueMapping' the foreign-key 'OFFER_ID' gets the value of the id of the newly created offer.
\ No newline at end of file
diff --git a/others/guide/how to write JDito code.adoc b/others/guide/how to write JDito code.adoc
index cd6e8b4d635476ced35c0911c5ce7dff43b6e02e..e8ab96aef63360b0994d45cb45de3fd07b45230a 100644
--- a/others/guide/how to write JDito code.adoc	
+++ b/others/guide/how to write JDito code.adoc	
@@ -1,4 +1,3 @@
-How to write JDito code
 =======================
 :toc2: left
 :numbered:
@@ -115,7 +114,7 @@ function SqlCondition(pAlias) <4>
 {
    //setting null is only needed to provide autocomplete for the ADITO-designer
     this.preparedValues = null;
-    this._init();//the properties are initalized in an extra function because init is nearly the same as resetting (clearing) the SqlConditions
+    this._init();//the properties are initialized in an extra function because init is nearly the same as resetting (clearing) the SqlConditions
     this.alias = alias;
 }
 /**
@@ -142,12 +141,12 @@ So just start your functions / methods name with a _ if you need private methods
 
 --> do not use functions which start with a _ outside of the class!
 
-Add @ignore to the comment of the private functions.
+Add @ignore to the comment of those functions to prevent showing them in the generated jsdoc.
 
 == JS-Doc ==
 
 <1> JS-Doc comment: http://usejsdoc.org/
-<2> jsdoc-blocks have to start with /&#x002A;&#x002A; because the tool to generate docs out of jsdoc only works with /&#x002A;&#x002A;
+<2> jsdoc-blocks have to start with /&#x002A;&#x002A; otherwise JSDoc cannot generate a documentation
 <3> use the correct form for optional/required parameters: http://usejsdoc.org/tags-param.html
 Optional parameter: [alias=the current alias]
 Required parameter: alias
@@ -167,10 +166,9 @@ function SqlCondition(pAlias)
 ...
 }
 ----
-<3> examples are useful on more complex functions
-<4> constructor function; init properties (do not set functions ("methods") here!)
-<5> add functions ("methods") to the prototype, they are available through the prototype chain
-<6> the comments have to start with /&#x002A;&#x002A; not /&#x002A; otherwise JSDoc cannot generate a documentation
+<4> examples are useful on more complex functions
+<5> constructor function; init properties (do not set functions ("methods") here!)
+<6> add functions ("methods") to the prototype, they are available through the prototype chain
 
 And how to use it (normally you'd want to use preparedStatements but for the sake of an easy example it's a bit shorter here)
 See also HowToSqlConditionLib.adoc for a full documentation.
diff --git a/others/guide/whichDatatype.adoc b/others/guide/whichDatatype.adoc
index 391d8709372ab4cfddd037ec2cfb0a60e244a571..092ae1bf6ae5c02d56ced4bf133b5e956a8f23e2 100644
--- a/others/guide/whichDatatype.adoc
+++ b/others/guide/whichDatatype.adoc
@@ -17,7 +17,7 @@ TINYINT
 Add nullable="false" constraint, because for boolean null makes no sense and complicates searches and validations.
 
 == Text ==
-Text should be saved as Unicode. For this prefix the datatype with a 'N' (there are some exceptions lik the UUID)
+Text should be saved as Unicode. For this prefix the datatype with a 'N' (there are some exceptions like the UUID)
 
 === Big text ===
 For informations, descriptions, ...
diff --git a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod
index 336d6b092bda8ab38166821c8d50c82ace586ceb..581c9d3a6896bb001678073f2ebc276b89dd4112 100644
--- a/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod
+++ b/preferences/_____PREFERENCES_PROJECT/_____PREFERENCES_PROJECT.aod
@@ -10,11 +10,15 @@
       <value></value>
     </entry>
     <entry>
-      <key>Privat</key>
+      <key>Organisation</key>
       <value></value>
     </entry>
     <entry>
-      <key>Organisation</key>
+      <key>auswärts</key>
+      <value></value>
+    </entry>
+    <entry>
+      <key>Urlaub</key>
       <value></value>
     </entry>
   </calendarCategoriesEvent>
diff --git a/process/Activity_lib/process.js b/process/Activity_lib/process.js
index b9a50c73f494bd24a9771afa8ffcc40ed2396a79..8d8252e5b45e4f81ac8c237e5e5fa94478c45bb2 100644
--- a/process/Activity_lib/process.js
+++ b/process/Activity_lib/process.js
@@ -31,4 +31,28 @@ ActivityUtils.createNewActivity = function(pRowId)
     params["ObjectId_param"] = ContextUtils.getCurrentContextId();
     params["RowId_param"] = pRowId;
     neon.openContext("Activity", null, null, neon.OPERATINGSTATE_NEW, params);
+}
+
+/*
+ * Gets the date of the last activity
+ * 
+ * @param {String} pRowId the rowid of the dataset
+ * 
+ * @return {number|null} the date of the last actvity as long
+ */
+ActivityUtils.getLastActivityDate = function (pRowId)
+{
+    var context = ContextUtils.getCurrentContextId();
+    var sqlUtil = new SqlMaskingUtils();
+    var activitySql = "select " + sqlUtil.max("ENTRYDATE") + " from ACTIVITY "
+        + " join ACTIVITYLINK on ACTIVITY.ACTIVITYID = ACTIVITYLINK.ACTIVITY_ID";
+    activitySql = SqlCondition.begin()
+        .andPrepare("ACTIVITYLINK.OBJECT_TYPE", context)
+        .andPrepare("ACTIVITYLINK.OBJECT_ROWID", pRowId)
+        .buildSql(activitySql);
+    
+    var entryDate = db.cell(activitySql);
+    if (entryDate != "")
+        return parseInt(entryDate);
+    return null;
 }
\ No newline at end of file
diff --git a/process/Attribute_lib/process.js b/process/Attribute_lib/process.js
index 7039cc1af029b4c09ac6e18dcf0dcf2cea137993..755d9c190519f25facadb77f0c98302f89293b33 100644
--- a/process/Attribute_lib/process.js
+++ b/process/Attribute_lib/process.js
@@ -5,8 +5,8 @@ import("system.db");
 import("Sql_lib");
 
 /**
- * Provides functions for the work with attributes, like setting or getting the value of an attribute
- * or listing the available attributes for a context.
+ * Provides functions for the work with attributes, like
+ * listing the available attributes for a context.
  * Don't instanciate this!
  * 
  * @class
@@ -64,7 +64,7 @@ AttributeUtil.getFullAttributeName = function (pAttributeId)
         if (attribute.length > 0)
         {
             attributeNames.push(attribute[0]);
-            pAttributeId = attribute[1];
+                pAttributeId = attribute[1];
         }
         else
             pAttributeId = "";
@@ -91,14 +91,55 @@ AttributeUtil.getSimpleAttributeName = function (pAttributeId)
 }
 
 /**
- * gets the value of an attribute for one dataset (e. g. a person)
+ * returns the ids of all subordinated attributes of an attribute
+ * 
+ * @param {String} pAttributeId the id of the attribute
+ * 
+ * @result {String[]} array with the ids of every subordinated attribute
  */
-AttributeUtil.getAttribute = function (pAttributeId, pObjectType, pObjectRowId, pGetIdValue)
+AttributeUtil.getAllChildren = function (pAttributeId)
 {
-    //TODO: implement
+    var childIds = [];
+    var attributes= [pAttributeId];
+    while (attributes.length > 0)
+    {
+        attributes = db.array(db.COLUMN, SqlCondition.begin()
+            .and("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID in ('" + attributes.join("','") + "')")
+            .buildSql("select AB_ATTRIBUTEID from AB_ATTRIBUTE")
+        );
+        if (attributes.length > 0)
+            childIds = childIds.concat(attributes);
+    }
+    return childIds;
 }
 
-AttributeUtil.getAttributes = function ()
+/*********************************************************************************************************************/
+
+/**
+ * Provides functions for the work with attributeRelations, getting the value of an attributeRelation for an object.
+ * Don't instanciate this!
+ * 
+ * @class
+ */
+function AttributeRelationUtils () {}
+
+/**
+ * gets the value of an attributeRelation for one dataset (e. g. a person)
+ */
+AttributeRelationUtils.getAttribute = function (pAttributeId, pObjectRowId, pObjectType)
+{
+    var attrCond = SqlCondition().begin()
+        .andPrepare("AB_ATTRIBUTERELATION.AB_ATTRIBUTE_ID", pAttributeId)
+        .andPrepare("AB_ATTRIBUTERELATION.OBJECT_ROWID", pObjectRowId);
+    if (pObjectType != null)
+        attrCond.andPrepare("AB_ATTRIBUTERELATION.OBJECT_TYPE", pAttributeId);
+    
+    var attrSql = AttributeRelationUtils.getSqlUtil();
+    var attributeValues = db.array(db.ROW, attrCond.buildSql(attrSql.sqlSelect));
+    return attrSql.getFieldFromType(attributeValues);
+}
+
+AttributeRelationUtils.getAttributes = function ()
 {
     //TODO: implement maybe
 }
@@ -106,11 +147,62 @@ AttributeUtil.getAttributes = function ()
 /**
  * sets the value of an attribute for one dataset (e. g. a person)
  */
-AttributeUtil.setAttribute = function ()
+AttributeRelationUtils.setAttribute = function ()
 {
     //TODO: implement
 }
 
+/**
+ * Builds an object for the work with the values of attributeRelations. This should make
+ * the attribute type definition more flexible, the returned object has the following properties
+ * and methods:
+ *
+ * columns = array of all database columns in AB_ATTRIBUTERELATION that hold attribute values
+ * typeColMap = object with the attribute type as key and the index in the columns-array with the column holding
+ *      the value for that attribute type as value
+ * sqlSelect = an sql-select string where the columns are the type of the attribute plus the value columns
+ * getFieldFromType = a method that takes a one-dimensional array that has been created with a query using the 'sqlSelect' property
+ *      and returns the value at the right position of that array depending on the type. For example:
+ *                      //type,   values
+ *          vals = ["TEXT", "abcdef", "", "", "", ""];
+ *      the method would return "abcdef", because it looks at the first position where the type is, e. g. "TEXT"
+ *      and then it gets the value at, for example, index 1 because the typeColMap object says that the value for type "TEXT"
+ *      is at position 1.
+ * 
+ */
+AttributeRelationUtils.getSqlUtil = function ()
+{
+    var types = Object.keys($AttributeTypes);
+    var sqlMap = {
+        columns : [],
+        typeColMap : {}
+    };
+    types.forEach(function (type)
+    {
+        var typeKey = type.toString();
+        var colIndex = this.columns.indexOf(type.databaseField);
+        if (colIndex == -1)
+        {
+            colIndex = this.columns.length;
+            this.columns.push(type.databaseField);
+        }
+        this.typeColMap[typeKey] = colIndex;
+    }, sqlMap);
+    
+    sqlMap.sqlSelect = "select ATTRIBUTE_TYPE, " + sqlMap.columns.join(", ") + " from AB_ATTRIBUTERELATION "
+        + " join AB_ATTRIBUTE on AB_ATTRIBUTERELATION.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID ";
+    
+    sqlMap.getFieldFromType = function (pTypeAndValues)
+    {
+        if (pTypeAndValues.length > 0)
+            return pTypeAndValues[this.typeColMap[pTypeAndValues[0]] + 1];
+        return null;
+    }
+    
+    return sqlMap;
+}
+
+/*********************************************************************************************************************/
 
 /**
  * This is used in the AttributeRelation enitiy to make the work with attributes there
@@ -195,6 +287,7 @@ AttributeHandler.prototype.setAttributeValue = function (pValue)
  * should be done in AttributeUtils.
  * The values for each type are:
  * 
+ * keyword = the key of the corresponding keyword
  * contentType = the value that is returned in the contentType process for the attribute
  * databaseField = the database field that holds values of attributes with the type
  * entityField = the field in the AttributeRelation enity that holds the value of the attribute for that type
@@ -204,43 +297,50 @@ AttributeHandler.prototype.setAttributeValue = function (pValue)
 function $AttributeTypes () {}
 
 $AttributeTypes.TEXT = { 
-    toString : function () {return "TEXT"},
+    toString : function () {return this.keyword},
+    keyword : "TEXT",
     contentType : "TEXT", 
     databaseField : "CHAR_VALUE", 
     entityField : "CHAR_VALUE"
 };
 $AttributeTypes.DATE = {
-    toString : function () {return "DATE"},
+    toString : function () {return this.keyword},
+    keyword : "DATE",
     contentType : "DATE", 
     databaseField : "DATE_VALUE", 
     entityField : "DATE_VALUE"
 };
 $AttributeTypes.NUMBER = {
-    toString : function () {return "NUMBER"},
+    toString : function () {return this.keyword},
+    keyword : "NUMBER",
     contentType : "NUMBER", 
     databaseField : "NUMBER_VALUE", 
     entityField : "NUMBER_VALUE"
 };
 $AttributeTypes.BOOLEAN = {
-    toString : function () {return "BOOLEAN"},
+    toString : function () {return this.keyword},
+    keyword : "BOOLEAN",
     contentType : "BOOLEAN", 
     databaseField : "BOOL_VALUE", 
     entityField : "BOOL_VALUE"
 };
 $AttributeTypes.COMBO = {
-    toString : function () {return "COMBO"},
-    contentType : "TEXT", 
+    toString : function () {return this.keyword},
+    keyword : "COMBO",
+    contentType : "UNKNOWN",
     databaseField : "ID_VALUE", 
     entityField : "ID_VALUE"
 };
 $AttributeTypes.COMBOVALUE = {
-    toString : function () {return "COMBOVALUE"},
+    toString : function () {return this.keyword},
+    keyword : "COMBOVALUE",
     contentType : null, 
     databaseField : null, 
     entityField : null
 };
 $AttributeTypes.GROUP = {
-    toString : function () {return "GROUP"},
+    toString : function () {return this.keyword},
+    keyword : "GROUP",
     contentType : null, 
     databaseField : null, 
     entityField : null
diff --git a/process/Date_lib/process.js b/process/Date_lib/process.js
index bbfc15c251e6d76b1702f4eb712dc76cc8987d7f..f4121551b8f86159b971b9e69247f8749f2c2df6 100644
--- a/process/Date_lib/process.js
+++ b/process/Date_lib/process.js
@@ -74,4 +74,24 @@ DateUtils.getMonthName = function(pMonth) {
     
     
     return monthNames[pMonth];
-}
\ No newline at end of file
+}
+
+/**
+ * Calculates the passed days between two dates.
+ * 
+ *  @param {Number} pPastDate the first timestamp
+ *  @param {Number} [pCurrentDate=currentTimestamp] the second timestamp
+ *  
+ *  @return {Number|null} the amount of days (value is always positive) or null if pPastDate is null
+ */
+DateUtils.getDayDifference = function (pPastDate, pCurrentDate)
+{
+    if (pPastDate == null)
+        return null;
+    if (pCurrentDate == null)
+        pCurrentDate = datetime.date();
+    var millisecDiff = Math.abs(pCurrentDate - pPastDate);
+    var dayDiff = Math.floor(millisecDiff / datetime.ONE_DAY);
+    
+    return dayDiff;
+}
diff --git a/process/Money_lib/Money_lib.aod b/process/Money_lib/Money_lib.aod
new file mode 100644
index 0000000000000000000000000000000000000000..61248fd244213806e7a23ebd44d8353bed49dc4b
--- /dev/null
+++ b/process/Money_lib/Money_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.1.7" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.1.7">
+  <name>Money_lib</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <process>%aditoprj%/process/Money_lib/process.js</process>
+  <variants>
+    <element>LIBRARY</element>
+  </variants>
+</process>
diff --git a/process/Money_lib/process.js b/process/Money_lib/process.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b59e2d69db667b7904c12747574f8c20ed65ae8
--- /dev/null
+++ b/process/Money_lib/process.js
@@ -0,0 +1,70 @@
+import("system.logging");
+import("system.eMath");
+
+/**
+ * Class containing static utility functions for working with money
+ * Do not create an instance of this!
+ * 
+ * @class
+ */
+function MoneyUtils() {}
+
+/**
+ * round a price with eMath.ROUND_HALF_UP
+ * @param {Double} pPrice
+ * 
+ * @return rounded price
+ */
+MoneyUtils.round = function(pPrice) 
+{
+    return eMath.roundDec(pPrice, 2, eMath.ROUND_HALF_UP);
+}
+
+/**
+ * get net price
+ * @param {Double} pPrice
+ * @param {Double} [pQuantity=0.0]
+ * @param {Double} [pDiscount=0.0]
+ * 
+ * @return net of price
+ */
+MoneyUtils.getNet = function(pPrice, pQuantity, pDiscount) 
+{
+    pQuantity = pQuantity || 0;
+    pDiscount = pDiscount || 0;
+    return MoneyUtils.round(pPrice * pQuantity * (100 - pDiscount) / 100);
+}
+
+/**
+ * get vat of a price
+ * @param {Double} pVat
+ * @param {Double} pPrice
+ * @param {Double} [pQuantity=0.0]
+ * @param {Double} [pDiscount=0.0]
+ * 
+ * @return vat of price
+ */
+MoneyUtils.getVat = function(pVat, pPrice, pQuantity, pDiscount) 
+{
+    pQuantity = pQuantity || 0;
+    pDiscount = pDiscount || 0;
+    
+    return MoneyUtils.round(pPrice * pQuantity * (100 - pDiscount) / 100 * pVat / 100);
+}
+
+/**
+ * get gross of a price
+ * @param {Double} pVat
+ * @param {Double} pPrice
+ * @param {Double} [pQuantity=0.0]
+ * @param {Double} [pDiscount=0.0]
+ * 
+ * @return gross of price
+ */
+MoneyUtils.getGross = function(pVat, pPrice, pQuantity, pDiscount) {
+    
+    pQuantity = pQuantity || 0;
+    pDiscount = pDiscount || 0;
+    
+    return eMath.addDec(MoneyUtils.getNet(pPrice, pQuantity, pDiscount), MoneyUtils.getVat(pVat, pPrice, pQuantity, pDiscount));
+}
\ No newline at end of file
diff --git a/process/Neon_lib/process.js b/process/Neon_lib/process.js
index c811a8f7be0193ac7efff4c6f214d742caebbb3d..65e019d7c4c2bc5f6789467daf8e527f652eccab 100644
--- a/process/Neon_lib/process.js
+++ b/process/Neon_lib/process.js
@@ -153,6 +153,7 @@ CopyModuleUtils.copyModule = function(pInputMapping)
         var rootModule = Object.keys(pInputMapping)[0];
         var ModuleMapping = _ModuleMapping(rootModule, pInputMapping[rootModule]);
         var ModuleData = _getModuleData(rootModule, pInputMapping[rootModule].condition);
+        ModulesMapping[rootModule] = ModuleMapping;
 
         for(var row in ModuleData)
         {
@@ -282,7 +283,7 @@ CopyModuleUtils.copyModule = function(pInputMapping)
                 case "OFFERITEM":
                 {
                     //OFFER_ID mappen
-                    if(ModuleRowMapping.ParentModuleMapping.name == "OFFER")
+                    if(ModuleRowMapping.ParentModuleMapping != null && ModuleRowMapping.ParentModuleMapping.name == "OFFER")
                     {
                         ModuleRowMapping.ColumnMapping["OFFER_ID"].newValue = ModulesMapping[ModuleRowMapping.ParentModuleMapping.name].DataRows[ModuleRowMapping.ColumnMapping["OFFER_ID"].oldValue].newPrimaryKey;
                     }
diff --git a/process/OfferOrder_lib/process.js b/process/OfferOrder_lib/process.js
index cb1dc57b42c964b43850f223dfaee60a8aff5789..d96c87ce756caa5319eac5ad3ddba88aa09625e1 100644
--- a/process/OfferOrder_lib/process.js
+++ b/process/OfferOrder_lib/process.js
@@ -6,6 +6,7 @@ import("system.util");
 import("system.eMath");
 import("system.db");
 import("Product_lib");
+import("Money_lib");
 
 /**
  * Abstract class that provides methods for dealing with offer / order items.
@@ -163,8 +164,8 @@ ItemUtils.prototype.getNetAndVat = function(itemIds) {
 
     for (var i = 0; i < orderItems.length; i++)
     {
-        sum += this.getItemSum(orderItems[i][0], orderItems[i][1], orderItems[i][2], orderItems[i][4]);
-        vat += this.getItemVAT(orderItems[i][0], orderItems[i][1], orderItems[i][2], orderItems[i][3], orderItems[i][4]);
+        sum = eMath.addDec(sum, this.getItemSum(orderItems[i][0], orderItems[i][1], orderItems[i][2], orderItems[i][4]));
+        vat = eMath.addDec(vat, this.getItemVAT(orderItems[i][0], orderItems[i][1], orderItems[i][2], orderItems[i][3], orderItems[i][4]));
     }
 
     return [sum, vat];
@@ -200,33 +201,33 @@ ItemUtils.prototype.initItemTree = function() {
 /**
  * @abstract
  */
-ItemUtils.prototype.getItemSum = function(quantity, price, discount, optional) {
-    quantity = quantity || 0;
-    price = price || 0;
-    discount = discount || 0;
+ItemUtils.prototype.getItemSum = function(pQuantity, pPrice, pDiscount, pOptional) {
+    pQuantity = pQuantity || 0;
+    pPrice = pPrice || 0;
+    pDiscount = pDiscount || 0;
 
-    return optional ? (parseFloat(quantity) * parseFloat(price) * ((100 - parseFloat(discount)) / 100))
+    return pOptional == "0" ? (MoneyUtils.getNet(parseFloat(pPrice), parseFloat(pQuantity), parseFloat(pDiscount)))
                     : 0;
 }
 
 /**
  * @abstract
  */
-ItemUtils.prototype.getItemVAT = function(quantity, price, discount, vat, optional) {
-    quantity = quantity || 0;
-    price = price || 0;
-    discount = discount || 0;
-    vat = vat || 0;
-
-    return optional ? (parseFloat(quantity) * parseFloat(price) * ((100 - parseFloat(discount)) / 100) * (parseFloat(vat) / 100)) 
+ItemUtils.prototype.getItemVAT = function(pQuantity, pPrice, pDiscount, pVat, pOptional) {
+    pQuantity = pQuantity || 0;
+    pPrice = pPrice || 0;
+    pDiscount = pDiscount || 0;
+    pVat = pVat || 0;
+    logging.log(pOptional.toSource())
+    return pOptional == "0" ? (MoneyUtils.getVat(parseFloat(pVat), parseFloat(pPrice), parseFloat(pQuantity), parseFloat(pDiscount))) 
                     : 0;
 }
 
 /**
  * @abstract
  */
-ItemUtils.prototype.roundPrice = function(price) {
-    return eMath.roundDec(price, 2, eMath.ROUND_HALF_UP);
+ItemUtils.prototype.roundPrice = function(pPrice) {
+    return MoneyUtils.round(pPrice);
 }
 
 /**
diff --git a/process/Offer_lib/process.js b/process/Offer_lib/process.js
index 6f7515d1036833af71835a986d51e50568178501..716a56fb2ae06122dde7cf8903132805185f100f 100644
--- a/process/Offer_lib/process.js
+++ b/process/Offer_lib/process.js
@@ -13,6 +13,7 @@ import("Product_lib");
 import("Report_lib");
 import("OfferOrder_lib");
 import("PostalAddress_lib");
+import("Neon_lib");
 
 /**
  * Methods used by Offer.
@@ -273,6 +274,54 @@ OfferUtils.openOfferReport = function(pOfferID)
     offerReport.openReport();
 }
 
+/**
+ * opens an offer in NEW mode with values from an offer
+ * 
+ * @param pOfferId {String} id of the offer
+ * @param pContactId {String} contact id
+ * @param pLanguage {String} language
+ * @param pCurrency {String} [currency=""]
+ * @param pHeader {String} [header=""]
+ */
+OfferUtils.copyOffer = function (pOfferId, pContactId, pLanguage, pCurrency, pHeader)
+{
+    var params = {
+        "ContactId_param" : pContactId,
+        "OfferLanguage_param" : pLanguage,
+        "OfferOriginal_Id_param" : pOfferId,
+        "OfferCurrency_param" : pCurrency || "",
+        "OfferHeader_param" : pHeader || ""
+    };
+    neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params);
+}
+
+/**
+ * copies all offerItems from one offer to another
+ * 
+ * @param {String} pSourceOfferId
+ * @param {String} pTargetOfferId
+ */
+OfferUtils.copyOfferItems = function (pSourceOfferId, pTargetOfferId)
+{
+    var InputMapping = {
+        "OFFERITEM": {
+            condition: "OFFER_ID = '" + pSourceOfferId + "' order by ITEMSORT",
+            ValueMapping: {
+                "OFFER_ID" : pTargetOfferId
+            }
+        }
+    };
+    CopyModuleUtils.copyModule(InputMapping);
+    
+    var oiUtils = new OfferItemUtils(pTargetOfferId);
+    
+    //update order price
+    cols = ["NET", "VAT"];
+    var vals = oiUtils.getNetAndVat();
+    
+    db.updateData("OFFER", cols, null, vals, SqlCondition.equals("OFFER.OFFERID", pTargetOfferId, "1 = 2"));
+}
+
 /**
  * opens an order in NEW mode with values from an offer
  * 
diff --git a/process/Order_lib/process.js b/process/Order_lib/process.js
index 0c927b0ed370eb84461c5b0d40ee5c5b69f1a08e..818de7d7027bb5c0994fe4ae5743764e5a69c31f 100644
--- a/process/Order_lib/process.js
+++ b/process/Order_lib/process.js
@@ -82,62 +82,36 @@ OrderUtils.createNewOrder = function(pSalesprojectId, pRelationId)
  * 
  * @param {String} pOfferId the offer to get the items from
  * @param {String} pOrderId the order to create the items for
- * 
- * @return {Number[]} Array with the ids of the inserted orderItems
  */
 OrderUtils.copyOfferItemsToOrder = function (pOfferId, pOrderId)
 {
-    var cols = [
-        "UNIT", 
-        "QUANTITY", 
-        "GROUPCODEID", 
-        "ASSIGNEDTO", 
-        "PRICE", 
-        "ITEMSORT", 
-        "PRODUCT_ID", 
-        "VAT", 
-        "ITEMNAME", 
-        "OPTIONAL", 
-        "DISCOUNT", 
-        "ITEMPOSITION", 
-        "INFO"
-    ];
-    var offerItemSql = SqlCondition.begin()
-        .andPrepare("OFFERITEM.OFFER_ID", pOfferId)
-        .buildSql("select " + cols.concat(["OFFERITEMID"]).join(", ") + " from OFFERITEM", "1=0");
-    var offerItems = db.table(offerItemSql);
-
-    var table = "SALESORDERITEM";
-    cols = cols.concat(["SALESORDERITEMID", "SALESORDER_ID"]);
-    var types = db.getColumnTypes(table, cols);
-    
-    //the rows need new UIDs, but because items can be related over ASSIGNEDTO, ASSIGNEDTO must also be 
-    //changed to the newly generated id of the parent item, so the "oldId : newId" pairs have to be stored
-    //to set ASSIGNEDTO correctly
-    var idMap = {}; 
-    
-    var toInsert = [];
-    while (offerItems.length > 0)
-        for (let i = 0; i < offerItems.length; i++)
-        {
-            var row = offerItems[i];
-            
-            //checks if the parent attribute has already been put into the insert-array,
-            //otherwise the foreign-key ASSIGNEDTO could have the id of a row that hasn't been inserted yet
-            // -> toInsert needs to be in the correct order
-            if (row[3] == "" || row[3] in idMap)
-            {
-                row[3] = idMap[row[3]] || "";
-                var newId = util.getNewUUID();
-                idMap[row[13]] = newId;
-                row[13] = newId; //replace the UID
-                toInsert.push([table, cols, types, row.concat([pOrderId])]);
-                offerItems.splice(i, 1); //remove the row from offerItems
-                i--;
+    var InputMapping = {
+        "OFFERITEM": {
+            destinationModuleName : "SALESORDERITEM",
+            DestinationColumnMapping : {
+                "OFFERITEMID" : "SALESORDERITEMID",
+                "ITEMPOSITION" : "ITEMPOSITION", 
+                "GROUPCODEID" : "GROUPCODEID", 
+                "OFFER_ID" : "SALESORDER_ID",
+                "ASSIGNEDTO" : "ASSIGNEDTO", 
+                "PRODUCT_ID" : "PRODUCT_ID", 
+                "QUANTITY" : "QUANTITY", 
+                "ITEMSORT" : "ITEMSORT", 
+                "ITEMNAME" : "ITEMNAME", 
+                "OPTIONAL" : "OPTIONAL", 
+                "DISCOUNT" : "DISCOUNT", 
+                "PRICE" : "PRICE", 
+                "UNIT" : "UNIT", 
+                "INFO" : "INFO",
+                "VAT" : "VAT"
+            },
+            condition: "OFFER_ID = '" + pOfferId + "' order by ITEMSORT",
+            ValueMapping: {
+                "OFFER_ID" : pOrderId
             }
         }
-    
-    db.inserts(toInsert);
+    };
+    CopyModuleUtils.copyModule(InputMapping);
     
     var oiUtils = new OrderItemUtils(pOrderId);
     
@@ -146,11 +120,6 @@ OrderUtils.copyOfferItemsToOrder = function (pOfferId, pOrderId)
     var vals = oiUtils.getNetAndVat();
     
     db.updateData("SALESORDER", cols, null, vals, SqlCondition.equals("SALESORDER.SALESORDERID", pOrderId, "1 = 2"));
-    
-    return Object.keys(idMap).map(function (id) 
-    {
-        return idMap[id];
-    });
 }
 
 
diff --git a/process/Salesproject_lib/process.js b/process/Salesproject_lib/process.js
index 3ca5cd3d006d00d888830cf349654874a82ee57d..479848b10d7f01270ceddc1a6456d9a040897b96 100644
--- a/process/Salesproject_lib/process.js
+++ b/process/Salesproject_lib/process.js
@@ -56,7 +56,7 @@ Salesproject.insertMilestone = function(salesprojectId, type, value, notifyForec
             [util.getNewUUID(), salesprojectId, type, value, vars.get("$sys.date")]);
             
         if (notifyForecast) {
-            this.notifyToUpdateForecast()
+            Salesproject.notifyToUpdateForecast()
         }
         return true;
     }
diff --git a/process/Timetracking_lib/process.js b/process/Timetracking_lib/process.js
index 664d6574bedc18c220cea42395ecf787791d5e83..d2128cd195542977845b87086fe6bc0da1f74520 100644
--- a/process/Timetracking_lib/process.js
+++ b/process/Timetracking_lib/process.js
@@ -44,4 +44,19 @@ Timetracking.createNewTimeTracking = function (pRowId)
     };
     
     neon.openContext("Timetracking", null, null, neon.OPERATINGSTATE_NEW, params);
+}
+
+/*
+ * converts minutes tho hours and minuets. e.g. 105 to 1:45
+ * 
+ * @param {integer} pMinutes req 
+ * 
+ * @return {String} Hours:Minutes
+ */
+Timetracking.minutesToReadableHour = function(pMinutes) 
+{
+    var timeHour = parseInt(pMinutes / 60);
+    var minutes = parseInt(pMinutes % 60);
+    
+    return "" + timeHour + ":" + ((minutes <= 9) ? "0" + minutes : minutes);
 }
\ No newline at end of file