dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #30135
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15297: Support attribute categories in validation
------------------------------------------------------------
revno: 15297
committer: jimgrace@xxxxxxxxx
branch nick: dhis2
timestamp: Sat 2014-05-17 20:49:40 -0400
message:
Support attribute categories in validation
renamed:
dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/MapMap.java => dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MapMap.java
modified:
dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/ListMap.java
dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SetMap.java
dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java
dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java
dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationResult.java
dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationRuleService.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/OrganisationUnitExtended.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/PeriodTypeExtended.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRuleExtended.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.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/validation/ValidationRuleServiceTest.java
dhis-2/dhis-web/dhis-web-dataentry/src/main/java/org/hisp/dhis/de/action/ValidationAction.java
dhis-2/dhis-web/dhis-web-dataentry/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.js
dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/validationResult.vm
dhis-2/dhis-web/dhis-web-light/src/main/java/org/hisp/dhis/light/utils/FormUtilsImpl.java
dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/RunValidationAction.java
dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties
dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/viewValidationResultForm.vm
dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MapMap.java
--
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/common/ListMap.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/ListMap.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/ListMap.java 2014-05-18 00:49:40 +0000
@@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* @author Lars Helge Overland
@@ -38,6 +39,11 @@
public class ListMap<T, V>
extends HashMap<T, List<V>>
{
+ /**
+ * Determines if a de-serialized file is compatible with this class.
+ */
+ private static final long serialVersionUID = 4880664228933342003L;
+
public ListMap()
{
super();
@@ -56,4 +62,12 @@
super.put( key, list );
return null;
}
+
+ public void putValueMap( Map<T, V> map )
+ {
+ for ( Map.Entry<T, V> entry : map.entrySet() )
+ {
+ putValue( entry.getKey(), entry.getValue() );
+ }
+ }
}
=== renamed file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/MapMap.java' => 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MapMap.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/MapMap.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/MapMap.java 2014-05-18 00:49:40 +0000
@@ -1,4 +1,4 @@
-package org.hisp.dhis.system.util;
+package org.hisp.dhis.common;
/*
* Copyright (c) 2004-2014, University of Oslo
@@ -52,4 +52,9 @@
map.putAll( m );
this.put( key, map );
}
+
+ public V getValue( T key, U valueKey )
+ {
+ return this.get( key ) == null ? null : this.get( key ).get( valueKey );
+ }
}
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SetMap.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SetMap.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/SetMap.java 2014-05-18 00:49:40 +0000
@@ -55,4 +55,11 @@
set.add( value );
return super.put( key, set );
}
+
+ public Set<V> getSet( T key )
+ {
+ Set<V> set = this.get( key );
+ set = set == null ? new HashSet<V>() : set;
+ return super.put( key, set );
+ }
}
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java 2014-04-17 14:19:13 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueService.java 2014-05-18 00:49:40 +0000
@@ -32,6 +32,7 @@
import java.util.Date;
import java.util.Map;
+import org.hisp.dhis.common.MapMap;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
import org.hisp.dhis.dataelement.DataElementOperand;
@@ -296,33 +297,25 @@
* @return the number of DataValues.
*/
int getDataValueCount( int days );
-
- /**
- * Returns a map of values indexed by DataElementOperand.
- *
- * @param dataElements collection of DataElements to fetch for
- * @param period period for which to fetch the values
- * @param unit OrganisationUnit for which to fetch the values
- * @return
- */
- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Period period, OrganisationUnit source );
/**
- * Returns a map of values indexed by DataElementOperand.
- *
+ * Returns a map of values for each attribute option combo found.
+ * <p>
* In the (unlikely) event that the same dataElement/optionCombo is found in
- * more than one period for the same organisationUnit and date, the value
- * is returned from the period with the shortest duration.
- *
+ * more than one period for the same organisationUnit, date, and attribute
+ * combo, the value is returned from the period with the shortest duration.
+ *
* @param dataElements collection of DataElements to fetch for
* @param date date which must be present in the period
- * @param unit OrganisationUnit for which to fetch the values
+ * @param source OrganisationUnit for which to fetch the values
* @param periodTypes allowable period types in which to find the data
+ * @param attributeCombo the attribute combo to check (if restricted)
* @param lastUpdatedMap map in which to return the lastUpdated date for each value
- * @return
+ * @return map of values by attribute option combo id, then DataElementOperand
*/
- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
- Collection<PeriodType> periodTypes, Map<DataElementOperand, Date> lastUpdatedMap );
+ MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
+ OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
+ MapMap<Integer, DataElementOperand, Date> lastUpdatedMap );
/**
* Gets a Collection of DeflatedDataValues.
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datavalue/DataValueStore.java 2014-05-18 00:49:40 +0000
@@ -30,8 +30,8 @@
import java.util.Collection;
import java.util.Date;
-import java.util.Map;
+import org.hisp.dhis.common.MapMap;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
import org.hisp.dhis.dataelement.DataElementOperand;
@@ -229,19 +229,19 @@
* collection of Periods, and collection of Sources.
*
* @param dataElement the DataElements of the DataValues.
- * @param optionCombo the DataElementCategoryOptionCombo of the DataValues.
+ * @param categoryOptionCombo the DataElementCategoryOptionCombo of the DataValues.
* @param periods the Periods of the DataValues.
* @param sources the Sources of the DataValues.
* @return a collection of all DataValues which match the given DataElement,
* Periods, and Sources.
*/
- Collection<DataValue> getDataValues( DataElement dataElement, DataElementCategoryOptionCombo categoryOptionCombos,
+ Collection<DataValue> getDataValues( DataElement dataElement, DataElementCategoryOptionCombo categoryOptionCombo,
Collection<Period> periods, Collection<OrganisationUnit> sources );
/**
* Returns all DataValues for a given collection of DataElementCategoryOptionCombos.
*
- * @param optionCombos the DataElementCategoryOptionCombos of the DataValue.
+ * @param categoryOptionCombos the DataElementCategoryOptionCombos of the DataValue.
* @return a collection of all DataValues which match the given collection of
* DataElementCategoryOptionCombos.
*/
@@ -273,34 +273,25 @@
* @return the number of DataValues.
*/
int getDataValueCount( Date date );
-
- /**
- * Returns a map of values indexed by DataElementOperand.
- *
- * @param dataElements collection of DataElements to fetch for
- * @param period period for which to fetch the values
- * @param unit OrganisationUnit for which to fetch the values
- * @param lastUpdatedMap optional map in which to return the lastUpdated date for each value
- * @return
- */
- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Period period, OrganisationUnit source );
/**
- * Returns a map of values indexed by DataElementOperand.
- *
+ * Returns a map of values for each attribute option combo found.
+ * <p>
* In the (unlikely) event that the same dataElement/optionCombo is found in
- * more than one period for the same organisationUnit and date, the value
- * is returned from the period with the shortest duration.
+ * more than one period for the same organisationUnit, date, and attribute
+ * combo, the value is returned from the period with the shortest duration.
*
* @param dataElements collection of DataElements to fetch for
* @param date date which must be present in the period
- * @param unit OrganisationUnit for which to fetch the values
+ * @param source OrganisationUnit for which to fetch the values
* @param periodTypes allowable period types in which to find the data
+ * @param attributeCombo the attribute combo to check (if restricted)
* @param lastUpdatedMap map in which to return the lastUpdated date for each value
- * @return
+ * @return map of values by attribute option combo id, then DataElementOperand
*/
- Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
- Collection<PeriodType> periodTypes, Map<DataElementOperand, Date> lastUpdatedMap );
+ MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
+ OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
+ MapMap<Integer, DataElementOperand, Date> lastUpdatedMap );
/**
* Gets a Collection of DeflatedDataValues.
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationResult.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationResult.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationResult.java 2014-05-18 00:49:40 +0000
@@ -28,6 +28,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.period.Period;
@@ -48,6 +49,8 @@
private Period period;
+ private DataElementCategoryOptionCombo attributeOptionCombo;
+
private ValidationRule validationRule;
private Double leftsideValue;
@@ -62,11 +65,13 @@
{
}
- public ValidationResult( Period period, OrganisationUnit source, ValidationRule validationRule,
+ public ValidationResult( Period period, OrganisationUnit source,
+ DataElementCategoryOptionCombo attributeOptionCombo, ValidationRule validationRule,
Double leftsideValue, Double rightsideValue )
{
this.source = source;
this.period = period;
+ this.attributeOptionCombo = attributeOptionCombo;
this.validationRule = validationRule;
this.leftsideValue = leftsideValue;
this.rightsideValue = rightsideValue;
@@ -90,6 +95,11 @@
return result;
}
+ //
+ // Note: this method is called from threads in which it may not be possible
+ // to initialize lazy Hibernate properties. So object properties to compare
+ // must be chosen accordingly.
+ //
@Override
public boolean equals( Object object )
{
@@ -122,6 +132,18 @@
return false;
}
+ if ( attributeOptionCombo == null )
+ {
+ if ( other.attributeOptionCombo != null )
+ {
+ return false;
+ }
+ }
+ else if ( attributeOptionCombo.getId() != other.attributeOptionCombo.getId() )
+ {
+ return false;
+ }
+
if ( source == null )
{
if ( other.source != null )
@@ -157,7 +179,7 @@
{
return false;
}
- else if ( Math.round( 100.0 * leftsideValue ) != Math.round( 100 * other.leftsideValue ) )
+ else if ( Math.round( 100.0 * leftsideValue ) != Math.round( 100.0 * other.leftsideValue ) )
{
return false;
}
@@ -173,7 +195,7 @@
{
return false;
}
- else if ( Math.round( 100.0 * leftsideValue ) != Math.round( 100 * other.leftsideValue ) )
+ else if ( Math.round( 100.0 * leftsideValue ) != Math.round( 100.0 * other.leftsideValue ) )
{
return false;
}
@@ -181,14 +203,19 @@
return true;
}
+ //
+ // Note: this method is called from threads in which it may not be possible
+ // to initialize lazy Hibernate properties. So object properties to compare
+ // must be chosen accordingly.
+ //
public int compareTo( ValidationResult other )
{
int result = source.getName().compareTo( other.source.getName() );
if ( result != 0 )
- {
+ {
return result;
- }
+ }
result = period.getStartDate().compareTo( other.period.getStartDate() );
@@ -204,6 +231,13 @@
return result;
}
+ result = attributeOptionCombo.getId() - other.attributeOptionCombo.getId();
+
+ if ( result != 0 )
+ {
+ return result;
+ }
+
result = validationImportanceOrder( validationRule.getImportance() ) - validationImportanceOrder( other.validationRule.getImportance() );
if ( result != 0 )
@@ -257,7 +291,7 @@
@Override
public String toString()
{
- return source + " - " + period + " - " + validationRule + " - " + leftsideValue + " - " + rightsideValue;
+ return source + " - " + period + " - " + attributeOptionCombo.getName() + " - " + validationRule + " - " + leftsideValue + " - " + rightsideValue;
}
// -------------------------------------------------------------------------
@@ -284,6 +318,16 @@
this.period = period;
}
+ public DataElementCategoryOptionCombo getAttributeOptionCombo()
+ {
+ return attributeOptionCombo;
+ }
+
+ public void setAttributeOptionCombo( DataElementCategoryOptionCombo attributeOptionCombo )
+ {
+ this.attributeOptionCombo = attributeOptionCombo;
+ }
+
public ValidationRule getValidationRule()
{
return validationRule;
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationRuleService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationRuleService.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/validation/ValidationRuleService.java 2014-05-18 00:49:40 +0000
@@ -32,6 +32,7 @@
import java.util.Date;
import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
import org.hisp.dhis.dataset.DataSet;
import org.hisp.dhis.i18n.I18nFormat;
import org.hisp.dhis.organisationunit.OrganisationUnit;
@@ -55,37 +56,27 @@
/**
* Validate DataValues.
*
- * @param startDate the start date.
- * @param endDate the end date.
- * @param sources a collection of Sources.
- * @param sendAlerts whether to send alerts for surveillance.
- * @param format the i18n format.
- * @return a collection of ValidationResults for each validation violation.
- */
- Collection<ValidationResult> validate( Date startDate, Date endDate, Collection<OrganisationUnit> sources, boolean sendAlerts, I18nFormat format );
-
- /**
- * Validate DataValues.
- *
- * @param startDate the start date.
- * @param endDate the end date.
- * @param sources a collection of Sources.
- * @param group a group of ValidationRules.
- * @param sendAlerts whether to send alerts for surveillance.
- * @param format the i18n format.
- * @return a collection of ValidationResults for each validation violation.
- */
- Collection<ValidationResult> validate( Date startDate, Date endDate, Collection<OrganisationUnit> sources, ValidationRuleGroup group, boolean sendAlerts, I18nFormat format );
+ * @param startDate the start date.
+ * @param endDate the end date.
+ * @param sources a collection of Sources.
+ * @param attributeCombo attribute category option combo (null for all).
+ * @param group validation rule group (null for all validationRules).
+ * @param sendAlerts whether to send alerts for surveillance.
+ * @param format the i18n format.
+ * @return a collection of ValidationResults for each validation violation.
+ */
+ Collection<ValidationResult> validate( Date startDate, Date endDate, Collection<OrganisationUnit> sources, DataElementCategoryOptionCombo attributeCombo, ValidationRuleGroup group, boolean sendAlerts, I18nFormat format );
/**
* Validate DataValues.
*
* @param dataSet the DataSet.
- * @param period the Period.
- * @param source the Source.
+ * @param period the Period.
+ * @param source the Organisation unit.
+ * @param attributeCombo attribute category option combo (null for all).
* @return a collection of ValidationResults for each validation violation.
*/
- Collection<ValidationResult> validate( DataSet dataSet, Period period, OrganisationUnit source );
+ Collection<ValidationResult> validate( DataSet dataSet, Period period, OrganisationUnit source, DataElementCategoryOptionCombo attributeCombo );
/**
* Validate DataValues.
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2014-04-30 17:30:27 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2014-05-18 00:49:40 +0000
@@ -75,7 +75,7 @@
import org.hisp.dhis.period.PeriodType;
import org.hisp.dhis.system.util.CollectionUtils;
import org.hisp.dhis.system.util.ListUtils;
-import org.hisp.dhis.system.util.MapMap;
+import org.hisp.dhis.common.MapMap;
import org.hisp.dhis.system.util.MathUtils;
/**
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java 2014-04-17 14:19:13 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/DefaultDataValueService.java 2014-05-18 00:49:40 +0000
@@ -37,6 +37,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.common.MapMap;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
import org.hisp.dhis.dataelement.DataElementCategoryService;
@@ -241,15 +242,11 @@
return dataValueStore.getDataValueCount( cal.getTime() );
}
- public Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Period period, OrganisationUnit source )
- {
- return dataValueStore.getDataValueMap( dataElements, period, source );
- }
-
- public Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
- Collection<PeriodType> periodTypes, Map<DataElementOperand, Date> lastUpdatedMap )
- {
- return dataValueStore.getDataValueMap( dataElements, date, source, periodTypes, lastUpdatedMap );
+ public MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date,
+ OrganisationUnit source, Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo,
+ MapMap<Integer, DataElementOperand, Date> lastUpdatedMap )
+ {
+ return dataValueStore.getDataValueMapByAttributeCombo( dataElements, date, source, periodTypes, attributeCombo, lastUpdatedMap );
}
public Collection<DeflatedDataValue> getDeflatedDataValues( int dataElementId, int periodId, Collection<Integer> sourceIds )
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java 2014-05-18 00:49:40 +0000
@@ -28,15 +28,14 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import static org.hisp.dhis.system.util.ConversionUtils.getIdentifiers;
import static org.hisp.dhis.system.util.TextUtils.getCommaDelimitedString;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -47,7 +46,10 @@
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
import org.hisp.dhis.dataelement.DataElementOperand;
import org.hisp.dhis.datavalue.DataValue;
import org.hisp.dhis.datavalue.DataValueStore;
@@ -60,6 +62,7 @@
import org.hisp.dhis.system.objectmapper.DeflatedDataValueRowMapper;
import org.hisp.dhis.system.util.ConversionUtils;
import org.hisp.dhis.system.util.DateUtils;
+import org.hisp.dhis.common.MapMap;
import org.hisp.dhis.system.util.MathUtils;
import org.hisp.dhis.system.util.TextUtils;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -99,6 +102,13 @@
this.jdbcTemplate = jdbcTemplate;
}
+ private DataElementCategoryService dataElementCategoryService;
+
+ public void setDataElementCategoryService( DataElementCategoryService dataElementCategoryService )
+ {
+ this.dataElementCategoryService = dataElementCategoryService;
+ }
+
// -------------------------------------------------------------------------
// Basic DataValue
// -------------------------------------------------------------------------
@@ -459,76 +469,47 @@
return rs != null ? rs.intValue() : 0;
}
-
- public Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Period period, OrganisationUnit source )
- {
- Map<DataElementOperand, Double> map = new HashMap<DataElementOperand, Double>();
-
- if ( dataElements.isEmpty() )
- {
- return map;
- }
-
- final String sql =
- "select de.uid, coc.uid, dv.value " +
- "from datavalue dv " +
- "join dataelement de on dv.dataelementid = de.dataelementid " +
- "join categoryoptioncombo coc on dv.categoryoptioncomboid = coc.categoryoptioncomboid " +
- "where dv.dataelementid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( DataElement.class, dataElements ) ) + ") " +
- "and dv.periodid = " + period.getId() + " " +
- "and dv.sourceid = " + source.getId();
-
- SqlRowSet rowSet = jdbcTemplate.queryForRowSet( sql );
-
- while ( rowSet.next() )
- {
- String dataElement = rowSet.getString( 1 );
- String categoryOptionCombo = rowSet.getString( 2 );
- Double value = MathUtils.parseDouble( rowSet.getString( 3 ) );
-
- if ( value != null )
- {
- map.put( new DataElementOperand( dataElement, categoryOptionCombo ), value );
- }
- }
-
- return map;
- }
-
- public Map<DataElementOperand, Double> getDataValueMap( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
- Collection<PeriodType> periodTypes, Map<DataElementOperand, Date> lastUpdatedMap )
- {
- Map<DataElementOperand, Double> map = new HashMap<DataElementOperand, Double>();
-
+
+ public MapMap<Integer, DataElementOperand, Double> getDataValueMapByAttributeCombo( Collection<DataElement> dataElements, Date date, OrganisationUnit source,
+ Collection<PeriodType> periodTypes, DataElementCategoryOptionCombo attributeCombo, MapMap<Integer, DataElementOperand, Date> lastUpdatedMap )
+ {
+ MapMap<Integer, DataElementOperand, Double> map = new MapMap<Integer, DataElementOperand, Double>();
+
if ( dataElements.isEmpty() || periodTypes.isEmpty() )
{
return map;
}
-
- final String sql =
- "select de.uid, coc.uid, dv.value, dv.lastupdated, p.startdate, p.enddate " +
- "from datavalue dv " +
- "join dataelement de on dv.dataelementid = de.dataelementid " +
- "join categoryoptioncombo coc on dv.categoryoptioncomboid = coc.categoryoptioncomboid " +
- "join period p on p.periodid = dv.periodid " +
- "where dv.dataelementid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( DataElement.class, dataElements ) ) + ") " +
- "and dv.sourceid = " + source.getId() + " " +
- "and p.startdate <= '" + DateUtils.getMediumDateString( date ) + "' " +
- "and p.enddate >= '" + DateUtils.getMediumDateString( date ) + "' " +
- "and p.periodtypeid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( PeriodType.class, periodTypes ) ) + ") ";
+
+ String sql =
+ "select de.uid, coc.uid, dv.attributeoptioncomboid, dv.value, dv.lastupdated, p.startdate, p.enddate " +
+ "from datavalue dv " +
+ "join dataelement de on dv.dataelementid = de.dataelementid " +
+ "join categoryoptioncombo coc on dv.categoryoptioncomboid = coc.categoryoptioncomboid " +
+ "join period p on p.periodid = dv.periodid " +
+ "where dv.dataelementid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( DataElement.class, dataElements ) ) + ") " +
+ "and dv.sourceid = " + source.getId() + " " +
+ "and p.startdate <= '" + DateUtils.getMediumDateString( date ) + "' " +
+ "and p.enddate >= '" + DateUtils.getMediumDateString( date ) + "' " +
+ "and p.periodtypeid in (" + TextUtils.getCommaDelimitedString( ConversionUtils.getIdentifiers( PeriodType.class, periodTypes ) ) + ") ";
+
+ if ( attributeCombo != null )
+ {
+ sql += " and dv.attributeoptioncomboid = " + attributeCombo.getId();
+ }
SqlRowSet rowSet = jdbcTemplate.queryForRowSet( sql );
-
- Map<DataElementOperand, Long> checkForDuplicates = new HashMap<DataElementOperand, Long>();
+
+ MapMap<Integer, DataElementOperand, Long> checkForDuplicates = new MapMap<Integer, DataElementOperand, Long>();
while ( rowSet.next() )
{
String dataElement = rowSet.getString( 1 );
String categoryOptionCombo = rowSet.getString( 2 );
- Double value = MathUtils.parseDouble( rowSet.getString( 3 ) );
- Date lastUpdated = rowSet.getDate( 4 );
- Date periodStartDate = rowSet.getDate( 5 );
- Date periodEndDate = rowSet.getDate( 6 );
+ Integer attributeOptionComboId = rowSet.getInt( 3 );
+ Double value = MathUtils.parseDouble( rowSet.getString( 4 ) );
+ Date lastUpdated = rowSet.getDate( 5 );
+ Date periodStartDate = rowSet.getDate( 6 );
+ Date periodEndDate = rowSet.getDate( 7 );
long periodInterval = periodEndDate.getTime() - periodStartDate.getTime();
log.trace( "row: " + dataElement + " = " + value + " [" + periodStartDate + " : " + periodEndDate + "]");
@@ -536,22 +517,22 @@
if ( value != null )
{
DataElementOperand dataElementOperand = new DataElementOperand( dataElement, categoryOptionCombo );
- Long existingPeriodInterval = checkForDuplicates.get( dataElementOperand );
-
+
+ Long existingPeriodInterval = checkForDuplicates.getValue( attributeOptionComboId, dataElementOperand );
+
if ( existingPeriodInterval != null && existingPeriodInterval < periodInterval )
{
// Don't overwrite the previous value if for a shorter interval
- continue;
+ continue;
}
-
- map.put( dataElementOperand, value );
-
+ map.putEntry( attributeOptionComboId, dataElementOperand, value );
+
if ( lastUpdatedMap != null )
{
- lastUpdatedMap.put( dataElementOperand, lastUpdated );
+ lastUpdatedMap.putEntry( attributeOptionComboId, dataElementOperand, lastUpdated );
}
-
- checkForDuplicates.put( dataElementOperand, periodInterval );
+
+ checkForDuplicates.putEntry( attributeOptionComboId, dataElementOperand, periodInterval );
}
}
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java 2014-03-31 10:24:23 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/DefaultValidationRuleService.java 2014-05-18 00:49:40 +0000
@@ -51,6 +51,8 @@
import org.hisp.dhis.common.GenericIdentifiableObjectStore;
import org.hisp.dhis.constant.ConstantService;
import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
import org.hisp.dhis.dataelement.DataElementOperand;
import org.hisp.dhis.dataentryform.DataEntryFormService;
import org.hisp.dhis.dataset.DataSet;
@@ -129,6 +131,13 @@
this.dataValueService = dataValueService;
}
+ private DataElementCategoryService dataElementCategoryService;
+
+ public void setDataElementCategoryService( DataElementCategoryService dataElementCategoryService )
+ {
+ this.dataElementCategoryService = dataElementCategoryService;
+ }
+
private ConstantService constantService;
public void setConstantService( ConstantService constantService )
@@ -169,22 +178,16 @@
// -------------------------------------------------------------------------
@Override
- public Collection<ValidationResult> validate( Date startDate, Date endDate, Collection<OrganisationUnit> sources, boolean sendAlerts, I18nFormat format )
- {
- return validate( startDate, endDate, sources, null, sendAlerts, format );
- }
-
- @Override
public Collection<ValidationResult> validate( Date startDate, Date endDate, Collection<OrganisationUnit> sources,
- ValidationRuleGroup group, boolean sendAlerts, I18nFormat format )
+ DataElementCategoryOptionCombo attributeCombo, ValidationRuleGroup group, boolean sendAlerts, I18nFormat format )
{
log.info( "Validate start:" + startDate + " end: " + endDate + " sources: " + sources.size() + " group: " + group );
Collection<Period> periods = periodService.getPeriodsBetweenDates( startDate, endDate );
Collection<ValidationRule> rules = group != null ? group.getMembers() : getAllValidationRules();
- Collection<ValidationResult> results = Validator.validate( sources, periods, rules, null,
- constantService, expressionService, periodService, dataValueService );
+ Collection<ValidationResult> results = Validator.validate( sources, periods, rules, attributeCombo, null,
+ constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
formatPeriods( results, format );
@@ -207,17 +210,19 @@
Collection<ValidationRule> rules = getAllValidationRules();
Collection<OrganisationUnit> sources = new HashSet<OrganisationUnit>();
sources.add( source );
-
- return Validator.validate( sources, periods, rules, null,
- constantService, expressionService, periodService, dataValueService );
+
+ return Validator.validate( sources, periods, rules, null, null,
+ constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
}
@Override
- public Collection<ValidationResult> validate( DataSet dataSet, Period period, OrganisationUnit source )
+ public Collection<ValidationResult> validate( DataSet dataSet, Period period, OrganisationUnit source,
+ DataElementCategoryOptionCombo attributeCombo )
{
log.info( "Validate data set: " + dataSet.getName() + " period: " + period.getPeriodType().getName() + " "
- + period.getStartDate() + " " + period.getEndDate() + " source: " + source.getName() );
-
+ + period.getStartDate() + " " + period.getEndDate() + " source: " + source.getName()
+ + " attribute combo: " + ( attributeCombo == null ? "(null)" : attributeCombo.getName() ) );
+
Collection<Period> periods = new ArrayList<Period>();
periods.add( period );
@@ -237,8 +242,8 @@
Collection<OrganisationUnit> sources = new HashSet<OrganisationUnit>();
sources.add( source );
- return Validator.validate( sources, periods, rules, null,
- constantService, expressionService, periodService, dataValueService );
+ return Validator.validate( sources, periods, rules, attributeCombo, null,
+ constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
}
@Override
@@ -263,8 +268,8 @@
log.info( "Scheduled monitoring run sources: " + sources.size() + ", periods: " + periods.size() + ", rules:" + rules.size()
+ ", last run: " + ( lastScheduledRun == null ? "[none]" : lastScheduledRun ) );
- Collection<ValidationResult> results = Validator.validate( sources, periods, rules,
- lastScheduledRun, constantService, expressionService, periodService, dataValueService );
+ Collection<ValidationResult> results = Validator.validate( sources, periods, rules, null, lastScheduledRun,
+ constantService, expressionService, periodService, dataValueService, dataElementCategoryService );
log.info( "Validation run result count: " + results.size() );
@@ -505,7 +510,8 @@
{
ValidationRule rule = result.getValidationRule();
- builder.append( result.getSource().getName() ).append( " " ).append( result.getPeriod().getName() ).append( LN ).
+ builder.append( result.getSource().getName() ).append( " " ).append( result.getPeriod().getName() ).
+ append( result.getAttributeOptionCombo().isDefault() ? "" : " " + result.getAttributeOptionCombo().getName() ).append( LN ).
append( rule.getName() ).append( " (" ).append( rule.getImportance() ).append( ") " ).append( LN ).
append( rule.getLeftSide().getDescription() ).append( ": " ).append( result.getLeftsideValue() ).append( LN ).
append( rule.getRightSide().getDescription() ).append( ": " ).append( result.getRightsideValue() ).append( LN ).append( LN );
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/OrganisationUnitExtended.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/OrganisationUnitExtended.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/OrganisationUnitExtended.java 2014-05-18 00:49:40 +0000
@@ -37,7 +37,7 @@
/**
* Holds information for each organisation unit that is needed during a
- * validation run (either interactive or an alert run).
+ * validation run (either interactive or a scheduled run).
*
* It is important that they should be copied from Hibernate lazy collections
* before the multithreaded part of the run starts, otherwise the threads may
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/PeriodTypeExtended.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/PeriodTypeExtended.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/PeriodTypeExtended.java 2014-05-18 00:49:40 +0000
@@ -43,7 +43,7 @@
/**
* Holds information for each period type that is needed during
- * a validation run (either interactive or an alert run).
+ * a validation run (either interactive or a scheduled run).
*
* By computing these values once at the start of a validation run, we avoid
* the overhead of having to compute them during the processing of every
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRuleExtended.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRuleExtended.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRuleExtended.java 2014-05-18 00:49:40 +0000
@@ -34,7 +34,7 @@
/**
* Holds information for each validation rule that is needed during a validation
- * run (either interactive or an alert run).
+ * run (either interactive or a scheduled run).
*
* By computing these values once at the start of a validation run, we avoid the
* overhead of having to compute them during the processing of every
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidationRunContext.java 2014-05-18 00:49:40 +0000
@@ -42,6 +42,8 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
import org.hisp.dhis.dataset.DataSet;
import org.hisp.dhis.datavalue.DataValueService;
import org.hisp.dhis.expression.ExpressionService;
@@ -81,6 +83,8 @@
private Map<ValidationRule, ValidationRuleExtended> ruleXMap;
private Collection<OrganisationUnitExtended> sourceXs;
+
+ private DataElementCategoryOptionCombo attributeCombo;
private int countOfSourcesToValidate;
@@ -92,6 +96,8 @@
private DataValueService dataValueService;
+ private DataElementCategoryService dataElementCategoryService;
+
private ValidationRunContext()
{
}
@@ -113,15 +119,17 @@
*
* @param sources organisation units for validation
* @param periods periods for validation
+ * @param attributeCombo the attribute combo to check (if restricted)
* @param rules validation rules for validation
* @param runType whether this is an INTERACTIVE or SCHEDULED run
* @param lastScheduledRun (for SCHEDULED runs) date/time of previous run
* @return context object for this run
*/
public static ValidationRunContext getNewValidationRunContext( Collection<OrganisationUnit> sources,
- Collection<Period> periods, Collection<ValidationRule> rules, Map<String, Double> constantMap,
- ValidationRunType runType, Date lastScheduledRun, ExpressionService expressionService, PeriodService periodService,
- DataValueService dataValueService )
+ Collection<Period> periods, DataElementCategoryOptionCombo attributeCombo, Collection<ValidationRule> rules,
+ Map<String, Double> constantMap, ValidationRunType runType, Date lastScheduledRun,
+ ExpressionService expressionService, PeriodService periodService,
+ DataValueService dataValueService, DataElementCategoryService dataElementCategoryService )
{
ValidationRunContext context = new ValidationRunContext();
context.runType = runType;
@@ -134,6 +142,8 @@
context.expressionService = expressionService;
context.periodService = periodService;
context.dataValueService = dataValueService;
+ context.dataElementCategoryService = dataElementCategoryService;
+ context.attributeCombo = attributeCombo;
context.initialize( sources, periods, rules );
return context;
}
@@ -328,7 +338,6 @@
* creates a new PeriodTypeExtended object, puts it into the context object,
* and returns it.
*
- * @param context validation run context
* @param periodType period type to search for
* @return period type extended from the context object
*/
@@ -405,6 +414,11 @@
return sourceXs;
}
+ public DataElementCategoryOptionCombo getAttributeCombo()
+ {
+ return attributeCombo;
+ }
+
public int getCountOfSourcesToValidate()
{
return countOfSourcesToValidate;
@@ -429,4 +443,9 @@
{
return dataValueService;
}
+
+ public DataElementCategoryService getDataElementCategoryService()
+ {
+ return dataElementCategoryService;
+ }
}
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/Validator.java 2014-05-18 00:49:40 +0000
@@ -35,6 +35,9 @@
import java.util.concurrent.TimeUnit;
import org.hisp.dhis.constant.ConstantService;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
import org.hisp.dhis.datavalue.DataValueService;
import org.hisp.dhis.expression.ExpressionService;
import org.hisp.dhis.organisationunit.OrganisationUnit;
@@ -57,23 +60,25 @@
*
* @param sources the organisation units in which to run the validation rules
* @param periods the periods of data to check
+ * @param attributeCombo the attribute combo to check (if restricted)
* @param rules the ValidationRules to evaluate
- * @param runType whether this is an INTERACTIVE or SCHEDULED run
* @param lastScheduledRun date/time of the most recent successful
* scheduled monitoring run (needed only for scheduled runs)
* @param constantService Constant Service reference
* @param expressionService Expression Service reference
* @param periodService Period Service reference
* @param dataValueService Data Value Service reference
+ * @param dataElementCategoryService Data Element Category Service reference
* @return a collection of any validations that were found
*/
- public static Collection<ValidationResult> validate( Collection<OrganisationUnit> sources,
- Collection<Period> periods, Collection<ValidationRule> rules, Date lastScheduledRun,
- ConstantService constantService, ExpressionService expressionService, PeriodService periodService, DataValueService dataValueService )
+ public static Collection<ValidationResult> validate( Collection<OrganisationUnit> sources, Collection<Period> periods,
+ Collection<ValidationRule> rules, DataElementCategoryOptionCombo attributeCombo, Date lastScheduledRun,
+ ConstantService constantService, ExpressionService expressionService, PeriodService periodService,
+ DataValueService dataValueService, DataElementCategoryService dataElementCategoryService )
{
- ValidationRunContext context = ValidationRunContext.getNewValidationRunContext( sources, periods, rules,
- constantService.getConstantMap(), ValidationRunType.SCHEDULED, lastScheduledRun,
- expressionService, periodService, dataValueService );
+ ValidationRunContext context = ValidationRunContext.getNewValidationRunContext( sources, periods,
+ attributeCombo, rules, constantService.getConstantMap(), ValidationRunType.SCHEDULED, lastScheduledRun,
+ expressionService, periodService, dataValueService, dataElementCategoryService );
int threadPoolSize = getThreadPoolSize( context );
ExecutorService executor = Executors.newFixedThreadPool( threadPoolSize );
@@ -97,7 +102,9 @@
{
executor.shutdownNow();
}
-
+
+ reloadAttributeOptionCombos( context.getValidationResults(), dataElementCategoryService );
+
return context.getValidationResults();
}
@@ -123,4 +130,18 @@
return threadPoolSize;
}
+
+ /**
+ * Reload attribute category option combos into this Hibernate context.
+ *
+ * @param results
+ * @param dataElementCategoryService
+ */
+ private static void reloadAttributeOptionCombos( Collection<ValidationResult> results, DataElementCategoryService dataElementCategoryService )
+ {
+ for ( ValidationResult result : results )
+ {
+ result.setAttributeOptionCombo( dataElementCategoryService.getDataElementCategoryOptionCombo( result.getAttributeOptionCombo().getId() ) );
+ }
+ }
}
=== 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 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/validation/ValidatorThread.java 2014-05-18 00:49:40 +0000
@@ -32,7 +32,6 @@
import static org.hisp.dhis.system.util.MathUtils.roundSignificant;
import static org.hisp.dhis.system.util.MathUtils.zeroIfNull;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
@@ -46,8 +45,12 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.common.ListMap;
+import org.hisp.dhis.common.MapMap;
+import org.hisp.dhis.common.SetMap;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.dataelement.DataElementOperand;
+import org.hisp.dhis.expression.Expression;
import org.hisp.dhis.expression.Operator;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.period.CalendarPeriodType;
@@ -76,84 +79,88 @@
this.context = context;
}
+ /**
+ * Evaluates validation rules for a single organisation unit. This is the
+ * central method in validation rule evaluation.
+ */
@Override
public void run()
{
- validateSource( sourceX, context );
- }
-
- /**
- * Evaluates validation rules for a single organisation unit. This is the
- * central method in validation rule evaluation.
- *
- * @param sourceX extended object of the organisation unit in which to run
- * the validation rules
- * @param context the validation run context
- */
- private void validateSource( OrganisationUnitExtended sourceX, ValidationRunContext context )
- {
if ( context.getValidationResults().size() < ( ValidationRunType.INTERACTIVE == context.getRunType() ?
ValidationRuleService.MAX_INTERACTIVE_ALERTS : ValidationRuleService.MAX_SCHEDULED_ALERTS) )
{
for ( PeriodTypeExtended periodTypeX : context.getPeriodTypeExtendedMap().values() )
{
Collection<DataElement> sourceDataElements = periodTypeX.getSourceDataElements().get( sourceX.getSource() );
- Set<ValidationRule> rules = getRulesBySourceAndPeriodType( sourceX, periodTypeX, context,
- sourceDataElements );
+ Set<ValidationRule> rules = getRulesBySourceAndPeriodType( sourceX, periodTypeX, sourceDataElements );
if ( !rules.isEmpty() )
{
Set<DataElement> recursiveCurrentDataElements = getRecursiveCurrentDataElements( rules );
for ( Period period : periodTypeX.getPeriods() )
{
- Map<DataElementOperand, Date> lastUpdatedMap = new HashMap<DataElementOperand, Date>();
- Set<DataElementOperand> incompleteValues = new HashSet<DataElementOperand>();
- Map<DataElementOperand, Double> currentValueMap = getDataValueMapRecursive( periodTypeX,
- periodTypeX.getDataElements(), sourceDataElements, recursiveCurrentDataElements,
- periodTypeX.getAllowedPeriodTypes(), period, sourceX.getSource(), lastUpdatedMap, incompleteValues );
+ MapMap<Integer, DataElementOperand, Date> lastUpdatedMap2 = new MapMap<Integer, DataElementOperand, Date>();
+ SetMap<Integer, DataElementOperand> incompleteValuesMap2 = new SetMap<Integer, DataElementOperand>();
+ MapMap<Integer, DataElementOperand, Double> currentValueMap2 = getValueMap2( periodTypeX,
+ periodTypeX.getDataElements(), sourceDataElements, recursiveCurrentDataElements,
+ periodTypeX.getAllowedPeriodTypes(), period, sourceX.getSource(), lastUpdatedMap2, incompleteValuesMap2 );
log.trace( "Source " + sourceX.getSource().getName()
+ " [" + period.getStartDate() + " - " + period.getEndDate() + "]"
- + " valueMap[" + currentValueMap.size() + "]" );
+ + " currentValueMap2[" + currentValueMap2.size() + "]" );
for ( ValidationRule rule : rules )
{
- if ( evaluateCheck( lastUpdatedMap, rule, context ) )
+ if ( evaluateCheck( currentValueMap2, lastUpdatedMap2, rule ) )
{
- Double leftSide = context.getExpressionService().getExpressionValue( rule.getLeftSide(),
- currentValueMap, context.getConstantMap(), null, null, incompleteValues );
+ Map<Integer, Double> leftSideValues = getExpressionValueMap( rule.getLeftSide(),
+ currentValueMap2, incompleteValuesMap2 );
- if ( leftSide != null || Operator.compulsory_pair.equals( rule.getOperator() ) )
+ if ( !leftSideValues.isEmpty() || Operator.compulsory_pair.equals( rule.getOperator() ) )
{
- Double rightSide = getRightSideValue( sourceX.getSource(), periodTypeX, period, rule,
- currentValueMap, sourceDataElements, context );
+ Map<Integer, Double> rightSideValues = getRightSideValue( sourceX.getSource(), periodTypeX, period, rule,
+ currentValueMap2, sourceDataElements );
- if ( rightSide != null || Operator.compulsory_pair.equals( rule.getOperator() ) )
+ if ( !rightSideValues.isEmpty() || Operator.compulsory_pair.equals( rule.getOperator() ) )
{
- boolean violation = false;
-
+ Set<Integer> combos = leftSideValues.keySet();
if ( Operator.compulsory_pair.equals( rule.getOperator() ) )
{
- violation = (leftSide != null && rightSide == null)
- || (leftSide == null && rightSide != null);
- }
- else if ( leftSide != null && rightSide != null )
- {
- violation = !expressionIsTrue( leftSide, rule.getOperator(), rightSide );
- }
-
- if ( violation )
- {
- context.getValidationResults().add( new ValidationResult(
- period, sourceX.getSource(), rule,
- roundSignificant( zeroIfNull( leftSide ) ),
- roundSignificant( zeroIfNull( rightSide ) ) ) );
- }
-
- log.trace( "-->Evaluated " + rule.getName() + ": "
- + (violation ? "violation" : "OK") + " " + leftSide.toString() + " "
- + rule.getOperator() + " " + rightSide.toString() + " ("
- + context.getValidationResults().size() + " results)" );
+ combos = new HashSet<Integer>( combos );
+ combos.addAll( rightSideValues.keySet() );
+ }
+
+ for ( int combo : combos )
+ {
+ Double leftSide = leftSideValues.get ( combo );
+ Double rightSide = rightSideValues.get ( combo );
+ boolean violation = false;
+
+ if ( Operator.compulsory_pair.equals( rule.getOperator() ) )
+ {
+ violation = (leftSide != null && rightSide == null)
+ || (leftSide == null && rightSide != null);
+ }
+ else if ( leftSide != null && rightSide != null )
+ {
+ violation = !expressionIsTrue( leftSide, rule.getOperator(), rightSide );
+ }
+
+ if ( violation )
+ {
+ context.getValidationResults().add( new ValidationResult(
+ period, sourceX.getSource(),
+ context.getDataElementCategoryService().getDataElementCategoryOptionCombo( combo ), rule,
+ roundSignificant( zeroIfNull( leftSide ) ),
+ roundSignificant( zeroIfNull( rightSide ) ) ) );
+ }
+
+ log.trace( "-->Evaluated " + rule.getName()
+ + ", combo id " + combo + ": "
+ + (violation ? "violation" : "OK") + " " + ( leftSide == null ? "(null)" : leftSide.toString() )
+ + " " + rule.getOperator() + " " + ( rightSide == null ? "(null)" : rightSide.toString() )
+ + " (" + context.getValidationResults().size() + " results)" );
+ }
}
}
}
@@ -170,13 +177,12 @@
*
* @param sourceX the organisation unit extended information
* @param periodTypeX the period type extended information
- * @param context the validation run context
* @param sourceDataElements all data elements collected for this
* organisation unit
- * @return
+ * @return set of rules for this org unit and period type
*/
private Set<ValidationRule> getRulesBySourceAndPeriodType( OrganisationUnitExtended sourceX,
- PeriodTypeExtended periodTypeX, ValidationRunContext context, Collection<DataElement> sourceDataElements )
+ PeriodTypeExtended periodTypeX, Collection<DataElement> sourceDataElements )
{
Set<ValidationRule> periodTypeRules = new HashSet<ValidationRule>();
@@ -210,22 +216,24 @@
return periodTypeRules;
}
-
/**
* Checks to see if the evaluation should go further for this
* evaluationRule, after the "current" data to evaluate has been fetched.
* For INTERACTIVE runs, we always go further (always return true.) For
* SCHEDULED runs, we go further only if something has changed since the
* last successful scheduled run -- either the rule definition or one of
- * the "current" data element / option values.
- *
- * @param lastUpdatedMap when each data value was last updated
+ * the "current" data element / option values on the left or right sides.
+ *
+ * For scheduled runs, remove all values for any attribute option combos
+ * where nothing has changed since the last run.
+ *
+ * @param lastUpdatedMapMap when each data value was last updated
* @param rule the rule that may be evaluated
- * @param context the evaluation run context
* @return true if the rule should be evaluated with this data, false if not
*/
- private boolean evaluateCheck( Map<DataElementOperand, Date> lastUpdatedMap, ValidationRule rule,
- ValidationRunContext context )
+ private boolean evaluateCheck( MapMap<Integer, DataElementOperand, Double> currentValueMapMap,
+ MapMap<Integer, DataElementOperand, Date> lastUpdatedMapMap,
+ ValidationRule rule )
{
boolean evaluate = true; // Assume true for now.
@@ -237,7 +245,7 @@
{
// Get the "current" DataElementOperands from this rule:
// Left+Right sides for VALIDATION, Left side only for
- // SURVEILLANCE
+ // SURVEILLANCE.
Collection<DataElementOperand> deos = context.getExpressionService().getOperandsInExpression(
rule.getLeftSide().getExpression() );
@@ -251,13 +259,25 @@
// Return true if any data is more recent than the last
// scheduled run, otherwise return false.
evaluate = false;
- for ( DataElementOperand deo : deos )
+
+ for ( Map.Entry<Integer, Map<DataElementOperand, Date>> entry : lastUpdatedMapMap.entrySet() )
{
- Date lastUpdated = lastUpdatedMap.get( deo );
- if ( lastUpdated != null && lastUpdated.after( context.getLastScheduledRun() ) )
- {
- evaluate = true; // True if new/updated data.
- break;
+ boolean saveThisCombo = false;
+
+ for ( DataElementOperand deo : deos )
+ {
+ Date lastUpdated = entry.getValue().get( deo );
+ if ( lastUpdated != null && lastUpdated.after( context.getLastScheduledRun() ) )
+ {
+ saveThisCombo = true; // True if new/updated data.
+ evaluate = true;
+ break;
+ }
+ }
+
+ if ( !saveThisCombo )
+ {
+ currentValueMapMap.remove( entry.getKey() );
}
}
}
@@ -266,7 +286,6 @@
return evaluate;
}
-
/**
* Gets the data elements for which values should be fetched recursively if
* they are not collected for an organisation unit.
@@ -297,17 +316,16 @@
* @param periodTypeX period type being evaluated
* @param period period being evaluated
* @param rule ValidationRule being evaluated
- * @param currentValueMap current values already fetched
+ * @param currentValueMap2 current values already fetched
* @param sourceDataElements the data elements collected by the organisation
* unit
- * @param context the validation run context
- * @return the right-side value
+ * @return the right-side values, map by attribute category combo
*/
- private Double getRightSideValue( OrganisationUnit source, PeriodTypeExtended periodTypeX, Period period,
- ValidationRule rule, Map<DataElementOperand, Double> currentValueMap,
- Collection<DataElement> sourceDataElements, ValidationRunContext context )
+ private Map<Integer, Double> getRightSideValue( OrganisationUnit source, PeriodTypeExtended periodTypeX, Period period,
+ ValidationRule rule, MapMap<Integer, DataElementOperand, Double> currentValueMap2,
+ Collection<DataElement> sourceDataElements )
{
- Double rightSideValue = null;
+ Map<Integer, Double> rightSideValues;
// If ruleType is VALIDATION, the right side is evaluated using the same
// (current) data values. If ruleType is SURVEILLANCE but there are no
@@ -318,8 +336,7 @@
if ( ValidationRule.RULE_TYPE_VALIDATION.equals( rule.getRuleType() )
|| rule.getRightSide().getDataElementsInExpression().isEmpty() )
{
- rightSideValue = context.getExpressionService().getExpressionValue( rule.getRightSide(),
- currentValueMap, context.getConstantMap(), null, null );
+ rightSideValues = getExpressionValueMap( rule.getRightSide(), currentValueMap2, new SetMap<Integer, DataElementOperand>() );
}
else
// ruleType equals SURVEILLANCE, and there are some data elements in the
@@ -327,7 +344,7 @@
{
CalendarPeriodType calendarPeriodType = ( CalendarPeriodType ) period.getPeriodType();
Collection<PeriodType> rightSidePeriodTypes = context.getRuleXMap().get( rule ).getAllowedPastPeriodTypes();
- List<Double> sampleValues = new ArrayList<Double>();
+ ListMap<Integer, Double> sampleValuesMap = new ListMap<Integer, Double>();
Calendar yearlyCalendar = PeriodType.createCalendarInstance( period.getStartDate() );
int annualSampleCount = rule.getAnnualSampleCount() == null ? 0 : rule.getAnnualSampleCount();
int sequentialSampleCount = rule.getSequentialSampleCount() == null ? 0 : rule
@@ -350,8 +367,8 @@
{
// Fetch the period at the same time of year as the
// starting period.
- evaluateRightSidePeriod( periodTypeX, sampleValues, source, rightSidePeriodTypes, yearlyPeriod,
- rule, sourceDataElements, context );
+ evaluateRightSidePeriod( periodTypeX, sampleValuesMap, source, rightSidePeriodTypes, yearlyPeriod,
+ rule, sourceDataElements );
// Fetch the sequential periods after this prior-year
// period.
@@ -359,8 +376,8 @@
for ( int sequentialCount = 0; sequentialCount < sequentialSampleCount; sequentialCount++ )
{
sequentialPeriod = calendarPeriodType.getNextPeriod( sequentialPeriod );
- evaluateRightSidePeriod( periodTypeX, sampleValues, source, rightSidePeriodTypes,
- sequentialPeriod, rule, sourceDataElements, context );
+ evaluateRightSidePeriod( periodTypeX, sampleValuesMap, source, rightSidePeriodTypes,
+ sequentialPeriod, rule, sourceDataElements );
}
}
@@ -370,17 +387,22 @@
for ( int sequentialCount = 0; sequentialCount < sequentialSampleCount; sequentialCount++ )
{
sequentialPeriod = calendarPeriodType.getPreviousPeriod( sequentialPeriod );
- evaluateRightSidePeriod( periodTypeX, sampleValues, source, rightSidePeriodTypes,
- sequentialPeriod, rule, sourceDataElements, context );
+ evaluateRightSidePeriod( periodTypeX, sampleValuesMap, source, rightSidePeriodTypes,
+ sequentialPeriod, rule, sourceDataElements );
}
// Move to the previous year:
yearlyCalendar.set( Calendar.YEAR, yearlyCalendar.get( Calendar.YEAR ) - 1 );
}
-
- rightSideValue = rightSideAverage( rule, sampleValues, annualSampleCount, sequentialSampleCount );
+
+ rightSideValues = new HashMap<Integer, Double>();
+ for ( Map.Entry<Integer, List<Double>> e : sampleValuesMap.entrySet() )
+ {
+ rightSideValues.put( e.getKey(), rightSideAverage( rule, e.getValue(), annualSampleCount, sequentialSampleCount) );
+ }
+
}
- return rightSideValue;
+ return rightSideValues;
}
/**
@@ -393,18 +415,17 @@
* organisation units.
*
* @param periodTypeX the period type extended information
- * @param sampleValues the list of sample values to add to
+ * @param sampleValuesMap the lists of sample values to add to
* @param source the organisation unit
* @param allowedPeriodTypes the period types in which the data may exist
* @param period the main period for the validation rule evaluation
* @param rule the surveillance-type rule being evaluated
* @param sourceDataElements the data elements configured for this
* organisation unit
- * @param context the evaluation run context
*/
- private void evaluateRightSidePeriod( PeriodTypeExtended periodTypeX, List<Double> sampleValues,
+ private void evaluateRightSidePeriod( PeriodTypeExtended periodTypeX, ListMap<Integer, Double> sampleValuesMap,
OrganisationUnit source, Collection<PeriodType> allowedPeriodTypes, Period period, ValidationRule rule,
- Collection<DataElement> sourceDataElements, ValidationRunContext context )
+ Collection<DataElement> sourceDataElements )
{
Period periodInstance = context.getPeriodService().getPeriod( period.getStartDate(), period.getEndDate(),
period.getPeriodType() );
@@ -412,24 +433,41 @@
if ( periodInstance != null )
{
Set<DataElement> dataElements = rule.getRightSide().getDataElementsInExpression();
- Set<DataElementOperand> incompleteValues = new HashSet<DataElementOperand>();
- 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, null, incompleteValues );
-
- if ( value != null )
- {
- sampleValues.add( value );
- }
-
- log.trace( "ValidationRightSide[" + dataValueMap.size()+ "] - sample "
- + (value == null ? "(null)" : value) + " [" + period.getStartDate() + " - " + period.getEndDate() + "]" );
+ SetMap<Integer, DataElementOperand> incompleteValuesMap = new SetMap<Integer, DataElementOperand>();
+ MapMap<Integer, DataElementOperand, Double> dataValueMapByAttributeCombo = getValueMap2( periodTypeX, dataElements,
+ sourceDataElements, dataElements, allowedPeriodTypes, period, source, null, incompleteValuesMap );
+ sampleValuesMap.putValueMap( getExpressionValueMap( rule.getRightSide(), dataValueMapByAttributeCombo, incompleteValuesMap ) );
}
- else
+ }
+
+ /**
+ * Evaluates an expresssion, returning a map of values by attribute option
+ * combo.
+ *
+ * @param expression expression to evaluate.
+ * @param valueMap2 Map of value maps, by attribute option combo.
+ * @param incompleteValuesMap map of values that were incomplete.
+ * @return map of values.
+ */
+ private Map<Integer, Double> getExpressionValueMap( Expression expression,
+ MapMap<Integer, DataElementOperand, Double> valueMap2,
+ SetMap<Integer, DataElementOperand> incompleteValuesMap )
+ {
+ Map<Integer, Double> expressionValueMap = new HashMap<Integer, Double>();
+
+ for ( Map.Entry<Integer, Map<DataElementOperand, Double>> e : valueMap2.entrySet() )
{
- log.trace( "ValidationRightSide - no period [" + period.getStartDate() + " - " + period.getEndDate() + "]" );
+ expressionValueMap.put(
+ e.getKey(),
+ context.getExpressionService()
+ .getExpressionValue( expression,
+ e.getValue(),
+ context.getConstantMap(),
+ null, null, incompleteValuesMap.getSet(
+ e.getKey() ) ) );
}
+
+ return expressionValueMap;
}
/**
@@ -442,7 +480,7 @@
* @param sequentialSampleCount number of sequential samples tried for
* @return average right-side sample value
*/
- Double rightSideAverage( ValidationRule rule, List<Double> sampleValues, int annualSampleCount,
+ private Double rightSideAverage( ValidationRule rule, List<Double> sampleValues, int annualSampleCount,
int sequentialSampleCount )
{
// Find the expected sample count for the last period of its type in the
@@ -500,14 +538,15 @@
* @param period period in which we are looking for values
* @param source organisation unit for which we are looking for values
* @param lastUpdatedMap map showing when each data values was last updated
- * @param incompleteValues ongoing list showing which values were found but
- * not from all children
- * @return the map of values found
+ * @param incompleteValuesMap ongoing set showing which values were found
+ * but not from all children, mapped by attribute option combo.
+ * @return map of attribute option combo to map of values found.
*/
- private Map<DataElementOperand, Double> getDataValueMapRecursive( PeriodTypeExtended periodTypeX,
- Collection<DataElement> ruleDataElements, Collection<DataElement> sourceDataElements,
- Set<DataElement> recursiveDataElements, Collection<PeriodType> allowedPeriodTypes, Period period,
- OrganisationUnit source, Map<DataElementOperand, Date> lastUpdatedMap, Set<DataElementOperand> incompleteValues )
+ private MapMap<Integer, DataElementOperand, Double> getValueMap2( PeriodTypeExtended periodTypeX,
+ Collection<DataElement> ruleDataElements, Collection<DataElement> sourceDataElements,
+ Set<DataElement> recursiveDataElements, Collection<PeriodType> allowedPeriodTypes, Period period,
+ OrganisationUnit source, MapMap<Integer, DataElementOperand, Date> lastUpdatedMap,
+ SetMap<Integer, DataElementOperand> incompleteValuesMap )
{
Set<DataElement> dataElementsToGet = new HashSet<DataElement>( ruleDataElements );
dataElementsToGet.retainAll( sourceDataElements );
@@ -518,17 +557,17 @@
+ "] recursiveDataElements[" + recursiveDataElements.size()
+ "] allowedPeriodTypes[" + allowedPeriodTypes.size() + "]" );
- Map<DataElementOperand, Double> dataValueMap;
+ MapMap<Integer, DataElementOperand, Double> dataValueMap2;
if ( dataElementsToGet.isEmpty() )
{
// We still might get something recursively
- dataValueMap = new HashMap<DataElementOperand, Double>();
+ dataValueMap2 = new MapMap<Integer, DataElementOperand, Double>();
}
else
{
- dataValueMap = context.getDataValueService().getDataValueMap( dataElementsToGet, period.getStartDate(), source,
- allowedPeriodTypes, lastUpdatedMap );
+ dataValueMap2 = context.getDataValueService().getDataValueMapByAttributeCombo( dataElementsToGet,
+ period.getStartDate(), source, allowedPeriodTypes, context.getAttributeCombo(), lastUpdatedMap );
}
// See if there are any data elements we need to get recursively:
@@ -537,38 +576,54 @@
if ( !recursiveDataElementsNeeded.isEmpty() )
{
int childCount = 0;
- Map<DataElementOperand, Integer> childValueCounts = new HashMap<DataElementOperand, Integer>();
+ MapMap<Integer, DataElementOperand, Integer> childValueCounts = new MapMap<Integer, DataElementOperand, Integer>();
for ( OrganisationUnit child : source.getChildren() )
{
Collection<DataElement> childDataElements = periodTypeX.getSourceDataElements().get( child );
- Map<DataElementOperand, Double> childMap = getDataValueMapRecursive( periodTypeX,
- recursiveDataElementsNeeded, childDataElements, recursiveDataElementsNeeded, allowedPeriodTypes,
- period, child, lastUpdatedMap, incompleteValues );
+ MapMap<Integer, DataElementOperand, Double> childMap = getValueMap2( periodTypeX,
+ recursiveDataElementsNeeded, childDataElements, recursiveDataElementsNeeded, allowedPeriodTypes,
+ period, child, lastUpdatedMap, incompleteValuesMap );
- for ( DataElementOperand deo : childMap.keySet() )
+ for ( Map.Entry<Integer, Map<DataElementOperand, Double>> entry : childMap.entrySet() )
{
- Double baseValue = dataValueMap.get( deo );
- dataValueMap.put( deo, baseValue == null ? childMap.get( deo ) : baseValue + childMap.get( deo ) );
-
- Integer childValueCount = childValueCounts.get( deo );
- childValueCounts.put( deo, childValueCount == null ? 1 : childValueCount + 1 );
+ int combo = entry.getKey();
+
+ for ( Map.Entry<DataElementOperand, Double> e : entry.getValue().entrySet() )
+ {
+ DataElementOperand deo = e.getKey();
+ Double childValue = e.getValue();
+
+ Double baseValue = dataValueMap2.getValue( combo, deo );
+ dataValueMap2.putEntry( combo, deo, baseValue == null ? childValue : baseValue + childValue );
+
+ Integer childValueCount = childValueCounts.getValue( combo, deo );
+ childValueCounts.putEntry( combo, deo, childValueCount == null ? 1 : childValueCount + 1 );
+ }
}
childCount++;
}
-
- for ( Map.Entry<DataElementOperand, Integer> entry : childValueCounts.entrySet() )
+
+ for ( Map.Entry<Integer, Map<DataElementOperand, Integer>> entry : childValueCounts.entrySet() )
{
- if ( childCount != entry.getValue() )
+ int combo = entry.getKey();
+
+ for ( Map.Entry<DataElementOperand, Integer> e : entry.getValue().entrySet() )
{
- // Remember that we found this DataElementOperand value
- // in some but not all children
- incompleteValues.add( entry.getKey() );
+ DataElementOperand deo = e.getKey();
+ Integer childValueCount = e.getValue();
+
+ if ( childValueCount != childCount )
+ {
+ // Remember that we found this DataElementOperand value
+ // in some but not all children
+ incompleteValuesMap.putValue( combo, deo );
+ }
}
}
}
- return dataValueMap;
+ return dataValueMap2;
}
}
=== 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-05-15 16:58:37 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2014-05-18 00:49:40 +0000
@@ -504,6 +504,7 @@
<property name="periodService" ref="org.hisp.dhis.period.PeriodService" />
<property name="constantService" ref="org.hisp.dhis.constant.ConstantService" />
<property name="dataValueService" ref="org.hisp.dhis.datavalue.DataValueService" />
+ <property name="dataElementCategoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
<property name="i18nService" ref="org.hisp.dhis.i18n.I18nService" />
<property name="messageService" ref="org.hisp.dhis.message.MessageService" />
<property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/validation/ValidationRuleServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/validation/ValidationRuleServiceTest.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/validation/ValidationRuleServiceTest.java 2014-05-18 00:49:40 +0000
@@ -48,6 +48,9 @@
import org.hisp.dhis.DhisTest;
import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategory;
+import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
import org.hisp.dhis.dataelement.DataElementCategoryService;
import org.hisp.dhis.dataelement.DataElementService;
@@ -179,6 +182,8 @@
private ValidationRule validationRuleD;
+ private ValidationRule validationRuleX;
+
private ValidationRule monitoringRuleE;
private ValidationRule monitoringRuleF;
@@ -203,6 +208,8 @@
private PeriodType periodTypeYearly;
+ private DataElementCategoryOptionCombo defaultCombo;
+
// -------------------------------------------------------------------------
// Fixture
// -------------------------------------------------------------------------
@@ -233,6 +240,8 @@
periodService = (PeriodService) getBean( PeriodService.ID );
+ categoryService = (DataElementCategoryService) getBean( DataElementCategoryService.ID );
+
periodTypeWeekly = new WeeklyPeriodType();
periodTypeMonthly = new MonthlyPeriodType();
periodTypeYearly = new YearlyPeriodType();
@@ -379,11 +388,12 @@
dataElementService.updateDataElement( dataElementD );
dataElementService.updateDataElement( dataElementE );
- validationRuleA = createValidationRule( 'A', equal_to, expressionA, expressionB, periodTypeMonthly );
- validationRuleB = createValidationRule( 'B', greater_than, expressionB, expressionC, periodTypeMonthly );
- validationRuleC = createValidationRule( 'C', less_than_or_equal_to, expressionB, expressionA, periodTypeMonthly );
- validationRuleD = createValidationRule( 'D', less_than, expressionA, expressionC, periodTypeMonthly );
-
+ validationRuleA = createValidationRule( 'A', equal_to, expressionA, expressionB, periodTypeMonthly ); // deA + deB = deC - deD
+ validationRuleB = createValidationRule( 'B', greater_than, expressionB, expressionC, periodTypeMonthly ); // deC - deD > deB * 2
+ validationRuleC = createValidationRule( 'C', less_than_or_equal_to, expressionB, expressionA, periodTypeMonthly ); // deC - deD <= deA + deB
+ validationRuleD = createValidationRule( 'D', less_than, expressionA, expressionC, periodTypeMonthly ); // deA + deB < deB * 2
+ validationRuleX = createValidationRule( 'X', equal_to, expressionA, expressionC, periodTypeMonthly ); // deA + deB = deB * 2
+
// Compare dataElementB with 1.5 times itself for one sequential previous period.
monitoringRuleE = createMonitoringRule( 'E', less_than_or_equal_to, expressionD, expressionE, periodTypeMonthly, 1, 1, 0, 0, 0 );
@@ -409,6 +419,8 @@
monitoringRuleL = createMonitoringRule( 'L', less_than_or_equal_to, expressionF, expressionG, periodTypeMonthly, 1, 0, 1, 0, 0 );
group = createValidationRuleGroup( 'A' );
+
+ defaultCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
}
@Override
@@ -479,19 +491,19 @@
// insures that if they are the same as the reference results, they will appear in the same order.
Collection<ValidationResult> results = validationRuleService.validate(
- getDate( 2000, 2, 1 ), getDate( 2000, 6, 1 ), sourcesA, false, null );
+ getDate( 2000, 2, 1 ), getDate( 2000, 6, 1 ), sourcesA, null, null, false, null );
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodA, sourceA, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodB, sourceA, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodA, sourceB, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodB, sourceB, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodB, sourceA, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodA, sourceB, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodB, sourceB, defaultCombo, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodA, sourceA, validationRuleB, -1.0, 4.0 ) );
- reference.add( new ValidationResult( periodB, sourceA, validationRuleB, -1.0, 4.0 ) );
- reference.add( new ValidationResult( periodA, sourceB, validationRuleB, -1.0, 4.0 ) );
- reference.add( new ValidationResult( periodB, sourceB, validationRuleB, -1.0, 4.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, defaultCombo, validationRuleB, -1.0, 4.0 ) );
+ reference.add( new ValidationResult( periodB, sourceA, defaultCombo, validationRuleB, -1.0, 4.0 ) );
+ reference.add( new ValidationResult( periodA, sourceB, defaultCombo, validationRuleB, -1.0, 4.0 ) );
+ reference.add( new ValidationResult( periodB, sourceB, defaultCombo, validationRuleB, -1.0, 4.0 ) );
for ( ValidationResult result : results )
{
@@ -537,14 +549,14 @@
validationRuleService.addValidationRuleGroup( group );
Collection<ValidationResult> results = validationRuleService.validate(
- getDate( 2000, 2, 1 ), getDate( 2000, 6, 1 ), sourcesA, group, false, null );
+ getDate( 2000, 2, 1 ), getDate( 2000, 6, 1 ), sourcesA, null, group, false, null );
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodA, sourceA, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodB, sourceA, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodA, sourceB, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodB, sourceB, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodB, sourceA, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodA, sourceB, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodB, sourceB, defaultCombo, validationRuleA, 3.0, -1.0 ) );
for ( ValidationResult result : results )
{
@@ -579,10 +591,10 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodA, sourceA, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodB, sourceA, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodA, sourceA, validationRuleB, -1.0, 4.0 ) );
- reference.add( new ValidationResult( periodB, sourceA, validationRuleB, -1.0, 4.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodB, sourceA, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, defaultCombo, validationRuleB, -1.0, 4.0 ) );
+ reference.add( new ValidationResult( periodB, sourceA, defaultCombo, validationRuleB, -1.0, 4.0 ) );
for ( ValidationResult result : results )
{
@@ -608,12 +620,12 @@
validationRuleService.saveValidationRule( validationRuleD );
Collection<ValidationResult> results = validationRuleService.validate(
- dataSetMonthly, periodA, sourceA );
+ dataSetMonthly, periodA, sourceA, null );
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodA, sourceA, validationRuleA, 3.0, -1.0 ) );
- reference.add( new ValidationResult( periodA, sourceA, validationRuleB, -1.0, 4.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, defaultCombo, validationRuleA, 3.0, -1.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, defaultCombo, validationRuleB, -1.0, 4.0 ) );
for ( ValidationResult result : results )
{
@@ -655,9 +667,9 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodL, sourceA, monitoringRuleE, 200.0, 150.0 /* 1.5 * 100 */ ) );
- reference.add( new ValidationResult( periodM, sourceA, monitoringRuleE, 400.0, 300.0 /* 1.5 * 200 */ ) );
- reference.add( new ValidationResult( periodN, sourceA, monitoringRuleE, 700.0, 600.0 /* 1.5 * 400 */ ) );
+ reference.add( new ValidationResult( periodL, sourceA, defaultCombo, monitoringRuleE, 200.0, 150.0 /* 1.5 * 100 */ ) );
+ reference.add( new ValidationResult( periodM, sourceA, defaultCombo, monitoringRuleE, 400.0, 300.0 /* 1.5 * 200 */ ) );
+ reference.add( new ValidationResult( periodN, sourceA, defaultCombo, monitoringRuleE, 700.0, 600.0 /* 1.5 * 400 */ ) );
for ( ValidationResult result : results )
{
@@ -697,9 +709,9 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodK, sourceA, monitoringRuleF, 100.0, 75.0 /* 1.5 * 50 */ ) );
- reference.add( new ValidationResult( periodM, sourceA, monitoringRuleF, 400.0, 300.0 /* 1.5 * 200 */ ) );
- reference.add( new ValidationResult( periodO, sourceA, monitoringRuleF, 800.0, 600.0 /* 1.5 * 400 */ ) );
+ reference.add( new ValidationResult( periodK, sourceA, defaultCombo, monitoringRuleF, 100.0, 75.0 /* 1.5 * 50 */ ) );
+ reference.add( new ValidationResult( periodM, sourceA, defaultCombo, monitoringRuleF, 400.0, 300.0 /* 1.5 * 200 */ ) );
+ reference.add( new ValidationResult( periodO, sourceA, defaultCombo, monitoringRuleF, 800.0, 600.0 /* 1.5 * 400 */ ) );
for ( ValidationResult result : results )
{
@@ -739,11 +751,11 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodK, sourceA, monitoringRuleG, 100.0, 83.6 /* 1.5 * ( 11 + 12 + 50 + 150 ) / 4 */ ) );
- reference.add( new ValidationResult( periodL, sourceA, monitoringRuleG, 200.0, 114.9 /* 1.5 * ( 11 + 12 + 13 + 50 + 150 + 200 + 100 ) / 7 */ ) );
- reference.add( new ValidationResult( periodM, sourceA, monitoringRuleG, 400.0, 254.8 /* 1.5 * ( 12 + 13 + 14 + 150 + 200 + 600 + 200 ) / 7 */ ) );
- reference.add( new ValidationResult( periodN, sourceA, monitoringRuleG, 700.0, 351.9 /* 1.5 * ( 13 + 14 + 15 + 200 + 600 + 400 + 400 ) / 7 */ ) );
- reference.add( new ValidationResult( periodO, sourceA, monitoringRuleG, 800.0, 518.7 /* 1.5 * ( 14 + 15 + 600 + 400 + 700 ) / 5 */ ) );
+ reference.add( new ValidationResult( periodK, sourceA, defaultCombo, monitoringRuleG, 100.0, 83.6 /* 1.5 * ( 11 + 12 + 50 + 150 ) / 4 */ ) );
+ reference.add( new ValidationResult( periodL, sourceA, defaultCombo, monitoringRuleG, 200.0, 114.9 /* 1.5 * ( 11 + 12 + 13 + 50 + 150 + 200 + 100 ) / 7 */ ) );
+ reference.add( new ValidationResult( periodM, sourceA, defaultCombo, monitoringRuleG, 400.0, 254.8 /* 1.5 * ( 12 + 13 + 14 + 150 + 200 + 600 + 200 ) / 7 */ ) );
+ reference.add( new ValidationResult( periodN, sourceA, defaultCombo, monitoringRuleG, 700.0, 351.9 /* 1.5 * ( 13 + 14 + 15 + 200 + 600 + 400 + 400 ) / 7 */ ) );
+ reference.add( new ValidationResult( periodO, sourceA, defaultCombo, monitoringRuleG, 800.0, 518.7 /* 1.5 * ( 14 + 15 + 600 + 400 + 700 ) / 5 */ ) );
for ( ValidationResult result : results )
{
@@ -784,10 +796,10 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
// Not in results: reference.add( new ValidationResult( periodK, sourceA, monitoringRuleH, 100.0, 109.0 /* 1.5 * ( 11 + 12 + 13 + 50 + 150 + 200 ) / 6 */ ) );
- reference.add( new ValidationResult( periodL, sourceA, monitoringRuleH, 200.0, 191.7 /* 1.5 * ( 11 + 12 + 13 + 14 + 50 + 150 + 200 + 600 + 100 ) / 9 */ ) );
- reference.add( new ValidationResult( periodM, sourceA, monitoringRuleH, 400.0, 220.6 /* 1.5 * ( 11 + 12 + 13 + 14 + 15 + 50 + 150 + 200 + 600 + 400 + 100 + 200 ) / 12 */ ) );
- reference.add( new ValidationResult( periodN, sourceA, monitoringRuleH, 700.0, 300.6 /* 1.5 * ( 12 + 13 + 14 + 15 + 150 + 200 + 600 + 400 + 200 + 400 ) / 10 */ ) );
- reference.add( new ValidationResult( periodO, sourceA, monitoringRuleH, 800.0, 439.1 /* 1.5 * ( 13 + 14 + 15 + 200 + 600 + 400 + 400 + 700 ) / 8 */ ) );
+ reference.add( new ValidationResult( periodL, sourceA, defaultCombo, monitoringRuleH, 200.0, 191.7 /* 1.5 * ( 11 + 12 + 13 + 14 + 50 + 150 + 200 + 600 + 100 ) / 9 */ ) );
+ reference.add( new ValidationResult( periodM, sourceA, defaultCombo, monitoringRuleH, 400.0, 220.6 /* 1.5 * ( 11 + 12 + 13 + 14 + 15 + 50 + 150 + 200 + 600 + 400 + 100 + 200 ) / 12 */ ) );
+ reference.add( new ValidationResult( periodN, sourceA, defaultCombo, monitoringRuleH, 700.0, 300.6 /* 1.5 * ( 12 + 13 + 14 + 15 + 150 + 200 + 600 + 400 + 200 + 400 ) / 10 */ ) );
+ reference.add( new ValidationResult( periodO, sourceA, defaultCombo, monitoringRuleH, 800.0, 439.1 /* 1.5 * ( 13 + 14 + 15 + 200 + 600 + 400 + 400 + 700 ) / 8 */ ) );
for ( ValidationResult result : results )
{
@@ -827,11 +839,11 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodK, sourceA, monitoringRuleI, 100.0, 32.3 /* 1.5 * ( 11 + 12 + 13 + 50 ) / 4 */ ) );
- reference.add( new ValidationResult( periodL, sourceA, monitoringRuleI, 200.0, 75.0 /* 1.5 * ( 11 + 12 + 13 + 14 + 50 + 150 + 100 ) / 7 */ ) );
- reference.add( new ValidationResult( periodM, sourceA, monitoringRuleI, 400.0, 114.8 /* 1.5 * ( 11 + 12 + 13 + 14 + 15 + 50 + 150 + 200 + 100 + 200 ) / 10 */ ) );
- reference.add( new ValidationResult( periodN, sourceA, monitoringRuleI, 700.0, 188.3 /* 1.5 * ( 12 + 13 + 14 + 15 + 150 + 200 + 200 + 400 ) / 8 */ ) );
- reference.add( new ValidationResult( periodO, sourceA, monitoringRuleI, 800.0, 260.5 /* 1.5 * ( 13 + 14 + 15 + 200 + 400 + 400 ) / 6 */ ) );
+ reference.add( new ValidationResult( periodK, sourceA, defaultCombo, monitoringRuleI, 100.0, 32.3 /* 1.5 * ( 11 + 12 + 13 + 50 ) / 4 */ ) );
+ reference.add( new ValidationResult( periodL, sourceA, defaultCombo, monitoringRuleI, 200.0, 75.0 /* 1.5 * ( 11 + 12 + 13 + 14 + 50 + 150 + 100 ) / 7 */ ) );
+ reference.add( new ValidationResult( periodM, sourceA, defaultCombo, monitoringRuleI, 400.0, 114.8 /* 1.5 * ( 11 + 12 + 13 + 14 + 15 + 50 + 150 + 200 + 100 + 200 ) / 10 */ ) );
+ reference.add( new ValidationResult( periodN, sourceA, defaultCombo, monitoringRuleI, 700.0, 188.3 /* 1.5 * ( 12 + 13 + 14 + 15 + 150 + 200 + 200 + 400 ) / 8 */ ) );
+ reference.add( new ValidationResult( periodO, sourceA, defaultCombo, monitoringRuleI, 800.0, 260.5 /* 1.5 * ( 13 + 14 + 15 + 200 + 400 + 400 ) / 6 */ ) );
for ( ValidationResult result : results )
{
@@ -873,9 +885,9 @@
// Not in results: reference.add( new ValidationResult( periodK, sourceA, monitoringRuleH, 100.0, 154.9 /* 1.5 * ( 13 + 50 + 150 + 200 ) / 4 */ ) );
// Not in results: reference.add( new ValidationResult( periodL, sourceA, monitoringRuleJ, 200.0, 241.5 /* 1.5 * ( 13 + 14 + 50 + 150 + 200 + 600 + 100 ) / 7 */ ) );
- reference.add( new ValidationResult( periodM, sourceA, monitoringRuleJ, 400.0, 261.3 /* 1.5 * ( 13 + 14 + 15 + 50 + 150 + 200 + 600 + 400 + 100 + 200 ) / 10 */ ) );
- reference.add( new ValidationResult( periodN, sourceA, monitoringRuleJ, 700.0, 371.1 /* 1.5 * ( 14 + 15 + 150 + 200 + 600 + 400 + 200 + 400 ) / 8 */ ) );
- reference.add( new ValidationResult( periodO, sourceA, monitoringRuleJ, 800.0, 578.8 /* 1.5 * ( 15 + 200 + 600 + 400 + 400 + 700 ) / 6 */ ) );
+ reference.add( new ValidationResult( periodM, sourceA, defaultCombo, monitoringRuleJ, 400.0, 261.3 /* 1.5 * ( 13 + 14 + 15 + 50 + 150 + 200 + 600 + 400 + 100 + 200 ) / 10 */ ) );
+ reference.add( new ValidationResult( periodN, sourceA, defaultCombo, monitoringRuleJ, 700.0, 371.1 /* 1.5 * ( 14 + 15 + 150 + 200 + 600 + 400 + 200 + 400 ) / 8 */ ) );
+ reference.add( new ValidationResult( periodO, sourceA, defaultCombo, monitoringRuleJ, 800.0, 578.8 /* 1.5 * ( 15 + 200 + 600 + 400 + 400 + 700 ) / 6 */ ) );
for ( ValidationResult result : results )
{
@@ -915,11 +927,11 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodK, sourceA, monitoringRuleK, 100.0, 47.3 /* 1.5 * ( 13 + 50 ) / 2 */ ) );
- reference.add( new ValidationResult( periodL, sourceA, monitoringRuleK, 200.0, 98.1 /* 1.5 * ( 13 + 14 + 50 + 150 + 100 ) / 5 */ ) );
- reference.add( new ValidationResult( periodM, sourceA, monitoringRuleK, 400.0, 139.1 /* 1.5 * ( 13 + 14 + 15 + 50 + 150 + 200 + 100 + 200 ) / 8 */ ) );
- reference.add( new ValidationResult( periodN, sourceA, monitoringRuleK, 700.0, 244.8 /* 1.5 * ( 14 + 15 + 150 + 200 + 200 + 400 ) / 6 */ ) );
- reference.add( new ValidationResult( periodO, sourceA, monitoringRuleK, 800.0, 380.6 /* 1.5 * ( 15 + 200 + 400 + 400 ) / 4 */ ) );
+ reference.add( new ValidationResult( periodK, sourceA, defaultCombo, monitoringRuleK, 100.0, 47.3 /* 1.5 * ( 13 + 50 ) / 2 */ ) );
+ reference.add( new ValidationResult( periodL, sourceA, defaultCombo, monitoringRuleK, 200.0, 98.1 /* 1.5 * ( 13 + 14 + 50 + 150 + 100 ) / 5 */ ) );
+ reference.add( new ValidationResult( periodM, sourceA, defaultCombo, monitoringRuleK, 400.0, 139.1 /* 1.5 * ( 13 + 14 + 15 + 50 + 150 + 200 + 100 + 200 ) / 8 */ ) );
+ reference.add( new ValidationResult( periodN, sourceA, defaultCombo, monitoringRuleK, 700.0, 244.8 /* 1.5 * ( 14 + 15 + 150 + 200 + 200 + 400 ) / 6 */ ) );
+ reference.add( new ValidationResult( periodO, sourceA, defaultCombo, monitoringRuleK, 800.0, 380.6 /* 1.5 * ( 15 + 200 + 400 + 400 ) / 4 */ ) );
for ( ValidationResult result : results )
{
@@ -966,11 +978,11 @@
Collection<ValidationResult> reference = new HashSet<ValidationResult>();
- reference.add( new ValidationResult( periodK, sourceB, monitoringRuleL, 10.0 /* 100 / 10 */, 1.5 /* 1.5 * 50 / 50 */ ) );
- reference.add( new ValidationResult( periodL, sourceB, monitoringRuleL, 20.0 /* 200 / 10 */, 4.5 /* 1.5 * 150 / 50 */ ) );
- reference.add( new ValidationResult( periodM, sourceB, monitoringRuleL, 40.0 /* 400 / 10 */, 6.0 /* 1.5 * 200 / 50 */ ) );
- reference.add( new ValidationResult( periodN, sourceB, monitoringRuleL, 70.0 /* 700 / 10 */, 18.0 /* 1.5 * 600 / 50 */ ) );
- reference.add( new ValidationResult( periodO, sourceB, monitoringRuleL, 80.0 /* 800 / 10 */, 12.0 /* 1.5 * 400 / 50 */ ) );
+ reference.add( new ValidationResult( periodK, sourceB, defaultCombo, monitoringRuleL, 10.0 /* 100 / 10 */, 1.5 /* 1.5 * 50 / 50 */ ) );
+ reference.add( new ValidationResult( periodL, sourceB, defaultCombo, monitoringRuleL, 20.0 /* 200 / 10 */, 4.5 /* 1.5 * 150 / 50 */ ) );
+ reference.add( new ValidationResult( periodM, sourceB, defaultCombo, monitoringRuleL, 40.0 /* 400 / 10 */, 6.0 /* 1.5 * 200 / 50 */ ) );
+ reference.add( new ValidationResult( periodN, sourceB, defaultCombo, monitoringRuleL, 70.0 /* 700 / 10 */, 18.0 /* 1.5 * 600 / 50 */ ) );
+ reference.add( new ValidationResult( periodO, sourceB, defaultCombo, monitoringRuleL, 80.0 /* 800 / 10 */, 12.0 /* 1.5 * 400 / 50 */ ) );
for ( ValidationResult result : results )
{
@@ -982,6 +994,92 @@
assertEquals( orderedList( reference ), orderedList( results ) );
}
+ @Test
+ public void testValidateWithAttributeOptions()
+ {
+ DataElementCategoryOption optionA = new DataElementCategoryOption( "CategoryOptionA" );
+ DataElementCategoryOption optionB = new DataElementCategoryOption( "CategoryOptionB" );
+ DataElementCategoryOption optionC = new DataElementCategoryOption( "CategoryOptionC" );
+
+ categoryService.addDataElementCategoryOption( optionA );
+ categoryService.addDataElementCategoryOption( optionB );
+ categoryService.addDataElementCategoryOption( optionC );
+
+ DataElementCategory categoryA = createDataElementCategory( 'A', optionA, optionB );
+ DataElementCategory categoryB = createDataElementCategory( 'B', optionC );
+ categoryA.setDataDimension( true );
+ categoryB.setDataDimension( true );
+
+ categoryService.addDataElementCategory( categoryA );
+ categoryService.addDataElementCategory( categoryB );
+
+ DataElementCategoryCombo categoryComboAB = createCategoryCombo( 'A', categoryA, categoryB );
+
+ categoryService.addDataElementCategoryCombo( categoryComboAB );
+
+ DataElementCategoryOptionCombo optionComboAC = createCategoryOptionCombo( 'A', categoryComboAB, optionA, optionC );
+ DataElementCategoryOptionCombo optionComboBC = createCategoryOptionCombo( 'A', categoryComboAB, optionB, optionC );
+
+ categoryService.addDataElementCategoryOptionCombo( optionComboAC );
+ categoryService.addDataElementCategoryOptionCombo( optionComboBC );
+
+ dataValueService.addDataValue( createDataValue( dataElementA, periodA, sourceA, "4", optionCombo, optionComboAC ) );
+ dataValueService.addDataValue( createDataValue( dataElementB, periodA, sourceA, "3", optionCombo, optionComboAC ) );
+
+ dataValueService.addDataValue( createDataValue( dataElementA, periodA, sourceA, "2", optionCombo, optionComboBC ) );
+ dataValueService.addDataValue( createDataValue( dataElementB, periodA, sourceA, "1", optionCombo, optionComboBC ) );
+
+ validationRuleService.saveValidationRule( validationRuleD ); // deA + deB < deB * 2
+ validationRuleService.saveValidationRule( validationRuleX ); // deA + deB = deB * 2
+
+ //
+ // optionComboAC
+ //
+ Collection<ValidationResult> results = validationRuleService.validate( dataSetMonthly, periodA, sourceA, optionComboAC );
+
+ Collection<ValidationResult> reference = new HashSet<ValidationResult>();
+
+ reference.add( new ValidationResult( periodA, sourceA, optionComboAC, validationRuleD, 7.0, 6.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, optionComboAC, validationRuleX, 7.0, 6.0 ) );
+
+ for ( ValidationResult result : results )
+ {
+ assertFalse( MathUtils.expressionIsTrue( result.getLeftsideValue(), result.getValidationRule()
+ .getOperator(), result.getRightsideValue() ) );
+ }
+
+ assertEquals( 2, results.size() );
+ assertEquals( orderedList( reference ), orderedList( results ) );
+
+ //
+ // All optionCombos
+ //
+ results = validationRuleService.validate( dataSetMonthly, periodA, sourceA, null );
+
+ reference = new HashSet<ValidationResult>();
+
+ reference.add( new ValidationResult( periodA, sourceA, optionComboAC, validationRuleD, 7.0, 6.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, optionComboAC, validationRuleX, 7.0, 6.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, optionComboBC, validationRuleD, 3.0, 2.0 ) );
+ reference.add( new ValidationResult( periodA, sourceA, optionComboBC, validationRuleX, 3.0, 2.0 ) );
+
+ for ( ValidationResult result : results )
+ {
+ assertFalse( MathUtils.expressionIsTrue( result.getLeftsideValue(), result.getValidationRule()
+ .getOperator(), result.getRightsideValue() ) );
+ }
+
+ assertEquals( 4, results.size() );
+ assertEquals( orderedList( reference ), orderedList( results ) );
+
+ //
+ // Default optionCombo
+ //
+ results = validationRuleService.validate( dataSetMonthly, periodA, sourceA, optionCombo );
+
+ assertEquals( 0, results.size() );
+ }
+
// -------------------------------------------------------------------------
// CURD functionality tests
// -------------------------------------------------------------------------
=== modified file 'dhis-2/dhis-web/dhis-web-dataentry/src/main/java/org/hisp/dhis/de/action/ValidationAction.java'
--- dhis-2/dhis-web/dhis-web-dataentry/src/main/java/org/hisp/dhis/de/action/ValidationAction.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-web/dhis-web-dataentry/src/main/java/org/hisp/dhis/de/action/ValidationAction.java 2014-05-18 00:49:40 +0000
@@ -38,10 +38,14 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.struts2.ServletActionContext;
+import org.hisp.dhis.api.utils.InputUtils;
import org.hisp.dhis.common.comparator.IdentifiableObjectNameComparator;
import org.hisp.dhis.dataanalysis.DataAnalysisService;
import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategoryOption;
import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
import org.hisp.dhis.dataelement.DataElementOperand;
import org.hisp.dhis.dataset.DataSet;
import org.hisp.dhis.dataset.DataSetService;
@@ -54,9 +58,11 @@
import org.hisp.dhis.period.PeriodService;
import org.hisp.dhis.period.PeriodType;
import org.hisp.dhis.validation.ValidationResult;
+import org.hisp.dhis.validation.ValidationRule;
import org.hisp.dhis.validation.ValidationRuleService;
import com.opensymphony.xwork2.Action;
+import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Margrethe Store
@@ -105,7 +111,14 @@
{
this.organisationUnitService = organisationUnitService;
}
-
+
+ private DataElementCategoryService dataElementCategoryService;
+
+ public void setDataElementCategoryService( DataElementCategoryService dataElementCategoryService )
+ {
+ this.dataElementCategoryService = dataElementCategoryService;
+ }
+
private DataValueService dataValueService;
public void setDataValueService( DataValueService dataValueService )
@@ -113,6 +126,9 @@
this.dataValueService = dataValueService;
}
+ @Autowired
+ private InputUtils inputUtils;
+
// -------------------------------------------------------------------------
// Input
// -------------------------------------------------------------------------
@@ -138,6 +154,20 @@
this.ou = ou;
}
+ private String cc;
+
+ public void setCc( String cc )
+ {
+ this.cc = cc;
+ }
+
+ private String cp;
+
+ public void setCp( String cp )
+ {
+ this.cp = cp;
+ }
+
private boolean multiOu;
public boolean isMultiOu()
@@ -188,6 +218,13 @@
Period selectedPeriod = PeriodType.getPeriodFromIsoString( pe );
+ DataElementCategoryOptionCombo attributeOptionCombo = inputUtils.getAttributeOptionCombo( ServletActionContext.getResponse(), cc, cp );
+
+ if ( attributeOptionCombo == null )
+ {
+ attributeOptionCombo = dataElementCategoryService.getDefaultDataElementCategoryOptionCombo();
+ }
+
if ( selectedPeriod == null || orgUnit == null || ( multiOu && !orgUnit.hasChild() ) )
{
return SUCCESS;
@@ -218,7 +255,7 @@
dataValues.put( organisationUnit, values );
}
- List<ValidationResult> results = validationRuleAnalysis( organisationUnit, dataSet, period );
+ List<ValidationResult> results = validationRuleAnalysis( organisationUnit, dataSet, period, attributeOptionCombo );
if ( !results.isEmpty() )
{
@@ -254,9 +291,9 @@
// Validation rule analysis
// -------------------------------------------------------------------------
- private List<ValidationResult> validationRuleAnalysis( OrganisationUnit organisationUnit, DataSet dataSet, Period period )
+ private List<ValidationResult> validationRuleAnalysis( OrganisationUnit organisationUnit, DataSet dataSet, Period period, DataElementCategoryOptionCombo attributeOptionCombo )
{
- List<ValidationResult> validationResults = new ArrayList<ValidationResult>( validationRuleService.validate( dataSet, period, organisationUnit ) );
+ List<ValidationResult> validationResults = new ArrayList<ValidationResult>( validationRuleService.validate( dataSet, period, organisationUnit, attributeOptionCombo ) );
log.debug( "Number of validation violations: " + validationResults.size() );
=== modified file 'dhis-2/dhis-web/dhis-web-dataentry/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-dataentry/src/main/resources/META-INF/dhis/beans.xml 2014-03-04 00:59:32 +0000
+++ dhis-2/dhis-web/dhis-web-dataentry/src/main/resources/META-INF/dhis/beans.xml 2014-05-18 00:49:40 +0000
@@ -66,6 +66,7 @@
<property name="minMaxOutlierAnalysisService" ref="org.hisp.dhis.dataanalysis.MinMaxOutlierAnalysisService" />
<property name="dataSetService" ref="org.hisp.dhis.dataset.DataSetService" />
<property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
+ <property name="dataElementCategoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
<property name="dataValueService" ref="org.hisp.dhis.datavalue.DataValueService" />
</bean>
=== modified file 'dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.js'
--- dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.js 2014-05-06 10:29:22 +0000
+++ dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/javascript/form.js 2014-05-18 00:49:40 +0000
@@ -1711,8 +1711,17 @@
var validCompleteOnly = dhis2.de.dataSets[dhis2.de.currentDataSetId].validCompleteOnly;
+ var cc = dhis2.de.getCurrentCategoryCombo();
+ var cp = dhis2.de.getCurrentCategoryOptionsQueryValue();
+
var params = dhis2.de.storageManager.getCurrentCompleteDataSetParams();
+ if ( cc && cp )
+ {
+ params.cc = dhis2.de.getCurrentCategoryCombo();
+ params.cp = dhis2.de.getCurrentCategoryOptionsQueryValue();
+ }
+
$( '#validationDiv' ).load( 'validate.action', params, function( response, status, xhr ) {
var success = null;
=== modified file 'dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/validationResult.vm'
--- dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/validationResult.vm 2014-03-04 00:59:32 +0000
+++ dhis-2/dhis-web/dhis-web-dataentry/src/main/webapp/dhis-web-dataentry/validationResult.vm 2014-05-18 00:49:40 +0000
@@ -22,9 +22,9 @@
#set ( $rightFormula = $rightSideFormulaMap.get( $key ).get( $id ) )
<tr>
<td style="height:32px"#alternate( $mark )>$!encoder.htmlEncode( $validationResult.validationRule.getInstructionFallback() )</td>
- <td#alternate( $mark )>$validationResult.leftsideValue</td>
- <td#alternate( $mark )>$encoder.htmlEncode( $i18n.getString( $validationResult.validationRule.operator.mathematicalOperator ) )</td>
- <td#alternate( $mark )>$validationResult.rightsideValue</td>
+ <td #alternate( $mark )>$validationResult.leftsideValue</td>
+ <td #alternate( $mark )>$encoder.htmlEncode( $i18n.getString( $validationResult.validationRule.operator.mathematicalOperator ) )</td>
+ <td #alternate( $mark )>$validationResult.rightsideValue</td>
</tr>
#if( $mark )
#set( $mark = false )
=== modified file 'dhis-2/dhis-web/dhis-web-light/src/main/java/org/hisp/dhis/light/utils/FormUtilsImpl.java'
--- dhis-2/dhis-web/dhis-web-light/src/main/java/org/hisp/dhis/light/utils/FormUtilsImpl.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-web/dhis-web-light/src/main/java/org/hisp/dhis/light/utils/FormUtilsImpl.java 2014-05-18 00:49:40 +0000
@@ -174,7 +174,7 @@
public List<String> getValidationRuleViolations( OrganisationUnit organisationUnit, DataSet dataSet, Period period )
{
List<ValidationResult> validationRuleResults = new ArrayList<ValidationResult>( validationRuleService.validate(
- dataSet, period, organisationUnit ) );
+ dataSet, period, organisationUnit, null ) );
List<String> validationRuleViolations = new ArrayList<String>( validationRuleResults.size() );
=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/RunValidationAction.java'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/RunValidationAction.java 2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/java/org/hisp/dhis/validationrule/action/RunValidationAction.java 2014-05-18 00:49:40 +0000
@@ -32,6 +32,8 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hisp.dhis.common.Grid;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
import org.hisp.dhis.i18n.I18nFormat;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.organisationunit.OrganisationUnitService;
@@ -82,7 +84,14 @@
{
this.organisationUnitService = organisationUnitService;
}
-
+
+ private DataElementCategoryService dataElementCategoryService;
+
+ public void setDataElementCategoryService( DataElementCategoryService dataElementCategoryService )
+ {
+ this.dataElementCategoryService = dataElementCategoryService;
+ }
+
// -------------------------------------------------------------------------
// Input/output
// -------------------------------------------------------------------------
@@ -118,13 +127,20 @@
this.endDate = endDate;
}
+ private Integer attributeOptionComboId;
+
+ public void setAttributeOptionComboId( Integer attributeOptionComboId )
+ {
+ this.attributeOptionComboId = attributeOptionComboId;
+ }
+
private Integer validationRuleGroupId;
public void setValidationRuleGroupId( Integer validationRuleGroupId )
{
this.validationRuleGroupId = validationRuleGroupId;
}
-
+
private boolean sendAlerts;
public void setSendAlerts( boolean sendAlerts )
@@ -153,6 +169,13 @@
return maxExceeded;
}
+ private boolean showAttributeCombos;
+
+ public boolean isShowAttributeCombos()
+ {
+ return showAttributeCombos;
+ }
+
private OrganisationUnit organisationUnit;
public OrganisationUnit getOrganisationUnit()
@@ -170,22 +193,14 @@
Collection<OrganisationUnit> organisationUnits = organisationUnitService.getOrganisationUnitWithChildren( organisationUnit.getId() );
- if ( validationRuleGroupId == -1 )
- {
- log.info( "Validating captured data for all rules" );
-
- validationResults = new ArrayList<ValidationResult>( validationRuleService.validate( format
- .parseDate( startDate ), format.parseDate( endDate ), organisationUnits, sendAlerts, format ) );
- }
- else
- {
- ValidationRuleGroup group = validationRuleService.getValidationRuleGroup( validationRuleGroupId );
-
- log.info( "Validating captured data for rules for group: '" + group.getName() + "'" );
-
- validationResults = new ArrayList<ValidationResult>( validationRuleService.validate( format
- .parseDate( startDate ), format.parseDate( endDate ), organisationUnits, group, sendAlerts, format ) );
- }
+ ValidationRuleGroup group = validationRuleGroupId == -1 ? null : validationRuleService.getValidationRuleGroup( validationRuleGroupId );
+
+ DataElementCategoryOptionCombo attributeOptionCombo = attributeOptionComboId == null || attributeOptionComboId == -1 ? null : dataElementCategoryService.getDataElementCategoryOptionCombo( attributeOptionComboId );
+
+ log.info( "Validating data for " + ( group == null ? "all rules" : "group: " + group.getName() ) );
+
+ validationResults = new ArrayList<ValidationResult>( validationRuleService.validate( format
+ .parseDate( startDate ), format.parseDate( endDate ), organisationUnits, attributeOptionCombo, group, sendAlerts, format ) );
maxExceeded = validationResults.size() > ValidationRuleService.MAX_INTERACTIVE_ALERTS;
@@ -193,8 +208,25 @@
SessionUtils.setSessionVar( KEY_VALIDATIONRESULT, validationResults );
+ computeShowAttributeCombos();
+
log.info( "Validation done" );
return SUCCESS;
}
+
+ private void computeShowAttributeCombos()
+ {
+ showAttributeCombos = false;
+
+ for ( ValidationResult result : validationResults )
+ {
+ if ( !result.getAttributeOptionCombo().isDefault() )
+ {
+ showAttributeCombos = true;
+
+ break;
+ }
+ }
+ }
}
=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/META-INF/dhis/beans.xml 2014-03-28 01:51:34 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/META-INF/dhis/beans.xml 2014-05-18 00:49:40 +0000
@@ -146,6 +146,7 @@
scope="prototype">
<property name="validationRuleService" ref="org.hisp.dhis.validation.ValidationRuleService" />
<property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
+ <property name="dataElementCategoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
</bean>
<bean id="org.hisp.dhis.validationrule.action.GetValidationResultDetailsAction"
=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties 2014-03-28 01:51:34 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/resources/org/hisp/dhis/validationrule/i18n_module.properties 2014-05-18 00:49:40 +0000
@@ -141,6 +141,7 @@
medium=Medium
low=Low
rule_type=Rule type
+attributes=Attributes
validation=Validation
surveillance=Surveillance
organisation_unit_level=Organisation unit level
=== modified file 'dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/viewValidationResultForm.vm'
--- dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/viewValidationResultForm.vm 2014-03-04 00:59:32 +0000
+++ dhis-2/dhis-web/dhis-web-validationrule/src/main/webapp/dhis-web-validationrule/viewValidationResultForm.vm 2014-05-18 00:49:40 +0000
@@ -84,6 +84,9 @@
<!-- Note: in the headers below keeps the jquery.tablesorter icons from overlapping the labels. -->
<th>$i18n.getString( "organisation_unit" ) </th>
<th>$i18n.getString( "period" ) </th>
+ #if( $showAttributeCombos )
+ <th>$i18n.getString( "attributes" ) </th>
+ #end
<!-- Note: column-level sortInitialOrder only works in tablesorter 2.0.8 and later (an earlier version in use as of this writing.) --->
<th class="{sorter: 'importanceSorter', sortInitialOrder: 'desc'}">$i18n.getString( "importance" ) </th>
<th class="{sorter: false}">$i18n.getString( "validation_rule" )</th>
@@ -98,6 +101,9 @@
<tr id="tr${result.id}">
<td>$encoder.htmlEncode( $!result.source.name )</td>
<td>$!format.formatPeriod( $result.period )</td>
+ #if( $showAttributeCombos )
+ <td>#if($result.attributeOptionCombo.isDefault()=='false') $encoder.htmlEncode( $!result.attributeOptionCombo.name ) #end</td>
+ #end
<td>$encoder.htmlEncode( $i18n.getString( $!result.validationRule.importance ) )</td>
<td>$encoder.htmlEncode( $!result.validationRule.getInstructionFallback() )</td>
<td>$encoder.htmlEncode( $!result.leftsideValue )</td>