diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/dataitem/ItemOrgUnitGroupCount.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/dataitem/ItemOrgUnitGroupCount.java index 7b66e49a9726..52d97dc66077 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/dataitem/ItemOrgUnitGroupCount.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/dataitem/ItemOrgUnitGroupCount.java @@ -30,6 +30,7 @@ import static org.hisp.dhis.parser.expression.ParserUtils.DOUBLE_VALUE_IF_NULL; import static org.hisp.dhis.parser.expression.antlr.ExpressionParser.ExprContext; +import java.util.Map; import org.hisp.dhis.antlr.ParserExceptionWithoutContext; import org.hisp.dhis.organisationunit.OrganisationUnitGroup; import org.hisp.dhis.parser.expression.CommonExpressionVisitor; @@ -65,14 +66,13 @@ public Object getExpressionInfo(ExprContext ctx, CommonExpressionVisitor visitor @Override public Object evaluate(ExprContext ctx, CommonExpressionVisitor visitor) { - Integer count = visitor.getParams().getOrgUnitCountMap().get(ctx.uid0.getText()); + Map orgUnitCountMap = visitor.getParams().getOrgUnitCountMap(); - if (count == null) // Shouldn't happen for a valid expression. - { - throw new ParserExceptionWithoutContext( - "Can't find count for organisation unit " + ctx.uid0.getText()); - } + // The count map is absent for an organisation unit whose subtree contains no members of the + // group (the analytics org unit target aggregation returns no row for it), so a missing entry + // means a count of zero rather than an error. + Integer count = orgUnitCountMap != null ? orgUnitCountMap.get(ctx.uid0.getText()) : null; - return count.doubleValue(); + return count != null ? count.doubleValue() : 0d; } } diff --git a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionService2Test.java b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionService2Test.java index afb04995662d..4640467ccab8 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionService2Test.java +++ b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionService2Test.java @@ -926,6 +926,31 @@ void testGetExpressionValue() { assertEquals(54d, exprValue(expressionR, itemMap, valueMap, orgUnitCountMap, null), DELTA); } + @Test + void testGetExpressionValueOrgUnitGroupCountMissingMemberCountIsZero() { + // An OUG{} indicator queried for an org unit whose subtree has no members of the group: the + // analytics target map then has no entry for that org unit, so DataHandler passes a null (or + // entry-less) orgUnitCountMap down to expression evaluation. The org unit group count must + // resolve to 0 rather than throwing (previously a NullPointerException / "Cannot find count"). + mockConstantService(); + + Map itemMap = + ImmutableMap.builder() + .put(getId(opA), opA) + .build(); + + Map valueMap = new HashMap<>(); + valueMap.put(opA, 12d); + + // expressionH = #{deA.coc} * OUG{groupA}; with the group count resolving to 0 -> 12 * 0 = 0. + + // Null map (no target entry for this org unit at all). + assertEquals(0d, exprValue(expressionH, itemMap, valueMap, null, null), DELTA); + + // Non-null map missing this group's uid. + assertEquals(0d, exprValue(expressionH, itemMap, valueMap, new HashMap<>(), null), DELTA); + } + @Test void testGetIndicatorDimensionalItemMap2() { Set itemIds = Sets.newHashSet(getId(opA));