Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/ggw 364/fix m&e reporting #4346

Open
wants to merge 5 commits into
base: future/GGW
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();
Expand All @@ -58,7 +63,7 @@ public MetaInfoSet getMetaInfo() {
public BigDecimal getPercentage() {
return percentage;
}

@Override
public int compareTo(Object o) {
PercentageTextCell ptc = (PercentageTextCell) o;
Expand All @@ -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);
Expand Down
123 changes: 101 additions & 22 deletions amp/WEB-INF/src/org/dgfoundation/amp/nireports/runtime/NiCell.java
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -25,31 +37,31 @@ public class NiCell implements Comparable<NiCell> {
* 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<NiDimensionUsage, List<IdsAcceptor>> passedFilters;

public NiCell(Cell cell, NiReportedEntity<?> entity, HierarchiesTracker hiersTracker) {
this(cell, entity, hiersTracker, Collections.emptyMap());
}

public NiCell(Cell cell, NiReportedEntity<?> entity, HierarchiesTracker hiersTracker, Map<NiDimensionUsage, List<IdsAcceptor>> passedFilters) {
NiUtils.failIf(cell == null, "not allowed to have NiCells without contents");
this.cell = cell;
Expand All @@ -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<NiDimensionUsage, IdsAcceptor> 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<NiDimensionUsage, IdsAcceptor> acceptors)
{
List<String> cellNames = newContents.coordinates.keySet().stream().map(x->x.instanceName.toLowerCase()).collect(Collectors.toList());
Long activityId = newContents.activityId;
if (!cellNames.isEmpty() && cellNames.contains("indicator")) {
List<Long> 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<String> 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<NiDimensionUsage, List<IdsAcceptor>> mergeAcceptors(Map<NiDimensionUsage, IdsAcceptor> acceptors) {
if (acceptors == null || acceptors.isEmpty())
return passedFilters;

Map<NiDimensionUsage, List<IdsAcceptor>> res = new HashMap<>();
passedFilters.forEach((dimUsg, oldList) -> {
List<IdsAcceptor> resList = acceptors.containsKey(dimUsg) ? AmpCollections.cat(oldList, acceptors.get(dimUsg)) : oldList;
Expand All @@ -89,37 +168,37 @@ public Map<NiDimensionUsage, List<IdsAcceptor>> mergeAcceptors(Map<NiDimensionUs
for(NiDimensionUsage dimUsg:acceptors.keySet()) {
if (!res.containsKey(dimUsg)) // else the element has been added in the list above
res.put(dimUsg, Arrays.asList(acceptors.get(dimUsg)));
}
}
return res;
}

public NiReportedEntity<?> getEntity() {
return entity;
}

public Cell getCell() {
return cell;
}

public long getMainId() {
return cell.activityId;
}

public boolean isUndefinedCell() {
return this.undefinedCell;
}

public Map<NiDimensionUsage, List<IdsAcceptor>> 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);
// }
Expand All @@ -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)
Expand All @@ -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
*/
Expand All @@ -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());
Expand Down
24 changes: 24 additions & 0 deletions amp/xmlpatches/4.0/Add-Indicator-Report-Visibility.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<tns:patch closeOnSuccess="true" retryOnFail="true"
xmlns:tns="http://docs.ampdev.net/schemas/xmlpatcher" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docs.ampdev.net/schemas/xmlpatcher ../../doc/xmlpatcher.xsd ">
<jira>AMP-30863</jira>
<keyword>Add indicator report to visibility template</keyword>
<author>bmokandu</author>
<apply>
<script>
<lang delimiter=";" type="postgres">
INSERT INTO amp_features_templates (template, feature)
SELECT
(SELECT cast(settingsvalue AS int) AS template FROM amp_global_settings WHERE settingsname = 'Visibility Template'),
(SELECT id AS feature FROM amp_features_visibility WHERE name = 'Indicator Report')
WHERE NOT EXISTS (
SELECT template FROM amp_features_templates
WHERE template = (SELECT cast(settingsvalue AS int) AS template FROM amp_global_settings WHERE settingsname = 'Visibility Template')
AND feature = (SELECT id FROM amp_features_visibility WHERE name = 'Indicator Report')
);

</lang>
</script>
</apply>
</tns:patch>