From 725f1d17034aa30320883d9a7c8613ae2fe6df48 Mon Sep 17 00:00:00 2001 From: Stefanos Hadjipetrou Date: Tue, 11 Jun 2024 16:33:07 +0300 Subject: [PATCH] feat: feedback changes --- src/config/mapping/budgets/sankey.json | 7 +- src/config/mapping/budgets/table.json | 8 +- src/config/mapping/expenditures/heatmap.json | 1 + src/controllers/allocations.controller.ts | 28 ++--- src/controllers/budgets.controller.ts | 126 ++++++++++++------- src/controllers/expenditures.controller.ts | 14 ++- 6 files changed, 110 insertions(+), 74 deletions(-) diff --git a/src/config/mapping/budgets/sankey.json b/src/config/mapping/budgets/sankey.json index a060d46..babdc02 100644 --- a/src/config/mapping/budgets/sankey.json +++ b/src/config/mapping/budgets/sankey.json @@ -1,9 +1,10 @@ { "dataPath": "value", - "level1Field": ".parent.name", - "level2Field": ".name", + "level1Field": "financialCategory.parent.parent.name", + "level2Field": "financialCategory.parent.name", + "level3Field": "financialCategory.name", "valueField": "value", "cycle": "periodFrom", "nodeColors": ["#252C34", "#252C34", "#252C34"], - "urlParams": "?$apply=filter(contains(indicatorName, 'reference') AND financialDataSet eq 'GrantBudget_ReferenceRate')/groupby((/parent/name,/name),aggregate(plannedAmount with sum as value))" + "urlParams": "?$apply=filter(contains(indicatorName, 'reference') AND financialDataSet eq 'GrantBudget_ReferenceRate')/groupby((financialCategory/name,financialCategory/parent/name,financialCategory/parent/parent/name),aggregate(plannedAmount with sum as value))" } diff --git a/src/config/mapping/budgets/table.json b/src/config/mapping/budgets/table.json index 0e1b4f6..82daa20 100644 --- a/src/config/mapping/budgets/table.json +++ b/src/config/mapping/budgets/table.json @@ -1,9 +1,9 @@ { "dataPath": "value", - "parentField": ".parent.name", - "childrenField": ".name", + "level1Field": "financialCategory.parent.parent.name", + "level2Field": "financialCategory.parent.name", + "level3Field": "financialCategory.name", "valueField": "value", "cycle": "periodFrom", - "countField": "count", - "urlParams": "?$apply=filter(contains(indicatorName, 'reference') AND financialDataSet eq 'GrantBudget_ReferenceRate')/groupby((/parent/name,/name),aggregate(plannedAmount with sum as value,implementationPeriod/grantId with countdistinct as count))" + "urlParams": "?$apply=filter(contains(indicatorName, 'reference') AND financialDataSet eq 'GrantBudget_ReferenceRate')/groupby((financialCategory/name,financialCategory/parent/name,financialCategory/parent/parent/name),aggregate(plannedAmount with sum as value))" } diff --git a/src/config/mapping/expenditures/heatmap.json b/src/config/mapping/expenditures/heatmap.json index 5dddb53..be7c26a 100644 --- a/src/config/mapping/expenditures/heatmap.json +++ b/src/config/mapping/expenditures/heatmap.json @@ -6,6 +6,7 @@ "urlParams": "?$apply=filter(financialDataSet eq 'Expenditure_Intervention_ReferenceRate' AND isLatestReported eq true)/groupby((,),aggregate(actualAmountCumulative with sum as value1,plannedAmountCumulative with sum as value2))", "fields": { "principalRecipient": "implementationPeriod/grant/principalRecipient/name", + "principalRecipientSubType": "implementationPeriod/grant/principalRecipient/parent/name", "principalRecipientType": "implementationPeriod/grant/principalRecipient/type/name", "component": "/parent/parent/name" } diff --git a/src/controllers/allocations.controller.ts b/src/controllers/allocations.controller.ts index f352116..e78ba66 100644 --- a/src/controllers/allocations.controller.ts +++ b/src/controllers/allocations.controller.ts @@ -417,28 +417,16 @@ export class AllocationsController { async allocationsRadialChartInLocation( @param.path.string('countryCode') countryCode: string, ) { - let filterString = AllocationRadialFieldsMapping.urlParams; - if (this.req.query.cycle && countryCode) { - filterString = filterString.replace( - '', - ` AND ${AllocationRadialFieldsMapping.cycle} eq '${this.req.query.cycle}' AND ${AllocationRadialFieldsMapping.countryCode} eq '${countryCode}'`, - ); - } else if (this.req.query.cycle && !countryCode) { - filterString = filterString.replace( - '', - ` AND ${AllocationRadialFieldsMapping.cycle} eq '${this.req.query.cycle}'`, - ); - } else if (!this.req.query.cycle && countryCode) { - filterString = filterString.replace( - '', - ` AND ${AllocationRadialFieldsMapping.countryCode} eq '${countryCode}'`, - ); - } else { - filterString = filterString.replace('', ''); - } + let filterString = filterFinancialIndicators( + {...this.req.query, geographies: countryCode}, + AllocationRadialFieldsMapping.urlParams, + ); + const url = `${urls.FINANCIAL_INDICATORS}/${filterString}`; - return getAllocationsData(url); + const data = await getAllocationsData(url); + + return {data}; } @get('/allocations/cycles') diff --git a/src/controllers/budgets.controller.ts b/src/controllers/budgets.controller.ts index 9ad02a5..8ae5626 100644 --- a/src/controllers/budgets.controller.ts +++ b/src/controllers/budgets.controller.ts @@ -123,15 +123,12 @@ export class BudgetsController { .catch(handleDataApiError); } - @get('/budgets/sankey/{componentField}') + @get('/budgets/sankey') @response(200) - async sankey(@param.path.string('componentField') componentField: string) { + async sankey() { const filterString = filterFinancialIndicators( this.req.query, - BudgetsSankeyFieldsMapping.urlParams.replace( - //g, - componentField, - ), + BudgetsSankeyFieldsMapping.urlParams, ); const url = `${urls.FINANCIAL_INDICATORS}/${filterString}`; @@ -157,10 +154,7 @@ export class BudgetsController { }; const groupedDataLevel1 = _.groupBy( rawData, - BudgetsSankeyFieldsMapping.level1Field.replace( - '', - componentField, - ), + BudgetsSankeyFieldsMapping.level1Field, ); _.forEach(groupedDataLevel1, (level1Data, level1) => { data.nodes.push({ @@ -175,12 +169,10 @@ export class BudgetsController { target: level1, value: _.sumBy(level1Data, BudgetsSankeyFieldsMapping.valueField), }); + const groupedDataLevel2 = _.groupBy( level1Data, - BudgetsSankeyFieldsMapping.level2Field.replace( - '', - componentField, - ), + BudgetsSankeyFieldsMapping.level2Field, ); _.forEach(groupedDataLevel2, (level2Data, level2) => { const level2inLevel1 = _.find(data.nodes, { @@ -199,6 +191,32 @@ export class BudgetsController { target: level2inLevel1 ? `${level2}1` : level2, value: _.sumBy(level2Data, BudgetsSankeyFieldsMapping.valueField), }); + + const groupedDataLevel3 = _.groupBy( + level2Data, + BudgetsSankeyFieldsMapping.level3Field, + ); + _.forEach(groupedDataLevel3, (level3Data, level3) => { + const level3inLevel2 = _.find(data.nodes, { + name: level3, + level: 2, + }); + data.nodes.push({ + name: level3inLevel2 ? `${level3}1` : level3, + level: 3, + itemStyle: { + color: BudgetsSankeyFieldsMapping.nodeColors[2], + }, + }); + data.links.push({ + source: level2, + target: level3inLevel2 ? `${level3}1` : level3, + value: _.sumBy( + level3Data, + BudgetsSankeyFieldsMapping.valueField, + ), + }); + }); }); }); data.nodes = _.uniqBy(data.nodes, 'name'); @@ -266,15 +284,12 @@ export class BudgetsController { .catch(handleDataApiError); } - @get('/budgets/table/{componentField}') + @get('/budgets/table') @response(200) - async table(@param.path.string('componentField') componentField: string) { + async table() { const filterString = filterFinancialIndicators( this.req.query, - BudgetsTableFieldsMapping.urlParams.replace( - //g, - componentField, - ), + BudgetsTableFieldsMapping.urlParams, ); const url = `${urls.FINANCIAL_INDICATORS}/${filterString}`; @@ -286,45 +301,64 @@ export class BudgetsController { BudgetsTableFieldsMapping.dataPath, [], ); - const groupedByParent = _.groupBy( + const groupedByLevel1 = _.groupBy( rawData, - BudgetsTableFieldsMapping.parentField.replace( - '', - componentField, - ), + BudgetsTableFieldsMapping.level1Field, ); const data: { name: string; - grants: number; amount: number; _children: { name: string; - grants: number; amount: number; + _children: { + name: string; + amount: number; + }[]; }[]; }[] = []; - _.forEach(groupedByParent, (parentData, parent) => { - const children = parentData.map((child: any) => { - return { - name: _.get( - child, - BudgetsTableFieldsMapping.childrenField.replace( - '', - componentField, - ), - '', - ), - grants: _.get(child, BudgetsTableFieldsMapping.countField, 0), - amount: _.get(child, BudgetsTableFieldsMapping.valueField, 0), - }; - }); + _.forEach(groupedByLevel1, (level1Data, level1) => { + const grouepdByLevel2 = _.groupBy( + level1Data, + BudgetsTableFieldsMapping.level2Field, + ); + const level1Amount = _.sumBy( + level1Data, + BudgetsTableFieldsMapping.valueField, + ); + const level1Children = _.map( + grouepdByLevel2, + (level2Data, level2) => { + const groupedByLevel3 = _.groupBy( + level2Data, + BudgetsTableFieldsMapping.level3Field, + ); + const level2Amount = _.sumBy( + level2Data, + BudgetsTableFieldsMapping.valueField, + ); + return { + name: level2, + amount: level2Amount, + _children: _.map(groupedByLevel3, (level3Data, level3) => { + const level3Amount = _.sumBy( + level3Data, + BudgetsTableFieldsMapping.valueField, + ); + return { + name: level3, + amount: level3Amount, + }; + }), + }; + }, + ); data.push({ - name: parent, - grants: _.sumBy(children, 'grants'), - amount: _.sumBy(children, 'amount'), - _children: children, + name: level1, + amount: level1Amount, + _children: level1Children, }); }); diff --git a/src/controllers/expenditures.controller.ts b/src/controllers/expenditures.controller.ts index adf2651..5813370 100644 --- a/src/controllers/expenditures.controller.ts +++ b/src/controllers/expenditures.controller.ts @@ -23,6 +23,7 @@ export class ExpendituresController { let filterString = ExpendituresHeatmapMapping.urlParams; let rowField = ''; let subRowField = ''; + let subSubRowField = ''; let columnField = ''; let subColumnField = ''; if (row.split(',').length > 1) { @@ -36,6 +37,13 @@ export class ExpendituresController { `fields["${row.split(',')[1]}"]`, ExpendituresHeatmapMapping.fields.principalRecipient, ); + if (row.split(',').length > 2) { + subSubRowField = _.get( + ExpendituresHeatmapMapping, + `fields["${row.split(',')[2]}"]`, + ExpendituresHeatmapMapping.fields.principalRecipient, + ); + } } else { rowField = _.get( ExpendituresHeatmapMapping, @@ -61,9 +69,12 @@ export class ExpendituresController { ExpendituresHeatmapMapping.fields.component, ).replace(//g, componentField); } + const rowFieldArray = [rowField, subRowField, subSubRowField].filter( + item => item.length > 0, + ); filterString = filterString.replace( '', - [rowField, subRowField].join(',').replace(/(^,)|(,$)/g, ''), + rowFieldArray.join(',').replace(/(^,)|(,$)/g, ''), ); filterString = filterString.replace( '', @@ -75,6 +86,7 @@ export class ExpendituresController { rowField = rowField.replace(/\//g, '.'); subRowField = subRowField.replace(/\//g, '.'); + subSubRowField = subSubRowField.replace(/\//g, '.'); columnField = columnField.replace(/\//g, '.'); subColumnField = subColumnField.replace(/\//g, '.');