← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 16407: applied patch from tw-msf, adds support for multiple approvals/unapprovals and multiple complete/...

 

------------------------------------------------------------
revno: 16407
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2014-08-14 12:46:19 +0700
message:
  applied patch from tw-msf, adds support for multiple approvals/unapprovals and multiple complete/uncomplete for datasets
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequest.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequests.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponse.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponses.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequest.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequests.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalState.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultCompleteDataSetRegistrationService.java
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationServiceTest.java
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationStoreTest.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingJsonDataValue.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/datasetreport/impl/DefaultDataSetReportService.java
  dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.java
  dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceTest.java
  dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java
  dhis-2/dhis-support/dhis-support-jdbc-test/src/test/java/org/hisp/dhis/jdbc/batchhandler/CompleteDataSetRegistrationBatchHandlerTest.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataApprovalController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/UserSettingController.java
  dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js
  dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js


--
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/calendar/DateUnitPeriodTypeParser.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java	2014-08-11 05:27:09 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java	2014-08-14 05:46:19 +0000
@@ -97,6 +97,8 @@
             return null;
         }
 
+        Calendar calendar = getCalendar();
+
         if ( DateUnitType.DAILY.equals( type ) )
         {
             int year = Integer.parseInt( matcher.group( 1 ) );
@@ -104,7 +106,7 @@
             int day = Integer.parseInt( matcher.group( 3 ) );
 
             DateUnit dateUnit = new DateUnit( year, month, day );
-            dateUnit.setDayOfWeek( getCalendar().weekday( dateUnit ) );
+            dateUnit.setDayOfWeek(calendar.weekday(dateUnit));
 
             return new DateInterval( dateUnit, dateUnit );
         }
@@ -113,27 +115,27 @@
             int year = Integer.parseInt( matcher.group( 1 ) );
             int week = Integer.parseInt( matcher.group( 2 ) );
 
-            if ( week < 1 || week > getCalendar().weeksInYear( year ) )
+            if ( week < 1 || week > calendar.weeksInYear(year) )
             {
                 return null;
             }
 
             DateUnit start = new DateUnit( year, 1, 1 );
-            start = getCalendar().minusDays( start, getCalendar().weekday( start ) - 1 ); // rewind to start of week
+            start = calendar.minusDays(start, calendar.weekday(start) - 1); // rewind to start of week
 
             // since we rewind to start of week, we might end up in the previous years weeks, so we check and forward if needed
-            if ( getCalendar().isoWeek( start ) == getCalendar().weeksInYear( year ) )
+            if ( calendar.isoWeek(start) == calendar.weeksInYear(year) )
             {
-                start = getCalendar().plusWeeks( start, 1 );
+                start = calendar.plusWeeks(start, 1);
             }
 
-            start = getCalendar().plusWeeks( start, week - 1 );
+            start = calendar.plusWeeks(start, week - 1);
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusWeeks( end, 1 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusWeeks(end, 1);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek( calendar.weekday(end) );
 
             return new DateInterval( start, end );
         }
@@ -143,10 +145,10 @@
             int month = Integer.parseInt( matcher.group( 2 ) );
 
             DateUnit start = new DateUnit( year, month, 1 );
-            DateUnit end = new DateUnit( year, month, getCalendar().daysInMonth( start.getYear(), start.getMonth() ) );
+            DateUnit end = new DateUnit( year, month, calendar.daysInMonth(start.getYear(), start.getMonth()) );
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }
@@ -162,11 +164,11 @@
 
             DateUnit start = new DateUnit( year, (month * 2) - 1, 1 );
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusMonths( end, 2 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusMonths(end, 2);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }
@@ -183,11 +185,11 @@
 
             DateUnit start = new DateUnit( year, ((quarter - 1) * 3) + 1, 1 );
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusMonths( end, 3 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusMonths(end, 3);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }
@@ -204,11 +206,11 @@
 
             DateUnit start = new DateUnit( year, semester == 1 ? 1 : 7, 1 );
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusMonths( end, 6 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusMonths(end, 6);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }
@@ -225,11 +227,11 @@
 
             DateUnit start = new DateUnit( year, semester == 1 ? 4 : 10, 1 );
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusMonths( end, 6 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusMonths(end, 6);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }
@@ -238,11 +240,11 @@
             int year = Integer.parseInt( matcher.group( 1 ) );
 
             DateUnit start = new DateUnit( year, 1, 1 );
-            DateUnit end = new DateUnit( year, getCalendar().monthsInYear(),
-                getCalendar().daysInMonth( start.getYear(), getCalendar().monthsInYear() ) );
+            DateUnit end = new DateUnit( year, calendar.monthsInYear(),
+                calendar.daysInMonth(start.getYear(), calendar.monthsInYear()) );
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek(calendar.weekday(start));
+            end.setDayOfWeek( calendar.weekday(end) );
 
             return new DateInterval( start, end );
         }
@@ -252,11 +254,11 @@
 
             DateUnit start = new DateUnit( year, 4, 1 );
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusYears( end, 1 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusYears(end, 1);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }
@@ -266,11 +268,11 @@
 
             DateUnit start = new DateUnit( year, 7, 1 );
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusYears( end, 1 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusYears(end, 1);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }
@@ -280,11 +282,11 @@
 
             DateUnit start = new DateUnit( year, 10, 1 );
             DateUnit end = new DateUnit( start );
-            end = getCalendar().plusYears( end, 1 );
-            end = getCalendar().minusDays( end, 1 );
+            end = calendar.plusYears(end, 1);
+            end = calendar.minusDays(end, 1);
 
-            start.setDayOfWeek( getCalendar().weekday( start ) );
-            end.setDayOfWeek( getCalendar().weekday( end ) );
+            start.setDayOfWeek( calendar.weekday(start) );
+            end.setDayOfWeek(calendar.weekday(end));
 
             return new DateInterval( start, end );
         }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java	2014-04-20 00:18:20 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java	2014-08-14 05:46:19 +0000
@@ -35,6 +35,7 @@
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.period.Period;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -46,6 +47,13 @@
     String ID = DataApprovalService.class.getName();
 
     /**
+     * Adds a list of DataApproval in order to approve data.
+     *
+     * @param dataApprovalList the DataApproval to add.
+     */
+    void addAllDataApprovals(List<DataApproval> dataApprovalList);
+
+    /**
      * Adds a DataApproval in order to approve data.
      *
      * @param dataApproval the DataApproval to add.
@@ -62,6 +70,15 @@
     void deleteDataApproval( DataApproval dataApproval );
 
     /**
+     * Deletes a list of DataApproval in order to un-approve data.
+     * Any higher-level DataApprovals above this organisation unit
+     * are also deleted for the same period and data set.
+     *
+     * @param dataApprovalList the DataApproval to delete.
+     */
+    void deleteDataApprovals( List<DataApproval> dataApprovalList );
+
+    /**
      * Returns the data approval status for a given data set, period,
      * organisation unit and attribute category combination.
      * If attributeOptionCombo is null, the default option combo will be used.

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalState.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalState.java	2014-06-06 19:29:39 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalState.java	2014-08-14 05:46:19 +0000
@@ -188,3 +188,4 @@
         return ready;
     }
 }
+

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequest.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequest.java	2014-08-14 05:46:19 +0000
@@ -0,0 +1,131 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import org.hisp.dhis.common.DxfNamespaces;
+
+import java.util.Date;
+
+/**
+ * Represents a data approval state request
+ */
+@JacksonXmlRootElement( localName = "dataApprovalStateRequest", namespace = DxfNamespaces.DXF_2_0 )
+public class DataApprovalStateRequest
+{
+    private String ds;
+
+    private String pe;
+
+    private String ou;
+
+    private String cog;
+
+    private String ab;
+
+    private Date ad;
+
+    public DataApprovalStateRequest()
+    {
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getDs()
+    {
+        return ds;
+    }
+
+    public void setDs( String ds )
+    {
+        this.ds = ds;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getPe()
+    {
+        return pe;
+    }
+
+    public void setPe( String pe )
+    {
+        this.pe = pe;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getOu()
+    {
+        return ou;
+    }
+
+    public void setOu( String ou )
+    {
+        this.ou = ou;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getCog()
+    {
+        return cog;
+    }
+
+    public void setCog( String cog )
+    {
+        this.cog = cog;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getAb()
+    {
+        return ab;
+    }
+
+    public void setAb( String ab )
+    {
+        this.ab = ab;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public Date getAd()
+    {
+        return ad;
+    }
+
+    public void setAd( Date ad )
+    {
+        this.ad = ad;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequests.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequests.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateRequests.java	2014-08-14 05:46:19 +0000
@@ -0,0 +1,39 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.HashSet;
+
+/**
+ * Represents a collection of data approval state responses
+ */
+public class DataApprovalStateRequests
+    extends HashSet<DataApprovalStateRequest>
+{
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponse.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponse.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponse.java	2014-08-14 05:46:19 +0000
@@ -0,0 +1,203 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import org.hisp.dhis.common.BaseIdentifiableObject;
+import org.hisp.dhis.common.DxfNamespaces;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+
+import java.util.Date;
+
+@JacksonXmlRootElement( localName = "dataApprovalStateResponse", namespace = DxfNamespaces.DXF_2_0 )
+public class DataApprovalStateResponse
+{
+    private DataSet dataSet;
+
+    private Period period;
+
+    private OrganisationUnit organisationUnit;
+
+    private String state;
+
+    private String createdByUsername;
+
+    private Date createdDate;
+
+    private boolean mayApprove;
+
+    private boolean mayUnapprove;
+
+    private boolean mayAccept;
+
+    private boolean mayUnaccept;
+
+    public DataApprovalStateResponse( DataSet dataSet, Period period, OrganisationUnit organisationUnit, String state, Date createdDate, String createdByUsername,
+        boolean mayApprove, boolean mayUnapprove, boolean mayAccept, boolean mayUnaccept )
+    {
+        this.dataSet = dataSet;
+        this.period = period;
+        this.organisationUnit = organisationUnit;
+        this.state = state;
+        this.createdDate = createdDate;
+        this.createdByUsername = createdByUsername;
+        this.mayApprove = mayApprove;
+        this.mayUnapprove = mayUnapprove;
+        this.mayAccept = mayAccept;
+        this.mayUnaccept = mayUnaccept;
+    }
+
+    @JsonProperty
+    @JsonSerialize( as = BaseIdentifiableObject.class )
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public DataSet getDataSet()
+    {
+        return dataSet;
+    }
+
+    public void setDataSet( DataSet dataSet )
+    {
+        this.dataSet = dataSet;
+    }
+
+    @JsonProperty
+    @JsonSerialize( as = BaseIdentifiableObject.class )
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public Period getPeriod()
+    {
+        return period;
+    }
+
+    public void setPeriod( Period period )
+    {
+        this.period = period;
+    }
+
+    @JsonProperty
+    @JsonSerialize( as = BaseIdentifiableObject.class )
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public OrganisationUnit getOrganisationUnit()
+    {
+        return organisationUnit;
+    }
+
+    public void setOrganisationUnit( OrganisationUnit organisationUnit )
+    {
+        this.organisationUnit = organisationUnit;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getState()
+    {
+        return state;
+    }
+
+    public void setState( String state )
+    {
+        this.state = state;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public boolean isMayApprove()
+    {
+        return mayApprove;
+    }
+
+    public void setMayApprove( boolean mayApprove )
+    {
+        this.mayApprove = mayApprove;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public boolean isMayUnapprove()
+    {
+        return mayUnapprove;
+    }
+
+    public void setMayUnapprove( boolean mayUnapprove )
+    {
+        this.mayUnapprove = mayUnapprove;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public boolean isMayAccept()
+    {
+        return mayAccept;
+    }
+
+    public void setMayAccept( boolean mayAccept )
+    {
+        this.mayAccept = mayAccept;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public boolean isMayUnaccept()
+    {
+        return mayUnaccept;
+    }
+
+    public void setMayUnaccept( boolean mayUnaccept )
+    {
+        this.mayUnaccept = mayUnaccept;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getCreatedByUsername()
+    {
+        return createdByUsername;
+    }
+
+    public void setCreatedByUsername( String createdByUsername )
+    {
+        this.createdByUsername = createdByUsername;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public Date getCreatedDate()
+    {
+        return createdDate;
+    }
+
+    public void setCreatedDate( Date createdDate )
+    {
+        this.createdDate = createdDate;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponses.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponses.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStateResponses.java	2014-08-14 05:46:19 +0000
@@ -0,0 +1,33 @@
+package org.hisp.dhis.dataapproval;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import org.hisp.dhis.common.DxfNamespaces;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DataApprovalStateResponses
+{
+    List<DataApprovalStateResponse> dataApprovalStateResponses = new ArrayList<>();
+
+    public DataApprovalStateResponses()
+    {
+    }
+
+    @JsonProperty
+    public List<DataApprovalStateResponse> getDataApprovalStateResponses()
+    {
+        return dataApprovalStateResponses;
+    }
+
+    public void setDataApprovalStateResponses( List<DataApprovalStateResponse> dataApprovalStateResponses )
+    {
+        this.dataApprovalStateResponses = dataApprovalStateResponses;
+    }
+
+    public void add( DataApprovalStateResponse dataApprovalStateResponse )
+    {
+        dataApprovalStateResponses.add( dataApprovalStateResponse );
+    }
+}

=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion'
=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequest.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequest.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequest.java	2014-08-14 05:46:19 +0000
@@ -0,0 +1,159 @@
+package org.hisp.dhis.datacompletion;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import org.hisp.dhis.common.DxfNamespaces;
+
+import java.util.Date;
+
+/**
+ * Represents a dataset completion registration request
+ */
+@JacksonXmlRootElement( localName = "completeDataSetRegistrationRequest", namespace = DxfNamespaces.DXF_2_0 )
+public class CompleteDataSetRegistrationRequest
+{
+    private String ds;
+
+    private String pe;
+
+    private String ou;
+
+    private String sb;
+
+    private Date cd;
+
+    private String cc;
+
+    private String cp;
+
+    private boolean multiOu;
+
+    public CompleteDataSetRegistrationRequest()
+    {
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getDs()
+    {
+        return ds;
+    }
+
+    public void setDs( String ds )
+    {
+        this.ds = ds;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getPe()
+    {
+        return pe;
+    }
+
+    public void setPe( String pe )
+    {
+        this.pe = pe;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getOu()
+    {
+        return ou;
+    }
+
+    public void setOu( String ou )
+    {
+        this.ou = ou;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getSb()
+    {
+        return sb;
+    }
+
+    public void setSb( String sb )
+    {
+        this.sb = sb;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public Date getCd()
+    {
+        return cd;
+    }
+
+    public void setCd( Date cd )
+    {
+        this.cd = cd;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getCc()
+    {
+        return cc;
+    }
+
+    public void setCc( String cc )
+    {
+        this.cc = cc;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public String getCp()
+    {
+        return cp;
+    }
+
+    public void setCp( String cp )
+    {
+        this.cp = cp;
+    }
+
+    @JsonProperty
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public boolean isMultiOu()
+    {
+        return multiOu;
+    }
+
+    public void setMultiOu( boolean multiOu )
+    {
+        this.multiOu = multiOu;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequests.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequests.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/datacompletion/CompleteDataSetRegistrationRequests.java	2014-08-14 05:46:19 +0000
@@ -0,0 +1,40 @@
+package org.hisp.dhis.datacompletion;
+
+/*
+ * Copyright (c) 2004-2014, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.HashSet;
+
+/**
+ * Represents a collection of dataset completion registration requests
+ */
+public class CompleteDataSetRegistrationRequests
+    extends HashSet<CompleteDataSetRegistrationRequest>
+{
+
+}

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java	2014-08-11 21:36:11 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java	2014-08-14 05:46:19 +0000
@@ -28,9 +28,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import java.util.Collection;
-import java.util.Set;
-
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -49,6 +46,10 @@
 import org.hisp.dhis.user.User;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
 /**
  * @author Jim Grace
  */
@@ -115,9 +116,18 @@
     // DataApproval
     // -------------------------------------------------------------------------
 
+    @Override
+    public void addAllDataApprovals( List<DataApproval> dataApprovalList )
+    {
+        for ( DataApproval dataApproval : dataApprovalList )
+        {
+            addDataApproval( dataApproval );
+        }
+    }
+
     public void addDataApproval( DataApproval dataApproval )
     {
-        if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
+        if ( (dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ))
             && mayApprove( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) )
         {
             PeriodType selectionPeriodType = dataApproval.getPeriod().getPeriodType();
@@ -130,7 +140,7 @@
             else if ( selectionPeriodType.getFrequencyOrder() <= dataSetPeriodType.getFrequencyOrder() )
             {
                 log.warn( "Attempted data approval for period " + dataApproval.getPeriod().getIsoDate()
-                + " is incompatible with data set period type " + dataSetPeriodType.getName() + "." );
+                    + " is incompatible with data set period type " + dataSetPeriodType.getName() + "." );
             }
             else
             {
@@ -140,16 +150,24 @@
         else
         {
             warnNotPermitted( dataApproval, "approve",
-                    mayApprove( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) );
+                mayApprove( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) );
+        }
+    }
+
+    public void deleteDataApprovals( List<DataApproval> dataApprovalList )
+    {
+        for ( DataApproval dataApproval : dataApprovalList )
+        {
+            deleteDataApproval( dataApproval );
         }
     }
 
     public void deleteDataApproval( DataApproval dataApproval )
     {
         boolean mayUnapprove = mayUnapprove( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit(), dataApproval.isAccepted() )
-                || mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() );
+            || mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() );
 
-        if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
+        if ( (dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ))
             && mayUnapprove )
         {
             PeriodType selectionPeriodType = dataApproval.getPeriod().getPeriodType();
@@ -162,18 +180,18 @@
                 for ( OrganisationUnit ancestor : dataApproval.getOrganisationUnit().getAncestors() )
                 {
                     DataApproval ancestorApproval = dataApprovalStore.getDataApproval(
-                            dataApproval.getDataSet(), dataApproval.getPeriod(), ancestor, dataApproval.getCategoryOptionGroup() );
+                        dataApproval.getDataSet(), dataApproval.getPeriod(), ancestor, dataApproval.getCategoryOptionGroup() );
 
                     if ( ancestorApproval != null )
                     {
-                        dataApprovalStore.deleteDataApproval ( ancestorApproval );
+                        dataApprovalStore.deleteDataApproval( ancestorApproval );
                     }
                 }
             }
             else if ( selectionPeriodType.getFrequencyOrder() <= dataSetPeriodType.getFrequencyOrder() )
             {
                 log.warn( "Attempted data unapproval for period " + dataApproval.getPeriod().getIsoDate()
-                        + " is incompatible with data set period type " + dataSetPeriodType.getName() + "." );
+                    + " is incompatible with data set period type " + dataSetPeriodType.getName() + "." );
             }
             else
             {
@@ -188,10 +206,10 @@
 
     public DataApprovalStatus getDataApprovalStatus( DataSet dataSet, Period period, OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo )
     {
-        Set<DataElementCategoryOption> categoryOptions = 
-            attributeOptionCombo == null || attributeOptionCombo.equals( categoryService.getDefaultDataElementCategoryOptionCombo() ) ? 
+        Set<DataElementCategoryOption> categoryOptions =
+            attributeOptionCombo == null || attributeOptionCombo.equals( categoryService.getDefaultDataElementCategoryOptionCombo() ) ?
                 null : attributeOptionCombo.getCategoryOptions();
-        
+
         return getDataApprovalStatus( dataSet, period, organisationUnit, null, categoryOptions );
     }
 
@@ -199,20 +217,20 @@
         Set<CategoryOptionGroup> categoryOptionGroups, Set<DataElementCategoryOption> dataElementCategoryOptions )
     {
         DataApprovalSelection dataApprovalSelection = new DataApprovalSelection( dataSet, period, organisationUnit,
-                categoryOptionGroups, dataElementCategoryOptions,
-                dataApprovalStore, dataApprovalLevelService,
-                organisationUnitService, categoryService, periodService);
+            categoryOptionGroups, dataElementCategoryOptions,
+            dataApprovalStore, dataApprovalLevelService,
+            organisationUnitService, categoryService, periodService );
 
         return dataApprovalSelection.getDataApprovalStatus();
     }
 
-    public DataApprovalPermissions getDataApprovalPermissions( DataSet dataSet, Period period, 
+    public DataApprovalPermissions getDataApprovalPermissions( DataSet dataSet, Period period,
         OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo )
     {
-        Set<DataElementCategoryOption> categoryOptions = 
+        Set<DataElementCategoryOption> categoryOptions =
             attributeOptionCombo == null || attributeOptionCombo.equals( categoryService.getDefaultDataElementCategoryOptionCombo() ) ?
                 null : attributeOptionCombo.getCategoryOptions();
-        
+
         return getDataApprovalPermissions( dataSet, period, organisationUnit, null, categoryOptions );
     }
 
@@ -231,7 +249,7 @@
         DataApprovalLevel dataApprovalLevel = status.getDataApprovalLevel();
 
         if ( dataApprovalLevel != null && securityService.canRead( dataApprovalLevel )
-            && ( dataApprovalLevel.getCategoryOptionGroupSet() == null || securityService.canRead( dataApprovalLevel.getCategoryOptionGroupSet() ))
+            && (dataApprovalLevel.getCategoryOptionGroupSet() == null || securityService.canRead( dataApprovalLevel.getCategoryOptionGroupSet() ))
             && canReadOneCategoryOptionGroup( categoryOptionGroups ) )
         {
             switch ( status.getDataApprovalState() )
@@ -256,11 +274,11 @@
         }
 
         log.debug( "Returning permissions for " + organisationUnit.getName()
-                + " " + status.getDataApprovalState().name()
-                + " may approve = " + permissions.isMayApprove()
-                + " may unapprove = " + permissions.isMayUnapprove()
-                + " may accept = " + permissions.isMayAccept()
-                + " may unaccept = " + permissions.isMayUnaccept() );
+            + " " + status.getDataApprovalState().name()
+            + " may approve = " + permissions.isMayApprove()
+            + " may unapprove = " + permissions.isMayUnapprove()
+            + " may accept = " + permissions.isMayAccept()
+            + " may unaccept = " + permissions.isMayUnaccept() );
 
         return permissions;
     }
@@ -283,12 +301,12 @@
      * Accept or unaccept a data approval.
      *
      * @param dataApproval the data approval object.
-     * @param accepted true to accept, false to unaccept.
+     * @param accepted     true to accept, false to unaccept.
      */
-    public void acceptOrUnaccept ( DataApproval dataApproval, boolean accepted )
+    public void acceptOrUnaccept( DataApproval dataApproval, boolean accepted )
     {
-        if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
-                && mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) )
+        if ( (dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ))
+            && mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) )
         {
             PeriodType selectionPeriodType = dataApproval.getPeriod().getPeriodType();
             PeriodType dataSetPeriodType = dataApproval.getDataSet().getPeriodType();
@@ -297,18 +315,21 @@
             {
                 dataApproval.setAccepted( accepted );
                 dataApprovalStore.updateDataApproval( dataApproval );
-            } else if ( selectionPeriodType.getFrequencyOrder() <= dataSetPeriodType.getFrequencyOrder() )
+            }
+            else if ( selectionPeriodType.getFrequencyOrder() <= dataSetPeriodType.getFrequencyOrder() )
             {
                 log.warn( "Attempted data approval for period " + dataApproval.getPeriod().getIsoDate()
-                        + " is incompatible with data set period type " + dataSetPeriodType.getName() + "." );
-            } else
+                    + " is incompatible with data set period type " + dataSetPeriodType.getName() + "." );
+            }
+            else
             {
                 acceptOrUnacceptCompositePeriod( dataApproval, accepted );
             }
-        } else
+        }
+        else
         {
             warnNotPermitted( dataApproval, accepted ? "accept" : "unaccept",
-                    mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) );
+                mayAcceptOrUnaccept( dataApproval.getDataApprovalLevel(), dataApproval.getOrganisationUnit() ) );
         }
     }
 
@@ -322,14 +343,14 @@
     private void approveCompositePeriod( DataApproval da )
     {
         Collection<Period> periods = periodService.getPeriodsBetweenDates(
-                da.getDataSet().getPeriodType(),
-                da.getPeriod().getStartDate(),
-                da.getPeriod().getEndDate() );
+            da.getDataSet().getPeriodType(),
+            da.getPeriod().getStartDate(),
+            da.getPeriod().getEndDate() );
 
         for ( Period period : periods )
         {
             DataApprovalStatus status = getDataApprovalStatus( da.getDataSet(), period, da.getOrganisationUnit(),
-                    da.getCategoryOptionGroup() == null ? null : org.hisp.dhis.system.util.CollectionUtils.asSet( da.getCategoryOptionGroup() ), null );
+                da.getCategoryOptionGroup() == null ? null : org.hisp.dhis.system.util.CollectionUtils.asSet( da.getCategoryOptionGroup() ), null );
 
             if ( status.getDataApprovalState().isReady() && !status.getDataApprovalState().isApproved() )
             {
@@ -345,7 +366,7 @@
      * Unapproves data for a longer period that contains multiple data approval
      * periods. When individual periods are already unapproved, no action is
      * necessary.
-     * <p>
+     * <p/>
      * Note that when we delete approval for a period, we also need to make
      * sure that approval is removed for any ancestors at higher levels of
      * approval. For this reason, we go back through the main deleteDataApproval
@@ -356,14 +377,14 @@
     void unapproveCompositePeriod( DataApproval da )
     {
         Collection<Period> periods = periodService.getPeriodsBetweenDates(
-                da.getDataSet().getPeriodType(),
-                da.getPeriod().getStartDate(),
-                da.getPeriod().getEndDate() );
+            da.getDataSet().getPeriodType(),
+            da.getPeriod().getStartDate(),
+            da.getPeriod().getEndDate() );
 
         for ( Period period : periods )
         {
             DataApprovalStatus status = getDataApprovalStatus( da.getDataSet(), period, da.getOrganisationUnit(),
-                    da.getCategoryOptionGroup() == null ? null : org.hisp.dhis.system.util.CollectionUtils.asSet( da.getCategoryOptionGroup() ), null );
+                da.getCategoryOptionGroup() == null ? null : org.hisp.dhis.system.util.CollectionUtils.asSet( da.getCategoryOptionGroup() ), null );
 
             if ( status.getDataApprovalState().isApproved() )
             {
@@ -377,20 +398,20 @@
      * data approval periods. When individual periods are already at the
      * desired accptance state, no action is necessary.
      *
-     * @param da data approval object describing the longer period.
+     * @param da       data approval object describing the longer period.
      * @param accepted true to accept, false to unaccept.
      */
     private void acceptOrUnacceptCompositePeriod( DataApproval da, boolean accepted )
     {
         Collection<Period> periods = periodService.getPeriodsBetweenDates(
-                da.getDataSet().getPeriodType(),
-                da.getPeriod().getStartDate(),
-                da.getPeriod().getEndDate() );
+            da.getDataSet().getPeriodType(),
+            da.getPeriod().getStartDate(),
+            da.getPeriod().getEndDate() );
 
         for ( Period period : periods )
         {
             DataApprovalStatus status = getDataApprovalStatus( da.getDataSet(), period, da.getOrganisationUnit(),
-                    da.getCategoryOptionGroup() == null ? null : org.hisp.dhis.system.util.CollectionUtils.asSet( da.getCategoryOptionGroup() ), null );
+                da.getCategoryOptionGroup() == null ? null : org.hisp.dhis.system.util.CollectionUtils.asSet( da.getCategoryOptionGroup() ), null );
 
             if ( status.getDataApprovalState().isApprovable() && status.getDataApprovalState().isAccepted() != accepted )
             {
@@ -419,7 +440,7 @@
             return false;
         }
 
-        return ( securityService.canRead( (CategoryOptionGroup) categoryOptionGroups.toArray()[0] ) );
+        return (securityService.canRead( (CategoryOptionGroup) categoryOptionGroups.toArray()[0] ));
     }
 
     /**
@@ -451,7 +472,7 @@
      * organisation unit.
      *
      * @param dataApprovalLevel This data approval level.
-     * @param organisationUnit The organisation unit to check for permission.
+     * @param organisationUnit  The organisation unit to check for permission.
      * @return true if the user may approve, otherwise false
      */
     private boolean mayApprove( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
@@ -474,7 +495,7 @@
                 }
 
                 log.debug( "mayApprove = true because organisation unit " + organisationUnit.getName()
-                        + " is assigned to user and user may approve at same level." );
+                    + " is assigned to user and user may approve at same level." );
 
                 return true;
             }
@@ -483,7 +504,7 @@
                 organisationUnit.getAncestors() ) )
             {
                 log.debug( "mayApprove = true because organisation unit " + organisationUnit.getName()
-                        + " is under user and user may approve at lower levels." );
+                    + " is under user and user may approve at lower levels." );
 
                 return true;
             }
@@ -498,12 +519,12 @@
      * Checks to see whether a user may approve data at the next higher
      * approval level for this orgnaisation unit -- because they can
      * approve only at that next higher level (and not at lower levels.)
-     * <p>
+     * <p/>
      * It is assumed that the user has the authority to approve at their
      * level -- and not the authority to approve at lower levels.
      *
      * @param dataApprovalLevel This data approval level.
-     * @param organisationUnit The organisation unit to check for permission.
+     * @param organisationUnit  The organisation unit to check for permission.
      * @return true if the user may approve at the next higher level.
      */
     private boolean mayApproveAtNextHigherLevelOnly( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
@@ -513,9 +534,9 @@
             DataApprovalLevel nextLevel = dataApprovalLevelService.getDataApprovalLevelByLevelNumber( dataApprovalLevel.getLevel() - 1 );
 
             if ( securityService.canRead( nextLevel )
-                    && ( nextLevel.getCategoryOptionGroupSet() == null ||
-                    ( securityService.canRead( nextLevel.getCategoryOptionGroupSet() )
-                            && canReadSomeCategoryOptionGroup( nextLevel.getCategoryOptionGroupSet().getMembers() ) ) ) )
+                && (nextLevel.getCategoryOptionGroupSet() == null ||
+                (securityService.canRead( nextLevel.getCategoryOptionGroupSet() )
+                    && canReadSomeCategoryOptionGroup( nextLevel.getCategoryOptionGroupSet().getMembers() ))) )
             {
                 OrganisationUnit acceptOrgUnit = organisationUnit;
                 for ( int i = nextLevel.getOrgUnitLevel(); i < dataApprovalLevel.getOrgUnitLevel(); i++ )
@@ -535,15 +556,15 @@
 
     /**
      * Checks to see whether a user may unapprove a data approval.
-     * <p>
+     * <p/>
      * A user may unapprove data for organisation unit A if they have the
      * authority to approve data for organisation unit B, and B is an
      * ancestor of A.
-     * <p>
+     * <p/>
      * A user may also unapprove data for organisation unit A if they have
      * the authority to approve data for organisation unit A, and A has no
      * ancestors.
-     * <p>
+     * <p/>
      * But a user may not unapprove data for an organisation unit if the data
      * has been approved already at a higher level for the same period and
      * data set, and the user is not authorized to remove that approval as well.
@@ -571,7 +592,7 @@
      * @param dataApproval The approval to check for permission.
      * @return true if the user may accept or unaccept, otherwise false.
      */
-    private boolean mayAcceptOrUnaccept ( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
+    private boolean mayAcceptOrUnaccept( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
     {
         User user = currentUserService.getCurrentUser();
 
@@ -589,9 +610,9 @@
         }
 
         log.debug( "User with AUTH_ACCEPT_LOWER_LEVELS " + user.getUserCredentials().isAuthorized( DataApproval.AUTH_ACCEPT_LOWER_LEVELS )
-                + " with " + user.getOrganisationUnits().size() + " org units"
-                + " may not accept or unaccept for organisation unit "
-                + ( organisationUnit == null ? "(null)" : organisationUnit.getName() ) );
+            + " with " + user.getOrganisationUnits().size() + " org units"
+            + " may not accept or unaccept for organisation unit "
+            + (organisationUnit == null ? "(null)" : organisationUnit.getName()) );
 
         return false;
     }
@@ -599,11 +620,11 @@
     /**
      * Checks to see whether a user may access the next higher approval
      * level to see if they can accept at this approval level.
-     * <p>
+     * <p/>
      * It is assumed that the user has the authority to accept at lower levels.
      *
      * @param dataApprovalLevel This data approval level.
-     * @param organisationUnit The organisation unit to check for permission.
+     * @param organisationUnit  The organisation unit to check for permission.
      * @return true if the user may approve at the next higher level.
      */
     private boolean mayAccessNextHigherLevel( DataApprovalLevel dataApprovalLevel, OrganisationUnit organisationUnit )
@@ -613,9 +634,9 @@
             DataApprovalLevel nextLevel = dataApprovalLevelService.getDataApprovalLevelByLevelNumber( dataApprovalLevel.getLevel() - 1 );
 
             if ( securityService.canRead( nextLevel )
-                    && ( nextLevel.getCategoryOptionGroupSet() == null ||
-                    ( securityService.canRead( nextLevel.getCategoryOptionGroupSet() )
-                            && canReadSomeCategoryOptionGroup( nextLevel.getCategoryOptionGroupSet().getMembers() ) ) ) )
+                && (nextLevel.getCategoryOptionGroupSet() == null ||
+                (securityService.canRead( nextLevel.getCategoryOptionGroupSet() )
+                    && canReadSomeCategoryOptionGroup( nextLevel.getCategoryOptionGroupSet().getMembers() ))) )
             {
                 OrganisationUnit acceptOrgUnit = organisationUnit;
                 for ( int i = nextLevel.getOrgUnitLevel(); i < dataApprovalLevel.getOrgUnitLevel(); i++ )
@@ -626,7 +647,7 @@
                 User user = currentUserService.getCurrentUser();
 
                 if ( user.getOrganisationUnits().contains( acceptOrgUnit ) ||
-                        CollectionUtils.containsAny( user.getOrganisationUnits(), acceptOrgUnit.getAncestors() ) )
+                    CollectionUtils.containsAny( user.getOrganisationUnits(), acceptOrgUnit.getAncestors() ) )
                 {
                     return true;
                 }
@@ -639,7 +660,7 @@
     /**
      * Tests whether the user is authorized to unapprove for this organisation
      * unit.
-     * <p>
+     * <p/>
      * Whether the user actually may unapprove an existing approval depends
      * also on whether there are higher-level approvals that the user is
      * authorized to unapprove.
@@ -681,17 +702,17 @@
      * an operation that the UI would not normally offer.
      *
      * @param dataApproval the data approval object for the attempted operation.
-     * @param operation the name of the operation attempted.
-     * @param mayOperate whether the user may perform this operation.
+     * @param operation    the name of the operation attempted.
+     * @param mayOperate   whether the user may perform this operation.
      */
     private void warnNotPermitted( DataApproval dataApproval, String operation, boolean mayOperate )
     {
         String warning = "User " + currentUserService.getCurrentUsername() + " tried to " + operation
-                + " data for (org unit " + dataApproval.getOrganisationUnit().getName()
-                + ", period " + dataApproval.getPeriod().getName()
-                + ", data set " + dataApproval.getDataSet().getName()
-                + ", COG " + ( dataApproval.getCategoryOptionGroup() == null ? "[null]" : dataApproval.getCategoryOptionGroup().getName() )
-                + ")";
+            + " data for (org unit " + dataApproval.getOrganisationUnit().getName()
+            + ", period " + dataApproval.getPeriod().getName()
+            + ", data set " + dataApproval.getDataSet().getName()
+            + ", COG " + (dataApproval.getCategoryOptionGroup() == null ? "[null]" : dataApproval.getCategoryOptionGroup().getName())
+            + ")";
 
         if ( dataApproval.getCategoryOptionGroup() != null && !securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
         {
@@ -700,7 +721,7 @@
 
         if ( !mayOperate )
         {
-            warning += " but couldn't " + operation  + " for " + dataApproval.getOrganisationUnit().getName();
+            warning += " but couldn't " + operation + " for " + dataApproval.getOrganisationUnit().getName();
         }
 
         log.warn( warning + "." );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultCompleteDataSetRegistrationService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultCompleteDataSetRegistrationService.java	2014-07-09 07:19:02 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataset/DefaultCompleteDataSetRegistrationService.java	2014-08-14 05:46:19 +0000
@@ -124,7 +124,8 @@
     public CompleteDataSetRegistration getCompleteDataSetRegistration( DataSet dataSet, Period period,
         OrganisationUnit source, DataElementCategoryOptionCombo attributeOptionCombo )
     {
-        return completeDataSetRegistrationStore.getCompleteDataSetRegistration( dataSet, period, source, attributeOptionCombo );
+        return completeDataSetRegistrationStore
+            .getCompleteDataSetRegistration( dataSet, period, source, attributeOptionCombo );
     }
 
     public Collection<CompleteDataSetRegistration> getAllCompleteDataSetRegistrations()

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java	2014-08-03 22:03:34 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java	2014-08-14 05:46:19 +0000
@@ -40,13 +40,7 @@
 
 import org.hisp.dhis.DhisSpringTest;
 import org.hisp.dhis.common.IdentifiableObjectManager;
-import org.hisp.dhis.dataelement.CategoryOptionGroup;
-import org.hisp.dhis.dataelement.CategoryOptionGroupSet;
-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.*;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.DataSetService;
 import org.hisp.dhis.mock.MockCurrentUserService;
@@ -60,6 +54,7 @@
 import org.hisp.dhis.user.UserService;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import static com.google.common.collect.Lists.newArrayList;
 
 /**
  * @author Jim Grace
@@ -407,7 +402,7 @@
     // -------------------------------------------------------------------------
 
     @Test
-    public void testAddAndGetDataApproval() throws Exception
+    public void testAddAllAndGetDataApproval() throws Exception
     {
         dataApprovalLevelService.addDataApprovalLevel( level1, 1 );
         dataApprovalLevelService.addDataApprovalLevel( level2, 2 );
@@ -425,10 +420,7 @@
         DataApproval dataApprovalC = new DataApproval( level1, dataSetA, periodB, organisationUnitA, NO_GROUP, NOT_ACCEPTED, date, userA );
         DataApproval dataApprovalD = new DataApproval( level1, dataSetB, periodA, organisationUnitA, NO_GROUP, NOT_ACCEPTED, date, userA );
 
-        dataApprovalService.addDataApproval( dataApprovalA );
-        dataApprovalService.addDataApproval( dataApprovalB );
-        dataApprovalService.addDataApproval( dataApprovalC );
-        dataApprovalService.addDataApproval( dataApprovalD );
+        dataApprovalService.addAllDataApprovals( newArrayList(dataApprovalA, dataApprovalB, dataApprovalC, dataApprovalD) );
 
         dataSetA.setApproveData( true );
         dataSetB.setApproveData( true );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationServiceTest.java	2014-06-23 21:31:31 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationServiceTest.java	2014-08-14 05:46:19 +0000
@@ -28,15 +28,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
 import org.hisp.dhis.DhisSpringTest;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
@@ -47,6 +38,12 @@
 import org.hisp.dhis.period.PeriodService;
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import static org.junit.Assert.*;
+
 /**
  * @author Lars Helge Overland
  * @version $Id$
@@ -55,78 +52,114 @@
     extends DhisSpringTest
 {
     private CompleteDataSetRegistration registrationA;
+
     private CompleteDataSetRegistration registrationB;
+
     private CompleteDataSetRegistration registrationC;
+
     private CompleteDataSetRegistration registrationD;
+
     private CompleteDataSetRegistration registrationE;
+
     private CompleteDataSetRegistration registrationF;
+
     private CompleteDataSetRegistration registrationG;
+
     private CompleteDataSetRegistration registrationH;
-    
+
+    private CompleteDataSetRegistration registrationI;
+
+    private CompleteDataSetRegistration registrationJ;
+
+    private CompleteDataSetRegistration registrationK;
+
+    private CompleteDataSetRegistration registrationL;
+
     private DataSet dataSetA;
+
     private DataSet dataSetB;
+
     private DataSet dataSetC;
-    
+
     private Period periodA;
+
     private Period periodB;
-    
+
     private OrganisationUnit sourceA;
+
     private OrganisationUnit sourceB;
+
     private OrganisationUnit sourceC;
 
     private Date onTimeA;
-    
+
+    private Date onTimeB;
+
+    private Date deadlineA;
+
+    private Date deadlineB;
+
+    private Date tooLateA;
+
+    private Date tooLateB;
+
     private DataElementCategoryOptionCombo optionCombo;
 
     // -------------------------------------------------------------------------
     // Fixture
     // -------------------------------------------------------------------------
-    
+
     @Override
     public void setUpTest()
     {
-        completeDataSetRegistrationService = (CompleteDataSetRegistrationService) getBean( CompleteDataSetRegistrationService.ID );
-        
+        completeDataSetRegistrationService = (CompleteDataSetRegistrationService) getBean(
+            CompleteDataSetRegistrationService.ID );
+
         dataSetService = (DataSetService) getBean( DataSetService.ID );
-        
+
         periodService = (PeriodService) getBean( PeriodService.ID );
 
         organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
-        
+
         categoryService = (DataElementCategoryService) getBean( DataElementCategoryService.ID );
-        
+
         sourceA = createOrganisationUnit( 'A' );
         sourceB = createOrganisationUnit( 'B' );
         sourceC = createOrganisationUnit( 'C' );
-        
+
         organisationUnitService.addOrganisationUnit( sourceA );
-        organisationUnitService.addOrganisationUnit( sourceB ); 
-        organisationUnitService.addOrganisationUnit( sourceC );    
-        
+        organisationUnitService.addOrganisationUnit( sourceB );
+        organisationUnitService.addOrganisationUnit( sourceC );
+
         periodA = createPeriod( new MonthlyPeriodType(), getDate( 2000, 1, 1 ), getDate( 2000, 1, 31 ) );
         periodB = createPeriod( new MonthlyPeriodType(), getDate( 2000, 2, 1 ), getDate( 2000, 2, 28 ) );
-        
+
         periodService.addPeriod( periodA );
-        periodService.addPeriod( periodB );  
+        periodService.addPeriod( periodB );
 
         dataSetA = createDataSet( 'A', new MonthlyPeriodType() );
         dataSetB = createDataSet( 'B', new MonthlyPeriodType() );
         dataSetC = createDataSet( 'C', new MonthlyPeriodType() );
-        
+
         dataSetA.getSources().add( sourceA );
         dataSetA.getSources().add( sourceB );
         dataSetB.getSources().add( sourceA );
         dataSetB.getSources().add( sourceB );
         dataSetC.getSources().add( sourceA );
-        dataSetC.getSources().add( sourceB );        
-        
+        dataSetC.getSources().add( sourceB );
+
         dataSetService.addDataSet( dataSetA );
         dataSetService.addDataSet( dataSetB );
         dataSetService.addDataSet( dataSetC );
-        
+
         optionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
 
         onTimeA = getDate( 2000, 1, 10 );
+        onTimeB = getDate( 2000, 2, 10 );
+        deadlineA = getDate( 2000, 1, 15 );
+        deadlineB = getDate( 2000, 2, 15 );
+        tooLateA = getDate( 2000, 1, 25 );
+        tooLateB = getDate( 2000, 2, 25 );
     }
 
     // -------------------------------------------------------------------------
@@ -136,50 +169,65 @@
     @Test
     public void testSaveGet()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), ""
+        );
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), ""
+        );
+
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationA );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationB );
-        
-        assertEquals( registrationA, completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
-        assertEquals( registrationB, completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
+
+        assertEquals( registrationA, completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
+        assertEquals( registrationB, completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
     }
 
     @Test
     public void testDelete()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), ""
+        );
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), ""
+        );
+
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationA );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationB );
-        
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
+
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
 
         completeDataSetRegistrationService.deleteCompleteDataSetRegistration( registrationA );
-        
-        assertNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
+
+        assertNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
 
         completeDataSetRegistrationService.deleteCompleteDataSetRegistration( registrationB );
-        
-        assertNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
-        assertNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );        
+
+        assertNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
+        assertNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
     }
 
     @Test
     public void testGetAll()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), ""
+        );
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), ""
+        );
+
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationA );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationB );
-        
-        Collection<CompleteDataSetRegistration> registrations = completeDataSetRegistrationService.getAllCompleteDataSetRegistrations();
-        
+
+        Collection<CompleteDataSetRegistration> registrations = completeDataSetRegistrationService
+            .getAllCompleteDataSetRegistrations();
+
         assertEquals( 2, registrations.size() );
         assertTrue( registrations.contains( registrationA ) );
         assertTrue( registrations.contains( registrationB ) );
@@ -188,15 +236,23 @@
     @Test
     public void testGetDataSetsSourcesPeriods()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, new Date(), "" );
-        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, new Date(), "" );
-        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, new Date(), "" );
-        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, new Date(), "" );
-        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), ""
+        );
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, new Date(), ""
+        );
+        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, new Date(), ""
+        );
+        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), ""
+        );
+        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, new Date(), ""
+        );
+        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, new Date(), ""
+        );
+        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, new Date(), ""
+        );
+        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, new Date(), ""
+        );
+
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationA );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationB );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationC );
@@ -205,52 +261,64 @@
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationF );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationG );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationH );
-        
+
         Collection<DataSet> dataSets = new ArrayList<DataSet>();
-        
+
         dataSets.add( dataSetB );
-        
+
         Collection<OrganisationUnit> sources = new ArrayList<OrganisationUnit>();
 
         sources.add( sourceA );
         sources.add( sourceB );
-        
+
         Collection<Period> periods = new ArrayList<Period>();
-        
+
         periods.add( periodA );
-        
+
         Collection<CompleteDataSetRegistration> registrations = completeDataSetRegistrationService.
             getCompleteDataSetRegistrations( dataSets, sources, periods );
-        
+
         assertNotNull( registrations );
         assertEquals( 2, registrations.size() );
         assertTrue( registrations.contains( registrationB ) );
-        assertTrue( registrations.contains( registrationF ) );        
+        assertTrue( registrations.contains( registrationF ) );
     }
 
     @Test
     public void testDeleteByDataSet()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, onTimeA, "" );
-        registrationB = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, onTimeA, "" );
-        registrationC = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, onTimeA, "" );
-        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, onTimeA, "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, onTimeA, ""
+        );
+        registrationB = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, onTimeA, ""
+        );
+        registrationC = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, onTimeA, ""
+        );
+        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, onTimeA, ""
+        );
+
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationA );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationB );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationC );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationD );
-        
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
-        
+
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
+
         completeDataSetRegistrationService.deleteCompleteDataSetRegistrations( dataSetA );
 
-        assertNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
-        assertNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );   
+        assertNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo ) );
+        assertNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo ) );
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationStoreTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationStoreTest.java	2014-06-23 21:31:31 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataset/CompleteDataSetRegistrationStoreTest.java	2014-08-14 05:46:19 +0000
@@ -28,15 +28,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
 import org.hisp.dhis.DhisSpringTest;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
@@ -47,6 +38,12 @@
 import org.hisp.dhis.period.PeriodService;
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import static org.junit.Assert.*;
+
 /**
  * @author Lars Helge Overland
  * @version $Id$
@@ -133,9 +130,9 @@
     @Test
     public void testSaveGet()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "");
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "");
+
         registrationStore.saveCompleteDataSetRegistration( registrationA );
         registrationStore.saveCompleteDataSetRegistration( registrationB );
         
@@ -146,9 +143,9 @@
     @Test
     public void testDelete()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "");
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "");
+
         registrationStore.saveCompleteDataSetRegistration( registrationA );
         registrationStore.saveCompleteDataSetRegistration( registrationB );
         
@@ -169,9 +166,9 @@
     @Test
     public void testGetAll()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "");
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "");
+
         registrationStore.saveCompleteDataSetRegistration( registrationA );
         registrationStore.saveCompleteDataSetRegistration( registrationB );
         
@@ -185,15 +182,15 @@
     @Test
     public void testGetDataSetsSourcesPeriods()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, new Date(), "" );
-        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, new Date(), "" );
-        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, new Date(), "" );
-        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, new Date(), "" );
-        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "");
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, new Date(), "");
+        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, new Date(), "");
+        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "");
+        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, new Date(), "");
+        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, new Date(), "");
+        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, new Date(), "");
+        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, new Date(), "");
+
         registrationStore.saveCompleteDataSetRegistration( registrationA );
         registrationStore.saveCompleteDataSetRegistration( registrationB );
         registrationStore.saveCompleteDataSetRegistration( registrationC );
@@ -228,15 +225,15 @@
     @Test
     public void testGetDataSetSourcesPeriod()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, new Date(), "" );
-        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, new Date(), "" );
-        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "" );
-        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, new Date(), "" );
-        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, new Date(), "" );
-        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, new Date(), "" );
-        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, new Date(), "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, new Date(), "");
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, new Date(), "");
+        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, new Date(), "");
+        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, new Date(), "");
+        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, new Date(), "");
+        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, new Date(), "");
+        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, new Date(), "");
+        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, new Date(), "");
+
         registrationStore.saveCompleteDataSetRegistration( registrationA );
         registrationStore.saveCompleteDataSetRegistration( registrationB );
         registrationStore.saveCompleteDataSetRegistration( registrationC );
@@ -263,15 +260,15 @@
     @Test
     public void testGetDataSetSourcesPeriodDate()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, onTimeA, "" );
-        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, tooLateA, "" );
-        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, onTimeB, "" );
-        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, tooLateB, "" );
-        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, tooLateA, "" );
-        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, onTimeA, "" );
-        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, tooLateB, "" );
-        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, onTimeB, "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, onTimeA, "");
+        registrationB = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, tooLateA, "");
+        registrationC = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, onTimeB, "");
+        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, tooLateB, "");
+        registrationE = new CompleteDataSetRegistration( dataSetA, periodA, sourceB, optionCombo, tooLateA, "");
+        registrationF = new CompleteDataSetRegistration( dataSetB, periodA, sourceB, optionCombo, onTimeA, "");
+        registrationG = new CompleteDataSetRegistration( dataSetA, periodB, sourceB, optionCombo, tooLateB, "");
+        registrationH = new CompleteDataSetRegistration( dataSetB, periodB, sourceB, optionCombo, onTimeB, "");
+
         registrationStore.saveCompleteDataSetRegistration( registrationA );
         registrationStore.saveCompleteDataSetRegistration( registrationB );
         registrationStore.saveCompleteDataSetRegistration( registrationC );
@@ -297,11 +294,11 @@
     @Test
     public void testDeleteByDataSet()
     {
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, onTimeA, "" );
-        registrationB = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, onTimeA, "" );
-        registrationC = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, onTimeA, "" );
-        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, onTimeA, "" );
-        
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, sourceA, optionCombo, onTimeA, "");
+        registrationB = new CompleteDataSetRegistration( dataSetA, periodB, sourceA, optionCombo, onTimeA, "");
+        registrationC = new CompleteDataSetRegistration( dataSetB, periodA, sourceA, optionCombo, onTimeA, "");
+        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, sourceA, optionCombo, onTimeA, "");
+
         registrationStore.saveCompleteDataSetRegistration( registrationA );
         registrationStore.saveCompleteDataSetRegistration( registrationB );
         registrationStore.saveCompleteDataSetRegistration( registrationC );

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingJsonDataValue.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingJsonDataValue.java	2014-07-22 16:44:27 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingJsonDataValue.java	2014-08-14 05:46:19 +0000
@@ -30,8 +30,6 @@
 
 import com.fasterxml.jackson.core.JsonGenerator;
 
-import org.hisp.dhis.dxf2.datavalue.DataValue;
-
 import java.io.IOException;
 
 /**
@@ -84,7 +82,7 @@
     {
         writeObjectField( "attributeOptionCombo", attributeOptionCombo );
     }
-    
+
     @Override
     public void setValue( String value )
     {

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java	2014-07-10 16:06:48 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java	2014-08-14 05:46:19 +0000
@@ -28,29 +28,27 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+
 import java.io.OutputStream;
 import java.io.Writer;
 import java.util.Date;
 import java.util.Set;
 
-import org.hisp.dhis.dataelement.DataElement;
-import org.hisp.dhis.dataset.DataSet;
-import org.hisp.dhis.organisationunit.OrganisationUnit;
-import org.hisp.dhis.period.Period;
-
 /**
  * @author Lars Helge Overland
  */
 public interface DataValueSetStore
 {
-    public void writeDataValueSetXml( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
-        Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out );
-
-    public void writeDataValueSetCsv( Set<DataElement> dataElements, Set<Period> periods, 
-        Set<OrganisationUnit> orgUnits, Writer writer );
-    
+    public void writeDataValueSetXml(Set<DataSet> dataSets, Date completeDate, Period period, OrganisationUnit orgUnit,
+                                     Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out);
+
+    public void writeDataValueSetCsv(Set<Period> periods, Set<OrganisationUnit> orgUnits, Writer writer);
+
+    public void writeDataValueSetJson(Set<DataSet> dataSets, Date completeDate, Period period, OrganisationUnit orgUnit,
+                                      Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out);
+
     void writeDataValueSetJson( Date lastUpdated, OutputStream outputStream );
-
-    public void writeDataValueSetJson( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit,
-        Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out );
 }

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java	2014-07-22 16:44:27 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java	2014-08-14 05:46:19 +0000
@@ -84,6 +84,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import static com.google.common.collect.Sets.newHashSet;
 import static org.apache.commons.lang.StringUtils.trimToNull;
 import static org.hisp.dhis.common.IdentifiableObject.IdentifiableProperty.UUID;
 import static org.hisp.dhis.system.notification.NotificationLevel.ERROR;
@@ -101,9 +102,13 @@
     private static final Log log = LogFactory.getLog( DefaultDataValueSetService.class );
 
     private static final String ERROR_INVALID_DATA_SET = "Invalid data set: ";
+
     private static final String ERROR_INVALID_PERIOD = "Invalid period: ";
+
     private static final String ERROR_INVALID_ORG_UNIT = "Invalid org unit: ";
+
     private static final String ERROR_INVALID_START_END_DATE = "Invalid start and/or end date: ";
+
     private static final String ERROR_OBJECT_NEEDED_TO_COMPLETE = "Must be provided to complete data set";
 
     @Autowired
@@ -163,14 +168,31 @@
         }
 
         DataElementCategoryOptionCombo optionCombo = categoryService.getDefaultDataElementCategoryOptionCombo(); //TODO
-        
-        CompleteDataSetRegistration registration = registrationService.getCompleteDataSetRegistration( dataSet_, period_, orgUnit_, optionCombo );
+
+        CompleteDataSetRegistration registration = registrationService
+            .getCompleteDataSetRegistration( dataSet_, period_, orgUnit_, optionCombo );
 
         Date completeDate = registration != null ? registration.getDate() : null;
 
         period_ = periodService.reloadPeriod( period_ );
 
-        dataValueSetStore.writeDataValueSetXml( dataSet_, completeDate, period_, orgUnit_, dataSet_.getDataElements(), wrap( period_ ), wrap( orgUnit_ ), out );
+        dataValueSetStore.writeDataValueSetXml( newHashSet( dataSet_ ), completeDate, period_, orgUnit_, wrap( period_ ),
+            wrap( orgUnit_ ), out );
+    }
+
+    @Override
+    public void writeDataValueSet( Set<String> dataSetUids, Date startDate, Date endDate, Set<String> orgUnits,
+        OutputStream out )
+    {
+        Set<Period> periods = new HashSet<>( periodService.getPeriodsBetweenDates( startDate, endDate ) );
+        List<DataSet> dataSets = dataSetService.getDataSetsByUid( dataSetUids );
+
+        if ( periods.isEmpty() )
+        {
+            throw new IllegalArgumentException( "At least one period must be specified" );
+        }
+
+        dataValueSetStore.writeDataValueSetXml( newHashSet( dataSets ), null, null, null, periods, getOrgUnits( orgUnits ), out );
     }
 
     @Override
@@ -196,28 +218,18 @@
         }
 
         DataElementCategoryOptionCombo optionCombo = categoryService.getDefaultDataElementCategoryOptionCombo(); //TODO
-        
-        CompleteDataSetRegistration registration = registrationService.getCompleteDataSetRegistration( dataSet_, period_, orgUnit_, optionCombo );
+
+        CompleteDataSetRegistration registration = registrationService
+            .getCompleteDataSetRegistration( dataSet_, period_, orgUnit_, optionCombo );
 
         Date completeDate = registration != null ? registration.getDate() : null;
 
         period_ = periodService.reloadPeriod( period_ );
 
-        dataValueSetStore.writeDataValueSetJson( dataSet_, completeDate, period_, orgUnit_, dataSet_.getDataElements(), wrap( period_ ), wrap( orgUnit_ ), outputStream );
-    }
-
-    @Override
-    public void writeDataValueSet( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits, OutputStream out )
-    {
-        dataValueSetStore.writeDataValueSetXml( null, null, null, null, getDataElements( dataSets ), getPeriods( startDate, endDate ), getOrgUnits( orgUnits ), out );
-    }
-
-    @Override
-    public void writeDataValueSetJson( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits, OutputStream outputStream )
-    {
-        dataValueSetStore.writeDataValueSetJson( null, null, null, null, getDataElements( dataSets ), getPeriods( startDate, endDate ), getOrgUnits( orgUnits ), outputStream );
-    }
-    
+        dataValueSetStore.writeDataValueSetJson( newHashSet( dataSet_ ), completeDate, period_, orgUnit_, wrap( period_ ),
+            wrap( orgUnit_ ), outputStream );
+    }
+
     @Override
     public void writeDataValueSetJson( Date lastUpdated, OutputStream outputStream )
     {
@@ -225,11 +237,35 @@
     }
 
     @Override
-    public void writeDataValueSetCsv( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits, Writer writer )
-    {
-        dataValueSetStore.writeDataValueSetCsv( getDataElements( dataSets ), getPeriods( startDate, endDate ), getOrgUnits( orgUnits ), writer );
-    }
-    
+    public void writeDataValueSetJson( Set<String> dataSetUids, Date startDate, Date endDate, Set<String> orgUnits,
+        OutputStream outputStream )
+    {
+        Set<Period> periods = new HashSet<>( periodService.getPeriodsBetweenDates( startDate, endDate ) );
+        List<DataSet> dataSets = dataSetService.getDataSetsByUid( dataSetUids );
+
+        if ( periods.isEmpty() )
+        {
+            throw new IllegalArgumentException( "At least one period must be specified" );
+        }
+
+        dataValueSetStore.writeDataValueSetJson( newHashSet( dataSets ), null, null, null, periods, getOrgUnits( orgUnits ),
+            outputStream );
+    }
+
+    @Override
+    public void writeDataValueSetCsv( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits,
+        Writer writer )
+    {
+        Set<Period> periods = new HashSet<Period>( periodService.getPeriodsBetweenDates( startDate, endDate ) );
+
+        if ( periods.isEmpty() )
+        {
+            throw new IllegalArgumentException( "At least one period must be specified" );
+        }
+
+        dataValueSetStore.writeDataValueSetCsv( periods, getOrgUnits( orgUnits ), writer );
+    }
+
     @Override
     public RootNode getDataValueSetTemplate( DataSet dataSet, Period period, List<String> orgUnits,
         boolean writeComments, String ouScheme, String deScheme )
@@ -245,7 +281,8 @@
         {
             for ( DataElement dataElement : dataSet.getDataElements() )
             {
-                CollectionNode collection = getDataValueTemplate( dataElement, deScheme, null, ouScheme, period, writeComments );
+                CollectionNode collection = getDataValueTemplate( dataElement, deScheme, null, ouScheme, period,
+                    writeComments );
                 collectionNode.addChildren( collection.getChildren() );
             }
         }
@@ -262,7 +299,8 @@
 
                 for ( DataElement dataElement : dataSet.getDataElements() )
                 {
-                    CollectionNode collection = getDataValueTemplate( dataElement, deScheme, organisationUnit, ouScheme, period, writeComments );
+                    CollectionNode collection = getDataValueTemplate( dataElement, deScheme, organisationUnit, ouScheme,
+                        period, writeComments );
                     collectionNode.addChildren( collection.getChildren() );
                 }
             }
@@ -271,7 +309,8 @@
         return rootNode;
     }
 
-    private CollectionNode getDataValueTemplate( DataElement dataElement, String deScheme, OrganisationUnit organisationUnit, String ouScheme, Period period, boolean comment )
+    private CollectionNode getDataValueTemplate( DataElement dataElement, String deScheme,
+        OrganisationUnit organisationUnit, String ouScheme, Period period, boolean comment )
     {
         CollectionNode collectionNode = new CollectionNode( "dataValues" );
         collectionNode.setWrapping( false );
@@ -292,7 +331,8 @@
                 complexNode.setComment( "Data element: " + label );
             }
 
-            if ( IdentifiableObject.IdentifiableProperty.CODE.toString().toLowerCase().equals( deScheme.toLowerCase() ) )
+            if ( IdentifiableObject.IdentifiableProperty.CODE.toString().toLowerCase()
+                .equals( deScheme.toLowerCase() ) )
             {
                 SimpleNode simpleNode = complexNode.addChild( new SimpleNode( "dataElement", dataElement.getCode() ) );
                 simpleNode.setAttribute( true );
@@ -313,12 +353,14 @@
             {
                 if ( IdentifiableObject.IdentifiableProperty.CODE.toString().toLowerCase().equals( ouScheme.toLowerCase() ) )
                 {
-                    simpleNode = complexNode.addChild( new SimpleNode( "orgUnit", organisationUnit.getCode() == null ? "" : organisationUnit.getCode() ) );
+                    simpleNode = complexNode.addChild( new SimpleNode( "orgUnit",
+                        organisationUnit.getCode() == null ? "" : organisationUnit.getCode() ) );
                     simpleNode.setAttribute( true );
                 }
                 else
                 {
-                    simpleNode = complexNode.addChild( new SimpleNode( "orgUnit", organisationUnit.getUid() == null ? "" : organisationUnit.getUid() ) );
+                    simpleNode = complexNode.addChild( new SimpleNode( "orgUnit",
+                        organisationUnit.getUid() == null ? "" : organisationUnit.getUid() ) );
                     simpleNode.setAttribute( true );
                 }
             }
@@ -400,7 +442,6 @@
         try
         {
             DataValueSet dataValueSet = PdfDataEntryFormUtil.getDataValueSet( in );
-
             return saveDataValueSet( importOptions, id, dataValueSet );
         }
         catch ( RuntimeException ex )
@@ -420,51 +461,54 @@
 
         importOptions = importOptions != null ? importOptions : ImportOptions.getDefaultImportOptions();
 
-        // ---------------------------------------------------------------------
-        // Options
-        // ---------------------------------------------------------------------
-
-        IdentifiableProperty dataElementIdScheme = dataValueSet.getDataElementIdScheme() != null ? IdentifiableProperty.valueOf( dataValueSet.getDataElementIdScheme().toUpperCase() ) : importOptions.getDataElementIdScheme();
-        IdentifiableProperty orgUnitIdScheme = dataValueSet.getOrgUnitIdScheme() != null ? IdentifiableProperty.valueOf( dataValueSet.getOrgUnitIdScheme().toUpperCase() ) : importOptions.getOrgUnitIdScheme();
+        IdentifiableProperty dataElementIdScheme = dataValueSet.getDataElementIdScheme() != null ?
+            IdentifiableProperty.valueOf( dataValueSet.getDataElementIdScheme().toUpperCase() ) :
+            importOptions.getDataElementIdScheme();
+        IdentifiableProperty orgUnitIdScheme = dataValueSet.getOrgUnitIdScheme() != null ?
+            IdentifiableProperty.valueOf( dataValueSet.getOrgUnitIdScheme().toUpperCase() ) :
+            importOptions.getOrgUnitIdScheme();
         boolean dryRun = dataValueSet.getDryRun() != null ? dataValueSet.getDryRun() : importOptions.isDryRun();
-        ImportStrategy strategy = dataValueSet.getStrategy() != null ? ImportStrategy.valueOf( dataValueSet.getStrategy() ) : importOptions.getImportStrategy();
+        ImportStrategy strategy = dataValueSet.getStrategy() != null ?
+            ImportStrategy.valueOf( dataValueSet.getStrategy() ) :
+            importOptions.getImportStrategy();
         boolean skipExistingCheck = importOptions.isSkipExistingCheck();
 
-        // ---------------------------------------------------------------------
-        // Object maps
-        // ---------------------------------------------------------------------
-
         Map<String, DataElement> dataElementMap = identifiableObjectManager.getIdMap( DataElement.class, dataElementIdScheme );
-        Map<String, OrganisationUnit> orgUnitMap = orgUnitIdScheme == UUID ? getUuidOrgUnitMap() : identifiableObjectManager.getIdMap( OrganisationUnit.class, orgUnitIdScheme );
-        Map<String, DataElementCategoryOptionCombo> categoryOptionComboMap = identifiableObjectManager.getIdMap( DataElementCategoryOptionCombo.class, IdentifiableProperty.UID );
+        Map<String, OrganisationUnit> orgUnitMap = orgUnitIdScheme == UUID ?
+            getUuidOrgUnitMap() :
+            identifiableObjectManager.getIdMap( OrganisationUnit.class, orgUnitIdScheme );
+        Map<String, DataElementCategoryOptionCombo> categoryOptionComboMap = identifiableObjectManager
+            .getIdMap( DataElementCategoryOptionCombo.class, IdentifiableProperty.UID );
         Map<String, Period> periodMap = new HashMap<String, Period>();
 
-        // ---------------------------------------------------------------------
-        // Data value set
-        // ---------------------------------------------------------------------
-
-        DataElementCategoryOptionCombo fallbackCategoryOptionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
-
-        DataSet dataSet = dataValueSet.getDataSet() != null ? identifiableObjectManager.getObject( DataSet.class, IdentifiableProperty.UID, dataValueSet.getDataSet() ) : null;
-        
+        DataSet dataSet = dataValueSet.getDataSet() != null ?
+            identifiableObjectManager.getObject( DataSet.class, IdentifiableProperty.UID, dataValueSet.getDataSet() ) :
+            null;
         Date completeDate = getDefaultDate( dataValueSet.getCompleteDate() );
-        
+
         Period outerPeriod = PeriodType.getPeriodFromIsoString( trimToNull( dataValueSet.getPeriod() ) );
 
         OrganisationUnit outerOrgUnit;
 
+        DataElementCategoryOptionCombo fallbackCategoryOptionCombo = categoryService
+            .getDefaultDataElementCategoryOptionCombo();
+
         if ( orgUnitIdScheme.equals( IdentifiableProperty.UUID ) )
         {
-            outerOrgUnit = dataValueSet.getOrgUnit() == null ? null : organisationUnitService.getOrganisationUnitByUuid( trimToNull( dataValueSet.getOrgUnit() ) );
+            outerOrgUnit = dataValueSet.getOrgUnit() == null ?
+                null :
+                organisationUnitService.getOrganisationUnitByUuid( dataValueSet.getOrgUnit() );
         }
         else
         {
-            outerOrgUnit = dataValueSet.getOrgUnit() != null ? identifiableObjectManager.getObject( OrganisationUnit.class, orgUnitIdScheme, trimToNull( dataValueSet.getOrgUnit() ) ) : null;
+            outerOrgUnit = dataValueSet.getOrgUnit() != null ?
+                identifiableObjectManager.getObject( OrganisationUnit.class, orgUnitIdScheme, dataValueSet.getOrgUnit() ) : null;
         }
 
-        DataElementCategoryOptionCombo outerAttrOptionCombo = dataValueSet.getAttributeOptionCombo() != null ? 
-            identifiableObjectManager.getObject( DataElementCategoryOptionCombo.class, IdentifiableProperty.UID, trimToNull( dataValueSet.getAttributeOptionCombo() ) ) : null;
-        
+        DataElementCategoryOptionCombo outerAttrOptionCombo = dataValueSet.getAttributeOptionCombo() != null ?
+            identifiableObjectManager.getObject( DataElementCategoryOptionCombo.class, IdentifiableProperty.UID,
+                trimToNull( dataValueSet.getAttributeOptionCombo() ) ) : null;
+
         if ( dataSet != null && completeDate != null )
         {
             notifier.notify( id, "Completing data set" );
@@ -474,10 +518,11 @@
         {
             summary.setDataSetComplete( Boolean.FALSE.toString() );
         }
-        
+
         String currentUser = currentUserService.getCurrentUsername();
 
-        BatchHandler<DataValue> batchHandler = batchHandlerFactory.createBatchHandler( DataValueBatchHandler.class ).init();
+        BatchHandler<DataValue> batchHandler = batchHandlerFactory.createBatchHandler( DataValueBatchHandler.class )
+            .init();
 
         int importCount = 0;
         int updateCount = 0;
@@ -499,14 +544,21 @@
             totalCount++;
 
             DataElement dataElement = dataElementMap.get( trimToNull( dataValue.getDataElement() ) );
-            Period period = outerPeriod != null ? outerPeriod : PeriodType.getPeriodFromIsoString( trimToNull( dataValue.getPeriod() ) );
-            OrganisationUnit orgUnit = outerOrgUnit != null ? outerOrgUnit : orgUnitMap.get( trimToNull( dataValue.getOrgUnit() ) );
-            DataElementCategoryOptionCombo categoryOptionCombo = categoryOptionComboMap.get( trimToNull( dataValue.getCategoryOptionCombo() ) );
-            DataElementCategoryOptionCombo attrOptionCombo = outerAttrOptionCombo != null ? outerAttrOptionCombo : categoryOptionComboMap.get( trimToNull( dataValue.getAttributeOptionCombo() ) );
+            DataElementCategoryOptionCombo categoryOptionCombo = categoryOptionComboMap
+                .get( trimToNull( dataValue.getCategoryOptionCombo() ) );
+            Period period = outerPeriod != null ?
+                outerPeriod :
+                PeriodType.getPeriodFromIsoString( trimToNull( dataValue.getPeriod() ) );
+            OrganisationUnit orgUnit =
+                outerOrgUnit != null ? outerOrgUnit : orgUnitMap.get( trimToNull( dataValue.getOrgUnit() ) );
+            DataElementCategoryOptionCombo attrOptionCombo = outerAttrOptionCombo != null ?
+                outerAttrOptionCombo :
+                categoryOptionComboMap.get( trimToNull( dataValue.getAttributeOptionCombo() ) );
 
             if ( dataElement == null )
             {
-                summary.getConflicts().add( new ImportConflict( DataElement.class.getSimpleName(), dataValue.getDataElement() ) );
+                summary.getConflicts()
+                    .add( new ImportConflict( DataElement.class.getSimpleName(), dataValue.getDataElement() ) );
                 continue;
             }
 
@@ -518,7 +570,8 @@
 
             if ( orgUnit == null )
             {
-                summary.getConflicts().add( new ImportConflict( OrganisationUnit.class.getSimpleName(), dataValue.getOrgUnit() ) );
+                summary.getConflicts()
+                    .add( new ImportConflict( OrganisationUnit.class.getSimpleName(), dataValue.getOrgUnit() ) );
                 continue;
             }
 
@@ -526,7 +579,7 @@
             {
                 categoryOptionCombo = fallbackCategoryOptionCombo;
             }
-            
+
             if ( attrOptionCombo == null )
             {
                 attrOptionCombo = fallbackCategoryOptionCombo;
@@ -629,7 +682,7 @@
     // Supportive methods
     //--------------------------------------------------------------------------
 
-    private void handleComplete( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
+    private void handleComplete( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit,
         DataElementCategoryOptionCombo attributeOptionCombo, ImportSummary summary )
     {
         if ( orgUnit == null )
@@ -646,7 +699,8 @@
 
         period = periodService.reloadPeriod( period );
 
-        CompleteDataSetRegistration completeAlready = registrationService.getCompleteDataSetRegistration( dataSet, period, orgUnit, attributeOptionCombo );
+        CompleteDataSetRegistration completeAlready = registrationService
+            .getCompleteDataSetRegistration( dataSet, period, orgUnit, attributeOptionCombo );
 
         String username = currentUserService.getCurrentUsername();
 
@@ -659,7 +713,8 @@
         }
         else
         {
-            CompleteDataSetRegistration registration = new CompleteDataSetRegistration( dataSet, period, orgUnit, attributeOptionCombo, completeDate, username );
+            CompleteDataSetRegistration registration = new CompleteDataSetRegistration( dataSet, period, orgUnit,
+                attributeOptionCombo, completeDate, username );
 
             registrationService.saveCompleteDataSetRegistration( registration );
         }
@@ -692,14 +747,14 @@
         {
             throw new IllegalArgumentException( ERROR_INVALID_START_END_DATE + startDate + ", " + endDate );
         }
-        
+
         Set<Period> periods = new HashSet<Period>( periodService.getPeriodsBetweenDates( startDate, endDate ) );
 
         if ( periods.isEmpty() )
         {
             throw new IllegalArgumentException( "No periods exist for start/end date: " + startDate + ", " + endDate );
         }
-        
+
         return periods;
     }
 

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java	2014-07-22 16:44:27 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java	2014-08-14 05:46:19 +0000
@@ -28,18 +28,8 @@
  * 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.DateUtils.getMediumDateString;
-import static org.hisp.dhis.system.util.TextUtils.getCommaDelimitedString;
-
-import java.io.OutputStream;
-import java.io.Writer;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Set;
-
+import com.csvreader.CsvWriter;
 import org.amplecode.staxwax.factory.XMLFactory;
-import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dxf2.datavalue.DataValue;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
@@ -47,11 +37,22 @@
 import org.hisp.dhis.period.PeriodType;
 import org.hisp.dhis.system.util.DateUtils;
 import org.hisp.dhis.system.util.StreamUtils;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.support.rowset.SqlRowSet;
 
-import com.csvreader.CsvWriter;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+
+import static org.hisp.dhis.system.util.ConversionUtils.getIdentifiers;
+import static org.hisp.dhis.system.util.DateUtils.getMediumDateString;
+import static org.hisp.dhis.system.util.TextUtils.getCommaDelimitedString;
 
 /**
  * @author Lars Helge Overland
@@ -69,69 +70,67 @@
     //--------------------------------------------------------------------------
 
     @Override
-    public void writeDataValueSetXml( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit,
-        Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out )
+    public void writeDataValueSetXml( Set<DataSet> dataSets, Date completeDate, Period period, OrganisationUnit orgUnit,
+        Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out )
     {
         DataValueSet dataValueSet = new StreamingDataValueSet( XMLFactory.getXMLWriter( out ) );
-        
-        SqlRowSet rowSet = jdbcTemplate.queryForRowSet( getDataValueSql( dataElements, periods, orgUnits ) );
-        
-        writeDataValueSet( rowSet, dataSet, completeDate, period, orgUnit, dataValueSet );
+
+        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet( getDataValueSql( dataSets, periods, orgUnits ) );
+
+        writeDataValueSet( sqlRowSet, dataSets, completeDate, period, orgUnit, periods, orgUnits, dataValueSet );
 
         StreamUtils.closeOutputStream( out );
     }
 
     @Override
-    public void writeDataValueSetJson( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
-        Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream outputStream )
+    public void writeDataValueSetJson( Set<DataSet> dataSets, Date completeDate, Period period, OrganisationUnit orgUnit, Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream outputStream )
     {
         DataValueSet dataValueSet = new StreamingJsonDataValueSet( outputStream );
-        
-        SqlRowSet rowSet = jdbcTemplate.queryForRowSet( getDataValueSql( dataElements, periods, orgUnits ) );
-        
-        writeDataValueSet( rowSet, dataSet, completeDate, period, orgUnit, dataValueSet );
+
+        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet( getDataValueSql( dataSets, periods, orgUnits ) );
+
+        writeDataValueSet( sqlRowSet, dataSets, completeDate, period, orgUnit, periods, orgUnits, dataValueSet );
 
         StreamUtils.closeOutputStream( outputStream );
     }
 
     @Override
+    public void writeDataValueSetCsv( Set<Period> periods, Set<OrganisationUnit> orgUnits, Writer writer )
+    {
+        DataValueSet dataValueSet = new StreamingCsvDataValueSet( new CsvWriter( writer, CSV_DELIM ) );
+
+        SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet( getDataValueSql( null, periods, orgUnits ) );
+
+        writeDataValueSet( sqlRowSet, null, null, null, null, periods, orgUnits, dataValueSet );
+    }
+
+    @Override
     public void writeDataValueSetJson( Date lastUpdated, OutputStream outputStream )
     {
         DataValueSet dataValueSet = new StreamingJsonDataValueSet( outputStream );
-        
+
         final String sql =
             "select de.uid as deuid, pe.startdate, pt.name, ou.uid as ouuid, coc.uid as cocuid, aoc.uid as aocuid, dv.value, dv.storedby, dv.created, dv.lastupdated, dv.comment, dv.followup " +
-            "from datavalue dv " +
-            "join dataelement de on (dv.dataelementid=de.dataelementid) " +
-            "join period pe on (dv.periodid=pe.periodid) " +
-            "join periodtype pt on (pe.periodtypeid=pt.periodtypeid) " +
-            "join organisationunit ou on (dv.sourceid=ou.organisationunitid) " +
-            "join categoryoptioncombo coc on (dv.categoryoptioncomboid=coc.categoryoptioncomboid) " +
-            "join categoryoptioncombo aoc on (dv.attributeoptioncomboid=aoc.categoryoptioncomboid) " +
-            "where dv.lastupdated >= '" + DateUtils.getLongDateString( lastUpdated ) + "'";
-        
+                "from datavalue dv " +
+                "join dataelement de on (dv.dataelementid=de.dataelementid) " +
+                "join period pe on (dv.periodid=pe.periodid) " +
+                "join periodtype pt on (pe.periodtypeid=pt.periodtypeid) " +
+                "join organisationunit ou on (dv.sourceid=ou.organisationunitid) " +
+                "join categoryoptioncombo coc on (dv.categoryoptioncomboid=coc.categoryoptioncomboid) " +
+                "join categoryoptioncombo aoc on (dv.attributeoptioncomboid=aoc.categoryoptioncomboid) " +
+                "where dv.lastupdated >= '" + DateUtils.getLongDateString( lastUpdated ) + "'";
+
         SqlRowSet rowSet = jdbcTemplate.queryForRowSet( sql );
 
-        writeDataValueSet( rowSet, null, null, null, null, dataValueSet );
-    }
-    
-    @Override
-    public void writeDataValueSetCsv( Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, Writer writer )
-    {
-        DataValueSet dataValueSet = new StreamingCsvDataValueSet( new CsvWriter( writer, CSV_DELIM ) );
-        
-        SqlRowSet rowSet = jdbcTemplate.queryForRowSet( getDataValueSql( dataElements, periods, orgUnits ) );
-        
-        writeDataValueSet( rowSet, null, null, null, null, dataValueSet );
-    }
-    
-    //--------------------------------------------------------------------------
-    // Supportive methods
-    //--------------------------------------------------------------------------
-
-    private void writeDataValueSet( SqlRowSet rowSet, DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, DataValueSet dataValueSet )
-    {
-        dataValueSet.setDataSet( dataSet != null ? dataSet.getUid() : null );
+        writeDataValueSet( rowSet, null, null, null, null, null, null, dataValueSet );
+    }
+
+    private void writeDataValueSet( SqlRowSet rowSet, Set<DataSet> dataSets, Date completeDate, Period period,
+        OrganisationUnit orgUnit, Set<Period> periods, Set<OrganisationUnit> orgUnits, DataValueSet dataValueSet )
+    {
+        DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+
+        dataValueSet.setDataSet( dataSets.size() == 1 ? dataSets.iterator().next().getUid() : null );
         dataValueSet.setCompleteDate( getMediumDateString( completeDate ) );
         dataValueSet.setPeriod( period != null ? period.getIsoDate() : null );
         dataValueSet.setOrgUnit( orgUnit != null ? orgUnit.getUid() : null );
@@ -151,8 +150,14 @@
             dataValue.setAttributeOptionCombo( rowSet.getString( "aocuid" ) );
             dataValue.setValue( rowSet.getString( "value" ) );
             dataValue.setStoredBy( rowSet.getString( "storedby" ) );
-            dataValue.setCreated( DateUtils.getLongDateString( rowSet.getDate( "created" ) ) );
-            dataValue.setLastUpdated( DateUtils.getLongDateString( rowSet.getDate( "lastupdated" ) ) );
+            java.sql.Date lastUpdated = rowSet.getDate( "lastupdated" );
+
+            if ( lastUpdated != null )
+            {
+                DateTime dt = new DateTime( lastUpdated );
+                dataValue.setLastUpdated( fmt.print( dt ) );
+            }
+
             dataValue.setComment( rowSet.getString( "comment" ) );
             dataValue.setFollowup( rowSet.getBoolean( "followup" ) );
             dataValue.close();
@@ -161,19 +166,21 @@
         dataValueSet.close();
     }
 
-    private String getDataValueSql( Collection<DataElement> dataElements, Collection<Period> periods, Collection<OrganisationUnit> orgUnits )
+    private String getDataValueSql( Set<DataSet> dataSets, Collection<Period> periods, Collection<OrganisationUnit> orgUnits )
     {
         return
-            "select de.uid as deuid, pe.startdate, pt.name, ou.uid as ouuid, coc.uid as cocuid, aoc.uid as aocuid, dv.value, dv.storedby, dv.created, dv.lastupdated, dv.comment, dv.followup " +
-            "from datavalue dv " +
-            "join dataelement de on (dv.dataelementid=de.dataelementid) " +
-            "join period pe on (dv.periodid=pe.periodid) " +
-            "join periodtype pt on (pe.periodtypeid=pt.periodtypeid) " +
-            "join organisationunit ou on (dv.sourceid=ou.organisationunitid) " +
-            "join categoryoptioncombo coc on (dv.categoryoptioncomboid=coc.categoryoptioncomboid) " +
-            "join categoryoptioncombo aoc on (dv.attributeoptioncomboid=aoc.categoryoptioncomboid) " +
-            "where dv.dataelementid in (" + getCommaDelimitedString( getIdentifiers( DataElement.class, dataElements ) ) + ") " +
-            "and dv.periodid in (" + getCommaDelimitedString( getIdentifiers( Period.class, periods ) ) + ") " +
-            "and dv.sourceid in (" + getCommaDelimitedString( getIdentifiers( OrganisationUnit.class, orgUnits ) ) + ")";
+            "select ds.name as dataSetName, ds.uid as dataSetId, de.uid as deuid, pe.startdate, pt.name, ou.uid as ouuid, coc.uid as cocuid, aoc.uid as aocuid, dv.value, dv.storedby, dv.lastupdated, dv.comment, dv.followup " +
+                "from datavalue dv " +
+                "join dataelement de on (dv.dataelementid=de.dataelementid) " +
+                "join period pe on (dv.periodid=pe.periodid) " +
+                "join periodtype pt on (pe.periodtypeid=pt.periodtypeid) " +
+                "join organisationunit ou on (dv.sourceid=ou.organisationunitid) " +
+                "join categoryoptioncombo coc on (dv.categoryoptioncomboid=coc.categoryoptioncomboid) " +
+                "join categoryoptioncombo aoc on (dv.attributeoptioncomboid=aoc.categoryoptioncomboid) " +
+                "join datasetmembers dsm on (dsm.dataelementid=de.dataelementid) " +
+                "join dataset ds on (ds.datasetid=dsm.datasetid) " +
+                "where ds.datasetid in (" + getCommaDelimitedString( getIdentifiers( DataSet.class, dataSets ) ) + ") " +
+                "and dv.periodid in (" + getCommaDelimitedString( getIdentifiers( Period.class, periods ) ) + ") " +
+                "and dv.sourceid in (" + getCommaDelimitedString( getIdentifiers( OrganisationUnit.class, orgUnits ) ) + ")";
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/datasetreport/impl/DefaultDataSetReportService.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/datasetreport/impl/DefaultDataSetReportService.java	2014-03-18 08:10:10 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/datasetreport/impl/DefaultDataSetReportService.java	2014-08-14 05:46:19 +0000
@@ -194,7 +194,7 @@
             for ( DataElement dataElement : dataElements )
             {
                 grid.addRow();
-                grid.addValue( new GridValue( dataElement.getName() ) ); // Data element name
+                grid.addValue( new GridValue( dataElement.getFormName() ) ); // Data element name
 
                 for ( DataElementCategoryOptionCombo optionCombo : optionCombos ) // Values
                 {

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.java	2014-06-23 19:13:26 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.java	2014-08-14 05:46:19 +0000
@@ -28,12 +28,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import static org.hisp.dhis.system.util.ConversionUtils.getIdentifiers;
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
 import org.hisp.dhis.DhisSpringTest;
 import org.hisp.dhis.dataset.CompleteDataSetRegistration;
 import org.hisp.dhis.dataset.CompleteDataSetRegistrationService;
@@ -41,14 +35,16 @@
 import org.hisp.dhis.dataset.DataSetService;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
-import org.hisp.dhis.period.MonthlyPeriodType;
-import org.hisp.dhis.period.Period;
-import org.hisp.dhis.period.PeriodService;
-import org.hisp.dhis.period.PeriodType;
-import org.hisp.dhis.period.QuarterlyPeriodType;
+import org.hisp.dhis.period.*;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.hisp.dhis.system.util.ConversionUtils.getIdentifiers;
+import static org.junit.Assert.assertEquals;
+
 /**
  * @author Lars Helge Overland
  * @version $Id$
@@ -58,76 +54,84 @@
     extends DhisSpringTest
 {
     private DataSetCompletenessEngine completenessEngine;
-    
+
     private DataSetCompletenessStore completenessStore;
 
     private CompleteDataSetRegistrationService registrationService;
-    
+
     private PeriodType monthly;
+
     private PeriodType quarterly;
-    
+
     private Period periodA;
+
     private Period periodB;
+
     private Period periodC;
+
     private Period periodD;
-    
+
     private OrganisationUnit unitA;
+
     private OrganisationUnit unitB;
+
     private OrganisationUnit unitC;
 
     private DataSet dataSetA;
-    
+
     private Collection<DataSet> dataSets;
+
     private Collection<Period> periods;
+
     private Collection<OrganisationUnit> units;
-    
+
     @Override
     public void setUpTest()
     {
         completenessEngine = (DataSetCompletenessEngine) getBean( DataSetCompletenessEngine.ID );
-        
+
         completenessStore = (DataSetCompletenessStore) getBean( DataSetCompletenessStore.ID );
-        
+
         periodService = (PeriodService) getBean( PeriodService.ID );
-        
+
         organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
-        
+
         dataSetService = (DataSetService) getBean( DataSetService.ID );
-        
+
         registrationService = (CompleteDataSetRegistrationService) getBean( CompleteDataSetRegistrationService.ID );
 
         dataSets = new ArrayList<DataSet>();
         periods = new ArrayList<Period>();
         units = new ArrayList<OrganisationUnit>();
-        
+
         monthly = new MonthlyPeriodType();
         quarterly = new QuarterlyPeriodType();
-        
+
         periodA = createPeriod( monthly, getDate( 2000, 1, 1 ), getDate( 2000, 1, 31 ) );
         periodB = createPeriod( monthly, getDate( 2000, 2, 1 ), getDate( 2000, 2, 28 ) );
         periodC = createPeriod( monthly, getDate( 2000, 3, 1 ), getDate( 2000, 3, 31 ) );
         periodD = createPeriod( quarterly, getDate( 2000, 1, 1 ), getDate( 2000, 3, 31 ) );
-        
+
         periodService.addPeriod( periodA );
         periodService.addPeriod( periodB );
         periodService.addPeriod( periodC );
         periodService.addPeriod( periodD );
-        
+
         periods.add( periodA );
         periods.add( periodB );
         periods.add( periodC );
         periods.add( periodD );
-        
+
         unitA = createOrganisationUnit( 'A' );
         unitB = createOrganisationUnit( 'B' );
         unitC = createOrganisationUnit( 'C' );
-        
+
         unitB.setParent( unitA );
         unitC.setParent( unitA );
-        
+
         unitA.getChildren().add( unitB );
         unitA.getChildren().add( unitC );
-        
+
         organisationUnitService.addOrganisationUnit( unitA );
         organisationUnitService.addOrganisationUnit( unitB );
         organisationUnitService.addOrganisationUnit( unitC );
@@ -135,45 +139,61 @@
         units.add( unitA );
         units.add( unitB );
         units.add( unitC );
-        
+
         dataSetA = createDataSet( 'A', monthly );
-        
+
         dataSetA.getSources().add( unitA );
         dataSetA.getSources().add( unitB );
         dataSetA.getSources().add( unitC );
-        
+
         dataSetService.addDataSet( dataSetA );
-        
+
         dataSets.add( dataSetA );
     }
-    
+
     @Test
     public void testExportDataSetCompleteness()
     {
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, null, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitC, null, null, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitB, null, null, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, null, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodC, unitA, null, null, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodC, unitC, null, null, "" ) );
-        
+        registrationService.saveCompleteDataSetRegistration(
+            new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, null, "") );
+        registrationService.saveCompleteDataSetRegistration(
+            new CompleteDataSetRegistration( dataSetA, periodA, unitC, null, null, "") );
+        registrationService.saveCompleteDataSetRegistration(
+            new CompleteDataSetRegistration( dataSetA, periodB, unitB, null, null, "") );
+        registrationService.saveCompleteDataSetRegistration(
+            new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, null, "") );
+        registrationService.saveCompleteDataSetRegistration(
+            new CompleteDataSetRegistration( dataSetA, periodC, unitA, null, null, "") );
+        registrationService.saveCompleteDataSetRegistration(
+            new CompleteDataSetRegistration( dataSetA, periodC, unitC, null, null, "") );
+
         completenessEngine.exportDataSetCompleteness( getIdentifiers( DataSet.class, dataSets ),
             getIdentifiers( Period.class, periods ), getIdentifiers( OrganisationUnit.class, units ), null );
-        
-        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodA.getId(), unitB.getId() ), DELTA );
-        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodA.getId(), unitC.getId() ), DELTA );
-        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodA.getId(), unitA.getId() ), DELTA );
-        
-        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitB.getId() ), DELTA );
+
+        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodA.getId(), unitB.getId() ),
+            DELTA );
+        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodA.getId(), unitC.getId() ),
+            DELTA );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodA.getId(), unitA.getId() ),
+            DELTA );
+
+        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitB.getId() ),
+            DELTA );
         assertEquals( 0.0, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitC.getId() ), DELTA );
-        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitA.getId() ), DELTA );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitA.getId() ),
+            DELTA );
 
         assertEquals( 0.0, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitB.getId() ), DELTA );
-        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitC.getId() ), DELTA );
-        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitA.getId() ), DELTA );
-        
-        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitB.getId() ), DELTA );
-        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitC.getId() ), DELTA );
-        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitA.getId() ), DELTA );
+        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitC.getId() ),
+            DELTA );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitA.getId() ),
+            DELTA );
+
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitB.getId() ),
+            DELTA );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitC.getId() ),
+            DELTA );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitA.getId() ),
+            DELTA );
     }
 }

=== 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	2014-06-23 19:13:26 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceTest.java	2014-08-14 05:46:19 +0000
@@ -28,21 +28,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
-
 import org.hisp.dhis.DhisSpringTest;
-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.dataelement.DataElementService;
+import org.hisp.dhis.dataelement.*;
 import org.hisp.dhis.dataset.CompleteDataSetRegistration;
 import org.hisp.dhis.dataset.CompleteDataSetRegistrationService;
 import org.hisp.dhis.dataset.DataSet;
@@ -53,14 +40,17 @@
 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;
-import org.hisp.dhis.period.PeriodService;
-import org.hisp.dhis.period.PeriodType;
-import org.hisp.dhis.period.QuarterlyPeriodType;
+import org.hisp.dhis.period.*;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
 /**
  * @author Lars Helge Overland
  * @version $Id$
@@ -275,18 +265,16 @@
         dataSetService.addDataSet( dataSetB );
         dataSetService.addDataSet( dataSetC );
         
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitA, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, tooLateB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitD, null, tooLateA, "" ) );
-        
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitA, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitC, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodB, unitB, null, onTimeB, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitA, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, tooLateB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitD, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitA, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitC, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodB, unitB, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitC, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodB, unitA, null, tooLateB, "") );
 
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitC, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodB, unitA, null, tooLateB, "" ) );
-        
         Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA, null );
         
         assertNotNull( results );
@@ -321,18 +309,18 @@
         dataSetService.addDataSet( dataSetB );
         dataSetService.addDataSet( dataSetC );
         
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitA, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, onTimeB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitD, null, tooLateA, "" ) );
-        
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitA, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitB, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitC, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodB, unitC, null, tooLateB, "" ) );
-        
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitA, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitB, null, onTimeA, "" ) );
-        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitA, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitD, null, tooLateA, "") );
+        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitA, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitB, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitC, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodB, unitC, null, tooLateB, "") );
+        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitA, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitB, null, onTimeA, "") );
+
         Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA, null );
         
         assertNotNull( results );
@@ -363,15 +351,14 @@
         
         dataSetService.addDataSet( dataSetA );
 
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitC, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, onTimeA, "" ) );
-
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, onTimeB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, tooLateB, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitC, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, tooLateB, "") );
 
         Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdA, null );
         
@@ -402,18 +389,16 @@
         dataSetService.addDataSet( dataSetB );
         dataSetService.addDataSet( dataSetC );
         
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitA, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, tooLateB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitD, null, tooLateA, "" ) );
-        
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitA, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitC, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodB, unitB, null, onTimeB, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitA, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitB, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, tooLateB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitD, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitA, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodA, unitC, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetB, periodB, unitB, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitC, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodB, unitA, null, tooLateB, "") );
 
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodA, unitC, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetC, periodB, unitA, null, tooLateB, "" ) );
-        
         groupIds.clear();
         groupIds.add( groupA.getId() );
         
@@ -448,14 +433,13 @@
         
         dataSetIdA = dataSetService.addDataSet( dataSetA );
         
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, tooLateA, "" ) );
-        
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeA, "" ) );
-        
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeA, "") );
+
         Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA, null );
         
         assertNotNull( results );
@@ -482,13 +466,12 @@
 
         dataSetIdA = dataSetService.addDataSet( dataSetA );
 
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitH, null, tooLateA, "" ) );
-
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitH, null, onTimeB, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitH, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitH, null, onTimeB, "") );
 
         Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA, null );
         
@@ -517,15 +500,14 @@
 
         dataSetIdA = dataSetService.addDataSet( dataSetA );
 
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitH, null, tooLateA, "" ) );
-
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, tooLateB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeB, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitH, null, tooLateB, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitH, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, tooLateB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeB, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitH, null, tooLateB, "") );
 
         Collection<DataSetCompletenessResult> results = registrationCompletenessService.getDataSetCompleteness( periodIdA, unitIdsA, dataSetIdA, null );
 
@@ -554,13 +536,12 @@
         
         dataSetIdA = dataSetService.addDataSet( dataSetA );
         
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, tooLateA, "" ) );
-        
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, onTimeA, "" ) );
-        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeA, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitE, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitF, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitG, null, tooLateA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitE, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitF, null, onTimeA, "") );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitG, null, onTimeA, "") );
 
         groupIds.clear();
         groupIds.add( groupC.getId() );

=== modified file 'dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java'
--- dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java	2014-06-25 12:34:42 +0000
+++ dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java	2014-08-14 05:46:19 +0000
@@ -36,6 +36,7 @@
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
 import org.hibernate.criterion.Criterion;
+import org.hisp.dhis.acl.AccessStringHelper;
 import org.hisp.dhis.acl.AclService;
 import org.hisp.dhis.common.AuditLogUtil;
 import org.hisp.dhis.common.BaseIdentifiableObject;
@@ -47,7 +48,6 @@
 import org.hisp.dhis.hibernate.exception.ReadAccessDeniedException;
 import org.hisp.dhis.hibernate.exception.UpdateAccessDeniedException;
 import org.hisp.dhis.interpretation.Interpretation;
-import org.hisp.dhis.acl.AccessStringHelper;
 import org.hisp.dhis.user.CurrentUserService;
 import org.hisp.dhis.user.UserGroupAccess;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -193,6 +193,7 @@
             criteria.add( expression );
         }
 
+        criteria.setCacheable( cacheable );
         return criteria;
     }
 
@@ -202,7 +203,7 @@
      * @param expressions the Criterions for the Criteria.
      * @return an object of the implementation Class type.
      */
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     protected final T getObject( Criterion... expressions )
     {
         return (T) getCriteria( expressions ).uniqueResult();
@@ -214,7 +215,7 @@
      * @param expressions the Criterions for the Criteria.
      * @return a List with objects of the implementation Class type.
      */
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     protected final List<T> getList( Criterion... expressions )
     {
         return getCriteria( expressions ).list();
@@ -290,7 +291,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public final T get( int id )
     {
         T object = (T) sessionFactory.getCurrentSession().get( getClazz(), id );
@@ -305,7 +306,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public final T load( int id )
     {
         T object = (T) sessionFactory.getCurrentSession().load( getClazz(), id );
@@ -337,7 +338,7 @@
     }
 
     @Override
-    @SuppressWarnings( "unchecked" )
+    @SuppressWarnings("unchecked")
     public final List<T> getAll()
     {
         Query query = sharingEnabled() ? getQueryAllAcl() : getQueryAll();
@@ -360,39 +361,39 @@
 
     /**
      * Returns a Query instance. Allows for injecting a criteria part, such as
-     * "code = :code and name = :name". Note that the bound values must be set 
+     * "code = :code and name = :name". Note that the bound values must be set
      * on the query before executing it.
-     * 
+     *
      * @param hqlCriteria the HQL criteria.
      * @return a Query.
      */
     protected Query getQueryWithSelect( String hqlCriteria )
     {
         boolean sharingEnabled = sharingEnabled();
-        
+
         String hql = "select distinct c from " + clazz.getName() + " c";
-        
+
         if ( hqlCriteria != null )
         {
             hql += " where " + hqlCriteria;
         }
-        
+
         if ( sharingEnabled )
         {
             String criteria = hqlCriteria != null ? "and" : "where";
-            
+
             hql += " " + criteria + " ( c.publicAccess like 'r%' or c.user IS NULL or c.user=:user"
                 + " or exists "
                 + "     (from c.userGroupAccesses uga join uga.userGroup ug join ug.members ugm where ugm = :user and uga.access like 'r%') )";
         }
-        
+
         Query query = getQuery( hql );
-        
+
         if ( sharingEnabled )
         {
             query.setEntity( "user", currentUserService.getCurrentUser() );
         }
-        
+
         return query;
     }
 

=== modified file 'dhis-2/dhis-support/dhis-support-jdbc-test/src/test/java/org/hisp/dhis/jdbc/batchhandler/CompleteDataSetRegistrationBatchHandlerTest.java'
--- dhis-2/dhis-support/dhis-support-jdbc-test/src/test/java/org/hisp/dhis/jdbc/batchhandler/CompleteDataSetRegistrationBatchHandlerTest.java	2014-06-23 21:31:31 +0000
+++ dhis-2/dhis-support/dhis-support-jdbc-test/src/test/java/org/hisp/dhis/jdbc/batchhandler/CompleteDataSetRegistrationBatchHandlerTest.java	2014-08-14 05:46:19 +0000
@@ -28,14 +28,6 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Collection;
-import java.util.Date;
-
 import org.amplecode.quick.BatchHandler;
 import org.amplecode.quick.BatchHandlerFactory;
 import org.hisp.dhis.DhisTest;
@@ -53,6 +45,11 @@
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.util.Collection;
+import java.util.Date;
+
+import static org.junit.Assert.*;
+
 /**
  * @author Lars Helge Overland
  * @version $Id$
@@ -64,85 +61,92 @@
     private BatchHandlerFactory batchHandlerFactory;
 
     private BatchHandler<CompleteDataSetRegistration> batchHandler;
-    
+
     private DataSet dataSetA;
+
     private DataSet dataSetB;
-    
+
     private Period periodA;
+
     private Period periodB;
-    
+
     private OrganisationUnit unitA;
-    
+
     private DataElementCategoryOptionCombo optionCombo;
-    
+
     private Date dateA;
+
     private Date dateB;
-    
+
     private CompleteDataSetRegistration registrationA;
+
     private CompleteDataSetRegistration registrationB;
+
     private CompleteDataSetRegistration registrationC;
+
     private CompleteDataSetRegistration registrationD;
-    
+
     // -------------------------------------------------------------------------
     // Fixture
     // -------------------------------------------------------------------------
-    
+
     @Override
     public void setUpTest()
     {
         dataSetService = (DataSetService) getBean( DataSetService.ID );
         periodService = (PeriodService) getBean( PeriodService.ID );
         organisationUnitService = (OrganisationUnitService) getBean( OrganisationUnitService.ID );
-        completeDataSetRegistrationService = (CompleteDataSetRegistrationService) getBean( CompleteDataSetRegistrationService.ID );
+        completeDataSetRegistrationService = (CompleteDataSetRegistrationService) getBean(
+            CompleteDataSetRegistrationService.ID );
         categoryService = (DataElementCategoryService) getBean( DataElementCategoryService.ID );
-        
+
         batchHandler = batchHandlerFactory.createBatchHandler( CompleteDataSetRegistrationBatchHandler.class );
-        
+
         dataSetA = createDataSet( 'A', new MonthlyPeriodType() );
         dataSetB = createDataSet( 'B', new MonthlyPeriodType() );
-        
+
         dataSetService.addDataSet( dataSetA );
         dataSetService.addDataSet( dataSetB );
-        
+
         periodA = createPeriod( new MonthlyPeriodType(), getDate( 2000, 1, 1 ), getDate( 2000, 1, 31 ) );
         periodB = createPeriod( new MonthlyPeriodType(), getDate( 2000, 2, 1 ), getDate( 2000, 2, 28 ) );
-        
+
         periodService.addPeriod( periodA );
-        periodService.addPeriod( periodB );        
-        
+        periodService.addPeriod( periodB );
+
         unitA = createOrganisationUnit( 'A' );
-        
+
         organisationUnitService.addOrganisationUnit( unitA );
-        
+
         optionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
-        
+
         dateA = getDate( 2000, 1, 15 );
         dateB = getDate( 2000, 2, 15 );
-        
-        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, unitA, optionCombo, dateA, "" );
-        registrationB = new CompleteDataSetRegistration( dataSetA, periodB, unitA, optionCombo, dateB, "" );
-        registrationC = new CompleteDataSetRegistration( dataSetB, periodA, unitA, optionCombo, dateA, "" );
-        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, unitA, optionCombo, dateB, "" );
-        
+
+        registrationA = new CompleteDataSetRegistration( dataSetA, periodA, unitA, optionCombo, dateA, "");
+        registrationB = new CompleteDataSetRegistration( dataSetA, periodB, unitA, optionCombo, dateB, "");
+        registrationC = new CompleteDataSetRegistration( dataSetB, periodA, unitA, optionCombo, dateA, "");
+        registrationD = new CompleteDataSetRegistration( dataSetB, periodB, unitA, optionCombo, dateB, "");
+
         batchHandler.init();
     }
-    
+
     @Override
     public void tearDownTest()
     {
         batchHandler.flush();
     }
-    
+
     @Override
     public boolean emptyDatabaseAfterTest()
     {
         return true;
     }
-    
+
     // -------------------------------------------------------------------------
     // Tests
     // -------------------------------------------------------------------------
-    
+
     @Test
     public void testAddObject()
     {
@@ -150,14 +154,15 @@
         batchHandler.addObject( registrationB );
         batchHandler.addObject( registrationC );
         batchHandler.addObject( registrationD );
-        
+
         batchHandler.flush();
-        
-        Collection<CompleteDataSetRegistration> registrations = completeDataSetRegistrationService.getAllCompleteDataSetRegistrations();
-        
+
+        Collection<CompleteDataSetRegistration> registrations = completeDataSetRegistrationService
+            .getAllCompleteDataSetRegistrations();
+
         assertNotNull( registrations );
         assertEquals( 4, registrations.size() );
-        
+
         assertTrue( registrations.contains( registrationA ) );
         assertTrue( registrations.contains( registrationB ) );
         assertTrue( registrations.contains( registrationC ) );
@@ -171,24 +176,29 @@
         batchHandler.insertObject( registrationB, false );
         batchHandler.insertObject( registrationC, false );
         batchHandler.insertObject( registrationD, false );
-        
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, unitA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodB, unitA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodA, unitA, optionCombo ) );
-        assertNotNull( completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetB, periodB, unitA, optionCombo ) );
+
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, unitA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodB, unitA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodA, unitA, optionCombo ) );
+        assertNotNull( completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetB, periodB, unitA, optionCombo ) );
     }
 
     @Test
     public void testUpdateObject()
     {
         batchHandler.insertObject( registrationA, false );
-        
+
         registrationA.setDate( dateB );
-        
+
         batchHandler.updateObject( registrationA );
-        
-        registrationA = completeDataSetRegistrationService.getCompleteDataSetRegistration( dataSetA, periodA, unitA, optionCombo );
-        
+
+        registrationA = completeDataSetRegistrationService
+            .getCompleteDataSetRegistration( dataSetA, periodA, unitA, optionCombo );
+
         assertEquals( dateB, registrationA.getDate() );
     }
 
@@ -197,10 +207,10 @@
     {
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationA );
         completeDataSetRegistrationService.saveCompleteDataSetRegistration( registrationB );
-        
+
         assertTrue( batchHandler.objectExists( registrationA ) );
         assertTrue( batchHandler.objectExists( registrationB ) );
-        
+
         assertFalse( batchHandler.objectExists( registrationC ) );
         assertFalse( batchHandler.objectExists( registrationD ) );
     }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java	2014-06-24 08:23:44 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java	2014-08-14 05:46:19 +0000
@@ -28,10 +28,11 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import org.hisp.dhis.webapi.utils.ContextUtils;
-import org.hisp.dhis.webapi.utils.InputUtils;
+import org.apache.commons.lang.StringUtils;
 import org.hisp.dhis.common.IdentifiableObjectManager;
 import org.hisp.dhis.common.view.BasicView;
+import org.hisp.dhis.datacompletion.CompleteDataSetRegistrationRequest;
+import org.hisp.dhis.datacompletion.CompleteDataSetRegistrationRequests;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataset.CompleteDataSetRegistration;
 import org.hisp.dhis.dataset.CompleteDataSetRegistrationService;
@@ -47,9 +48,12 @@
 import org.hisp.dhis.period.PeriodService;
 import org.hisp.dhis.period.PeriodType;
 import org.hisp.dhis.user.CurrentUserService;
+import org.hisp.dhis.webapi.utils.ContextUtils;
+import org.hisp.dhis.webapi.utils.InputUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -59,6 +63,7 @@
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import static org.hisp.dhis.webapi.utils.ContextUtils.CONTENT_TYPE_JSON;
@@ -73,12 +78,14 @@
 {
     public static final String RESOURCE_PATH = "/completeDataSetRegistrations";
 
+    public static final String MULTIPLE_SAVE_RESOURCE_PATH = "/multiple";
+
     @Autowired
     private CompleteDataSetRegistrationService registrationService;
 
     @Autowired
     private DataSetService dataSetService;
-    
+
     @Autowired
     private PeriodService periodService;
 
@@ -87,16 +94,16 @@
 
     @Autowired
     private OrganisationUnitService organisationUnitService;
-    
+
     @Autowired
     private CurrentUserService currentUserService;
 
     @Autowired
     private InputUtils inputUtils;
-    
+
     @Autowired
     private I18nManager i18nManager;
-    
+
     @RequestMapping( method = RequestMethod.GET, produces = CONTENT_TYPE_XML )
     public void getCompleteDataSetRegistrationsXml(
         @RequestParam Set<String> dataSet,
@@ -108,7 +115,8 @@
         HttpServletResponse response ) throws IOException
     {
         response.setContentType( CONTENT_TYPE_XML );
-        CompleteDataSetRegistrations completeDataSetRegistrations = getCompleteDataSetRegistrations( dataSet, period, startDate, endDate, orgUnit, children );
+        CompleteDataSetRegistrations completeDataSetRegistrations = getCompleteDataSetRegistrations( dataSet, period,
+            startDate, endDate, orgUnit, children );
 
         JacksonUtils.toXmlWithView( response.getOutputStream(), completeDataSetRegistrations, BasicView.class );
     }
@@ -124,16 +132,17 @@
         HttpServletResponse response ) throws IOException
     {
         response.setContentType( CONTENT_TYPE_JSON );
-        CompleteDataSetRegistrations completeDataSetRegistrations = getCompleteDataSetRegistrations( dataSet, period, startDate, endDate, orgUnit, children );
-
+        CompleteDataSetRegistrations completeDataSetRegistrations = getCompleteDataSetRegistrations( dataSet, period,
+            startDate, endDate, orgUnit, children );
         JacksonUtils.toJsonWithView( response.getOutputStream(), completeDataSetRegistrations, BasicView.class );
     }
 
-    private CompleteDataSetRegistrations getCompleteDataSetRegistrations( Set<String> dataSet, String period, Date startDate, Date endDate, Set<String> orgUnit, boolean children )
+    private CompleteDataSetRegistrations getCompleteDataSetRegistrations( Set<String> dataSet, String period,
+        Date startDate, Date endDate, Set<String> orgUnit, boolean children )
     {
-        Set<Period> periods = new HashSet<Period>();
-        Set<DataSet> dataSets = new HashSet<DataSet>();
-        Set<OrganisationUnit> organisationUnits = new HashSet<OrganisationUnit>();
+        Set<Period> periods = new HashSet<>();
+        Set<DataSet> dataSets = new HashSet<>();
+        Set<OrganisationUnit> organisationUnits = new HashSet<>();
 
         PeriodType periodType = periodService.getPeriodTypeByName( period );
 
@@ -158,23 +167,25 @@
         dataSets.addAll( manager.getByUid( DataSet.class, dataSet ) );
 
         CompleteDataSetRegistrations completeDataSetRegistrations = new CompleteDataSetRegistrations();
-        completeDataSetRegistrations.setCompleteDataSetRegistrationList( new ArrayList<CompleteDataSetRegistration>(
+        completeDataSetRegistrations.setCompleteDataSetRegistrationList( new ArrayList<>(
             registrationService.getCompleteDataSetRegistrations( dataSets, organisationUnits, periods ) ) );
 
         return completeDataSetRegistrations;
     }
 
     @RequestMapping( method = RequestMethod.POST, produces = "text/plain" )
-    public void saveCompleteDataSetRegistration( 
+    public void saveCompleteDataSetRegistration(
         @RequestParam String ds,
         @RequestParam String pe,
         @RequestParam String ou,
-        @RequestParam( required = false ) String cc, 
-        @RequestParam( required = false ) String cp, 
+        @RequestParam( required = false ) String cc,
+        @RequestParam( required = false ) String cp,
+        @RequestParam( required = false ) Date cd,
+        @RequestParam( required = false ) String sb,
         @RequestParam( required = false ) boolean multiOu, HttpServletResponse response )
     {
         DataSet dataSet = dataSetService.getDataSet( ds );
-        
+
         if ( dataSet == null )
         {
             ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds );
@@ -198,7 +209,7 @@
         }
 
         DataElementCategoryOptionCombo attributeOptionCombo = inputUtils.getAttributeOptionCombo( response, cc, cp );
-        
+
         if ( attributeOptionCombo == null )
         {
             return;
@@ -217,14 +228,22 @@
         // ---------------------------------------------------------------------
         // Register as completed data set
         // ---------------------------------------------------------------------
-        
+
         Set<OrganisationUnit> children = organisationUnit.getChildren();
 
-        String storedBy = currentUserService.getCurrentUsername();
+        String storedBy = (sb == null) ? currentUserService.getCurrentUsername() : sb;
+
+        Date completionDate = (cd == null) ? new Date() : cd;
+
+        List<CompleteDataSetRegistration> registrations = new ArrayList<>();
 
         if ( !multiOu )
         {
-            registerCompleteDataSet( dataSet, period, organisationUnit, attributeOptionCombo, storedBy );
+            CompleteDataSetRegistration completeDataSetRegistration = registerCompleteDataSet( dataSet, period,
+                organisationUnit, attributeOptionCombo, storedBy, completionDate );
+
+            if ( completeDataSetRegistration != null )
+                registrations.add( completeDataSetRegistration );
         }
         else
         {
@@ -232,26 +251,129 @@
             {
                 if ( unit.getDataSets().contains( dataSet ) )
                 {
-                    registerCompleteDataSet( dataSet, period, unit, attributeOptionCombo, storedBy );
-                }
-            }
-        }
-    }
-    
+                    CompleteDataSetRegistration completeDataSetRegistration = registerCompleteDataSet( dataSet, period,
+                        organisationUnit, attributeOptionCombo, storedBy, completionDate );
+
+                    if ( completeDataSetRegistration != null )
+                        registrations.add( completeDataSetRegistration );
+                }
+            }
+        }
+
+        registrationService.saveCompleteDataSetRegistrations( registrations, true );
+    }
+
+    @RequestMapping( method = RequestMethod.POST, consumes = "application/json", value = MULTIPLE_SAVE_RESOURCE_PATH )
+    public void saveCompleteDataSetRegistration(
+        @RequestBody CompleteDataSetRegistrationRequests completeDataSetRegistrationRequests,
+        HttpServletResponse response )
+    {
+
+        List<CompleteDataSetRegistration> registrations = new ArrayList<>();
+
+        for ( CompleteDataSetRegistrationRequest completeDataSetRegistrationRequest : completeDataSetRegistrationRequests )
+        {
+            String ds = completeDataSetRegistrationRequest.getDs();
+            DataSet dataSet = dataSetService.getDataSet( ds );
+
+            if ( dataSet == null )
+            {
+                ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds );
+                return;
+            }
+
+            String pe = completeDataSetRegistrationRequest.getPe();
+            Period period = PeriodType.getPeriodFromIsoString( pe );
+
+            if ( period == null )
+            {
+                ContextUtils.conflictResponse( response, "Illegal period identifier: " + pe );
+                return;
+            }
+
+            String ou = completeDataSetRegistrationRequest.getOu();
+            OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( ou );
+
+            if ( organisationUnit == null )
+            {
+                ContextUtils.conflictResponse( response, "Illegal organisation unit identifier: " + ou );
+                return;
+            }
+
+            String cc = completeDataSetRegistrationRequest.getCc();
+            String cp = completeDataSetRegistrationRequest.getCp();
+            DataElementCategoryOptionCombo attributeOptionCombo = inputUtils
+                .getAttributeOptionCombo( response, cc, cp );
+
+            if ( attributeOptionCombo == null )
+            {
+                return;
+            }
+
+            // ---------------------------------------------------------------------
+            // Check locked status
+            // ---------------------------------------------------------------------
+
+            boolean multiOu = completeDataSetRegistrationRequest.isMultiOu();
+
+            if ( dataSetService.isLocked( dataSet, period, organisationUnit, attributeOptionCombo, null, multiOu ) )
+            {
+                ContextUtils.conflictResponse( response, "Data set is locked: " + ds );
+                return;
+            }
+
+            // ---------------------------------------------------------------------
+            // Register as completed data set
+            // ---------------------------------------------------------------------
+
+            String sb = completeDataSetRegistrationRequest.getSb();
+
+            String storedBy = (sb == null) ? currentUserService.getCurrentUsername() : sb;
+
+            Date cd = completeDataSetRegistrationRequest.getCd();
+
+            Date completionDate = (cd == null) ? new Date() : cd;
+
+            Set<OrganisationUnit> orgUnits = new HashSet<>();
+
+            orgUnits.add( organisationUnit );
+
+            if ( multiOu )
+            {
+                orgUnits.addAll( organisationUnit.getChildren() );
+            }
+
+            for ( OrganisationUnit orgUnit : orgUnits )
+            {
+                if ( orgUnit.getDataSets().contains( dataSet ) )
+                {
+                    CompleteDataSetRegistration completeDataSetRegistration = registerCompleteDataSet( dataSet, period,
+                        organisationUnit,
+                        attributeOptionCombo, storedBy, completionDate );
+
+                    if ( completeDataSetRegistration != null )
+                        registrations.add( completeDataSetRegistration );
+                }
+            }
+        }
+
+        registrationService.saveCompleteDataSetRegistrations( registrations, true );
+    }
+
     @RequestMapping( method = RequestMethod.DELETE, produces = "text/plain" )
-    public void deleteCompleteDataSetRegistration( 
-        @RequestParam String ds,
+    public void deleteCompleteDataSetRegistration(
+        @RequestParam Set<String> ds,
         @RequestParam String pe,
         @RequestParam String ou,
-        @RequestParam( required = false ) String cc, 
-        @RequestParam( required = false ) String cp, 
+        @RequestParam( required = false ) String cc,
+        @RequestParam( required = false ) String cp,
         @RequestParam( required = false ) boolean multiOu, HttpServletResponse response )
     {
-        DataSet dataSet = dataSetService.getDataSet( ds );
-        
-        if ( dataSet == null )
+        Set<DataSet> dataSets = new HashSet<>( manager.getByUid( DataSet.class, ds ) );
+
+        if ( dataSets.size() != ds.size() )
         {
-            ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds );
+            ContextUtils.conflictResponse( response, "Illegal data set identifier in this list: " + ds );
             return;
         }
 
@@ -272,7 +394,7 @@
         }
 
         DataElementCategoryOptionCombo attributeOptionCombo = inputUtils.getAttributeOptionCombo( response, cc, cp );
-        
+
         if ( attributeOptionCombo == null )
         {
             return;
@@ -282,68 +404,89 @@
         // Check locked status
         // ---------------------------------------------------------------------
 
-        if ( dataSetService.isLocked( dataSet, period, organisationUnit, attributeOptionCombo, null, multiOu ) )
-        {
-            ContextUtils.conflictResponse( response, "Data set is locked: " + ds );
+        List<String> lockedDataSets = new ArrayList<>();
+        for ( DataSet dataSet : dataSets )
+        {
+            if ( dataSetService.isLocked( dataSet, period, organisationUnit, attributeOptionCombo, null, multiOu ) )
+            {
+                lockedDataSets.add( dataSet.getUid() );
+            }
+        }
+
+        if ( lockedDataSets.size() != 0 )
+        {
+            ContextUtils
+                .conflictResponse( response, "Locked Data set(s) : " + StringUtils.join( lockedDataSets, ", " ) );
             return;
         }
 
         // ---------------------------------------------------------------------
         // Un-register as completed data set
         // ---------------------------------------------------------------------
-        
-        Set<OrganisationUnit> children = organisationUnit.getChildren();
-
-        if ( !multiOu )
-        {
-            unRegisterCompleteDataSet( dataSet, period, organisationUnit, attributeOptionCombo );
-        }
-        else
-        {
-            for ( OrganisationUnit unit : children )
-            {
-                if ( unit.getDataSets().contains( dataSet ) )
-                {
-                    unRegisterCompleteDataSet( dataSet, period, unit, attributeOptionCombo );
-                }
-            }
-        }
+
+        Set<OrganisationUnit> orgUnits = new HashSet<>();
+        orgUnits.add( organisationUnit );
+        if ( multiOu )
+        {
+            orgUnits.addAll( organisationUnit.getChildren() );
+        }
+
+        unRegisterCompleteDataSet( dataSets, period, orgUnits, attributeOptionCombo );
+
     }
 
     // -------------------------------------------------------------------------
     // Supportive methods
     // -------------------------------------------------------------------------
-
-    private void registerCompleteDataSet( DataSet dataSet, Period period, 
-        OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo, String storedBy )
+    private CompleteDataSetRegistration registerCompleteDataSet( DataSet dataSet, Period period,
+        OrganisationUnit orgUnit, DataElementCategoryOptionCombo attributeOptionCombo, String storedBy,
+        Date completionDate )
     {
         I18nFormat format = i18nManager.getI18nFormat();
-        
-        CompleteDataSetRegistration registration = new CompleteDataSetRegistration();
 
-        if ( registrationService.getCompleteDataSetRegistration( dataSet, period, organisationUnit, attributeOptionCombo ) == null )
+        if ( registrationService.getCompleteDataSetRegistration( dataSet, period, orgUnit, attributeOptionCombo ) ==
+            null )
         {
+            CompleteDataSetRegistration registration = new CompleteDataSetRegistration();
+
             registration.setDataSet( dataSet );
             registration.setPeriod( period );
-            registration.setSource( organisationUnit );
+            registration.setSource( orgUnit );
             registration.setAttributeOptionCombo( attributeOptionCombo );
-            registration.setDate( new Date() );
+            registration.setDate( completionDate );
             registration.setStoredBy( storedBy );
-
             registration.setPeriodName( format.formatPeriod( registration.getPeriod() ) );
 
-            registrationService.saveCompleteDataSetRegistration( registration, true );
+            return registration;
         }
+
+        return null;
     }
 
-    private void unRegisterCompleteDataSet( DataSet dataSet, Period period, 
-        OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo )
+    private void unRegisterCompleteDataSet( Set<DataSet> dataSets, Period period,
+        Set<OrganisationUnit> orgUnits, DataElementCategoryOptionCombo attributeOptionCombo )
     {
-        CompleteDataSetRegistration registration = registrationService.getCompleteDataSetRegistration( dataSet, period, organisationUnit, attributeOptionCombo );
-
-        if ( registration != null )
-        {
-            registrationService.deleteCompleteDataSetRegistration( registration );
+        List<CompleteDataSetRegistration> registrations = new ArrayList<>();
+
+        for ( OrganisationUnit unit : orgUnits )
+        {
+            for ( DataSet dataSet : dataSets )
+            {
+                if ( unit.getDataSets().contains( dataSet ) )
+                {
+                    CompleteDataSetRegistration registration = registrationService
+                        .getCompleteDataSetRegistration( dataSet, period, unit, attributeOptionCombo );
+
+                    if ( registration != null )
+                    {
+                        registrations.add( registration );
+                    }
+                }
+            }
+        }
+        if ( !registrations.isEmpty() )
+        {
+            registrationService.deleteCompleteDataSetRegistrations( registrations );
         }
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataApprovalController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataApprovalController.java	2014-06-06 19:29:39 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataApprovalController.java	2014-08-14 05:46:19 +0000
@@ -28,23 +28,19 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletResponse;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.hisp.dhis.webapi.utils.ContextUtils;
-import org.hisp.dhis.webapi.utils.InputUtils;
+import org.hisp.dhis.common.IdentifiableObjectManager;
+import org.hisp.dhis.common.view.BasicView;
 import org.hisp.dhis.dataapproval.DataApproval;
 import org.hisp.dhis.dataapproval.DataApprovalPermissions;
 import org.hisp.dhis.dataapproval.DataApprovalService;
 import org.hisp.dhis.dataapproval.DataApprovalState;
+import org.hisp.dhis.dataapproval.DataApprovalStateRequest;
+import org.hisp.dhis.dataapproval.DataApprovalStateRequests;
+import org.hisp.dhis.dataapproval.DataApprovalStateResponse;
+import org.hisp.dhis.dataapproval.DataApprovalStateResponses;
+import org.hisp.dhis.dataapproval.DataApprovalStatus;
 import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataset.DataSet;
@@ -53,34 +49,62 @@
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.Period;
+import org.hisp.dhis.period.PeriodService;
 import org.hisp.dhis.period.PeriodType;
 import org.hisp.dhis.user.CurrentUserService;
 import org.hisp.dhis.user.User;
+import org.hisp.dhis.user.UserService;
+import org.hisp.dhis.webapi.utils.ContextUtils;
+import org.hisp.dhis.webapi.utils.InputUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseStatus;
 
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.collect.Lists.newArrayList;
+
 /**
  * @author Lars Helge Overland
  */
 @Controller
-@RequestMapping(value = DataApprovalController.RESOURCE_PATH)
+@RequestMapping( value = DataApprovalController.RESOURCE_PATH )
 public class DataApprovalController
 {
     private final static Log log = LogFactory.getLog( DataApprovalController.class );
 
     public static final String RESOURCE_PATH = "/dataApprovals";
+
     public static final String ACCEPTANCES_PATH = "/acceptances";
 
+    private static final String STATUS_PATH = "/status";
+
+    private static final String MULTIPLE_SAVE_RESOURCE_PATH = "/multiple";
+
     private static final String APPROVAL_STATE = "state";
+
     private static final String APPROVAL_MAY_APPROVE = "mayApprove";
+
     private static final String APPROVAL_MAY_UNAPPROVE = "mayUnapprove";
+
     private static final String APPROVAL_MAY_ACCEPT = "mayAccept";
+
     private static final String APPROVAL_MAY_UNACCEPT = "mayUnaccept";
 
     @Autowired
@@ -88,13 +112,22 @@
 
     @Autowired
     private DataSetService dataSetService;
-    
+
+    @Autowired
+    private IdentifiableObjectManager manager;
+
     @Autowired
     private OrganisationUnitService organisationUnitService;
 
     @Autowired
+    private UserService userService;
+
+    @Autowired
     private CurrentUserService currentUserService;
-    
+
+    @Autowired
+    private PeriodService periodService;
+
     @Autowired
     private InputUtils inputUtils;
 
@@ -104,14 +137,15 @@
         @RequestParam String pe,
         @RequestParam String ou,
         @RequestParam( required = false ) Set<String> cog,
-        @RequestParam( required = false ) String cp, HttpServletResponse response ) throws IOException
+        @RequestParam( required = false ) String cp, HttpServletResponse response )
+        throws IOException
     {
         log.info( "GET " + RESOURCE_PATH + "?ds=" + ds + "&pe=" + pe + "&ou=" + ou
-                + ( cog == null || cog.isEmpty() ? "" : ( "&cog=" + Arrays.toString( cog.toArray() ) ) )
-                + ( cp == null ? "" : ( "&cp=" + cp ) ) );
+            + (cog == null || cog.isEmpty() ? "" : ("&cog=" + Arrays.toString( cog.toArray() )))
+            + (cp == null ? "" : ("&cp=" + cp)) );
 
         DataSet dataSet = dataSetService.getDataSet( ds );
-        
+
         if ( dataSet == null )
         {
             ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds );
@@ -152,10 +186,11 @@
         {
             return;
         }
-        
-        DataApprovalPermissions permissions = dataApprovalService.getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, categoryOptions );
-
-        Map<String, Object> approvalState = new HashMap<String, Object>();
+
+        DataApprovalPermissions permissions = dataApprovalService
+            .getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, categoryOptions );
+
+        Map<String, Object> approvalState = new HashMap<>();
         approvalState.put( APPROVAL_STATE, permissions.getDataApprovalStatus().getDataApprovalState().toString() );
         approvalState.put( APPROVAL_MAY_APPROVE, permissions.isMayApprove() );
         approvalState.put( APPROVAL_MAY_UNAPPROVE, permissions.isMayUnapprove() );
@@ -164,7 +199,86 @@
 
         JacksonUtils.toJson( response.getOutputStream(), approvalState );
     }
-    
+
+    @RequestMapping( method = RequestMethod.GET, produces = ContextUtils.CONTENT_TYPE_JSON, value = STATUS_PATH )
+    public void getApproval(
+        @RequestParam Set<String> ds,
+        @RequestParam( required = false ) String pe,
+        @RequestParam @DateTimeFormat( pattern = "yyyy-MM-dd" ) Date startDate,
+        @RequestParam @DateTimeFormat( pattern = "yyyy-MM-dd" ) Date endDate,
+        @RequestParam Set<String> ou,
+        @RequestParam( required = false ) boolean children,
+        HttpServletResponse response )
+        throws IOException
+    {
+
+        Set<DataSet> dataSets = new HashSet<>();
+
+        dataSets.addAll( manager.getByUid( DataSet.class, ds ) );
+
+        Set<Period> periods = new HashSet<>();
+
+        PeriodType periodType = periodService.getPeriodTypeByName( pe );
+
+        if ( periodType != null )
+        {
+            periods.addAll( periodService.getPeriodsBetweenDates( periodType, startDate, endDate ) );
+        }
+        else
+        {
+            periods.addAll( periodService.getPeriodsBetweenDates( startDate, endDate ) );
+        }
+
+        Set<OrganisationUnit> organisationUnits = new HashSet<>();
+
+        if ( children )
+        {
+            organisationUnits.addAll( organisationUnitService.getOrganisationUnitsWithChildren( ou ) );
+        }
+        else
+        {
+            organisationUnits.addAll( organisationUnitService.getOrganisationUnitsByUid( ou ) );
+        }
+
+        DataApprovalStateResponses dataApprovalStateResponses = new DataApprovalStateResponses();
+
+        for ( DataSet dataSet : dataSets )
+        {
+            for ( OrganisationUnit organisationUnit : organisationUnits )
+            {
+                if ( organisationUnit.getDataSets().contains( dataSet ) )
+                {
+                    for ( Period period : periods )
+                    {
+                        dataApprovalStateResponses.add(
+                            getDataApprovalStateResponse( dataSet, organisationUnit, period ) );
+                    }
+                }
+            }
+        }
+
+        JacksonUtils.toJsonWithView( response.getOutputStream(), dataApprovalStateResponses, BasicView.class );
+    }
+
+    private DataApprovalStateResponse getDataApprovalStateResponse( DataSet dataSet, OrganisationUnit organisationUnit,
+        Period period )
+    {
+        DataApprovalPermissions permissions = dataApprovalService.getDataApprovalPermissions( dataSet, period,
+            organisationUnit, null, null );
+
+        DataApprovalStatus dataApprovalStatus = permissions.getDataApprovalStatus();
+
+        DataApproval dataApproval = dataApprovalStatus.getDataApproval();
+        Date createdDate = (dataApproval == null) ? null : dataApproval.getCreated();
+        String createdByUsername = (dataApproval == null) ? null : dataApproval.getCreator().getUsername();
+
+        String state = dataApprovalStatus.getDataApprovalState().toString();
+
+        return new DataApprovalStateResponse( dataSet, period, organisationUnit, state, createdDate, createdByUsername,
+            permissions.isMayApprove(), permissions.isMayUnapprove(), permissions.isMayAccept(),
+            permissions.isMayUnaccept() );
+    }
+
     @PreAuthorize( "hasRole('ALL') or hasRole('F_APPROVE_DATA') or hasRole('F_APPROVE_DATA_LOWER_LEVELS')" )
     @RequestMapping( method = RequestMethod.POST )
     public void saveApproval(
@@ -174,10 +288,10 @@
         @RequestParam( required = false ) String cog, HttpServletResponse response )
     {
         log.info( "POST " + RESOURCE_PATH + "?ds=" + ds + "&pe=" + pe + "&ou=" + ou
-                + ( cog == null ? "" : ( "&cog=" + cog ) ) );
+            + (cog == null ? "" : ("&cog=" + cog)) );
 
         DataSet dataSet = dataSetService.getDataSet( ds );
-        
+
         if ( dataSet == null )
         {
             ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds );
@@ -212,51 +326,141 @@
             }
         }
 
-        DataApprovalPermissions permissions = dataApprovalService.getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
+        DataApprovalPermissions permissions = dataApprovalService
+            .getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
 
         DataApprovalState state = permissions.getDataApprovalStatus().getDataApprovalState();
 
         if ( state != DataApprovalState.UNAPPROVED_READY &&
-             state != DataApprovalState.PARTIALLY_APPROVED_HERE )
+            state != DataApprovalState.PARTIALLY_APPROVED_HERE )
         {
-            ContextUtils.conflictResponse( response, "Data is not ready for approval here, current state is: " + state.name() );
+            ContextUtils
+                .conflictResponse( response, "Data is not ready for approval here, current state is: " + state.name() );
             return;
         }
 
         if ( !permissions.isMayApprove() )
         {
             ContextUtils.conflictResponse( response, "Current user is not authorized to approve for "
-                    + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
+                + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
             return;
         }
 
         User user = currentUserService.getCurrentUser();
 
-        CategoryOptionGroup categoryOptionGroup = categoryOptionGroups == null || categoryOptionGroups.isEmpty() ? null : (CategoryOptionGroup) categoryOptionGroups.iterator().next();
+        CategoryOptionGroup categoryOptionGroup = categoryOptionGroups == null || categoryOptionGroups.isEmpty() ?
+            null : categoryOptionGroups.iterator().next();
 
         DataApproval approval = new DataApproval( permissions.getDataApprovalStatus().getDataApprovalLevel(),
-                dataSet, period, organisationUnit, categoryOptionGroup, false, new Date(), user );
+            dataSet, period, organisationUnit, categoryOptionGroup, false, new Date(), user );
 
         dataApprovalService.addDataApproval( approval );
     }
 
     @PreAuthorize( "hasRole('ALL') or hasRole('F_APPROVE_DATA') or hasRole('F_APPROVE_DATA_LOWER_LEVELS')" )
+    @RequestMapping( method = RequestMethod.POST, value = MULTIPLE_SAVE_RESOURCE_PATH )
+    public void saveApproval(
+        @RequestBody DataApprovalStateRequests dataApprovalStateRequests,
+        HttpServletResponse response )
+    {
+        List<DataApproval> dataApprovals = new ArrayList<>();
+
+        for ( DataApprovalStateRequest dataApprovalStateRequest : dataApprovalStateRequests )
+        {
+            DataSet dataSet = dataSetService.getDataSet( dataApprovalStateRequest.getDs() );
+
+            if ( dataSet == null )
+            {
+                ContextUtils
+                    .conflictResponse( response, "Illegal data set identifier: " + dataApprovalStateRequest.getDs() );
+                return;
+            }
+
+            Period period = PeriodType.getPeriodFromIsoString( dataApprovalStateRequest.getPe() );
+
+            if ( period == null )
+            {
+                ContextUtils.conflictResponse( response, "Illegal period identifier: " + dataApprovalStateRequest.getPe() );
+                return;
+            }
+
+            OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit(
+                dataApprovalStateRequest.getOu() );
+
+            if ( organisationUnit == null )
+            {
+                ContextUtils.conflictResponse( response,
+                    "Illegal organisation unit identifier: " + dataApprovalStateRequest.getOu() );
+                return;
+            }
+
+            Set<CategoryOptionGroup> categoryOptionGroups = null;
+
+            if ( dataApprovalStateRequest.getCog() != null )
+            {
+                categoryOptionGroups = inputUtils.getAttributeOptionGroup( response, dataApprovalStateRequest.getCog() );
+
+                if ( categoryOptionGroups == null )
+                {
+                    return;
+                }
+            }
+
+            DataApprovalPermissions permissions = dataApprovalService
+                .getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
+
+            DataApprovalState state = permissions.getDataApprovalStatus().getDataApprovalState();
+
+            if ( state != DataApprovalState.UNAPPROVED_READY &&
+                state != DataApprovalState.PARTIALLY_APPROVED_HERE )
+            {
+                ContextUtils.conflictResponse( response,
+                    "Data is not ready for approval here, current state is: " + state.name() );
+                return;
+            }
+
+            if ( !permissions.isMayApprove() )
+            {
+                ContextUtils.conflictResponse( response, "Current user is not authorized to approve for "
+                    + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
+                return;
+            }
+
+            User user = dataApprovalStateRequest.getAb() == null ?
+                currentUserService.getCurrentUser() :
+                userService.getUserCredentialsByUsername( dataApprovalStateRequest.getAb() ).getUser();
+
+            Date approvalDate = (dataApprovalStateRequest.getAd() == null) ? new Date() : dataApprovalStateRequest.getAd();
+
+            CategoryOptionGroup categoryOptionGroup =
+                categoryOptionGroups == null || categoryOptionGroups.isEmpty() ? null :
+                    categoryOptionGroups.iterator().next();
+
+            dataApprovals.add(
+                new DataApproval( permissions.getDataApprovalStatus().getDataApprovalLevel(), dataSet, period,
+                    organisationUnit, categoryOptionGroup, false, approvalDate, user ) );
+        }
+
+        dataApprovalService.addAllDataApprovals( dataApprovals );
+    }
+
+    @PreAuthorize( "hasRole('ALL') or hasRole('F_APPROVE_DATA') or hasRole('F_APPROVE_DATA_LOWER_LEVELS')" )
     @RequestMapping( method = RequestMethod.DELETE )
     @ResponseStatus( value = HttpStatus.NO_CONTENT )
     public void removeApproval(
-        @RequestParam String ds,
+        @RequestParam Set<String> ds,
         @RequestParam String pe,
         @RequestParam String ou,
         @RequestParam( required = false ) String cog, HttpServletResponse response )
     {
         log.info( "DELETE " + RESOURCE_PATH + "?ds=" + ds + "&pe=" + pe + "&ou=" + ou
-                + ( cog == null ? "" : ( "&cog=" + cog ) ) );
-
-        DataSet dataSet = dataSetService.getDataSet( ds );
-        
-        if ( dataSet == null )
+            + (cog == null ? "" : ("&cog=" + cog)) );
+
+        Set<DataSet> dataSets = new HashSet<>( manager.getByUid( DataSet.class, ds ) );
+
+        if ( dataSets.size() != ds.size() )
         {
-            ContextUtils.conflictResponse( response, "Illegal data set identifier: " + ds );
+            ContextUtils.conflictResponse( response, "Illegal data set identifier in this list: " + ds );
             return;
         }
 
@@ -288,39 +492,46 @@
             }
         }
 
-        DataApprovalPermissions permissions = dataApprovalService.getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
-
-        DataApprovalState state = permissions.getDataApprovalStatus().getDataApprovalState();
-
-        if ( state != DataApprovalState.APPROVED_HERE &&
-             state != DataApprovalState.ACCEPTED_HERE &&
-             state != DataApprovalState.PARTIALLY_APPROVED_HERE &&
-             state != DataApprovalState.PARTIALLY_ACCEPTED_HERE )
-        {
-            ContextUtils.conflictResponse( response, "Data is not approved here, current state is: " + state.name() );
-            return;
-        }
-
-        if ( !permissions.isMayUnapprove() )
-        {
-            ContextUtils.conflictResponse( response, "Current user is not authorized to unapprove for "
+        List<DataApproval> dataApprovalList = newArrayList();
+
+        for ( DataSet dataSet : dataSets )
+        {
+            DataApprovalPermissions permissions = dataApprovalService
+                .getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
+
+            DataApprovalState state = permissions.getDataApprovalStatus().getDataApprovalState();
+
+            if ( state != DataApprovalState.APPROVED_HERE && state != DataApprovalState.ACCEPTED_HERE &&
+                state != DataApprovalState.PARTIALLY_APPROVED_HERE && state != DataApprovalState.PARTIALLY_ACCEPTED_HERE )
+            {
+                ContextUtils
+                    .conflictResponse( response, "Data is not approved here, current state is: " + state.name() );
+                return;
+            }
+
+            if ( !permissions.isMayUnapprove() )
+            {
+                ContextUtils.conflictResponse( response, "Current user is not authorized to unapprove for "
                     + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
-            return;
+                return;
+            }
+
+            dataApprovalList.add( permissions.getDataApprovalStatus().getDataApproval() );
         }
-        
-        dataApprovalService.deleteDataApproval( permissions.getDataApprovalStatus().getDataApproval() );
+
+        dataApprovalService.deleteDataApprovals( dataApprovalList );
     }
 
     @PreAuthorize( "hasRole('ALL') or hasRole('F_ACCEPT_DATA_LOWER_LEVELS')" )
     @RequestMapping( value = ACCEPTANCES_PATH, method = RequestMethod.POST )
     public void acceptApproval(
-            @RequestParam String ds,
-            @RequestParam String pe,
-            @RequestParam String ou,
-            @RequestParam( required = false ) String cog, HttpServletResponse response )
+        @RequestParam String ds,
+        @RequestParam String pe,
+        @RequestParam String ou,
+        @RequestParam( required = false ) String cog, HttpServletResponse response )
     {
         log.info( "POST " + RESOURCE_PATH + ACCEPTANCES_PATH + "?ds=" + ds + "&pe=" + pe + "&ou=" + ou
-                + ( cog == null ? "" : ( "&cog=" + cog ) ) );
+            + (cog == null ? "" : ("&cog=" + cog)) );
 
         DataSet dataSet = dataSetService.getDataSet( ds );
 
@@ -358,21 +569,23 @@
             }
         }
 
-        DataApprovalPermissions permissions = dataApprovalService.getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
+        DataApprovalPermissions permissions = dataApprovalService
+            .getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
 
         DataApprovalState state = permissions.getDataApprovalStatus().getDataApprovalState();
 
         if ( state != DataApprovalState.APPROVED_HERE &&
-             state != DataApprovalState.PARTIALLY_ACCEPTED_HERE )
+            state != DataApprovalState.PARTIALLY_ACCEPTED_HERE )
         {
-            ContextUtils.conflictResponse( response, "Data is not ready for accepting here, current state is: " + state.name() );
+            ContextUtils.conflictResponse( response,
+                "Data is not ready for accepting here, current state is: " + state.name() );
             return;
         }
 
         if ( !permissions.isMayAccept() )
         {
             ContextUtils.conflictResponse( response, "Current user is not authorized to accept approval for "
-                    + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
+                + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
             return;
         }
 
@@ -383,13 +596,13 @@
     @RequestMapping( value = ACCEPTANCES_PATH, method = RequestMethod.DELETE )
     @ResponseStatus( value = HttpStatus.NO_CONTENT )
     public void unacceptApproval(
-            @RequestParam String ds,
-            @RequestParam String pe,
-            @RequestParam String ou,
-            @RequestParam( required = false ) String cog, HttpServletResponse response )
+        @RequestParam String ds,
+        @RequestParam String pe,
+        @RequestParam String ou,
+        @RequestParam( required = false ) String cog, HttpServletResponse response )
     {
         log.info( "DELETE " + RESOURCE_PATH + ACCEPTANCES_PATH + "?ds=" + ds + "&pe=" + pe + "&ou=" + ou
-                + ( cog == null ? "" : ( "&cog=" + cog ) ) );
+            + (cog == null ? "" : ("&cog=" + cog)) );
 
         DataSet dataSet = dataSetService.getDataSet( ds );
 
@@ -427,12 +640,13 @@
             }
         }
 
-        DataApprovalPermissions permissions = dataApprovalService.getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
+        DataApprovalPermissions permissions = dataApprovalService
+            .getDataApprovalPermissions( dataSet, period, organisationUnit, categoryOptionGroups, null );
 
         DataApprovalState state = permissions.getDataApprovalStatus().getDataApprovalState();
 
         if ( state != DataApprovalState.ACCEPTED_HERE &&
-             state != DataApprovalState.PARTIALLY_ACCEPTED_HERE )
+            state != DataApprovalState.PARTIALLY_ACCEPTED_HERE )
         {
             ContextUtils.conflictResponse( response, "Data is not accepted here, current state is: " + state.name() );
             return;
@@ -441,7 +655,7 @@
         if ( !permissions.isMayUnaccept() )
         {
             ContextUtils.conflictResponse( response, "Current user is not authorized to unaccept approval for "
-                    + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
+                + approvalParameters( dataSet, period, organisationUnit, categoryOptionGroups ) );
             return;
         }
 
@@ -452,11 +666,14 @@
     // Supportive methods
     // -------------------------------------------------------------------------
 
-    private String approvalParameters( DataSet dataSet, Period period, OrganisationUnit organisationUnit, Set<CategoryOptionGroup> categoryOptionGroups )
+    private String approvalParameters( DataSet dataSet, Period period, OrganisationUnit organisationUnit,
+        Set<CategoryOptionGroup> categoryOptionGroups )
     {
         return "dataSet " + dataSet.getName()
-                + ", period " + period.getName()
-                + ", org unit " + organisationUnit.getName()
-                + ", categoryOptionGroup " + ( categoryOptionGroups == null ? "null" : ( (CategoryOptionGroup) categoryOptionGroups.toArray() [0] ).getName() );
+            + ", period " + period.getName()
+            + ", org unit " + organisationUnit.getName()
+            + ", categoryOptionGroup " + (categoryOptionGroups == null ?
+            "null" :
+            ((CategoryOptionGroup) categoryOptionGroups.toArray()[0]).getName());
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/UserSettingController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/UserSettingController.java	2014-06-17 08:31:37 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/UserSettingController.java	2014-08-14 05:46:19 +0000
@@ -38,8 +38,10 @@
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
-
 import javax.servlet.http.HttpServletResponse;
+import org.hisp.dhis.system.util.LocaleUtils;
+import java.io.Serializable;
+import java.util.Locale;
 
 /**
  * @author Lars Helge Overland
@@ -72,13 +74,11 @@
 
         value = value != null ? value : valuePayload;
 
-        if ( username == null )
-        {
-            userSettingService.saveUserSetting( key, value );
-        }
-        else
-        {
-            userSettingService.saveUserSetting( key, value, username );
+        if (username == null) {
+            userSettingService.saveUserSetting(key, valueToSet(key, value));
+
+        } else {
+            userSettingService.saveUserSetting(key, valueToSet(key, value), username);
         }
 
         ContextUtils.okResponse( response, "User setting saved" );
@@ -87,7 +87,7 @@
     @RequestMapping( value = "/{key}", method = RequestMethod.GET, produces = ContextUtils.CONTENT_TYPE_TEXT )
     public @ResponseBody String getSystemSetting( @PathVariable( "key" ) String key, @RequestParam( value = "user", required = false ) String username )
     {
-        return (String) (username == null ? userSettingService.getUserSetting( key ) : userSettingService.getUserSetting( key, username ));
+        return username == null ? getStringValue(key, userSettingService.getUserSetting( key )) : getStringValue( key,userSettingService.getUserSetting( key, username ));
     }
 
     @RequestMapping( value = "/{key}", method = RequestMethod.DELETE )
@@ -95,4 +95,20 @@
     {
         userSettingService.deleteUserSetting( key );
     }
+
+    private Serializable valueToSet(String key, String value){
+        if (key.equals(UserSettingService.KEY_UI_LOCALE) || key.equals(UserSettingService.KEY_DB_LOCALE)) {
+            return LocaleUtils.getLocale(value);
+        } else {
+            return value;
+        }
+    }
+
+    private String getStringValue(String key, Serializable value) {
+        if (key.equals(UserSettingService.KEY_UI_LOCALE) || key.equals(UserSettingService.KEY_DB_LOCALE))
+            return ((Locale) value).getLanguage();
+        else
+            return (String) value;
+    }
+
 }

=== modified file 'dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js'
--- dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2014-08-08 11:18:55 +0000
+++ dhis-2/dhis-web/dhis-web-event-capture/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2014-08-14 05:46:19 +0000
@@ -333,7 +333,7 @@
 {
     return function() {
         return $.ajax( {
-            url: '../api/programStages.json?filter=id:eq:' + id +'&fields=id,name,version,description,reportDateDescription,captureCoordinates,dataEntryForm,minDaysFromStart,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowDateInFuture,compulsory,dataElement[id,name,type,optionSet[id]]]',
+            url: '../api/programStages.json?filter=id:eq:' + id +'&fields=id,name,version,description,reportDateDescription,captureCoordinates,dataEntryForm,minDaysFromStart,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowDateInFuture,compulsory,dataElement[id,name,type,formName,optionSet[id]]]',
             type: 'GET'
         }).done( function( response ){            
             _.each( _.values( response.programStages ), function( programStage ) {                

=== modified file 'dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js'
--- dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-08-13 08:20:00 +0000
+++ dhis-2/dhis-web/dhis-web-tracker-capture/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-08-14 05:46:19 +0000
@@ -456,7 +456,7 @@
             type: 'GET',
             data: 'filter=id:eq:' + id +'&fields=id,name,version,dataEntryForm,captureCoordinates,blockEntryForm,autoGenerateEvent,reportDateDescription,minDaysFromStart,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowDateInFuture,compulsory,dataElement[id,name,formName,type,optionSet[id]]]'
         }).done( function( response ){            
-            _.each( _.values( response.programStages ), function( programStage ) {                
+            _.each( _.values( response.programStages ), function( programStage ) {
                 dhis2.tc.store.set( 'programStages', programStage );
             });
         });