diff --git a/entity/TurnoverTree_entity/TurnoverTree_entity.aod b/entity/TurnoverTree_entity/TurnoverTree_entity.aod
new file mode 100644
index 0000000000000000000000000000000000000000..fdef45bc089615fa9bcedabc31524678826d41f5
--- /dev/null
+++ b/entity/TurnoverTree_entity/TurnoverTree_entity.aod
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.4" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.4">
+  <name>TurnoverTree_entity</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <title>Tree</title>
+  <iconId>NEON:LOGO</iconId>
+  <recordContainer>jdito</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+    </entityProvider>
+    <entityField>
+      <name>UID</name>
+    </entityField>
+    <entityField>
+      <name>CATEGORY</name>
+      <groupable v="true" />
+    </entityField>
+    <entityField>
+      <name>TURNOVERPRICE</name>
+      <title>Turnover</title>
+      <contentType>NUMBER</contentType>
+      <outputFormat>#,##0.00</outputFormat>
+    </entityField>
+    <entityParameter>
+      <name>YearCountToShow_param</name>
+      <valueProcess>%aditoprj%/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/valueProcess.js</valueProcess>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <documentation>%aditoprj%/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/documentation.adoc</documentation>
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityParameter>
+      <name>MaxYear_param</name>
+      <valueProcess>%aditoprj%/entity/TurnoverTree_entity/entityfields/maxyear_param/valueProcess.js</valueProcess>
+      <expose v="true" />
+      <triggerRecalculation v="true" />
+      <mandatory v="false" />
+      <documentation>%aditoprj%/entity/TurnoverTree_entity/entityfields/maxyear_param/documentation.adoc</documentation>
+      <description>PARAMETER</description>
+    </entityParameter>
+    <entityProvider>
+      <name>FilteredTurnovers</name>
+      <fieldType>DEPENDENCY_IN</fieldType>
+      <dependencies>
+        <entityDependency>
+          <name>0ea4ad47-985b-4a9c-81d8-946be324ae04</name>
+          <entityName>Turnover_entity</entityName>
+          <fieldName>Turnover_tree</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+      <children>
+        <entityParameter>
+          <name>YearCountToShow_param</name>
+          <expose v="true" />
+        </entityParameter>
+      </children>
+    </entityProvider>
+    <entityField>
+      <name>PARENT</name>
+    </entityField>
+    <entityField>
+      <name>GROUP</name>
+      <title>Product group</title>
+    </entityField>
+    <entityField>
+      <name>FORECASTPRICE</name>
+      <title>Forecast</title>
+      <contentType>NUMBER</contentType>
+      <outputFormat>#,##0.00</outputFormat>
+    </entityField>
+    <entityField>
+      <name>YEAR</name>
+    </entityField>
+    <entityField>
+      <name>MONTH</name>
+    </entityField>
+    <entityField>
+      <name>LAYER</name>
+    </entityField>
+  </entityFields>
+  <recordContainers>
+    <jDitoRecordContainer>
+      <name>jdito</name>
+      <jDitoRecordAlias>Data_alias</jDitoRecordAlias>
+      <contentProcess>%aditoprj%/entity/TurnoverTree_entity/recordcontainers/jdito/contentProcess.js</contentProcess>
+      <recordFields>
+        <element>UID.value</element>
+        <element>PARENT.value</element>
+        <element>GROUP.value</element>
+        <element>CATEGORY.value</element>
+        <element>TURNOVERPRICE.value</element>
+        <element>FORECASTPRICE.value</element>
+        <element>YEAR.value</element>
+        <element>MONTH.value</element>
+        <element>LAYER.value</element>
+      </recordFields>
+    </jDitoRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/TurnoverTree_entity/entityfields/maxyear_param/documentation.adoc b/entity/TurnoverTree_entity/entityfields/maxyear_param/documentation.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..fcbd74f60e6720f1d9085e894eb9220ec9ce8e85
--- /dev/null
+++ b/entity/TurnoverTree_entity/entityfields/maxyear_param/documentation.adoc
@@ -0,0 +1,3 @@
+this parameter is for setting the maximum year to show.
+
+The default is the current year.
\ No newline at end of file
diff --git a/entity/TurnoverTree_entity/entityfields/maxyear_param/valueProcess.js b/entity/TurnoverTree_entity/entityfields/maxyear_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..652de6453d7648618499d56b211e46eccefc2493
--- /dev/null
+++ b/entity/TurnoverTree_entity/entityfields/maxyear_param/valueProcess.js
@@ -0,0 +1,5 @@
+import("system.result");
+import("system.vars");
+import("system.datetime");
+
+result.string(datetime.toDate(vars.get("$sys.date"), "yyyy"));
\ No newline at end of file
diff --git a/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/documentation.adoc b/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/documentation.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..a0783738ca4add70cc06867ecfe633dd35f7d086
--- /dev/null
+++ b/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/documentation.adoc
@@ -0,0 +1,3 @@
+This parameter is for setting the number of years to show.
+
+Default is 4.
\ No newline at end of file
diff --git a/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/valueProcess.js b/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..02fc6e39ebb2c279000ffa389aa42a31bc2f6076
--- /dev/null
+++ b/entity/TurnoverTree_entity/entityfields/yearcounttoshow_param/valueProcess.js
@@ -0,0 +1,3 @@
+import("system.result");
+
+result.string("4");
\ No newline at end of file
diff --git a/entity/TurnoverTree_entity/recordcontainers/jdito/contentProcess.js b/entity/TurnoverTree_entity/recordcontainers/jdito/contentProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9ab2d319ba83e196acb2e09e5122e5767c62f30
--- /dev/null
+++ b/entity/TurnoverTree_entity/recordcontainers/jdito/contentProcess.js
@@ -0,0 +1,106 @@
+import("Turnover_lib");
+import("system.vars");
+import("system.result");
+import("Money_lib");
+import("Util_lib");
+import("system.datetime");
+import("KeywordRegistry_basic");
+import("Keyword_lib");
+import("system.translate");
+
+var turnoverCategory = translate.text('Turnover');
+var forecastCategory = translate.text('Forecast');
+
+var maxYear = parseInt(vars.get("$param.MaxYear_param"));
+var yearCountToShow = parseInt(vars.get("$param.YearCountToShow_param"));
+var minYear = maxYear - yearCountToShow + 1;
+
+var turnover = TurnoverUtil.getTurnoverData(maxYear, yearCountToShow);
+var forecast = TurnoverUtil.getForecastData(maxYear, yearCountToShow);
+
+var columns = {
+    type: 0,
+    year: 1,
+    month: 2,
+    discount: 3,
+    vat: 4,
+    price: 5,
+    quantity: 6,
+    groupcodeId: 7,
+    groupcodeName: 8
+};
+
+// combine both data sources
+
+
+var treeData = [];
+var countData = {};
+
+turnover.forEach(function(row) 
+{    
+    var monthDate = new Date(row[columns.year], row[columns.month]-1);
+    monthDate = datetime.toDate(monthDate.getTime(), "MMM yyyy", "UTC");
+    _addCount([row[columns.year], [row[columns.month], monthDate], [row[columns.groupcodeId], row[columns.groupcodeName]]], row[columns.type], row[columns.year], row[columns.month],
+        MoneyUtils.getGross(
+            (row[columns.vat] ? parseFloat(row[columns.vat]) : 0.0),
+            (row[columns.price] ? parseFloat(row[columns.price]) : 0.0),
+            (row[columns.quantity] ? parseFloat(row[columns.quantity]) : 0.0),
+            (row[columns.discount] ? parseFloat(row[columns.discount]) : 0.0)));
+});
+
+forecast.forEach(function(row) 
+{    
+    var monthDate = new Date(row[columns.year], row[columns.month]-1);
+    monthDate = datetime.toDate(monthDate.getTime(), "MMM yyyy", "UTC");
+    _addCount([row[columns.year], [row[columns.month], monthDate], [row[columns.groupcodeId], row[columns.groupcodeName]]], row[columns.type], row[columns.year], row[columns.month], row[columns.price]);
+});
+
+// create tree
+for (let key in countData) {
+    var countDataSet = countData[key];
+    treeData.push([key, countDataSet.parent, countDataSet.groupName, countDataSet.category, countDataSet[turnoverCategory], countDataSet[forecastCategory], parseInt(countDataSet.year), parseInt(countDataSet.month), parseInt(countDataSet.layer)]);
+}
+
+treeData = TreeUtils.treeOrderBy(treeData, 8, [[6, true], [7, false], [2, false]])
+result.object(treeData);
+
+/**
+ * add the counts to countData for the given key and value
+ * @param {Array} pKeys an array containing all keys for this value. If the x-value for one key is different from the key-value: add an array [key, value] instead of only the key
+ *                      the first key is year
+ * @param {String} pCategory the category to add
+ * @param {integer} pYear the year
+ * @param {integer} pMonth the month
+ * @param {float} pValue the value to display
+ */
+function _addCount(pKeys, pCategory, pYear, pMonth, pValue) {
+    var key = "";
+    
+    for (let i = 0; i < pKeys.length; i++) {
+        let keyId;
+        let keyName;
+        
+        if (typeof pKeys[i] != "object")
+        {
+            keyId = pKeys[i];
+            keyName = pKeys[i];
+        }
+        else // handle array: first is id seccond is name for X-value
+        {
+            keyId = pKeys[i][0];
+            keyName = pKeys[i][1];
+        }
+        var parent = key;
+
+        key += ";" + keyId;
+        
+        if (countData[key] == undefined)
+        {
+            countData[key] = {parent: parent, category: pCategory, groupName: keyName, data: pKeys[i], year: pYear, month: pMonth, layer: i}; // keys[0] is the category
+            countData[key][forecastCategory] = 0.0;
+            countData[key][turnoverCategory] = 0.0;
+        }
+
+        countData[key][pCategory] += parseFloat(pValue);
+    }
+}
\ No newline at end of file
diff --git a/entity/Turnover_entity/Turnover_entity.aod b/entity/Turnover_entity/Turnover_entity.aod
index 2f8ab9d9f8efd8b691957875730d30abf726283a..ea6be4be71dd3742873344433ca8e1ee34f90239 100644
--- a/entity/Turnover_entity/Turnover_entity.aod
+++ b/entity/Turnover_entity/Turnover_entity.aod
@@ -64,6 +64,25 @@
         </entityParameter>
       </children>
     </entityProvider>
+    <entityConsumer>
+      <name>Turnover_tree</name>
+      <fieldType>DEPENDENCY_OUT</fieldType>
+      <dependency>
+        <name>dependency</name>
+        <entityName>TurnoverTree_entity</entityName>
+        <fieldName>FilteredTurnovers</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>MaxYear_param</name>
+          <valueProcess>%aditoprj%/entity/Turnover_entity/entityfields/turnover_tree/children/maxyear_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>YearCountToShow_param</name>
+          <valueProcess>%aditoprj%/entity/Turnover_entity/entityfields/turnover_tree/children/yearcounttoshow_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
   </entityFields>
   <recordContainers>
     <jDitoRecordContainer>
diff --git a/entity/Turnover_entity/entityfields/turnover_tree/children/maxyear_param/valueProcess.js b/entity/Turnover_entity/entityfields/turnover_tree/children/maxyear_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..55220f39547358d4ac27319394796362654d50fc
--- /dev/null
+++ b/entity/Turnover_entity/entityfields/turnover_tree/children/maxyear_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$param.MaxYear_param"));
\ No newline at end of file
diff --git a/entity/Turnover_entity/entityfields/turnover_tree/children/yearcounttoshow_param/valueProcess.js b/entity/Turnover_entity/entityfields/turnover_tree/children/yearcounttoshow_param/valueProcess.js
new file mode 100644
index 0000000000000000000000000000000000000000..6769ee4809dd12cbe5af03ca76deeb956e801965
--- /dev/null
+++ b/entity/Turnover_entity/entityfields/turnover_tree/children/yearcounttoshow_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$param.YearCountToShow_param"));
\ 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 df5df1581fcc12c9ca8487eff061760459aa4526..4f94c77a16d4c1158c06232d605d56ad62009d08 100644
--- a/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js
@@ -1,13 +1,11 @@
+import("Turnover_lib");
 import("system.vars");
-import("Sql_lib");
 import("system.result");
 import("Money_lib");
 import("system.datetime");
-import("system.db");
 import("KeywordRegistry_basic");
 import("Keyword_lib");
 import("system.translate");
-import("system.SQLTYPES");
 
 var turnoverCategory = translate.text('Turnover');
 var forecastCategory = translate.text('Forecast');
@@ -16,19 +14,7 @@ var maxYear = parseInt(vars.get("$param.MaxYear_param"));
 var yearCountToShow = parseInt(vars.get("$param.YearCountToShow_param"));
 var minYear = maxYear - yearCountToShow + 1;
 
-// load data
-var data = db.table(SqlCondition.begin()
-                                .andPrepare("SALESPROJECT_FORECAST.DATE_START", maxYear, "year(#) <= ?", SQLTYPES.INTEGER)
-                                .andPrepare("SALESPROJECT_FORECAST.DATE_START", minYear, "year(#) >= ?", SQLTYPES.INTEGER)
-                                .buildSql("select 'Forecast', year(DATE_START) yearNum, month(DATE_START) monthNum, 0 discount, 0 vat, sum(VOLUME * 1000) price, 1 quantity, GROUPCODE prodGroup, (" + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.productGroupcode(), "GROUPCODE") + ") prodGroupName from SALESPROJECT_FORECAST", "1=2", " group by year(DATE_START), month(DATE_START), GROUPCODE order by yearNum, monthNum"))
-          .concat(db.table(SqlCondition.begin()
-                                .and("SALESORDERITEM.OPTIONAL <> 1")
-                                .andPrepare("SALESORDER.SALESORDERDATE", maxYear, "year(#) <= ?", SQLTYPES.INTEGER)
-                                .andPrepare("SALESORDER.SALESORDERDATE", minYear, "year(#) >= ?", SQLTYPES.INTEGER)
-                                .buildSql("select 'Turnover', year(SALESORDERDATE) yearNum, month(SALESORDERDATE) monthNum, SALESORDERITEM.DISCOUNT discount, SALESORDERITEM.VAT vat, SALESORDERITEM.PRICE price, sum(SALESORDERITEM.QUANTITY) quantity, SALESORDERITEM.GROUPCODEID prodGroup, (" + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.productGroupcode(), "SALESORDERITEM.GROUPCODEID") + ") prodGroupName \n\
-                                            from SALESORDER  \n\
-                                            join SALESORDERITEM on SALESORDERITEM.SALESORDER_ID = SALESORDER.SALESORDERID", "1=2", "group by year(SALESORDERDATE), month(SALESORDERDATE), SALESORDERITEM.GROUPCODEID, SALESORDERITEM.DISCOUNT, SALESORDERITEM.VAT, SALESORDERITEM.PRICE \n\
-                                            order by yearNum, monthNum ")))
+var data = TurnoverUtil.getTurnoverAndForecastData(maxYear, yearCountToShow);
 
 var columns = {
     type: 0,
@@ -54,9 +40,8 @@ for (let y = minYear; y <= maxYear; y++)
     {
         monthDate = new Date(y, m-1);
         monthDate = datetime.toDate(monthDate.getTime(), "MMM yyyy", "UTC");
-        logging.log(monthDate)
-        _addCount(["Forecast", ""+y, [m, monthDate]], 0.0);
-        _addCount(["Turnover", ""+y, [m, monthDate]], 0.0);
+        _addCount([forecastCategory, ""+y, [m, monthDate]], 0.0);
+        _addCount([turnoverCategory, ""+y, [m, monthDate]], 0.0);
     }
 }
 
@@ -67,10 +52,10 @@ data.forEach(function(row)
     
     switch(row[columns.type])
     {
-        case "Forecast":
+        case forecastCategory:
             _addCount([row[columns.type], row[columns.year], [row[columns.month], monthDate], [row[columns.groupcodeId], row[columns.groupcodeName]]], row[columns.price]);
             break;
-        case "Turnover":
+        case turnoverCategory:
             _addCount([row[columns.type], row[columns.year], [row[columns.month], monthDate], [row[columns.groupcodeId], row[columns.groupcodeName]]], 
                 MoneyUtils.getGross(
                     (row[columns.vat] ? parseFloat(row[columns.vat]) : 0.0),
diff --git a/neonContext/TurnoverTree/TurnoverTree.aod b/neonContext/TurnoverTree/TurnoverTree.aod
new file mode 100644
index 0000000000000000000000000000000000000000..767e00d8da61a3b203763da6fd71cff72bc26537
--- /dev/null
+++ b/neonContext/TurnoverTree/TurnoverTree.aod
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.0" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.0">
+  <name>TurnoverTree</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <filterview>TurnoverTree_view</filterview>
+  <entity>TurnoverTree_entity</entity>
+  <references>
+    <neonViewReference>
+      <name>b8135e50-da8e-424c-9073-e721b4822736</name>
+      <view>TurnoverTree_view</view>
+    </neonViewReference>
+  </references>
+</neonContext>
diff --git a/neonView/TurnoverChart_view/TurnoverChart_view.aod b/neonView/TurnoverChart_view/TurnoverChart_view.aod
index 9cb1a002e4c60759b370934cd77a611e9ab5ce18..5b05bdf764f29741f23e6c8a3f21fce8c55a0082 100644
--- a/neonView/TurnoverChart_view/TurnoverChart_view.aod
+++ b/neonView/TurnoverChart_view/TurnoverChart_view.aod
@@ -1,77 +1,82 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.1">
-  <name>TurnoverChart_view</name>
-  <title></title>
-  <majorModelMode>DISTRIBUTED</majorModelMode>
-  <dashletConfigurations>
-    <neonDashletConfiguration>
-      <name>TurnoverDashlet</name>
-      <title>Turnover</title>
-      <fragment>Turnover/full</fragment>
-      <singleton v="true" />
-      <storeRoles>
-        <element>INTERNAL_ADMINISTRATOR</element>
-        <element>INTERNAL_DASHBOARDSTOREADMIN</element>
-      </storeRoles>
-      <icon>VAADIN:CHART</icon>
-      <categories>
-        <neonDashletCategory>
-          <name>turnover</name>
-          <title>Turnover</title>
-        </neonDashletCategory>
-      </categories>
-    </neonDashletConfiguration>
-  </dashletConfigurations>
-  <layout>
-    <groupLayout>
-      <name>layout</name>
-    </groupLayout>
-  </layout>
-  <children>
-    <multiDataChartViewTemplate>
-      <name>ColumnChart</name>
-      <chartType>COLUMN</chartType>
-      <xAxis>X</xAxis>
-      <yAxis>Y</yAxis>
-      <parentField>PARENT</parentField>
-      <categoryField>CATEGORY</categoryField>
-      <entityField>#ENTITY</entityField>
-    </multiDataChartViewTemplate>
-    <multiDataChartViewTemplate>
-      <name>LineChart</name>
-      <chartType>LINE</chartType>
-      <xAxis>X</xAxis>
-      <yAxis>Y</yAxis>
-      <parentField>PARENT</parentField>
-      <categoryField>CATEGORY</categoryField>
-      <entityField>#ENTITY</entityField>
-    </multiDataChartViewTemplate>
-    <multiDataChartViewTemplate>
-      <name>AreaChart</name>
-      <chartType>AREA</chartType>
-      <xAxis>X</xAxis>
-      <yAxis>Y</yAxis>
-      <parentField>PARENT</parentField>
-      <categoryField>CATEGORY</categoryField>
-      <entityField>#ENTITY</entityField>
-    </multiDataChartViewTemplate>
-    <multiDataChartViewTemplate>
-      <name>BarChart</name>
-      <chartType>BAR</chartType>
-      <xAxis>X</xAxis>
-      <yAxis>Y</yAxis>
-      <parentField>PARENT</parentField>
-      <categoryField>CATEGORY</categoryField>
-      <entityField>#ENTITY</entityField>
-    </multiDataChartViewTemplate>
-    <multiDataChartViewTemplate>
-      <name>SplineChart</name>
-      <chartType>SPLINE</chartType>
-      <xAxis>X</xAxis>
-      <yAxis>Y</yAxis>
-      <parentField>PARENT</parentField>
-      <categoryField>CATEGORY</categoryField>
-      <entityField>#ENTITY</entityField>
-    </multiDataChartViewTemplate>
-  </children>
-</neonView>
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.1">
+  <name>TurnoverChart_view</name>
+  <title></title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <dashletConfigurations>
+    <neonDashletConfiguration>
+      <name>TurnoverDashlet</name>
+      <title>Turnover</title>
+      <fragment>Turnover/full</fragment>
+      <singleton v="true" />
+      <storeRoles>
+        <element>INTERNAL_ADMINISTRATOR</element>
+        <element>INTERNAL_DASHBOARDSTOREADMIN</element>
+      </storeRoles>
+      <icon>VAADIN:CHART</icon>
+      <categories>
+        <neonDashletCategory>
+          <name>turnover</name>
+          <title>Turnover</title>
+        </neonDashletCategory>
+      </categories>
+    </neonDashletConfiguration>
+  </dashletConfigurations>
+  <layout>
+    <groupLayout>
+      <name>layout</name>
+    </groupLayout>
+  </layout>
+  <children>
+    <multiDataChartViewTemplate>
+      <name>ColumnChart</name>
+      <chartType>COLUMN</chartType>
+      <xAxis>X</xAxis>
+      <yAxis>Y</yAxis>
+      <parentField>PARENT</parentField>
+      <categoryField>CATEGORY</categoryField>
+      <entityField>#ENTITY</entityField>
+    </multiDataChartViewTemplate>
+    <multiDataChartViewTemplate>
+      <name>LineChart</name>
+      <chartType>LINE</chartType>
+      <xAxis>X</xAxis>
+      <yAxis>Y</yAxis>
+      <parentField>PARENT</parentField>
+      <categoryField>CATEGORY</categoryField>
+      <entityField>#ENTITY</entityField>
+    </multiDataChartViewTemplate>
+    <multiDataChartViewTemplate>
+      <name>AreaChart</name>
+      <chartType>AREA</chartType>
+      <xAxis>X</xAxis>
+      <yAxis>Y</yAxis>
+      <parentField>PARENT</parentField>
+      <categoryField>CATEGORY</categoryField>
+      <entityField>#ENTITY</entityField>
+    </multiDataChartViewTemplate>
+    <multiDataChartViewTemplate>
+      <name>BarChart</name>
+      <chartType>BAR</chartType>
+      <xAxis>X</xAxis>
+      <yAxis>Y</yAxis>
+      <parentField>PARENT</parentField>
+      <categoryField>CATEGORY</categoryField>
+      <entityField>#ENTITY</entityField>
+    </multiDataChartViewTemplate>
+    <multiDataChartViewTemplate>
+      <name>SplineChart</name>
+      <chartType>SPLINE</chartType>
+      <xAxis>X</xAxis>
+      <yAxis>Y</yAxis>
+      <parentField>PARENT</parentField>
+      <categoryField>CATEGORY</categoryField>
+      <entityField>#ENTITY</entityField>
+    </multiDataChartViewTemplate>
+    <neonViewReference>
+      <name>b0a9f719-3768-4ce5-9d32-e0f5fa5bf1eb</name>
+      <entityField>Turnover_tree</entityField>
+      <view>TurnoverTree_view</view>
+    </neonViewReference>
+  </children>
+</neonView>
diff --git a/neonView/TurnoverTree_view/TurnoverTree_view.aod b/neonView/TurnoverTree_view/TurnoverTree_view.aod
new file mode 100644
index 0000000000000000000000000000000000000000..caa1df078ff99337f41287ff7ba3a67511fade52
--- /dev/null
+++ b/neonView/TurnoverTree_view/TurnoverTree_view.aod
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.1">
+  <name>TurnoverTree_view</name>
+  <title>Tree</title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <boxLayout>
+      <name>layout</name>
+    </boxLayout>
+  </layout>
+  <children>
+    <treeTableViewTemplate>
+      <name>turnover</name>
+      <parentField>PARENT</parentField>
+      <entityField>#ENTITY</entityField>
+      <title>Tree</title>
+      <columns>
+        <neonTableColumn>
+          <name>3925d6aa-6a42-4cdc-84c3-e96ce2eff27b</name>
+          <entityField>GROUP</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>bc75d6a3-b226-4b28-8090-7142a264552a</name>
+          <entityField>FORECASTPRICE</entityField>
+        </neonTableColumn>
+        <neonTableColumn>
+          <name>d56ec015-556a-4fd6-bf43-c127b10b07bc</name>
+          <entityField>TURNOVERPRICE</entityField>
+        </neonTableColumn>
+      </columns>
+    </treeTableViewTemplate>
+  </children>
+</neonView>
diff --git a/process/Turnover_lib/Turnover_lib.aod b/process/Turnover_lib/Turnover_lib.aod
new file mode 100644
index 0000000000000000000000000000000000000000..28bacd7d8eaa8d0f3bd01ed7f72c229487b2372e
--- /dev/null
+++ b/process/Turnover_lib/Turnover_lib.aod
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.2.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.2.1">
+  <name>Turnover_lib</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <process>%aditoprj%/process/Turnover_lib/process.js</process>
+  <variants>
+    <element>LIBRARY</element>
+  </variants>
+</process>
diff --git a/process/Turnover_lib/process.js b/process/Turnover_lib/process.js
index d2128cd195542977845b87086fe6bc0da1f74520..0a3a6fa24c6d861ce90733c86d86ab15615b5338 100644
--- a/process/Turnover_lib/process.js
+++ b/process/Turnover_lib/process.js
@@ -1,62 +1,78 @@
+import("system.translate");
+import("KeywordRegistry_basic");
+import("Keyword_lib");
+import("system.SQLTYPES");
 import("system.db");
 import("system.neon");
 import("Context_lib");
 
 /**
- * Methods used for time tracking.
+ * Methods used for turnover data.
  * Do not create an instance of this!
  * 
  * @class
  */
-function Timetracking() {}
+function TurnoverUtil() {}
    
 /**
- * calculates the total time of all time trackings of the object
+ * get all turnover data.
  * 
- * @param {String} pRowId the rowId
+ * @param {Number} pMaxYear the maximum year
+ * @param {Number} pYearCount count of years to select
  * 
- * @return {Number} total time in minutes
+ * @return {String[][]} 
  */
-Timetracking.getTotalTrackingTime = function (pRowId)
+TurnoverUtil.getTurnoverData = function (pMaxYear, pYearCount)
 {
-    var objectId = ContextUtils.getCurrentContextId();
-    var totalMinutes = db.cell(SqlCondition.begin()
-        .andPrepare("TIMETRACKING.OBJECT_ID", objectId)
-        .andPrepare("TIMETRACKING.ROW_ID", pRowId)
-        .buildSql("select sum(MINUTES) from TIMETRACKING", "1=0"));
+    var turnoverCategory = translate.text('Turnover');
+
+    var minYear = pMaxYear - pYearCount + 1;
+
+    // load data
+    var data = db.table(SqlCondition.begin()
+                                    .and("SALESORDERITEM.OPTIONAL <> 1")
+                                    .andPrepare("SALESORDER.SALESORDERDATE", pMaxYear, "year(#) <= ?", SQLTYPES.INTEGER)
+                                    .andPrepare("SALESORDER.SALESORDERDATE", minYear, "year(#) >= ?", SQLTYPES.INTEGER)
+                                    .buildSql("select '" + turnoverCategory + "', year(SALESORDERDATE) yearNum, month(SALESORDERDATE) monthNum, SALESORDERITEM.DISCOUNT discount, SALESORDERITEM.VAT vat, SALESORDERITEM.PRICE price, sum(SALESORDERITEM.QUANTITY) quantity, SALESORDERITEM.GROUPCODEID prodGroup, (" + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.productGroupcode(), "SALESORDERITEM.GROUPCODEID") + ") prodGroupName \n\
+                                                from SALESORDER  \n\
+                                                join SALESORDERITEM on SALESORDERITEM.SALESORDER_ID = SALESORDER.SALESORDERID", "1=2", "group by year(SALESORDERDATE), month(SALESORDERDATE), SALESORDERITEM.GROUPCODEID, SALESORDERITEM.DISCOUNT, SALESORDERITEM.VAT, SALESORDERITEM.PRICE \n\
+                                                order by yearNum, monthNum "));
     
-    return Number(totalMinutes);
+    return data;
 }
 
 /**
- * Create a new time tracking
+ * get forecast data
  * 
- * @param {String} pRowId the rowId
+ * @param {Number} pMaxYear the maximum year
+ * @param {Number} pYearCount count of years to select
  * 
- * @return {Number} total time in minutes
+ * @return {String[][]} 
  */
-Timetracking.createNewTimeTracking = function (pRowId)
+TurnoverUtil.getForecastData = function (pMaxYear, pYearCount)
 {
-    var objectId = ContextUtils.getCurrentContextId();
-    var params = {
-        "ObjectId_param" : objectId,
-        "RowId_param" : pRowId
-    };
+    var forecastCategory = translate.text('Forecast');
+
+    var minYear = pMaxYear - pYearCount + 1;
+
+    // load data
+    var data = db.table(SqlCondition.begin()
+                                    .andPrepare("SALESPROJECT_FORECAST.DATE_START", pMaxYear, "year(#) <= ?", SQLTYPES.INTEGER)
+                                    .andPrepare("SALESPROJECT_FORECAST.DATE_START", minYear, "year(#) >= ?", SQLTYPES.INTEGER)
+                                    .buildSql("select '" + forecastCategory + "', year(DATE_START) yearNum, month(DATE_START) monthNum, 0 discount, 0 vat, sum(VOLUME * 1000) price, 1 quantity, GROUPCODE prodGroup, (" + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.productGroupcode(), "GROUPCODE") + ") prodGroupName from SALESPROJECT_FORECAST", "1=2", " group by year(DATE_START), month(DATE_START), GROUPCODE order by yearNum, monthNum"))
     
-    neon.openContext("Timetracking", null, null, neon.OPERATINGSTATE_NEW, params);
+    return data;
 }
 
-/*
- * converts minutes tho hours and minuets. e.g. 105 to 1:45
+/**
+ * get turnover data
  * 
- * @param {integer} pMinutes req 
+ * @param {Number} pMaxYear the maximum year
+ * @param {Number} pYearCount count of years to select
  * 
- * @return {String} Hours:Minutes
+ * @return {String[][]} 
  */
-Timetracking.minutesToReadableHour = function(pMinutes) 
-{
-    var timeHour = parseInt(pMinutes / 60);
-    var minutes = parseInt(pMinutes % 60);
-    
-    return "" + timeHour + ":" + ((minutes <= 9) ? "0" + minutes : minutes);
+TurnoverUtil.getTurnoverAndForecastData = function (pMaxYear, pYearCount)
+{   
+    return TurnoverUtil.getTurnoverData(pMaxYear, pYearCount).concat(TurnoverUtil.getForecastData(pMaxYear, pYearCount));
 }
\ No newline at end of file
diff --git a/process/Util_lib/process.js b/process/Util_lib/process.js
index a09c5ac5bb0049ca0f665e12fa6f9cce0c82bb87..ddbb258a847462214bdf71f3c3870b3974d65e65 100644
--- a/process/Util_lib/process.js
+++ b/process/Util_lib/process.js
@@ -547,7 +547,10 @@ NumberSequencingUtils.getMaxUniqueNumber = function(pColumn, pTable, pCondition)
 function TreeUtils () {}
 
 /**
- * sorts an array in a way that a tree(-table) can be built
+ * sorts an array in a way that a tree(-table) can be built (parents are added before children)
+ * This function does not garantee that the order of the children stays the same. If you need this, use TreeUtils.treeOrderBy
+ * 
+ * consider the use of TreeUtils.treeOrderBy as it may be more performant, but it needs the layernumber of each row.
  * 
  * @param {Array} pArray two-dimensional array to sort
  * @param {Number} pUidIndex the index of the uid in a row
@@ -583,4 +586,32 @@ TreeUtils.sortArrayForTree = function (pArray, pUidIndex, pParentIdIndex)
     for (let i in rows)
         sortedArray[rows[i].index] = rows[i].data;
     return sortedArray;
+}
+
+/**
+ * like TreeUtils.sortArrayForTree, this function garantees that parents are added before children
+ * But it works in a different way based on the layer number.
+ * 
+ * It can also sort all children based on the given orderBys. For this you can Probvide an array of Indexes and direction (pOrderByIndexes)
+ *  
+ * @param {Array} pData two-dimensional array to sort
+ * @param {Number} pLayerIndex The index of the layernumber-Field
+ * @param {Array[][]} pOrderByIndexes Array containing arrays of [field-index, direction]. The direction can be true (desc) or false (asc).
+ * 
+ * @return {Array} the sorted array
+ */
+TreeUtils.treeOrderBy = function(pData, pLayerIndex, pOrderByIndexes)
+{
+    pOrderByIndexes = [[pLayerIndex, false]].concat(pOrderByIndexes)
+    
+    return pData.sort(function(pRow1, pRow2) 
+    {
+        for (let i = 0; i < pOrderByIndexes.length; i++) {
+            var orderBy = pOrderByIndexes[i];
+            if (pRow1[orderBy[0]] > pRow2[orderBy[0]]) return (orderBy[1] ? -1 : 1);
+            if (pRow1[orderBy[0]] < pRow2[orderBy[0]]) return (orderBy[1] ? 1 : -1);
+        }
+
+        return 0;
+    })
 }
\ No newline at end of file