diff --git a/entity/Turnover_entity/documentation.adoc b/entity/Turnover_entity/documentation.adoc index cf423b86bc2a151b237b0f04f7499918af7ec2d8..6c6f179cbc067b974b9f6cebbd36da8a5941c6c8 100644 --- a/entity/Turnover_entity/documentation.adoc +++ b/entity/Turnover_entity/documentation.adoc @@ -1,3 +1,6 @@ = Turnover -This entity provides charts to display the Turnover. \ No newline at end of file +This entity provides charts to display the Turnover. +This chart can show any data in a cumulative way: + * It loads the most specific data (e.g. Productgroups) and calculates the layers above (e.g. Productgroups -> Months -> years) + * And then it shows the most top layer (years) at the top. If you click on it, it drills down to the more specific layer (Months / Productgroups) \ 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 f8be0738cc3f1f21620f6de50751beac38a60d34..02befbe14cce3d34c0e60f50777da046c11bfe1f 100644 --- a/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js +++ b/entity/Turnover_entity/recordcontainers/jdito/contentProcess.js @@ -7,6 +7,26 @@ import("KeywordRegistry_basic"); import("Keyword_lib"); import("system.translate"); +/** + * Documentation: + * This chart can show any data in a cumulative way: + * It loads the most specific data (e.g. Productgroups) and calculates the layers above (e.g. Productgroups -> Months -> years) + * And then it shows the most top layer (years) at the top. If you click on it, it drills down to the more specific layer (Months / Productgroups) + * + * Technic: + * 1. Loading data + * The data is loaded via selects in the TurnoverUtil. (You may change this in your porjects to your liking) + * The select has to provide at least the following fields: + * - Type (e.g. "Forecast" / "Turnover") this will split the data into different groups which are displayed ina a seperate color (connected to the chart viewtemplate as "Category" + * - For each layer an ID (e.g. for the years layer a year-number, for the Productgroups the productgroup keyid,...) + * - Optionally: if the displayvalue should be different: a display value for the id. + * The X-axis will display either the ID or the disply value + * - The Value (used as Y-Value) which should be a number + * + * ... (see next comment block) + */ + + var turnoverCategory = translate.text('Turnover'); var forecastCategory = translate.text('Forecast'); @@ -21,6 +41,7 @@ var salesprojectId = vars.exists("$param.SalesprojectId_param") && vars.get("$pa var data = TurnoverUtil.getTurnoverAndForecastData(maxYear, yearCountToShow, showForecast, showTurnover, salesprojectId); +// this object is for better code with readable names to access the data-fields var columns = { type: 0, year: 1, @@ -38,12 +59,22 @@ var countData = {} var monthDate; -// add all months for all years +/** + * 2. Special treatment for some layers + * Some data needs special treatment. You may ommit these if you don't need it. + * - As there should each month of a year be displayed, this for loops add empty (0.0) datasets for each month. + * (note that it is done for each month to set it initally to 0.0) + * + * NOTE: the _addCount function will be explaned later + * + * ... + */ for (let y = minYear; y <= maxYear; y++) { for (let m = 0; m < 12; m++) { - monthDate = new Date(y, m-1); + // load the display value for the months + monthDate = new Date(y, m); monthDate = datetime.toDate(monthDate.getTime(), "MMM yyyy", "UTC"); if (showForecast) @@ -54,9 +85,21 @@ for (let y = minYear; y <= maxYear; y++) } } +/** + * 3. iterate through all data and add it to the chart + * - this is done via _addCount-calls + * - Note that for turnover MoneyUtils.getGross is called. This is needed because the raw data does provides vat, price, quantity and discount but not the final gross-price + * You may ommit this if it is not needed by your project + * + * + * NOTE: the _addCount function will be explaned later + * + * ... + */ data.forEach(function(row) { - monthDate = new Date(row[columns.year], row[columns.month]-1); + // load the display value for the months + monthDate = new Date(row[columns.year], row[columns.month]); monthDate = datetime.toDate(monthDate.getTime(), "MMM yyyy", "UTC"); switch(row[columns.type]) @@ -75,50 +118,92 @@ data.forEach(function(row) } }); +/** + * 4. iterate through the final counts - generate chart + * - this is done via simple push to the final chartData + */ for (let key in countData) { var countDataSet = countData[key]; chartData.push([key, countDataSet.parent, countDataSet.category, countDataSet.x, countDataSet.count]); } +// return the final chart result.object(chartData); /** - * add the counts to countData for the given key and value + * 5. _addCount + * - It counts the final values for each layer. So if you put in: (simplified) + * [year1, month5, product10, 50.8] + * it counts +50.8 for each layer: + * year1; += 50.8 + * year1;month5; += 50.8 + * year1;month5;product10; += 50.8 + * + * This values are all stored in the "countData" object and the keys of it are later used as UID. + * The Keys just consist of the concatenated id's mentioned in 1. + * + * You can provide any count of keys so if you need another layer, just add it to the data (1.) and add the keyid (or [keyid, keydisplayvalue]) to the _addCount-calls appended to the array provided as first parameter + * * @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 the Category + * e.g. + * [ + * category, + * year, + * [ + * month(number), + * monthName(displayValue) + * ], + * [ + * productGroupcodeId, + * productGroupcodeName(displayValue) + * ] + * ] + * This will lead to 3 layers: year -> month -> productGroup + * * @param {float} pValue the value to display */ function _addCount(pKeys, pValue) { var key = ""; + // iterate through all keys (e.g. through each layer) and count for each of them seperately for (let i = 0; i < pKeys.length; i++) { let keyId; let keyName; + // if the key type is not "object" it is a string ("object" means Array of ["id", "displayValue"], "string" means only "id" if (typeof pKeys[i] != "object") { + // add key as id and display value keyId = pKeys[i]; keyName = pKeys[i]; } - else // handle array: first is id seccond is name for X-value + else { + // handle array: first is id seccond is name for X-value keyId = pKeys[i][0]; keyName = pKeys[i][1]; } var parent = key; + // if we are first or second: we are category or the top layer -> we have no parent if (i < 2) { parent = "" } - + + // concatenate the previous (parent) key with the new one to get a new unique id key += ";" + keyId; + // if we are not category if (i > 0) { + // add the data to the count-object if (countData[key] == undefined) { + // if the key was not added before create it with initial value 0.0 countData[key] = {parent: parent, count: 0.0, category: pKeys[0], x: keyName}; // keys[0] is the category } - + + // count countData[key].count += parseFloat(pValue); } }