dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #27912
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 13910: Impl support for count of org units in groups in indicator formulas. Step 1 of 2.
------------------------------------------------------------
revno: 13910
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2014-01-31 20:08:43 +0200
message:
Impl support for count of org units in groups in indicator formulas. Step 1 of 2.
modified:
dhis-2/dhis-api/src/main/java/org/hisp/dhis/expression/ExpressionService.java
dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/DefaultDataIntegrityService.java
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/JdbcAnalyticsManager.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcOrgUnitTargetTableManager.java
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/validation/ValidatorThread.java
dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/expression/ExpressionServiceTest.java
dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/indicator/DefaultIndicatorDataMart.java
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/webapp/dhis-web-maintenance-datadictionary/indicatorExpressionBuilderForm.vm
--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk
Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== 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<Expression> getAllExpressions();
Double getIndicatorValue( Indicator indicator, Period period, Map<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days );
+ Map<String, Double> 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<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days );
+ Map<String, Double> 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<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days, Set<DataElementOperand> incompleteValues );
+ Map<String, Double> constantMap, Integer orgUnitCount, Integer days, Set<DataElementOperand> incompleteValues );
/**
* Returns the uids of the data element totals in the given expression.
@@ -171,6 +177,14 @@
Set<DataElement> 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<OrganisationUnitGroup> 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<String> dataElements, Set<String> categoryOptionCombos, Set<String> constants );
+ String expressionIsValid( String formula, Set<String> dataElements, Set<String> categoryOptionCombos, Set<String> constants, Set<String> 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<DataElementOperand, Double> valueMap, Map<String, Double> constantMap, Integer days, boolean nullIfNoValues );
+ String generateExpression( String expression, Map<DataElementOperand, Double> valueMap, Map<String, Double> 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<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+ Set<String> orgUnitGroups = new HashSet<String>( 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<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+ Set<String> orgUnitGroups = new HashSet<String>( 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<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+ Set<String> orgUnitGroups = new HashSet<String>( 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<String> dataElements = new HashSet<String>( getUids( dataElementService.getAllDataElements() ) );
Set<String> categoryOptionCombos = new HashSet<String>( getUids( categoryService.getAllDataElementCategoryOptionCombos() ) );
Set<String> constants = new HashSet<String>( getUids( constantService.getAllConstants() ) );
+ Set<String> orgUnitGroups = new HashSet<String>( 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<String, Double> 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<String, Double> 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<String[]> columns = new ArrayList<String[]>();
- Collection<OrganisationUnitGroupSet> orgUnitGroupSets =
- organisationUnitGroupService.getDataDimensionOrganisationUnitGroupSets();
-
Collection<OrganisationUnitLevel> 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<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days )
+ Map<String, Double> 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<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days )
+ Map<String, Double> 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<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days, Set<DataElementOperand> incompleteValues )
+ Map<String, Double> constantMap, Integer orgUnitCount, Integer days, Set<DataElementOperand> 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<OrganisationUnitGroup> getOrganisationUnitGroupsInExpresion( String expression )
+ {
+ Set<OrganisationUnitGroup> groupsInExpression = null;
+
+ if ( expression != null )
+ {
+ groupsInExpression = new HashSet<OrganisationUnitGroup>();
+
+ 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<String> getDataElementTotalUids( String expression )
{
Set<String> uids = new HashSet<String>();
@@ -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<String> dataElements, Set<String> categoryOptionCombos, Set<String> constants )
+ public String expressionIsValid( String expression, Set<String> dataElements, Set<String> categoryOptionCombos, Set<String> orgUnitGroups, Set<String> 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<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days, boolean nullIfNoValues )
+ Map<String, Double> 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<DataElementOperand, Double> valueMap,
- Map<String, Double> constantMap, Integer days, boolean nullIfNoValues, Set<DataElementOperand> incompleteValues )
+ Map<String, Double> constantMap, Integer orgUnitCount, Integer days, boolean nullIfNoValues, Set<DataElementOperand> 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<DataElementOperand, Double> 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 @@
<property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />
<property name="constantService" ref="org.hisp.dhis.constant.ConstantService" />
<property name="categoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
+ <property name="organisationUnitGroupService" ref="org.hisp.dhis.organisationunit.OrganisationUnitGroupService" />
</bean>
<bean id="org.hisp.dhis.validation.ValidationRuleService" class="org.hisp.dhis.validation.DefaultValidationRuleService">
=== 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<String, Double> constantMap = new HashMap<String, Double>();
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<String, Double> constantMap = new HashMap<String, Double>();
- 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<DataElementOperand, Double> valueMap = new HashMap<DataElementOperand, Double>();
valueMap.put( new DataElementOperand( dataElementA.getUid(), categoryOptionCombo.getUid() ), new Double( 12 ) );
@@ -356,9 +388,10 @@
Map<String, Double> constantMap = new HashMap<String, Double>();
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<String, Double> constantMap = new HashMap<String, Double>();
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( '<option value="C{'+item.id+'}">' + item.name + '</option>' );
+ target.append( '<option value="C{' + item.id + '}">' + item.name + '</option>' );
});
});
}
+ 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( '<option value="OUG{' + item.id + '}">' + item.name + '</option>' );
+ });
+ });
+ }
+
function getOperandsPage()
{
var key = getFieldValue( "indicator-expression-container input[id=filter]");
@@ -149,11 +163,13 @@
<colgroup>
<col width="250"/>
<col width="10"/>
+ <col width="250"/>
<col/>
</colgroup>
<tr>
<th colspan="2">$i18n.getString( "description" )</th>
<th>$i18n.getString( "constants" )</th>
+ <th>$i18n.getString( "organisation_unit_counts" )</th>
</tr>
<tr>
<td>
@@ -162,16 +178,18 @@
</td>
<td></td>
<td>
- <select id="constantId" name="constantId" size="3" style="width:500px" ondblclick="insertText( 'expression', this.value )">
- </select>
+ <select id="constantId" name="constantId" size="3" style="width:250px" ondblclick="insertText( 'expression', this.value )"></select>
</td>
+ <td>
+ <select id="orgUnitGroupId" name="orgUnitGroupId" size="3" style="width:270px" ondblclick="insertText( 'expression', this.value )"></select>
+ </td>
</tr>
<tr>
- <td colspan="3"></td>
+ <td colspan="4"></td>
</tr>
<tr>
<th colspan="2">$i18n.getString( "formula" )</th>
- <th style="width:100%">$i18n.getString( "list_of_data_elements" )</th>
+ <th colspan="2" style="width:100%">$i18n.getString( "data_elements" )</th>
</tr>
<tr>
<td valign="top">
@@ -185,7 +203,7 @@
<a href="javascript:insertText( 'expression', '[days]' )"><img src="../images/no_of_days.png" title="$i18n.getString( 'no_of_days' )"/></a>
</td>
<td></td>
- <td valign="top" style="width:100%">
+ <td colspan="2" valign="top" style="width:100%">
<input type="text" id="filter" name="filter" style="width:370px">
<input type="button" value="$i18n.getString( 'filter' )" onclick="getOperandsPage()" style="width:60px">
<input type="button" value="$i18n.getString( 'clear' )" onclick="clearSearchText();" style="width:60px"><br/>
@@ -195,16 +213,16 @@
</td>
</tr>
<tr>
- <th colspan="3" style="width:100%">$i18n.getString( "description" )</th>
- </tr>
- <tr>
- <td colspan="3" style="width:100%"><div id="formulaText" style="width:740px;height:100px;overflow:auto"></div></td>
- </tr>
- <tr>
- <td colspan="3"></td>
- </tr>
- <tr>
- <td colspan="3">
+ <th colspan="4" style="width:100%">$i18n.getString( "description" )</th>
+ </tr>
+ <tr>
+ <td colspan="4" style="width:100%"><div id="formulaText" style="width:740px;height:100px;overflow:auto"></div></td>
+ </tr>
+ <tr>
+ <td colspan="4"></td>
+ </tr>
+ <tr>
+ <td colspan="4">
<input type="submit" value="$i18n.getString( 'save' )" style="width:125px"/>
<input type="button" value="$i18n.getString( 'cancel' )" style="width:125px" onclick="closeExpressionBuilder()"/>
</td>