=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java 2013-10-08 17:20:57 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java 2014-01-31 18:08:43 +0000 @@ -37,6 +37,7 @@ import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; import org.hisp.dhis.dataelement.DataElementOperand; import org.hisp.dhis.indicator.Indicator; +import org.hisp.dhis.organisationunit.OrganisationUnitGroup; import org.hisp.dhis.period.Period; /** @@ -61,6 +62,7 @@ final String DATAELEMENT_DOES_NOT_EXIST = "data_element_does_not_exist"; final String CATEGORYOPTIONCOMBO_DOES_NOT_EXIST = "category_option_combo_does_not_exist"; final String CONSTANT_DOES_NOT_EXIST = "constant_does_not_exist"; + final String OU_GROUP_DOES_NOT_EXIST = "org_unit_group_does_not_exist"; final String EXPRESSION_NOT_WELL_FORMED = "expression_not_well_formed"; final String DAYS_DESCRIPTION = "[Number of days]"; @@ -71,12 +73,14 @@ final String OPERAND_UID_EXPRESSION = "(\\w+)\\.?(\\w*)"; final String DATA_ELEMENT_TOTAL_EXPRESSION = "#\\{(\\w+)\\}"; final String CONSTANT_EXPRESSION = "C\\{(\\w+)\\}"; + final String OU_GROUP_EXPRESSION = "OUG\\{(\\w+)\\}"; final String DAYS_EXPRESSION = "\\[days\\]"; final Pattern OPERAND_PATTERN = Pattern.compile( OPERAND_EXPRESSION ); final Pattern OPERAND_UID_PATTERN = Pattern.compile( OPERAND_UID_EXPRESSION ); final Pattern DATA_ELEMENT_TOTAL_PATTERN = Pattern.compile( DATA_ELEMENT_TOTAL_EXPRESSION ); final Pattern CONSTANT_PATTERN = Pattern.compile( CONSTANT_EXPRESSION ); + final Pattern OU_GROUP_PATTERN = Pattern.compile( OU_GROUP_EXPRESSION ); final Pattern DAYS_PATTERN = Pattern.compile( DAYS_EXPRESSION ); final String DAYS_SYMBOL = "[days]"; @@ -119,7 +123,7 @@ Collection getAllExpressions(); Double getIndicatorValue( Indicator indicator, Period period, Map valueMap, - Map constantMap, Integer days ); + Map constantMap, Integer orgUnitCount, Integer days ); /** * Generates the calculated value for the given expression base on the values @@ -130,11 +134,12 @@ * use in the calculation. * @param constantMap the mapping between the constant uid and value to use * in the calculation. + * @param orgUnitCount the number of org units to use in the calculation. * @param days the number of days to use in the calculation. * @return the calculated value as a double. */ Double getExpressionValue( Expression expression, Map valueMap, - Map constantMap, Integer days ); + Map constantMap, Integer orgUnitCount, Integer days ); /** * Generates the calculated value for the given expression base on the values @@ -145,6 +150,7 @@ * use in the calculation. * @param constantMap the mapping between the constant uid and value to use * in the calculation. + * @param orgUnitCount the number of org units to use in the calculation. * @param days the number of days to use in the calculation. * @param set of data element operands that have values but they are incomplete * (for example due to aggregation from organisationUnit children where @@ -152,7 +158,7 @@ * @return the calculated value as a double. */ Double getExpressionValue( Expression expression, Map valueMap, - Map constantMap, Integer days, Set incompleteValues ); + Map constantMap, Integer orgUnitCount, Integer days, Set incompleteValues ); /** * Returns the uids of the data element totals in the given expression. @@ -171,6 +177,14 @@ Set getDataElementsInExpression( String expression ); /** + * Returns all OrganisationUnitGroups in the given expression string. + * + * @param expression the expression string. + * @return a Set of OrganisationUnitGroups included in the expression string. + */ + Set getOrganisationUnitGroupsInExpresion( String expression ); + + /** * Returns all CategoryOptionCombos in the given expression string. * * @param expression the expression string. @@ -230,7 +244,7 @@ * CONSTANT_DOES_NOT_EXIST if the constant does not exist. * EXPRESSION_NOT_WELL_FORMED if the expression is not well-formed. */ - String expressionIsValid( String formula, Set dataElements, Set categoryOptionCombos, Set constants ); + String expressionIsValid( String formula, Set dataElements, Set categoryOptionCombos, Set constants, Set orgUnitGroups ); /** * Creates an expression string containing DataElement names and the names of @@ -295,11 +309,12 @@ * by the aggregated value for the relevant combination of data element, * period, and source. * - * @param formula The formula to parse. - * @param valueMap The map containing data element identifiers and aggregated value. + * @param formula formula to parse. + * @param valueMap map containing data element identifiers and aggregated value. + * @param constantMap map between constants and values. * @param days The number to be substituted with the days expression in the formula. */ - String generateExpression( String expression, Map valueMap, Map constantMap, Integer days, boolean nullIfNoValues ); + String generateExpression( String expression, Map valueMap, Map constantMap, Integer orgUnitCount, Integer days, boolean nullIfNoValues ); /** * Returns all Operands included in the formulas for the given collection of === modified file 'dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java' --- dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java 2014-01-28 12:20:49 +0000 +++ dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java 2014-01-31 18:08:43 +0000 @@ -360,10 +360,11 @@ Set dataElements = new HashSet( getUids( dataElementService.getAllDataElements() ) ); Set categoryOptionCombos = new HashSet( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) ); Set constants = new HashSet( getUids( constantService.getAllConstants() ) ); + Set orgUnitGroups = new HashSet( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) ); for ( Indicator indicator : indicatorService.getAllIndicators() ) { - String result = expressionService.expressionIsValid( indicator.getNumerator(), dataElements, categoryOptionCombos, constants ); + String result = expressionService.expressionIsValid( indicator.getNumerator(), dataElements, categoryOptionCombos, constants, orgUnitGroups ); if ( !result.equals( ExpressionService.VALID ) ) { @@ -381,10 +382,11 @@ Set dataElements = new HashSet( getUids( dataElementService.getAllDataElements() ) ); Set categoryOptionCombos = new HashSet( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) ); Set constants = new HashSet( getUids( constantService.getAllConstants() ) ); + Set orgUnitGroups = new HashSet( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) ); for ( Indicator indicator : indicatorService.getAllIndicators() ) { - String result = expressionService.expressionIsValid( indicator.getDenominator(), dataElements, categoryOptionCombos, constants ); + String result = expressionService.expressionIsValid( indicator.getDenominator(), dataElements, categoryOptionCombos, constants, orgUnitGroups ); if ( !result.equals( ExpressionService.VALID ) ) { @@ -541,10 +543,11 @@ Set dataElements = new HashSet( getUids( dataElementService.getAllDataElements() ) ); Set categoryOptionCombos = new HashSet( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) ); Set constants = new HashSet( getUids( constantService.getAllConstants() ) ); + Set orgUnitGroups = new HashSet( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) ); for ( ValidationRule rule : validationRuleService.getAllValidationRules() ) { - String result = expressionService.expressionIsValid( rule.getLeftSide().getExpression(), dataElements, categoryOptionCombos, constants ); + String result = expressionService.expressionIsValid( rule.getLeftSide().getExpression(), dataElements, categoryOptionCombos, constants, orgUnitGroups ); if ( !result.equals( ExpressionService.VALID ) ) { @@ -563,10 +566,11 @@ Set dataElements = new HashSet( getUids( dataElementService.getAllDataElements() ) ); Set categoryOptionCombos = new HashSet( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) ); Set constants = new HashSet( getUids( constantService.getAllConstants() ) ); + Set orgUnitGroups = new HashSet( getUids( organisationUnitGroupService.getAllOrganisationUnitGroups() ) ); for ( ValidationRule rule : validationRuleService.getAllValidationRules() ) { - String result = expressionService.expressionIsValid( rule.getRightSide().getExpression(), dataElements, categoryOptionCombos, constants ); + String result = expressionService.expressionIsValid( rule.getRightSide().getExpression(), dataElements, categoryOptionCombos, constants, orgUnitGroups ); if ( !result.equals( ExpressionService.VALID ) ) { === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2014-01-07 15:52:34 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2014-01-31 18:08:43 +0000 @@ -31,6 +31,7 @@ import static org.hisp.dhis.analytics.AnalyticsTableManager.ANALYTICS_TABLE_NAME; import static org.hisp.dhis.analytics.AnalyticsTableManager.COMPLETENESS_TABLE_NAME; import static org.hisp.dhis.analytics.AnalyticsTableManager.COMPLETENESS_TARGET_TABLE_NAME; +import static org.hisp.dhis.analytics.AnalyticsTableManager.ORGUNIT_TARGET_TABLE_NAME; import static org.hisp.dhis.analytics.DataQueryParams.DISPLAY_NAME_CATEGORYOPTIONCOMBO; import static org.hisp.dhis.analytics.DataQueryParams.DISPLAY_NAME_DATA_X; import static org.hisp.dhis.analytics.DataQueryParams.DISPLAY_NAME_ORGUNIT; @@ -259,7 +260,7 @@ int days = daysBetween( period.getStartDate(), period.getEndDate() ); - Double value = expressionService.getIndicatorValue( indicator, period, valueMap, constantMap, days ); + Double value = expressionService.getIndicatorValue( indicator, period, valueMap, constantMap, null, days ); //TODO oug if ( value != null ) { @@ -545,14 +546,31 @@ } /** + * Generates a mapping between the the data set dimension key and the count + * of expected data sets to report. * - * @param params - * @return + * @param params the data query parameters. + * @return a mapping between the the data set dimension key and the count of + * expected data sets to report. */ private Map getAggregatedCompletenessTargetMap( DataQueryParams params ) { return getAggregatedValueMap( params, COMPLETENESS_TARGET_TABLE_NAME ); } + + /** + * Generates a mapping between the the org unit dimension key and the count + * of org units inside the subtree of the given organisation units and + * members of the given organisation unit groups. + * + * @param params the data query parameters. + * @return a mapping between the the data set dimension key and the count of + * expected data sets to report. + */ + private Map getAggregatedOrganisationUnitTargetMap( DataQueryParams params ) + { + return getAggregatedValueMap( params, ORGUNIT_TARGET_TABLE_NAME ); + } /** * Generates a mapping between a dimension key and the aggregated value. The === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java 2014-01-24 08:41:50 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java 2014-01-31 18:08:43 +0000 @@ -32,13 +32,13 @@ import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT; import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT_DISAGGREGATION; import static org.hisp.dhis.analytics.AggregationType.COUNT; -import static org.hisp.dhis.common.DimensionalObject.DIMENSION_SEP; import static org.hisp.dhis.analytics.DataQueryParams.VALUE_ID; import static org.hisp.dhis.analytics.MeasureFilter.EQ; import static org.hisp.dhis.analytics.MeasureFilter.GE; import static org.hisp.dhis.analytics.MeasureFilter.GT; import static org.hisp.dhis.analytics.MeasureFilter.LE; import static org.hisp.dhis.analytics.MeasureFilter.LT; +import static org.hisp.dhis.common.DimensionalObject.DIMENSION_SEP; import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids; import static org.hisp.dhis.system.util.TextUtils.getQuotedCommaDelimitedString; import static org.hisp.dhis.system.util.TextUtils.trimEnd; === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java 2014-01-30 10:13:58 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java 2014-01-31 18:08:43 +0000 @@ -36,7 +36,6 @@ import java.util.concurrent.Future; import org.hisp.dhis.analytics.AnalyticsTable; -import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet; import org.hisp.dhis.organisationunit.OrganisationUnitLevel; import org.springframework.scheduling.annotation.Async; import org.springframework.transaction.annotation.Transactional; @@ -135,18 +134,9 @@ { List columns = new ArrayList(); - Collection orgUnitGroupSets = - organisationUnitGroupService.getDataDimensionOrganisationUnitGroupSets(); - Collection levels = organisationUnitService.getOrganisationUnitLevels(); - - for ( OrganisationUnitGroupSet groupSet : orgUnitGroupSets ) - { - String[] col = { quote( groupSet.getUid() ), "character(11)", "ougs." + quote( groupSet.getUid() ) }; - columns.add( col ); - } - + for ( OrganisationUnitLevel level : levels ) { String column = quote( PREFIX_ORGUNITLEVEL + level.getLevel() ); === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java 2014-01-30 10:13:58 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java 2014-01-31 18:08:43 +0000 @@ -58,6 +58,8 @@ import org.hisp.dhis.dataelement.DataElementOperand; import org.hisp.dhis.dataelement.DataElementService; import org.hisp.dhis.indicator.Indicator; +import org.hisp.dhis.organisationunit.OrganisationUnitGroup; +import org.hisp.dhis.organisationunit.OrganisationUnitGroupService; import org.hisp.dhis.period.Period; import org.hisp.dhis.system.util.DateUtils; import org.hisp.dhis.system.util.MathUtils; @@ -107,6 +109,13 @@ { this.categoryService = categoryService; } + + private OrganisationUnitGroupService organisationUnitGroupService; + + public void setOrganisationUnitGroupService( OrganisationUnitGroupService organisationUnitGroupService ) + { + this.organisationUnitGroupService = organisationUnitGroupService; + } // ------------------------------------------------------------------------- // Expression CRUD operations @@ -147,14 +156,14 @@ // ------------------------------------------------------------------------- public Double getIndicatorValue( Indicator indicator, Period period, Map valueMap, - Map constantMap, Integer days ) + Map constantMap, Integer orgUnitCount, Integer days ) { if ( indicator == null || indicator.getExplodedNumeratorFallback() == null || indicator.getExplodedDenominatorFallback() == null ) { return null; } - final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), valueMap, constantMap, days, false ); + final String denominatorExpression = generateExpression( indicator.getExplodedDenominatorFallback(), valueMap, constantMap, orgUnitCount, days, false ); if ( denominatorExpression == null ) { @@ -165,7 +174,7 @@ if ( !isEqual( denominatorValue, 0d ) ) { - final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), valueMap, constantMap, days, false ); + final String numeratorExpression = generateExpression( indicator.getExplodedNumeratorFallback(), valueMap, constantMap, orgUnitCount, days, false ); if ( numeratorExpression == null ) { @@ -185,18 +194,18 @@ } public Double getExpressionValue( Expression expression, Map valueMap, - Map constantMap, Integer days ) + Map constantMap, Integer orgUnitCount, Integer days ) { - final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, days, - expression.isNullIfBlank() ); + final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, + orgUnitCount, days, expression.isNullIfBlank() ); return expressionString != null ? calculateExpression( expressionString ) : null; } public Double getExpressionValue( Expression expression, Map valueMap, - Map constantMap, Integer days, Set incompleteValues ) + Map constantMap, Integer orgUnitCount, Integer days, Set incompleteValues ) { - final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, days, + final String expressionString = generateExpression( expression.getExpression(), valueMap, constantMap, orgUnitCount, days, expression.isNullIfBlank(), incompleteValues ); return expressionString != null ? calculateExpression( expressionString ) : null; @@ -227,6 +236,30 @@ return dataElementsInExpression; } + public Set getOrganisationUnitGroupsInExpresion( String expression ) + { + Set groupsInExpression = null; + + if ( expression != null ) + { + groupsInExpression = new HashSet(); + + final Matcher matcher = OU_GROUP_PATTERN.matcher( expression ); + + while ( matcher.find() ) + { + final OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( matcher.group( 1 ) ); + + if ( group != null ) + { + groupsInExpression.add( group ); + } + } + } + + return groupsInExpression; + } + public Set getDataElementTotalUids( String expression ) { Set uids = new HashSet(); @@ -338,11 +371,11 @@ @Transactional public String expressionIsValid( String formula ) { - return expressionIsValid( formula, null, null, null ); + return expressionIsValid( formula, null, null, null, null ); } @Transactional - public String expressionIsValid( String expression, Set dataElements, Set categoryOptionCombos, Set constants ) + public String expressionIsValid( String expression, Set dataElements, Set categoryOptionCombos, Set orgUnitGroups, Set constants ) { if ( expression == null || expression.isEmpty() ) { @@ -398,6 +431,31 @@ expression = appendTail( matcher, sb ); + // --------------------------------------------------------------------- + // Org unit groups + // --------------------------------------------------------------------- + + matcher = OU_GROUP_PATTERN.matcher( expression ); + sb = new StringBuffer(); + + while ( matcher.find() ) + { + String group = matcher.group( 1 ); + + if ( orgUnitGroups != null ? !orgUnitGroups.contains( group ) : organisationUnitGroupService.getOrganisationUnitGroup( group ) == null ) + { + return OU_GROUP_DOES_NOT_EXIST; + } + + matcher.appendReplacement( sb, "1.1" ); + } + + expression = appendTail( matcher, sb ); + + // --------------------------------------------------------------------- + // Days + // --------------------------------------------------------------------- + expression = expression.replaceAll( DAYS_EXPRESSION, "1.1" ); // --------------------------------------------------------------------- @@ -474,6 +532,29 @@ expression = appendTail( matcher, sb ); // --------------------------------------------------------------------- + // Org unit groups + // --------------------------------------------------------------------- + + sb = new StringBuffer(); + matcher = OU_GROUP_PATTERN.matcher( expression ); + + while ( matcher.find() ) + { + String oug = matcher.group( 1 ); + + OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( oug ); + + if ( group == null ) + { + throw new IllegalArgumentException( "Identifier does not reference an organisation unit group: " + oug ); + } + + matcher.appendReplacement( sb, group.getDisplayName() ); + } + + expression = appendTail( matcher, sb ); + + // --------------------------------------------------------------------- // Days // --------------------------------------------------------------------- @@ -630,6 +711,28 @@ } expression = appendTail( matcher, sb ); + + // --------------------------------------------------------------------- + // Org unit groups + // --------------------------------------------------------------------- + + sb = new StringBuffer(); + matcher = OU_GROUP_PATTERN.matcher( expression ); + + while ( matcher.find() ) + { + String oug = matcher.group( 1 ); + + OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( oug ); + + String replacement = group != null ? String.valueOf( group.getMembers().size() ) : NULL_REPLACEMENT; + + matcher.appendReplacement( sb, replacement ); + + //TODO sub tree + } + + expression = appendTail( matcher, sb ); // --------------------------------------------------------------------- // Days @@ -650,13 +753,13 @@ @Transactional public String generateExpression( String expression, Map valueMap, - Map constantMap, Integer days, boolean nullIfNoValues ) + Map constantMap, Integer orgUnitCount, Integer days, boolean nullIfNoValues ) { - return generateExpression( expression, valueMap, constantMap, days, nullIfNoValues, null ); + return generateExpression( expression, valueMap, constantMap, orgUnitCount, days, nullIfNoValues, null ); } private String generateExpression( String expression, Map valueMap, - Map constantMap, Integer days, boolean nullIfNoValues, Set incompleteValues ) + Map constantMap, Integer orgUnitCount, Integer days, boolean nullIfNoValues, Set incompleteValues ) { if ( expression == null || expression.isEmpty() ) { @@ -705,6 +808,22 @@ } expression = appendTail( matcher, sb ); + + // --------------------------------------------------------------------- + // Org unit groups + // --------------------------------------------------------------------- + + sb = new StringBuffer(); + matcher = OU_GROUP_PATTERN.matcher( expression ); + + while ( matcher.find() ) + { + String replacement = orgUnitCount != null ? String.valueOf( orgUnitCount ) : NULL_REPLACEMENT; + + matcher.appendReplacement( sb, replacement ); + } + + expression = appendTail( matcher, sb ); // --------------------------------------------------------------------- // Days === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java 2013-10-17 04:03:14 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java 2014-01-31 18:08:43 +0000 @@ -121,7 +121,7 @@ if ( evaluateCheck( lastUpdatedMap, rule, context ) ) { Double leftSide = context.getExpressionService().getExpressionValue( rule.getLeftSide(), - currentValueMap, context.getConstantMap(), null, incompleteValues ); + currentValueMap, context.getConstantMap(), null, null, incompleteValues ); if ( leftSide != null || Operator.compulsory_pair.equals( rule.getOperator() ) ) { @@ -319,7 +319,7 @@ || rule.getRightSide().getDataElementsInExpression().isEmpty() ) { rightSideValue = context.getExpressionService().getExpressionValue( rule.getRightSide(), - currentValueMap, context.getConstantMap(), null ); + currentValueMap, context.getConstantMap(), null, null ); } else // ruleType equals SURVEILLANCE, and there are some data elements in the @@ -416,7 +416,7 @@ Map dataValueMap = getDataValueMapRecursive( periodTypeX, dataElements, sourceDataElements, dataElements, allowedPeriodTypes, period, source, null, incompleteValues ); Double value = context.getExpressionService().getExpressionValue( rule.getRightSide(), dataValueMap, - context.getConstantMap(), null, incompleteValues ); + context.getConstantMap(), null, null, incompleteValues ); if ( value != null ) { === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2014-01-29 13:39:43 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2014-01-31 18:08:43 +0000 @@ -449,6 +449,7 @@ + === modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java' --- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java 2013-12-19 18:12:57 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java 2014-01-31 18:08:43 +0000 @@ -56,6 +56,8 @@ import org.hisp.dhis.indicator.Indicator; import org.hisp.dhis.indicator.IndicatorType; import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.organisationunit.OrganisationUnitGroup; +import org.hisp.dhis.organisationunit.OrganisationUnitGroupService; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.period.Period; import org.junit.Test; @@ -84,12 +86,16 @@ private Period period; - private OrganisationUnit source; + private OrganisationUnit unitA; + private OrganisationUnit unitB; + private OrganisationUnit unitC; private DataElementCategoryOptionCombo categoryOptionCombo; private Constant constantA; + private OrganisationUnitGroup groupA; + private String expressionA; private String expressionB; private String expressionC; @@ -97,6 +103,7 @@ private String expressionE; private String expressionF; private String expressionG; + private String expressionH; private String descriptionA; private String descriptionB; @@ -124,6 +131,8 @@ dataValueService = (DataValueService) getBean( DataValueService.ID ); organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID ); + + organisationUnitGroupService = (OrganisationUnitGroupService) getBean( OrganisationUnitGroupService.ID ); categoryOptionA = new DataElementCategoryOption( "Under 5" ); categoryOptionB = new DataElementCategoryOption( "Over 5" ); @@ -171,13 +180,24 @@ period = createPeriod( getDate( 2000, 1, 1 ), getDate( 2000, 2, 1 ) ); - source = createOrganisationUnit( 'A' ); + unitA = createOrganisationUnit( 'A' ); + unitB = createOrganisationUnit( 'B' ); + unitC = createOrganisationUnit( 'C' ); - organisationUnitService.addOrganisationUnit( source ); + organisationUnitService.addOrganisationUnit( unitA ); + organisationUnitService.addOrganisationUnit( unitB ); + organisationUnitService.addOrganisationUnit( unitC ); constantA = new Constant( "ConstantA", 2.0 ); - + constantService.saveConstant( constantA ); + + groupA = createOrganisationUnitGroup( 'A' ); + groupA.addOrganisationUnit( unitA ); + groupA.addOrganisationUnit( unitB ); + groupA.addOrganisationUnit( unitC ); + + organisationUnitGroupService.addOrganisationUnitGroup( groupA ); expressionA = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}+#{" + dataElementB.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}"; @@ -188,6 +208,7 @@ expressionE = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}*C{" + constantA.getUid() + "}"; expressionF = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}"; expressionG = expressionF + "+#{" + dataElementB.getUid() + "}-#{" + dataElementC.getUid() + "}"; + expressionH = "#{" + dataElementA.getUid() + SEPARATOR + categoryOptionCombo.getUid() + "}*OUG{" + groupA.getUid() + "}"; descriptionA = "Expression A"; descriptionB = "Expression B"; @@ -198,8 +219,8 @@ dataElements.add( dataElementD ); dataElements.add( dataElementE ); - dataValueService.addDataValue( createDataValue( dataElementA, period, source, "10", categoryOptionCombo, categoryOptionCombo ) ); - dataValueService.addDataValue( createDataValue( dataElementB, period, source, "5", categoryOptionCombo, categoryOptionCombo ) ); + dataValueService.addDataValue( createDataValue( dataElementA, period, unitA, "10", categoryOptionCombo, categoryOptionCombo ) ); + dataValueService.addDataValue( createDataValue( dataElementB, period, unitA, "5", categoryOptionCombo, categoryOptionCombo ) ); } // ------------------------------------------------------------------------- @@ -276,6 +297,7 @@ assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionC ) ); assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionD ) ); assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionE ) ); + assertEquals( ExpressionService.VALID, expressionService.expressionIsValid( expressionH ) ); expressionA = "#{NonExistingUid" + SEPARATOR + categoryOptionCombo.getUid() + "} + 12"; @@ -297,6 +319,10 @@ expressionA = "12 + C{999999}"; assertEquals( ExpressionService.CONSTANT_DOES_NOT_EXIST, expressionService.expressionIsValid( expressionA ) ); + + expressionA = "12 + OUG{999999}"; + + assertEquals( ExpressionService.OU_GROUP_DOES_NOT_EXIST, expressionService.expressionIsValid( expressionA ) ); } @Test @@ -313,6 +339,10 @@ description = expressionService.getExpressionDescription( expressionE ); assertEquals( "DataElementA*ConstantA", description ); + + description = expressionService.getExpressionDescription( expressionH ); + + assertEquals( "DataElementA*OrganisationUnitGroupA", description ); } @Test @@ -325,9 +355,10 @@ Map constantMap = new HashMap(); constantMap.put( constantA.getUid(), 2.0 ); - assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, constantMap, null, false ) ); - assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, constantMap, 5, false ) ); - assertEquals( "12.0*2.0", expressionService.generateExpression( expressionE, valueMap, constantMap, null, false ) ); + assertEquals( "12.0+34.0", expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, false ) ); + assertEquals( "12.0+5", expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, false ) ); + assertEquals( "12.0*2.0", expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, false ) ); + assertEquals( "12.0*3", expressionService.generateExpression( expressionH, valueMap, constantMap, 3, null, false ) ); } @Test @@ -337,9 +368,9 @@ Map constantMap = new HashMap(); - assertNull( expressionService.generateExpression( expressionA, valueMap, constantMap, null, true ) ); - assertNull( expressionService.generateExpression( expressionD, valueMap, constantMap, 5, true ) ); - assertNotNull( expressionService.generateExpression( expressionE, valueMap, constantMap, null, false ) ); + assertNull( expressionService.generateExpression( expressionA, valueMap, constantMap, null, null, true ) ); + assertNull( expressionService.generateExpression( expressionD, valueMap, constantMap, null, 5, true ) ); + assertNotNull( expressionService.generateExpression( expressionE, valueMap, constantMap, null, null, false ) ); } @Test @@ -348,6 +379,7 @@ Expression expA = createExpression( 'A', expressionA, null, null ); Expression expD = createExpression( 'D', expressionD, null, null ); Expression expE = createExpression( 'E', expressionE, null, null ); + Expression expH = createExpression( 'H', expressionH, null, null ); Map valueMap = new HashMap(); valueMap.put( new DataElementOperand( dataElementA.getUid(), categoryOptionCombo.getUid() ), new Double( 12 ) ); @@ -356,9 +388,10 @@ Map constantMap = new HashMap(); constantMap.put( constantA.getUid(), 2.0 ); - assertEquals( 46d, expressionService.getExpressionValue( expA, valueMap, constantMap, null ), DELTA ); - assertEquals( 17d, expressionService.getExpressionValue( expD, valueMap, constantMap, 5 ), DELTA ); - assertEquals( 24d, expressionService.getExpressionValue( expE, valueMap, constantMap, null ), DELTA ); + assertEquals( 46d, expressionService.getExpressionValue( expA, valueMap, constantMap, null, null ), DELTA ); + assertEquals( 17d, expressionService.getExpressionValue( expD, valueMap, constantMap, null, 5 ), DELTA ); + assertEquals( 24d, expressionService.getExpressionValue( expE, valueMap, constantMap, null, null ), DELTA ); + assertEquals( 36d, expressionService.getExpressionValue( expH, valueMap, constantMap, 3, null ), DELTA ); } @Test @@ -376,7 +409,7 @@ Map constantMap = new HashMap(); constantMap.put( constantA.getUid(), 2.0 ); - assertEquals( 200d, expressionService.getIndicatorValue( indicatorA, period, valueMap, constantMap, null ), DELTA ); + assertEquals( 200d, expressionService.getIndicatorValue( indicatorA, period, valueMap, constantMap, null, null ), DELTA ); } // ------------------------------------------------------------------------- === modified file 'dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java' --- dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java 2013-08-23 16:05:01 +0000 +++ dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java 2014-01-31 18:08:43 +0000 @@ -164,11 +164,11 @@ { for ( final Indicator indicator : indicators ) { - final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, constantMap, days, false ) ); + final double denominatorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedDenominator(), valueMap, constantMap, null, days, false ) ); if ( !isEqual( denominatorValue, 0d ) ) { - final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, constantMap, days, false ) ); + final double numeratorValue = calculateExpression( expressionService.generateExpression( indicator.getExplodedNumerator(), valueMap, constantMap, null, days, false ) ); if ( !( omitZeroNumerator && isEqual( numeratorValue, 0d ) ) ) { === modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/resources/org/hisp/dhis/dd/i18n_module.properties' --- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/resources/org/hisp/dhis/dd/i18n_module.properties 2014-01-23 19:05:43 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/resources/org/hisp/dhis/dd/i18n_module.properties 2014-01-31 18:08:43 +0000 @@ -27,7 +27,7 @@ data_element=Data Element data_element_group=Data Element Group data_element_groups=Data Element Groups -list_of_data_elements=Data elements +data_elements=Data elements indicator=Indicator indicator_group=Indicator Group indicator_groups=Indicator Groups @@ -215,4 +215,5 @@ disaggregation=Disaggregation attribute=Attribute option_set_for_data_values=Option set for data values -option_set_for_comments=Option set for comments \ No newline at end of file +option_set_for_comments=Option set for comments +organisation_unit_counts=Organisation unit counts \ No newline at end of file === modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm' --- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm 2013-08-09 10:02:06 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-datadictionary/src/main/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm 2014-01-31 18:08:43 +0000 @@ -16,6 +16,7 @@ }); getConstantsPage(); + getOrgUnitGroupsPage(); getOperandsPage(); }); @@ -62,14 +63,27 @@ var target = jQuery( "#indicator-expression-container select[id=constantId]" ); target.children().remove(); - jQuery.get( '../api/constants.json?paging=false&links=false', {}, + jQuery.get( '../api/constants.json?paging=false&links=false', function( json ) { jQuery.each( json.constants, function(i, item) { - target.append( '' ); + target.append( '' ); }); }); } + function getOrgUnitGroupsPage() + { + var target = jQuery( "#indicator-expression-container select[id=orgUnitGroupId]" ); + target.children().remove(); + + jQuery.get( '../api/organisationUnitGroups.json?paging=false&links=false', + function( json ) { + jQuery.each( json.organisationUnitGroups, function(i, item) { + target.append( '' ); + }); + }); + } + function getOperandsPage() { var key = getFieldValue( "indicator-expression-container input[id=filter]"); @@ -149,11 +163,13 @@ + $i18n.getString( "description" ) $i18n.getString( "constants" ) + $i18n.getString( "organisation_unit_counts" ) @@ -162,16 +178,18 @@ - + + + + - + $i18n.getString( "formula" ) - $i18n.getString( "list_of_data_elements" ) + $i18n.getString( "data_elements" ) @@ -185,7 +203,7 @@ - +
@@ -195,16 +213,16 @@ - $i18n.getString( "description" ) - - -
- - - - - - + $i18n.getString( "description" ) + + +
+ + + + + +