From 1d425198416906a0ea31e8a0344841760bad84f2 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 30 Aug 2024 18:18:54 +0300 Subject: [PATCH 1/5] Indicator Report issue --- .../4.0/Add-Indicator-Report-Visibility.xml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 amp/xmlpatches/4.0/Add-Indicator-Report-Visibility.xml diff --git a/amp/xmlpatches/4.0/Add-Indicator-Report-Visibility.xml b/amp/xmlpatches/4.0/Add-Indicator-Report-Visibility.xml new file mode 100644 index 00000000000..d278f727f8f --- /dev/null +++ b/amp/xmlpatches/4.0/Add-Indicator-Report-Visibility.xml @@ -0,0 +1,24 @@ + + + AMP-30863 + Add indicator report to visibility template + bmokandu + + + + From 8505599992092e699d79194ba3f3c618022eff19 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Mon, 2 Sep 2024 04:20:11 +0300 Subject: [PATCH 2/5] Indicator Report issue --- .../amp/nireports/runtime/NiCell.java | 67 +++++++++++++------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java index 59468737056..096ac9f9afd 100644 --- a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java +++ b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java @@ -1,17 +1,23 @@ package org.dgfoundation.amp.nireports.runtime; +import org.apache.commons.lang3.StringUtils; import org.dgfoundation.amp.algo.AmpCollections; import org.dgfoundation.amp.nireports.Cell; import org.dgfoundation.amp.nireports.NiUtils; import org.dgfoundation.amp.nireports.NumberedCell; +import org.dgfoundation.amp.nireports.PercentageTextCell; import org.dgfoundation.amp.nireports.schema.IdsAcceptor; import org.dgfoundation.amp.nireports.schema.NiDimension.Coordinate; import org.dgfoundation.amp.nireports.schema.NiDimension.NiDimensionUsage; import org.dgfoundation.amp.nireports.schema.NiReportedEntity; +import org.digijava.kernel.persistence.PersistenceManager; +import org.hibernate.Session; +import org.hibernate.query.Query; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; +import java.util.stream.Collectors; /** * An immutable {@link Cell} wrapper which has identity and is not shared between reports or columns. @@ -25,31 +31,31 @@ public class NiCell implements Comparable { * the entity to which this instance belongs */ protected final NiReportedEntity entity; - + /** * the enclosed raw cell */ protected final Cell cell; - + /** * whether this is an undefined cell (e.g. one with a negative entityId) */ protected final boolean undefinedCell; - + /** * the per-NiDimensionUsage coordinates-and-percentages */ protected final HierarchiesTracker hiersTracker; - + /** * the upstream-passed filters during the "filters as collapsed hierarchies" phase */ protected final Map> passedFilters; - + public NiCell(Cell cell, NiReportedEntity entity, HierarchiesTracker hiersTracker) { this(cell, entity, hiersTracker, Collections.emptyMap()); } - + public NiCell(Cell cell, NiReportedEntity entity, HierarchiesTracker hiersTracker, Map> passedFilters) { NiUtils.failIf(cell == null, "not allowed to have NiCells without contents"); this.cell = cell; @@ -61,26 +67,43 @@ public NiCell(Cell cell, NiReportedEntity entity, HierarchiesTracker hiersTra /** * creates a new instance, obtained by advancing the hierarchy and passed filters of the given cell - * + * * @param newContents the cell to embed in the new instance. Unless you are doing some voodoo, this would equal {@link #cell} * @param splitCell the splitter cell used to advance {@link #hiersTracker} * @param acceptors might be null, in which case {@link #passedFilters} won't be advanced * @return */ public NiCell advanceHierarchy(Cell newContents, Cell splitCell, Map acceptors) { +// return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(splitCell), mergeAcceptors(acceptors)); + return advanceHierachyFixForIndicators(newContents,splitCell,acceptors); + } + + private NiCell advanceHierachyFixForIndicators(Cell newContents, Cell splitCell, Map acceptors) + { + List cellNames = newContents.coordinates.keySet().stream().map(x->x.instanceName).collect(Collectors.toList()); + if (!cellNames.isEmpty() && (StringUtils.containsIgnoreCase(cellNames.get(0),"indicator"))) { + PercentageTextCell cell = (PercentageTextCell) splitCell; + cell.setPercentage(BigDecimal.valueOf(1)); + Session session = PersistenceManager.getRequestDBSession(); +// String sql= "SELECT t.id" +// Query query = + return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(cell), mergeAcceptors(acceptors)); + + } return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(splitCell), mergeAcceptors(acceptors)); + } - + /** * computes a map of acceptors which is the result of merging this cell's {@link #passedFilters} with the given acceptors. - * In case both the cell and the given acceptors contain a mapping for a given {@link NiDimensionUsage}, the given map has priority + * In case both the cell and the given acceptors contain a mapping for a given {@link NiDimensionUsage}, the given map has priority * @param acceptors * @return */ public Map> mergeAcceptors(Map acceptors) { if (acceptors == null || acceptors.isEmpty()) return passedFilters; - + Map> res = new HashMap<>(); passedFilters.forEach((dimUsg, oldList) -> { List resList = acceptors.containsKey(dimUsg) ? AmpCollections.cat(oldList, acceptors.get(dimUsg)) : oldList; @@ -89,10 +112,10 @@ public Map> mergeAcceptors(Map getEntity() { return entity; } @@ -100,11 +123,11 @@ public NiReportedEntity getEntity() { public Cell getCell() { return cell; } - + public long getMainId() { return cell.activityId; } - + public boolean isUndefinedCell() { return this.undefinedCell; } @@ -112,14 +135,14 @@ public boolean isUndefinedCell() { public Map> getPassedFilters() { return this.passedFilters; } - + /** * returns true IFF this cell passes the filters of a given splitCell by consulting against the stored {@link #passedFilters} * @param splitCell * @return */ public boolean passesFilters(Cell splitCell) { -// boolean debug = this.cell instanceof TextCell; +// boolean debug = this.cell instanceof TextCell; // if (debug) { // System.err.format("testing passesFilters for id %d, <%s>, passedFilters <%s>...", System.identityHashCode(this), this.cell, this.passedFilters); // } @@ -144,7 +167,7 @@ public boolean passesFilters(Cell splitCell) { public BigDecimal calculatePercentage() { return hiersTracker.calculatePercentage(getEntity().getBehaviour().getHierarchiesListener()).setScale(6, RoundingMode.HALF_EVEN); //TODO: maybe use the per-report precision setting } - + @Override public int compareTo(NiCell o) { if (undefinedCell && o.undefinedCell) @@ -154,11 +177,11 @@ public int compareTo(NiCell o) { return 1; return -1; } - + // gone till here -> neither of the cells is undefined return cell.compareTo(o.cell); } - + /** * computes, taking into account percentages, the amount stored in this cell. In case this NiCell is not holding a NumberedCell, the function will crash OR return a meaningless result */ @@ -167,15 +190,15 @@ public BigDecimal getAmount() { BigDecimal value = ((NumberedCell) cell).getAmount().multiply(percentage); return value; } - + public String getDisplayedValue() { return cell.getDisplayedValue(); } - + public HierarchiesTracker getHiersTracker() { return this.hiersTracker; } - + @Override public String toString() { return String.format("%s %s", cell.getDisplayedValue(), hiersTracker == null ? "" : hiersTracker.toString()); From 4b5f6f40e8bae9bc7cc1880df8d4a4e2149d4d04 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Mon, 2 Sep 2024 13:23:42 +0300 Subject: [PATCH 3/5] Indicator Report issue --- .../amp/nireports/PercentageTextCell.java | 21 ++++--- .../amp/nireports/runtime/NiCell.java | 58 ++++++++++++++++--- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/PercentageTextCell.java b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/PercentageTextCell.java index ce3191b8258..59f481ac1a5 100644 --- a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/PercentageTextCell.java +++ b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/PercentageTextCell.java @@ -8,24 +8,24 @@ import java.util.Optional; /** - * A {@link Cell} which holds a text and a fractional number called "percentage". + * A {@link Cell} which holds a text and a fractional number called "percentage". * The MetaInfo is always empty, while the coordinates are either empty or with a single entry, depending on the #mainLevel) * @author Dolghier Constantin * */ public final class PercentageTextCell extends Cell { - + /** * DUMMY SOZO * the non-null fractional number. 0.0 <= percentage <= 1.0 */ - public final BigDecimal percentage; - + public BigDecimal percentage; + /** * the non-null text */ public final String text; - + /** * constructs an instance with the given parameters. Will throw a {@link RuntimeException} (or one of its subclasses) in case it is given an invalid input * @param text @@ -44,11 +44,16 @@ public PercentageTextCell(String text, long activityId, long entityId, Optional< this.text = text; } + public void setPercentage(BigDecimal percentage) + { + this.percentage=percentage; + } + @Override public PercentageTextCell changeOwnerId(long newActivityId) { return new PercentageTextCell(this.text, newActivityId, this.entityId, this.mainLevel, this.percentage); } - + @Override public MetaInfoSet getMetaInfo() { return MetaInfoSet.empty(); @@ -58,7 +63,7 @@ public MetaInfoSet getMetaInfo() { public BigDecimal getPercentage() { return percentage; } - + @Override public int compareTo(Object o) { PercentageTextCell ptc = (PercentageTextCell) o; @@ -69,7 +74,7 @@ public int compareTo(Object o) { delta = Long.compare(activityId, ptc.activityId); return delta; } - + @Override public String toString() { String entityStr = String.format(", eid: %d", this.entityId); diff --git a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java index 096ac9f9afd..a97eac557d5 100644 --- a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java +++ b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java @@ -2,6 +2,8 @@ import org.apache.commons.lang3.StringUtils; import org.dgfoundation.amp.algo.AmpCollections; +import org.dgfoundation.amp.ar.viewfetcher.RsInfo; +import org.dgfoundation.amp.ar.viewfetcher.SQLUtils; import org.dgfoundation.amp.nireports.Cell; import org.dgfoundation.amp.nireports.NiUtils; import org.dgfoundation.amp.nireports.NumberedCell; @@ -12,10 +14,14 @@ import org.dgfoundation.amp.nireports.schema.NiReportedEntity; import org.digijava.kernel.persistence.PersistenceManager; import org.hibernate.Session; +import org.hibernate.jdbc.Work; import org.hibernate.query.Query; import java.math.BigDecimal; import java.math.RoundingMode; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; @@ -75,18 +81,56 @@ public NiCell(Cell cell, NiReportedEntity entity, HierarchiesTracker hiersTra */ public NiCell advanceHierarchy(Cell newContents, Cell splitCell, Map acceptors) { // return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(splitCell), mergeAcceptors(acceptors)); - return advanceHierachyFixForIndicators(newContents,splitCell,acceptors); + return advanceHierachyWithAVeryDirtyFixForIndicators(newContents,splitCell,acceptors); } + /** + *Offers a dirty fix for indicators splitting as we look for a better solution + * The problem was the report splits indicator values by percentage associated with the programs when MGDS Theme 1 is a hieararchy + * Ensures the indicator values are either 100% or 0 percent and avoid splitting by pillar + */ - private NiCell advanceHierachyFixForIndicators(Cell newContents, Cell splitCell, Map acceptors) + private NiCell advanceHierachyWithAVeryDirtyFixForIndicators(Cell newContents, Cell splitCell, Map acceptors) { - List cellNames = newContents.coordinates.keySet().stream().map(x->x.instanceName).collect(Collectors.toList()); + List cellNames = newContents.coordinates.keySet().stream().map(x->x.instanceName).collect(Collectors.toList()); + Long activityId = newContents.activityId; if (!cellNames.isEmpty() && (StringUtils.containsIgnoreCase(cellNames.get(0),"indicator"))) { - PercentageTextCell cell = (PercentageTextCell) splitCell; + List ids = newContents.coordinates.values().stream().map(x->x.id).collect(Collectors.toList()); + PercentageTextCell cell = (PercentageTextCell) splitCell; cell.setPercentage(BigDecimal.valueOf(1)); - Session session = PersistenceManager.getRequestDBSession(); -// String sql= "SELECT t.id" -// Query query = + List levelNames = new ArrayList<>(); + if (cell.mainLevel.isPresent()) { + + String mainLevelName = cell.mainLevel.get().dimensionUsage.instanceName; + int mainLevel = cell.mainLevel.get().level; + if (StringUtils.equalsIgnoreCase(mainLevelName, "national plan objective") && (mainLevel == 1)) { + String sql = String.format("SELECT nol1.name as name FROM v_nationalobjectives_level_1 nol1 WHERE nol1.amp_activity_id = %d", activityId); + PersistenceManager.getSession().doWork(connection -> { + RsInfo rsi = SQLUtils.rawRunQuery(connection, sql, null); + ResultSet rs = rsi.rs; + while (rs.next()) { + String levelName = rs.getString("name"); + levelNames.add(levelName); + } + }); + + } + } + if (!ids.isEmpty()) { + String sql = String.format("SELECT ind.indicator_id as id, th.name as theme_name FROM amp_indicator ind JOIN amp_theme th ON ind.program_id=th.amp_theme_id WHERE ind.indicator_id = %d",ids.get(0)); + PersistenceManager.getSession().doWork(connection -> { + RsInfo rsi = SQLUtils.rawRunQuery(connection, sql, null); + ResultSet rs = rsi.rs; + while (rs.next()) { + String programName = rs.getString("theme_name"); + if (levelNames.contains(programName) && !StringUtils.equalsIgnoreCase(programName,cell.text)) + { + cell.setPercentage(BigDecimal.ZERO); + } + + + } + }); + } return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(cell), mergeAcceptors(acceptors)); } From 1239a4e62eeb559d7a93e5709984454a968502f0 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Mon, 2 Sep 2024 13:28:52 +0300 Subject: [PATCH 4/5] Indicator Report issue --- .../src/org/dgfoundation/amp/nireports/runtime/NiCell.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java index a97eac557d5..64bd68b7d42 100644 --- a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java +++ b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java @@ -102,8 +102,8 @@ private NiCell advanceHierachyWithAVeryDirtyFixForIndicators(Cell newContents, C String mainLevelName = cell.mainLevel.get().dimensionUsage.instanceName; int mainLevel = cell.mainLevel.get().level; - if (StringUtils.equalsIgnoreCase(mainLevelName, "national plan objective") && (mainLevel == 1)) { - String sql = String.format("SELECT nol1.name as name FROM v_nationalobjectives_level_1 nol1 WHERE nol1.amp_activity_id = %d", activityId); + if (StringUtils.equalsIgnoreCase(mainLevelName, "national plan objective")) { + String sql = String.format("SELECT nol.name as name FROM v_nationalobjectives_level_%d nol WHERE nol.amp_activity_id = %d",mainLevel, activityId); PersistenceManager.getSession().doWork(connection -> { RsInfo rsi = SQLUtils.rawRunQuery(connection, sql, null); ResultSet rs = rsi.rs; From 7cfed4c06ce6925e719c76d5058e972136c20115 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Wed, 4 Sep 2024 20:40:01 +0300 Subject: [PATCH 5/5] Indicator Report issue --- .../amp/nireports/runtime/NiCell.java | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java index 64bd68b7d42..b1b36e61355 100644 --- a/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java +++ b/amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java @@ -91,53 +91,65 @@ public NiCell advanceHierarchy(Cell newContents, Cell splitCell, Map acceptors) { - List cellNames = newContents.coordinates.keySet().stream().map(x->x.instanceName).collect(Collectors.toList()); + List cellNames = newContents.coordinates.keySet().stream().map(x->x.instanceName.toLowerCase()).collect(Collectors.toList()); Long activityId = newContents.activityId; - if (!cellNames.isEmpty() && (StringUtils.containsIgnoreCase(cellNames.get(0),"indicator"))) { + if (!cellNames.isEmpty() && cellNames.contains("indicator")) { List ids = newContents.coordinates.values().stream().map(x->x.id).collect(Collectors.toList()); - PercentageTextCell cell = (PercentageTextCell) splitCell; + PercentageTextCell cell = convertCell(splitCell); + if(cell!=null) { cell.setPercentage(BigDecimal.valueOf(1)); List levelNames = new ArrayList<>(); - if (cell.mainLevel.isPresent()) { + if (cell.mainLevel.isPresent()) { + + String mainLevelName = cell.mainLevel.get().dimensionUsage.instanceName; + int mainLevel = cell.mainLevel.get().level; + if (StringUtils.equalsIgnoreCase(mainLevelName, "national plan objective")) { + String sql = String.format("SELECT nol.name as name FROM v_nationalobjectives_level_%d nol WHERE nol.amp_activity_id = %d", mainLevel, activityId); + PersistenceManager.getSession().doWork(connection -> { + RsInfo rsi = SQLUtils.rawRunQuery(connection, sql, null); + ResultSet rs = rsi.rs; + while (rs.next()) { + String levelName = rs.getString("name"); + levelNames.add(levelName); + } + }); - String mainLevelName = cell.mainLevel.get().dimensionUsage.instanceName; - int mainLevel = cell.mainLevel.get().level; - if (StringUtils.equalsIgnoreCase(mainLevelName, "national plan objective")) { - String sql = String.format("SELECT nol.name as name FROM v_nationalobjectives_level_%d nol WHERE nol.amp_activity_id = %d",mainLevel, activityId); + } + } + if (!ids.isEmpty()) { + String sql = String.format("SELECT ind.indicator_id as id, th.name as theme_name FROM amp_indicator ind JOIN amp_theme th ON ind.program_id=th.amp_theme_id WHERE ind.indicator_id = %d", ids.get(0)); PersistenceManager.getSession().doWork(connection -> { RsInfo rsi = SQLUtils.rawRunQuery(connection, sql, null); ResultSet rs = rsi.rs; while (rs.next()) { - String levelName = rs.getString("name"); - levelNames.add(levelName); + String programName = rs.getString("theme_name"); + if (levelNames.contains(programName) && !StringUtils.equalsIgnoreCase(programName, cell.text)) { + cell.setPercentage(BigDecimal.ZERO); + } + + } }); - } - } - if (!ids.isEmpty()) { - String sql = String.format("SELECT ind.indicator_id as id, th.name as theme_name FROM amp_indicator ind JOIN amp_theme th ON ind.program_id=th.amp_theme_id WHERE ind.indicator_id = %d",ids.get(0)); - PersistenceManager.getSession().doWork(connection -> { - RsInfo rsi = SQLUtils.rawRunQuery(connection, sql, null); - ResultSet rs = rsi.rs; - while (rs.next()) { - String programName = rs.getString("theme_name"); - if (levelNames.contains(programName) && !StringUtils.equalsIgnoreCase(programName,cell.text)) - { - cell.setPercentage(BigDecimal.ZERO); - } + return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(cell), mergeAcceptors(acceptors)); - - } - }); } - return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(cell), mergeAcceptors(acceptors)); } return new NiCell(newContents, entity, hiersTracker.advanceHierarchy(splitCell), mergeAcceptors(acceptors)); } + private PercentageTextCell convertCell(Cell cell) + { + try { + return (PercentageTextCell) cell; + }catch (Exception e) + { + return null; + } + } + /** * computes a map of acceptors which is the result of merging this cell's {@link #passedFilters} with the given acceptors. * In case both the cell and the given acceptors contain a mapping for a given {@link NiDimensionUsage}, the given map has priority