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 59468737056..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 @@ -1,17 +1,29 @@ package org.dgfoundation.amp.nireports.runtime; +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; +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.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; /** * An immutable {@link Cell} wrapper which has identity and is not shared between reports or columns. @@ -25,31 +37,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 +73,93 @@ 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 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 advanceHierachyWithAVeryDirtyFixForIndicators(Cell newContents, Cell splitCell, Map acceptors) + { + List cellNames = newContents.coordinates.keySet().stream().map(x->x.instanceName.toLowerCase()).collect(Collectors.toList()); + Long activityId = newContents.activityId; + if (!cellNames.isEmpty() && cellNames.contains("indicator")) { + List ids = newContents.coordinates.values().stream().map(x->x.id).collect(Collectors.toList()); + PercentageTextCell cell = convertCell(splitCell); + if(cell!=null) { + cell.setPercentage(BigDecimal.valueOf(1)); + 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")) { + 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); + } + }); + + } + } + 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(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 + * 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 +168,10 @@ public Map> mergeAcceptors(Map getEntity() { return entity; } @@ -100,11 +179,11 @@ public NiReportedEntity getEntity() { public Cell getCell() { return cell; } - + public long getMainId() { return cell.activityId; } - + public boolean isUndefinedCell() { return this.undefinedCell; } @@ -112,14 +191,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 +223,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 +233,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 +246,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()); 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 + + + +