← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 9096: Reporting rate summary, impl analysis by org unit group set, eg type and ownership

 

------------------------------------------------------------
revno: 9096
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2012-11-21 14:04:45 +0100
message:
  Reporting rate summary, impl analysis by org unit group set, eg type and ownership
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/completeness/DataSetCompletenessService.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceTest.java
  dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessAction.java
  dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessOptionsAction.java
  dhis-2/dhis-web/dhis-web-reporting/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-reporting/src/main/resources/org/hisp/dhis/reporting/i18n_module.properties
  dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataCompleteness.js
  dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/viewDataCompletenessForm.vm


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/completeness/DataSetCompletenessService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/completeness/DataSetCompletenessService.java	2012-04-06 20:02:26 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/completeness/DataSetCompletenessService.java	2012-11-21 13:04:45 +0000
@@ -28,6 +28,7 @@
  */
 
 import java.util.Collection;
+import java.util.Set;
 import java.util.concurrent.Future;
 
 import org.hisp.dhis.dataset.DataSet;
@@ -58,7 +59,7 @@
      * @param organisationUnitId the identifier of the root OrganisationUnit.
      * @return a Collection of DataSetCompletenessResults.
      */
-    Collection<DataSetCompletenessResult> getDataSetCompleteness( int periodId, int organisationUnitId );
+    Collection<DataSetCompletenessResult> getDataSetCompleteness( int periodId, int organisationUnitId, Set<Integer> groupIds );
 
     /**
      * Returns a Collection of DataSetCompletenessResults. The
@@ -76,7 +77,7 @@
      * @return a Collection of DataSetCompletenessResults.
      */
     Collection<DataSetCompletenessResult> getDataSetCompleteness( int periodId,
-        Collection<Integer> organisationUnitIds, int dataSetId );
+        Collection<Integer> organisationUnitIds, int dataSetId, Set<Integer> groupIds );
 
     /**
      * Delete all data set completeness registrations.

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java	2012-04-06 20:02:26 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java	2012-11-21 13:04:45 +0000
@@ -34,6 +34,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.Future;
 
 import org.amplecode.quick.BatchHandler;
@@ -44,12 +45,13 @@
 import org.hisp.dhis.completeness.DataSetCompletenessResult;
 import org.hisp.dhis.completeness.DataSetCompletenessService;
 import org.hisp.dhis.completeness.DataSetCompletenessStore;
-import org.hisp.dhis.dataelement.DataElementService;
 import org.hisp.dhis.datamart.aggregation.cache.AggregationCache;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.DataSetService;
 import org.hisp.dhis.jdbc.batchhandler.DataSetCompletenessResultBatchHandler;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
 import org.hisp.dhis.organisationunit.OrganisationUnitHierarchy;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.Period;
@@ -72,7 +74,7 @@
     // Dependencies
     // -------------------------------------------------------------------------
 
-    protected BatchHandlerFactory batchHandlerFactory;
+    private BatchHandlerFactory batchHandlerFactory;
 
     public void setBatchHandlerFactory( BatchHandlerFactory batchHandlerFactory )
     {
@@ -86,28 +88,28 @@
         this.aggregationCache = aggregationCache;
     }
 
-    protected OrganisationUnitService organisationUnitService;
+    private OrganisationUnitService organisationUnitService;
 
     public void setOrganisationUnitService( OrganisationUnitService organisationUnitService )
     {
         this.organisationUnitService = organisationUnitService;
     }
-
-    protected DataSetService dataSetService;
+    
+    private OrganisationUnitGroupService organisationUnitGroupService;
+
+    public void setOrganisationUnitGroupService( OrganisationUnitGroupService organisationUnitGroupService )
+    {
+        this.organisationUnitGroupService = organisationUnitGroupService;
+    }
+
+    private DataSetService dataSetService;
 
     public void setDataSetService( DataSetService dataSetService )
     {
         this.dataSetService = dataSetService;
     }
 
-    protected DataElementService dataElementService;
-
-    public void setDataElementService( DataElementService dataElementService )
-    {
-        this.dataElementService = dataElementService;
-    }
-
-    protected PeriodService periodService;
+    private PeriodService periodService;
 
     public void setPeriodService( PeriodService periodService )
     {
@@ -165,7 +167,7 @@
             {
                 Collection<Integer> sources = hierarchy.getChildren( unit.getId() );
 
-                Collection<Integer> relevantSources = getRelevantSources( dataSet, sources );
+                Collection<Integer> relevantSources = getRelevantSources( dataSet, sources, null );
 
                 for ( final Period period : periods )
                 {
@@ -194,9 +196,9 @@
         
         return null;
     }
-
+    
     @Transactional
-    public Collection<DataSetCompletenessResult> getDataSetCompleteness( int periodId, int organisationUnitId )
+    public Collection<DataSetCompletenessResult> getDataSetCompleteness( int periodId, int organisationUnitId, Set<Integer> groupIds )
     {
         final Period period = periodService.getPeriod( periodId );
 
@@ -215,7 +217,7 @@
             final Collection<Integer> periodsBetweenDates = getIdentifiers( Period.class, 
                 periodService.getPeriodsBetweenDates( dataSet.getPeriodType(), period.getStartDate(), period.getEndDate() ) );
 
-            final Collection<Integer> relevantSources = getRelevantSources( dataSet, children );
+            final Collection<Integer> relevantSources = getRelevantSources( dataSet, children, groupIds );
 
             final DataSetCompletenessResult result = new DataSetCompletenessResult();
 
@@ -240,7 +242,7 @@
 
     @Transactional
     public Collection<DataSetCompletenessResult> getDataSetCompleteness( int periodId,
-        Collection<Integer> organisationUnitIds, int dataSetId )
+        Collection<Integer> organisationUnitIds, int dataSetId, Set<Integer> groupIds )
     {
         final DataSet dataSet = dataSetService.getDataSet( dataSetId );
 
@@ -260,7 +262,7 @@
             final Collection<Integer> children = organisationUnitService.getOrganisationUnitHierarchy().getChildren(
                 unit.getId() );
 
-            final Collection<Integer> relevantSources = getRelevantSources( dataSet, children );
+            final Collection<Integer> relevantSources = getRelevantSources( dataSet, children, groupIds );
 
             final DataSetCompletenessResult result = getDataSetCompleteness( period, periodsBetweenDates, days, unit, relevantSources, dataSet );
 
@@ -322,11 +324,21 @@
     }
 
     @SuppressWarnings( "unchecked" )
-    private Collection<Integer> getRelevantSources( DataSet dataSet, Collection<Integer> sources )
+    private Collection<Integer> getRelevantSources( DataSet dataSet, Collection<Integer> sources, Set<Integer> groupIds )
     {
         Collection<Integer> dataSetSources = ConversionUtils.getIdentifiers( OrganisationUnit.class,
             new HashSet<OrganisationUnit>( dataSet.getSources() ) );
 
+        if ( groupIds != null )
+        {
+            for ( Integer groupId : groupIds )
+            {
+                OrganisationUnitGroup group = organisationUnitGroupService.getOrganisationUnitGroup( groupId );
+                Collection<Integer> ids = ConversionUtils.getIdentifiers( OrganisationUnitGroup.class, group.getMembers() );
+                dataSetSources.retainAll( ids );
+            }
+        }
+        
         return CollectionUtils.intersection( dataSetSources, sources );
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml	2012-11-06 07:01:56 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml	2012-11-21 13:04:45 +0000
@@ -107,8 +107,8 @@
     <property name="batchHandlerFactory" ref="batchHandlerFactory" />
 	<property name="aggregationCache" ref="org.hisp.dhis.datamart.aggregation.cache.AggregationCache" />
     <property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
+    <property name="organisationUnitGroupService" ref="org.hisp.dhis.organisationunit.OrganisationUnitGroupService" />
     <property name="dataSetService" ref="org.hisp.dhis.dataset.DataSetService" />
-    <property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />
     <property name="periodService" ref="org.hisp.dhis.period.PeriodService" />
     <property name="completenessStore" ref="org.hisp.dhis.completeness.DataSetCompletenessStore" />
     <property name="systemSettingManager" ref="org.hisp.dhis.setting.SystemSettingManager" />

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceTest.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceTest.java	2012-11-20 17:04:08 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceTest.java	2012-11-21 13:04:45 +0000
@@ -34,6 +34,7 @@
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Set;
 
 import org.hisp.dhis.DhisTest;
 import org.hisp.dhis.dataelement.DataElement;
@@ -48,6 +49,8 @@
 import org.hisp.dhis.datavalue.DataValueService;
 import org.hisp.dhis.external.location.LocationManager;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.MonthlyPeriodType;
 import org.hisp.dhis.period.Period;
@@ -86,6 +89,10 @@
     private OrganisationUnit unitF;
     private OrganisationUnit unitG;
     private OrganisationUnit unitH;
+    
+    private OrganisationUnitGroup groupA;
+    private OrganisationUnitGroup groupB;
+    private OrganisationUnitGroup groupC;
         
     private int unitIdA;
     private int unitIdB;
@@ -103,12 +110,12 @@
     
     private DataElementCategoryOptionCombo categoryOptionCombo;
     
-    private Collection<OrganisationUnit> sources = new HashSet<OrganisationUnit>();
-
     private Date onTimeA;
     private Date tooLateA;
     private Date onTimeB;
     private Date tooLateB;
+    
+    private Set<Integer> groupIds = new HashSet<Integer>();
 
     // -------------------------------------------------------------------------
     // Fixture
@@ -125,6 +132,8 @@
         
         organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
         
+        organisationUnitGroupService = (OrganisationUnitGroupService) getBean( OrganisationUnitGroupService.ID );
+        
         dataSetService = (DataSetService) getBean( DataSetService.ID );
         
         dataElementService = (DataElementService) getBean( DataElementService.ID );
@@ -186,9 +195,19 @@
         unitIdsA.add( unitIdB );
         unitIdsA.add( unitIdC );
         
-        sources.add( unitA );
-        sources.add( unitB );
-        sources.add( unitC );
+        groupA = createOrganisationUnitGroup( 'A' );
+        groupB = createOrganisationUnitGroup( 'B' );
+        groupC = createOrganisationUnitGroup( 'C' );
+        
+        groupA.addOrganisationUnit( unitA );
+        groupB.addOrganisationUnit( unitA );
+        groupB.addOrganisationUnit( unitB );
+        groupC.addOrganisationUnit( unitE );
+        groupC.addOrganisationUnit( unitF );
+        
+        organisationUnitGroupService.addOrganisationUnitGroup( groupA );
+        organisationUnitGroupService.addOrganisationUnitGroup( groupB );
+        organisationUnitGroupService.addOrganisationUnitGroup( groupC );
         
         dataSetA = createDataSet( 'A', periodType );
         dataSetB = createDataSet( 'B', periodType );
@@ -210,6 +229,12 @@
         tooLateB = getDate( 2000, 3, 25 );
     }
 
+    // -------------------------------------------------------------------------
+    //       A
+    //   B       C
+    // E   F   G   H
+    // -------------------------------------------------------------------------
+
     @Override
     public boolean emptyDatabaseAfterTest()
     {
@@ -265,7 +290,7 @@
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitC, tooLateA, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodB, unitA, tooLateB, "" ) );
         
-        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA );
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA, null );
         
         assertNotNull( results );
         assertEquals( 3, results.size() );        
@@ -273,7 +298,7 @@
         assertTrue( results.contains( new DataSetCompletenessResult( dataSetB.getName(), 2, 1, 0 ) ) );
         assertTrue( results.contains( new DataSetCompletenessResult( dataSetC.getName(), 2, 0, 0 ) ) );  
 
-        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA );
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA, null );
    
         assertNotNull( results );
         assertEquals( 3, results.size() );
@@ -311,7 +336,7 @@
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitA, tooLateA, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitB, onTimeA, "" ) );
         
-        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA );
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA, null );
         
         assertNotNull( results );
         assertEquals( 3, results.size() );        
@@ -319,7 +344,7 @@
         assertTrue( results.contains( new DataSetCompletenessResult( dataSetB.getName(), 2, 2, 2 ) ) );
         assertTrue( results.contains( new DataSetCompletenessResult( dataSetC.getName(), 2, 1, 1 ) ) );
         
-        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA );
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA, null );
         
         assertNotNull( results );
         assertEquals( 3, results.size() );        
@@ -351,13 +376,13 @@
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, onTimeB, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, tooLateB, "" ) );
 
-        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA );
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA, null );
         
         assertNotNull( results );
         assertEquals( 1, results.size() );        
         assertTrue( results.contains( new DataSetCompletenessResult( dataSetA.getName(), 7, 5, 3 ) ) );
 
-        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA );
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA, null );
         
         assertNotNull( results );
         assertEquals( 1, results.size() );        
@@ -365,6 +390,58 @@
     }
 
     @Test
+    public void testGetDataSetCompletenessByDataSetD()
+    {
+        dataSetA.getSources().add( unitA );
+        dataSetA.getSources().add( unitB );
+        
+        dataSetB.getSources().add( unitA );
+        dataSetB.getSources().add( unitB );
+
+        dataSetC.getSources().add( unitA );
+        dataSetC.getSources().add( unitB );
+        
+        dataSetService.addDataSet( dataSetA );
+        dataSetService.addDataSet( dataSetB );
+        dataSetService.addDataSet( dataSetC );
+        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitA, tooLateA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, tooLateA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, tooLateB, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitD, tooLateA, "" ) );
+        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitA, tooLateA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitC, tooLateA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodB, unitB, onTimeB, "" ) );
+
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitC, tooLateA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodB, unitA, tooLateB, "" ) );
+        
+        groupIds.clear();
+        groupIds.add( groupA.getId() );
+        
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA, groupIds );
+   
+        assertNotNull( results );
+        assertEquals( 3, results.size() );
+        assertTrue( results.contains( new DataSetCompletenessResult( dataSetA.getName(), 3, 2, 0 ) ) );
+        assertTrue( results.contains( new DataSetCompletenessResult( dataSetB.getName(), 3, 1, 0 ) ) );
+        assertTrue( results.contains( new DataSetCompletenessResult( dataSetC.getName(), 3, 1, 0 ) ) );
+
+        groupIds.clear();
+        groupIds.add( groupA.getId() );
+        groupIds.add( groupB.getId() );
+        
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdA, groupIds );
+        
+        assertNotNull( results );
+        assertEquals( 3, results.size() );
+        assertTrue( results.contains( new DataSetCompletenessResult( dataSetA.getName(), 3, 2, 0 ) ) );
+        assertTrue( results.contains( new DataSetCompletenessResult( dataSetB.getName(), 3, 1, 0 ) ) );
+        assertTrue( results.contains( new DataSetCompletenessResult( dataSetC.getName(), 3, 1, 0 ) ) );
+    }
+
+    @Test
     public void testGetDataSetCompletenessByOrganisationUnitA()
     {
         dataSetA.getSources().add( unitE );
@@ -382,7 +459,7 @@
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, onTimeA, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, onTimeA, "" ) );
         
-        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA );
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA, null );
         
         assertNotNull( results );
         assertEquals( 3, results.size() );
@@ -390,7 +467,7 @@
         assertTrue( results.contains( new DataSetCompletenessResult( unitC.getName(), 2, 1, 0 ) ) );
         assertTrue( results.contains( new DataSetCompletenessResult( unitA.getName(), 4, 3, 0 ) ) );
         
-        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdsA, dataSetIdA );
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdsA, dataSetIdA, null );
 
         assertNotNull( results );
         assertEquals( 3, results.size() );
@@ -416,7 +493,7 @@
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, onTimeB, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitH, onTimeB, "" ) );
 
-        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA );
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA, null );
         
         assertNotNull( results );
         assertEquals( 3, results.size() );
@@ -424,7 +501,7 @@
         assertTrue( results.contains( new DataSetCompletenessResult( unitC.getName(), 1, 1, 0 ) ) );
         assertTrue( results.contains( new DataSetCompletenessResult( unitA.getName(), 3, 2, 0 ) ) );
 
-        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdsA, dataSetIdA );
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdsA, dataSetIdA, null );
         
         assertNotNull( results );
         assertEquals( 3, results.size() );
@@ -453,7 +530,7 @@
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, onTimeB, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitH, tooLateB, "" ) );
 
-        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA );
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA, null );
 
         assertNotNull( results );
         assertEquals( 3, results.size() );
@@ -461,7 +538,7 @@
         assertTrue( results.contains( new DataSetCompletenessResult( unitC.getName(), 2, 2, 1 ) ) );
         assertTrue( results.contains( new DataSetCompletenessResult( unitA.getName(), 4, 4, 2 ) ) );
         
-        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdsA, dataSetIdA );
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdsA, dataSetIdA, null );
         
         assertNotNull( results );
         assertEquals( 3, results.size() );
@@ -469,4 +546,40 @@
         assertTrue( results.contains( new DataSetCompletenessResult( unitC.getName(), 6, 4, 2 ) ) );
         assertTrue( results.contains( new DataSetCompletenessResult( unitA.getName(), 12, 8, 4 ) ) );        
     }
+
+    @Test
+    public void testGetDataSetCompletenessByOrganisationUnitD()
+    {
+        dataSetA.getSources().add( unitE );
+        dataSetA.getSources().add( unitF );
+        dataSetA.getSources().add( unitG );
+        dataSetA.getSources().add( unitH );
+        
+        dataSetIdA = dataSetService.addDataSet( dataSetA );
+        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, tooLateA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, tooLateA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, tooLateA, "" ) );
+        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, onTimeA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, onTimeA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, onTimeA, "" ) );
+
+        groupIds.clear();
+        groupIds.add( groupC.getId() );
+        
+        Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA, groupIds );
+        
+        assertNotNull( results );
+        assertEquals( 2, results.size() );
+        assertTrue( results.contains( new DataSetCompletenessResult( unitB.getName(), 2, 2, 0 ) ) );
+        assertTrue( results.contains( new DataSetCompletenessResult( unitA.getName(), 2, 2, 0 ) ) );
+        
+        results = registrationCompletenessService.getDataSetCompleteness( periodIdC, unitIdsA, dataSetIdA, groupIds );
+
+        assertNotNull( results );
+        assertEquals( 2, results.size() );
+        assertTrue( results.contains( new DataSetCompletenessResult( unitB.getName(), 6, 4, 2 ) ) );
+        assertTrue( results.contains( new DataSetCompletenessResult( unitA.getName(), 6, 4, 2 ) ) );
+    }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessAction.java'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessAction.java	2012-11-06 16:12:35 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessAction.java	2012-11-21 13:04:45 +0000
@@ -27,9 +27,13 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import static org.hisp.dhis.system.util.ConversionUtils.getIdentifiers;
+
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.hisp.dhis.common.Grid;
 import org.hisp.dhis.common.GridHeader;
@@ -49,8 +53,6 @@
 
 import com.opensymphony.xwork2.Action;
 
-import static org.hisp.dhis.system.util.ConversionUtils.*;
-
 /**
  * @author Lars Helge Overland
  * @version $Id$
@@ -65,7 +67,7 @@
     private static final String TITLE_SEP = " - ";
     
     private static final String EMPTY = "";
-
+    
     // -------------------------------------------------------------------------
     // Dependencies
     // -------------------------------------------------------------------------
@@ -143,6 +145,13 @@
     {
         this.type = type;
     }
+    
+    private Set<Integer> groupId = new HashSet<Integer>();
+
+    public void setGroupId( Set<Integer> groupId )
+    {
+        this.groupId = groupId;
+    }
 
     // -------------------------------------------------------------------------
     // Output
@@ -194,18 +203,18 @@
                 if ( dataSetId != null && dataSetId != 0 ) // One ds for one ou
                 {
                     mainResults = new ArrayList<DataSetCompletenessResult>( completenessService.getDataSetCompleteness(
-                        _periodId, getIdentifiers( OrganisationUnit.class, selectedUnit.getChildren() ), dataSetId ) );
+                        _periodId, getIdentifiers( OrganisationUnit.class, selectedUnit.getChildren() ), dataSetId, groupId ) );
 
                     footerResults = new ArrayList<DataSetCompletenessResult>(
                         completenessService.getDataSetCompleteness( _periodId, Arrays.asList( selectedUnit.getId() ),
-                            dataSetId ) );
+                            dataSetId, groupId ) );
 
                     dataSet = dataSetService.getDataSet( dataSetId );
                 }
                 else // All ds for children of one ou               
                 {
                     mainResults = new ArrayList<DataSetCompletenessResult>( completenessService.getDataSetCompleteness(
-                        _periodId, selectedUnit.getId() ) );
+                        _periodId, selectedUnit.getId(), groupId ) );
                 }
 
                 grid = getGrid( mainResults, footerResults, selectedUnit, dataSet, period );

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessOptionsAction.java'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessOptionsAction.java	2012-01-25 17:11:43 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/java/org/hisp/dhis/reporting/completeness/action/GetDataCompletenessOptionsAction.java	2012-11-21 13:04:45 +0000
@@ -34,6 +34,8 @@
 import org.hisp.dhis.common.comparator.IdentifiableObjectNameComparator;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.DataSetService;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet;
 import org.hisp.dhis.period.PeriodType;
 
 import com.opensymphony.xwork2.Action;
@@ -56,6 +58,13 @@
         this.dataSetService = dataSetService;
     }
     
+    private OrganisationUnitGroupService organisationUnitGroupService;
+
+    public void setOrganisationUnitGroupService( OrganisationUnitGroupService organisationUnitGroupService )
+    {
+        this.organisationUnitGroupService = organisationUnitGroupService;
+    }
+
     // -------------------------------------------------------------------------
     // Output
     // -------------------------------------------------------------------------
@@ -66,14 +75,21 @@
     {
         return dataSets;
     }
-    
+
+    private List<OrganisationUnitGroupSet> groupSets = new ArrayList<OrganisationUnitGroupSet>();
+
+    public List<OrganisationUnitGroupSet> getGroupSets()
+    {
+        return groupSets;
+    }
+
     private List<PeriodType> periodTypes;
 
     public List<PeriodType> getPeriodTypes()
     {
         return periodTypes;
     }
-
+    
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -81,8 +97,10 @@
     public String execute()
     {
         dataSets = new ArrayList<DataSet>( dataSetService.getAllDataSets() );
+        groupSets = new ArrayList<OrganisationUnitGroupSet>( organisationUnitGroupService.getCompulsoryOrganisationUnitGroupSets() );
         
         Collections.sort( dataSets, IdentifiableObjectNameComparator.INSTANCE );
+        Collections.sort( groupSets, IdentifiableObjectNameComparator.INSTANCE );
         
         periodTypes = PeriodType.getAvailablePeriodTypes();
         

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/resources/META-INF/dhis/beans.xml	2012-09-24 05:42:39 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/resources/META-INF/dhis/beans.xml	2012-11-21 13:04:45 +0000
@@ -211,6 +211,7 @@
   <bean id="org.hisp.dhis.reporting.completeness.action.GetDataCompletenessOptionsAction" class="org.hisp.dhis.reporting.completeness.action.GetDataCompletenessOptionsAction"
     scope="prototype">
     <property name="dataSetService" ref="org.hisp.dhis.dataset.DataSetService" />
+    <property name="organisationUnitGroupService" ref="org.hisp.dhis.organisationunit.OrganisationUnitGroupService" />
   </bean>
 
   <bean id="org.hisp.dhis.reporting.completeness.action.GetDataCompletenessAction" class="org.hisp.dhis.reporting.completeness.action.GetDataCompletenessAction"

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/resources/org/hisp/dhis/reporting/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/resources/org/hisp/dhis/reporting/i18n_module.properties	2012-11-06 16:12:35 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/resources/org/hisp/dhis/reporting/i18n_module.properties	2012-11-21 13:04:45 +0000
@@ -142,6 +142,7 @@
 month=Month
 year=Year
 method=Method
+more_options=More options
 generate_before_export=Please generate table before exporting
 based_on_registration=Based on complete data set registrations
 based_on_compulsory=Based on compulsory data elements
@@ -225,4 +226,5 @@
 expected_reports=Expected Reports
 percent=Percent
 reports_on_time=Reports On Time
-percent_on_time=Percent On Time
\ No newline at end of file
+percent_on_time=Percent On Time
+view_all=View all
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataCompleteness.js'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataCompleteness.js	2012-07-26 08:23:00 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataCompleteness.js	2012-11-21 13:04:45 +0000
@@ -25,6 +25,14 @@
     var url = "getDataCompleteness.action" + "?periodId=" + periodId + "&criteria=" + criteria + "&dataSetId="
             + dataSetId + "&type=html&" + getDC();
 
+    $( '[name="groupId"]' ).each( function()
+    {
+    	if ( $( this ).val() != '-1' )
+    	{
+    		url += "&groupId=" + $( this ).val();
+    	}
+    } );
+    
     $( "#contentDiv" ).load( url, function()
     {
         hideLoader();
@@ -54,4 +62,11 @@
 function getCompleteness( type )
 {
     window.location.href = "getDataCompleteness.action?type=" + type + "&" + getDC();
-}
\ No newline at end of file
+}
+
+function showAdvancedOptions()
+{
+	$( "#selectionTree" ).css( "height", "292px" );
+	$( "#advancedOptionsLink" ).hide();
+	$( "#advancedOptions" ).slideDown();
+}

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/viewDataCompletenessForm.vm'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/viewDataCompletenessForm.vm	2012-10-18 14:06:40 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/viewDataCompletenessForm.vm	2012-11-21 13:04:45 +0000
@@ -11,58 +11,66 @@
 
 <h3>$i18n.getString( "reporting_rate_summary" ) #openHelp( "reporting_reporting_rate_summary" )</h3>
 
-<div id="critiera" class="inputCriteria" style="width:660px;height:310px;">
-<table>
-    <col width="300"/>
-    <col/>
-    <tr>
-    	<td><label>$i18n.getString( "organisation_unit" )</label></td>
-    	<td></td>
-    </tr>
-    <tr>
-	    <td><div id="selectionTree" style="width:280px; height:270px"></div></td>
-        <td valign="bottom">
-            <input type="radio" name="criteria" id="registrationRadio" value="registration" checked="checked"/>
-            <label for="registrationRadio">$i18n.getString( 'based_on_registration' )</label><br/>
-            <input type="radio" name="criteria" id="compulsoryRadio" value="compulsory" />
-            <label for="compulsoryRadio">$i18n.getString( 'based_on_compulsory' )</label><br/><br/>
-            
-            <!-- DataSet -->
-            
-        	<select id="dataSetId" name="dataSetId" style="width:330px">
-			<option value="0">[ $i18n.getString( "select_dataset_all" ) ]</option>
-			#foreach( $dataSet in $dataSets )
-				<option value="$dataSet.id">$dataSet.name</option>
-			#end
-			</select><br><br>
-            
-            <!-- PeriodType -->
-
-			<select id="periodTypeId" style="width:174px" onchange="getPeriods( 'periodTypeId', 'periodId', 'periodId', '0' )">
-				<option value="0">[ $i18n.getString( "select_period_type" ) ]</option>
-				#foreach ( $type in $periodTypes )
-					<option value="$type.name">$i18n.getString( $type.name )</option>
-				#end
-			</select>
-
-			<input type="button" style="width:75px" value="$i18n.getString( 'prev_year' )" onclick="getPeriods( 'periodTypeId', 'periodId', 'periodId', '-1' )" />
-			<input type="button" style="width:75px" value="$i18n.getString( 'next_year' )" onclick="getPeriods( 'periodTypeId', 'periodId', 'periodId', '1' )" /><br>
-
-			<!-- Period -->
-			
-            <select id="periodId" name="periodId" style="width:330px" disabled="disabled">
-            </select><br><br>
-            
-            <input id="reportButton" type="button" value="$i18n.getString( 'get_report' )" style="width:135px" onclick="displayCompleteness()"/><br><br>
-            
-            <!-- Export -->
-            
-        	<input type="button" value="$i18n.getString( 'get_report_as_pdf' )" style="width:135px" onclick="getCompleteness( 'pdf' )"/>
-            <input type="button" value="$i18n.getString( 'get_report_as_xls' )" style="width:135px" onclick="getCompleteness( 'xls' )"/><br>
-        	<input type="button" value="$i18n.getString( 'get_report_as_csv' )" style="width:135px" onclick="getCompleteness( 'csv' )"/>
-        </td>
-    </tr>
-</table>
+<div id="critiera" class="inputCriteria" style="width:660px; height:auto; padding:20px;">
+<div style="width:320px; float:left;">
+	<label>$i18n.getString( "organisation_unit" )</label>
+	<div id="selectionTree" style="width:290px; height:228px"></div>
+</div>
+<div>
+    <input type="radio" name="criteria" id="registrationRadio" value="registration" checked="checked"/>
+    <label for="registrationRadio">$i18n.getString( 'based_on_registration' )</label><br/>
+    <input type="radio" name="criteria" id="compulsoryRadio" value="compulsory" />
+    <label for="compulsoryRadio">$i18n.getString( 'based_on_compulsory' )</label><br/><br/>
+    
+    <!-- DataSet -->
+    
+	<select id="dataSetId" name="dataSetId" style="width:330px">
+	<option value="0">[ $i18n.getString( "select_dataset_all" ) ]</option>
+	#foreach( $dataSet in $dataSets )
+		<option value="$dataSet.id">$dataSet.name</option>
+	#end
+	</select><br><br>
+    
+    <!-- PeriodType -->
+
+	<select id="periodTypeId" style="width:174px" onchange="getPeriods( 'periodTypeId', 'periodId', 'periodId', '0' )">
+		<option value="0">[ $i18n.getString( "select_period_type" ) ]</option>
+		#foreach ( $type in $periodTypes )
+			<option value="$type.name">$i18n.getString( $type.name )</option>
+		#end
+	</select>
+
+	<input type="button" style="width:75px" value="$i18n.getString( 'prev_year' )" onclick="getPeriods( 'periodTypeId', 'periodId', 'periodId', '-1' )" />
+	<input type="button" style="width:75px" value="$i18n.getString( 'next_year' )" onclick="getPeriods( 'periodTypeId', 'periodId', 'periodId', '1' )" /><br>
+
+	<!-- Period -->
+	
+    <select id="periodId" name="periodId" style="width:330px" disabled="disabled">
+    </select><br><br>
+    
+    <!-- Org unit group sets -->
+    
+    <span id="advancedOptions" style="display:none">
+    #foreach( $groupSet in $groupSets )
+    <select name="groupId" style="width:330px" class="advanced">
+    	<option value="-1">[ $i18n.getString( "select" ) $encoder.htmlEncode( $groupSet.name ) / $i18n.getString( "view_all" ) ]</option>
+        #foreach( $group in $groupSet.organisationUnitGroups )
+    	<option value="${group.id}">$encoder.htmlEncode( $group.name )</option>
+        #end
+    </select><br>
+    #end <br></span>
+    
+    <!-- Get report -->
+    
+    <input id="reportButton" type="button" value="$i18n.getString( 'get_report' )" style="width:135px" onclick="displayCompleteness()"/> &nbsp;
+    <a id="advancedOptionsLink" href="javascript:showAdvancedOptions()">$i18n.getString( "more_options" )</a><br><br>
+    
+    <!-- Export -->
+    
+	<input type="button" value="$i18n.getString( 'get_report_as_pdf' )" style="width:135px" onclick="getCompleteness( 'pdf' )"/>
+    <input type="button" value="$i18n.getString( 'get_report_as_xls' )" style="width:135px" onclick="getCompleteness( 'xls' )"/><br>
+	<input type="button" value="$i18n.getString( 'get_report_as_csv' )" style="width:135px" onclick="getCompleteness( 'csv' )"/>
+</div>
 </div>
 
 #parse( "dhis-web-commons/loader/loader.vm" )