dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #27074
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 13427: Merged branch dataset-approval from Jim Grace. Implements service layer for data approval by data...
Merge authors:
Jim Grace (jimgrace)
Lars Helge Øverland (larshelge)
------------------------------------------------------------
revno: 13427 [merge]
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2013-12-25 16:01:48 +0100
message:
Merged branch dataset-approval from Jim Grace. Implements service layer for data approval by data set.
added:
dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/
dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApproval.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-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStore.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/
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/hibernate/
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java
dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/
dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/
dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/DataApproval.hbm.xml
dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/
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/DataApprovalStoreTest.java
modified:
.bzrignore
dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java
dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java
dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml
dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/batchhandler/DataSetBatchHandler.java
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/AddDataSetAction.java
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/UpdateDataSetAction.java
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/org/hisp/dhis/dataset/i18n_module.properties
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/addDataSet.vm
dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/editDataSet.vm
--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk
Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file '.bzrignore'
--- .bzrignore 2013-05-12 17:11:10 +0000
+++ .bzrignore 2013-12-06 05:00:46 +0000
@@ -25,3 +25,4 @@
./.gitattributes
./.gitignore
./.travis.yml
+.DS_Store
=== added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval'
=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApproval.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApproval.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApproval.java 2013-12-25 15:01:48 +0000
@@ -0,0 +1,178 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2013, 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.io.Serializable;
+import java.util.Date;
+
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+import org.hisp.dhis.user.User;
+
+/**
+ * Records the approval of DataSet values for a given OrganisationUnit and
+ * Period.
+ *
+ * @author Jim Grace
+ */
+public class DataApproval
+ implements Serializable
+{
+ private static final long serialVersionUID = -4034531921928532366L;
+
+ /**
+ * The DataSet for the values being approved.
+ */
+ private int id;
+
+ /**
+ * The DataSet for the values being approved.
+ */
+ private DataSet dataSet;
+
+ /**
+ * The Period of the DataSet values being approved.
+ */
+ private Period period;
+
+ /**
+ * The OrganisationUnit of the DataSet values being approved.
+ */
+ private OrganisationUnit organisationUnit;
+
+ /**
+ * The attribute DataElementCategoryOptionCombo being approved.
+ */
+ private DataElementCategoryOptionCombo attributeOptionCombo;
+
+ /**
+ * The Date (including time) when the DataSet values were approved.
+ */
+ private Date created;
+
+ /**
+ * The User who approved the DataSet values.
+ */
+ private User creator;
+
+ // -------------------------------------------------------------------------
+ // Constructors
+ // -------------------------------------------------------------------------
+
+ public DataApproval()
+ {
+ }
+
+ public DataApproval( DataSet dataSet, Period period, OrganisationUnit organisationUnit,
+ DataElementCategoryOptionCombo attributeOptionCombo, Date created, User creator )
+ {
+ this.dataSet = dataSet;
+ this.period = period;
+ this.organisationUnit = organisationUnit;
+ this.attributeOptionCombo = attributeOptionCombo;
+ this.created = created;
+ this.creator = creator;
+ }
+
+ // -------------------------------------------------------------------------
+ // Getters and setters
+ // -------------------------------------------------------------------------
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public void setId( int id )
+ {
+ this.id = id;
+ }
+
+ public DataSet getDataSet()
+ {
+ return dataSet;
+ }
+
+ public void setDataSet( DataSet dataSet )
+ {
+ this.dataSet = dataSet;
+ }
+
+ public Period getPeriod()
+ {
+ return period;
+ }
+
+ public void setPeriod( Period period )
+ {
+ this.period = period;
+ }
+
+ public OrganisationUnit getOrganisationUnit()
+ {
+ return organisationUnit;
+ }
+
+ public void setOrganisationUnit( OrganisationUnit organisationUnit )
+ {
+ this.organisationUnit = organisationUnit;
+ }
+
+ public DataElementCategoryOptionCombo getAttributeOptionCombo()
+ {
+ return attributeOptionCombo;
+ }
+
+ public void setAttributeOptionCombo( DataElementCategoryOptionCombo attributeOptionCombo )
+ {
+ this.attributeOptionCombo = attributeOptionCombo;
+ }
+
+ public Date getCreated()
+ {
+ return created;
+ }
+
+ public void setCreated( Date created )
+ {
+ this.created = created;
+ }
+
+ public User getCreator()
+ {
+ return creator;
+ }
+
+ public void setCreator( User creator )
+ {
+ this.creator = creator;
+ }
+}
=== added 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 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java 2013-12-25 15:01:48 +0000
@@ -0,0 +1,126 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2013, 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 org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+import org.hisp.dhis.user.User;
+
+/**
+ * @author Jim Grace
+ * @version $Id$
+ */
+public interface DataApprovalService
+{
+ String ID = DataApprovalService.class.getName();
+
+ /**
+ * Adds a DataApproval in order to approve data.
+ *
+ * @param dataApproval the DataApproval to add.
+ */
+ void addDataApproval( DataApproval dataApproval );
+
+ /**
+ * Deletes a 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 dataApproval the DataApproval to delete.
+ */
+ void deleteDataApproval( DataApproval dataApproval );
+
+ /**
+ * Returns the DataApproval object (if any) for a given
+ * dataset, period and organisation unit.
+ *
+ * @param dataSet DataSet for approval
+ * @param period Period for approval
+ * @param organisationUnit OrganisationUnit for approval
+ * @param attributeOptionCombo DataElementCategoryOptionCombo for approval.
+ * @return matching DataApproval object, if any
+ */
+ DataApproval getDataApproval( DataSet dataSet, Period period,
+ OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo );
+
+ /**
+ * Returns the DataApprovalState for a given data set, period and
+ * OrganisationUnit.
+ *
+ * @param dataSet DataSet to check for approval.
+ * @param period Period to check for approval.
+ * @param organisationUnit OrganisationUnit to check for approval.
+ * @return the data approval state.
+ */
+ DataApprovalState getDataApprovalState( DataSet dataSet, Period period,
+ OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo );
+
+ /**
+ * Checks to see whether a user may approve data for a given
+ * organisation unit.
+ *
+ * @param organisationUnit OrganisationUnit to check for approval.
+ * @param user The current user.
+ * @param mayApproveAtSameLevel Tells whether the user has the authority
+ * to approve data for the user's assigned organisation unit(s).
+ * @param mayApproveAtLowerLevels Tells whether the user has the authority
+ * to approve data below the user's assigned organisation unit(s).
+ * @return true if the user may approve, otherwise false
+ */
+ boolean mayApprove( OrganisationUnit organisationUnit, User user,
+ boolean mayApproveAtSameLevel, boolean mayApproveAtLowerLevels );
+
+ /**
+ * Checks to see whether a user may unapprove a given data approval.
+ * <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>
+ * 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>
+ * 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.
+ *
+ * @param dataApproval The data approval to check for access.
+ * @param user The current user.
+ * @param mayApproveAtSameLevel Tells whether the user has the authority
+ * to approve data for the user's assigned organisation unit(s).
+ * @param mayApproveAtLowerLevels Tells whether the user has the authority
+ * to approve data below the user's assigned organisation unit(s).
+ * @return true if the user may unapprove, otherwise false
+ */
+ boolean mayUnapprove( DataApproval dataApproval, User user,
+ boolean mayApproveAtSameLevel, boolean mayApproveAtLowerLevels );
+}
=== added 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 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalState.java 2013-12-21 01:36:12 +0000
@@ -0,0 +1,70 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2013, 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.
+ */
+
+/**
+ * Current state of data approval for a given combination of data set, period
+ * and organisation unit.
+ *
+ * @author Jim Grace
+ * @version $Id$
+ */
+
+public enum DataApprovalState
+{
+ /**
+ * Data in this data set is approved for this period and organisation unit.
+ */
+ APPROVED,
+
+ /**
+ * Data in this data set is ready to be approved for this period and
+ * organisation unit.
+ */
+ READY_FOR_APPROVAL,
+
+ /**
+ * Data in this data set is not yet ready to be approved for this period
+ * and organisation unit, because it is waiting for approval at a
+ * lower-level organisation unit under this one.
+ */
+ WAITING_FOR_LOWER_LEVEL_APPROVAL,
+
+ /**
+ * Data in this data set does not need approval for this period and
+ * organisation unit, for one of the following reasons:
+ * <ul>
+ * <li>Data approval is not enabled globally.</li>
+ * <li>Data approval is not enabled for this data set.</li>
+ * <li>No data is collected for this data set for this organisation
+ * unit or any lower-level organisation units under it.</li>
+ * </ul>
+ */
+ APPROVAL_NOT_NEEDED
+}
=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStore.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalStore.java 2013-12-25 15:01:48 +0000
@@ -0,0 +1,76 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2013, 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 org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+
+/**
+ * Defines the functionality for persisting DataApproval objects.
+ *
+ * @author Jim Grace
+ */
+public interface DataApprovalStore
+// extends GenericStore<DataApproval>
+{
+ String ID = DataApprovalStore.class.getName();
+
+ // -------------------------------------------------------------------------
+ // Basic DataApproval
+ // -------------------------------------------------------------------------
+
+ /**
+ * Adds a DataApproval in order to approve data.
+ *
+ * @param dataApproval the DataApproval to add.
+ */
+ void addDataApproval( DataApproval dataApproval );
+
+ /**
+ * Deletes a DataApproval in order to un-approve data.
+ *
+ * @param dataApproval the DataApproval to delete.
+ */
+ void deleteDataApproval( DataApproval dataApproval );
+
+ /**
+ * Returns the DataApproval object (if any) for a given
+ * dataset, period and organisation unit.
+ *
+ * @param dataSet DataSet for approval
+ * @param period Period for approval
+ * @param organisationUnit OrganisationUnit for approval
+ * @param attributeOptionCombo DataElementCategoryOptionCombo for approval.
+ * @return matching DataApproval object, if any
+ */
+ DataApproval getDataApproval( DataSet dataSet, Period period,
+ OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo );
+}
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataset/DataSet.java 2013-12-22 21:08:30 +0000
@@ -174,6 +174,11 @@
*/
private boolean notifyCompletingUser;
+ /**
+ * Indicating whether to approve data for this data set.
+ */
+ private boolean approveData;
+
// -------------------------------------------------------------------------
// Form properties
// -------------------------------------------------------------------------
@@ -691,6 +696,19 @@
@JsonProperty
@JsonView({ DetailedView.class, ExportView.class, WithoutOrganisationUnitsView.class })
@JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+ public boolean isApproveData()
+ {
+ return approveData;
+ }
+
+ public void setApproveData( boolean approveData )
+ {
+ this.approveData = approveData;
+ }
+
+ @JsonProperty
+ @JsonView( { DetailedView.class, ExportView.class } )
+ @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
public boolean isAllowFuturePeriods()
{
return allowFuturePeriods;
=== added directory 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval'
=== added 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 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java 2013-12-25 15:01:48 +0000
@@ -0,0 +1,218 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2013, 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 org.apache.commons.collections.CollectionUtils;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+import org.hisp.dhis.user.User;
+
+/**
+ * @author Jim Grace
+ */
+public class DefaultDataApprovalService
+ implements DataApprovalService
+{
+ // -------------------------------------------------------------------------
+ // Dependencies
+ // -------------------------------------------------------------------------
+
+ private DataApprovalStore dataApprovalStore;
+
+ public void setDataApprovalStore( DataApprovalStore dataApprovalStore )
+ {
+ this.dataApprovalStore = dataApprovalStore;
+ }
+
+ // -------------------------------------------------------------------------
+ // DataApproval
+ // -------------------------------------------------------------------------
+
+ public void addDataApproval( DataApproval dataApproval )
+ {
+ dataApprovalStore.addDataApproval( dataApproval );
+ }
+
+ public void deleteDataApproval( DataApproval dataApproval )
+ {
+ dataApprovalStore.deleteDataApproval( dataApproval );
+
+ for ( OrganisationUnit ancestor : dataApproval.getOrganisationUnit().getAncestors() )
+ {
+ DataApproval ancestorApproval = dataApprovalStore.getDataApproval(
+ dataApproval.getDataSet(), dataApproval.getPeriod(), ancestor, dataApproval.getAttributeOptionCombo() );
+
+ if ( ancestorApproval != null ) {
+ dataApprovalStore.deleteDataApproval ( ancestorApproval );
+ }
+ }
+ }
+
+ public DataApproval getDataApproval( DataSet dataSet, Period period, OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo )
+ {
+ return dataApprovalStore.getDataApproval( dataSet, period, organisationUnit, attributeOptionCombo );
+ }
+
+ public DataApprovalState getDataApprovalState( DataSet dataSet, Period period, OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo )
+ {
+ if ( !dataSet.isApproveData() )
+ {
+ return DataApprovalState.APPROVAL_NOT_NEEDED;
+ }
+
+ if ( null != dataApprovalStore.getDataApproval( dataSet, period, organisationUnit, attributeOptionCombo ) )
+ {
+ return DataApprovalState.APPROVED;
+ }
+
+ boolean approvedAtLowerLevels = false; // Until proven otherwise
+
+ for ( OrganisationUnit child : organisationUnit.getChildren() )
+ {
+ switch ( getDataApprovalState( dataSet, period, child, attributeOptionCombo ) )
+ {
+ //
+ // If ready or waiting at a lower level, return
+ // WAITING_FOR_LOWER_LEVEL_APPROVAL at this level.
+ //
+ case READY_FOR_APPROVAL:
+ case WAITING_FOR_LOWER_LEVEL_APPROVAL:
+ return DataApprovalState.WAITING_FOR_LOWER_LEVEL_APPROVAL;
+
+ case APPROVED:
+ approvedAtLowerLevels = true;
+ break;
+
+ case APPROVAL_NOT_NEEDED:
+ break; // Do nothing.
+ }
+
+ }
+
+ //
+ // If approved at lower levels (and not ready or waiting at any),
+ // and/or if data is configured for entry at this level (whether or
+ // not it has been entered), return READY_FOR_APPROVAL.
+ //
+ if ( approvedAtLowerLevels ||
+ organisationUnit.getAllDataSets().contains ( dataSet ) )
+ {
+ return DataApprovalState.READY_FOR_APPROVAL;
+ }
+
+ //
+ // Finally, if we haven't seen any approval action at lower levels,
+ // and this level is not configured for data entry from this data set,
+ // then return APPROVAL_NOT_NEEDED.
+ //
+ return DataApprovalState.APPROVAL_NOT_NEEDED;
+ }
+
+ public boolean mayApprove( OrganisationUnit source, User user,
+ boolean mayApproveAtSameLevel, boolean mayApproveAtLowerLevels )
+ {
+ if ( mayApproveAtSameLevel && user.getOrganisationUnits().contains( source ) )
+ {
+ return true;
+ }
+
+ if ( mayApproveAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(), source.getAncestors() ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean mayUnapprove( DataApproval dataApproval, User user,
+ boolean mayApproveAtSameLevel, boolean mayApproveAtLowerLevels )
+ {
+ if ( isAuthorizedToUnapprove( dataApproval.getOrganisationUnit(), user, mayApproveAtSameLevel, mayApproveAtLowerLevels ) )
+ {
+ // Check approvals at higher levels that may block this unapproval:
+
+ for ( OrganisationUnit ancestor : dataApproval.getOrganisationUnit().getAncestors() )
+ {
+ DataApproval ancestorDataApproval = dataApprovalStore.getDataApproval(
+ dataApproval.getDataSet(), dataApproval.getPeriod(), ancestor, dataApproval.getAttributeOptionCombo() );
+
+ if ( ancestorDataApproval != null &&
+ !isAuthorizedToUnapprove( ancestor, user, mayApproveAtSameLevel, mayApproveAtLowerLevels ) )
+ {
+ return false; // Could unapprove at that level, but higher-level approval is blocking.
+ }
+ }
+
+ return true; // May unapprove at that level, and no higher-level approval is blocking.
+ }
+
+ return false; // May not unapprove at that level.
+ }
+
+ // -------------------------------------------------------------------------
+ // Supportive methods
+ // -------------------------------------------------------------------------
+
+ /**
+ * Tests whether the user is authorized to unapprove for this organisation
+ * unit.
+ * <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.
+ *
+ * @param source OrganisationUnit to check for approval.
+ * @param user The current user.
+ * @param mayApproveAtSameLevel Tells whether the user has the authority
+ * to approve data for the user's assigned organisation unit(s).
+ * @param mayApproveAtLowerLevels Tells whether the user has the authority
+ * to approve data below the user's assigned organisation unit(s).
+ * @return true if the user may approve, otherwise false
+ */
+ private boolean isAuthorizedToUnapprove( OrganisationUnit source, User user,
+ boolean mayApproveAtSameLevel, boolean mayApproveAtLowerLevels )
+ {
+ if ( mayApprove( source, user, mayApproveAtSameLevel, mayApproveAtLowerLevels ) )
+ {
+ return true;
+ }
+
+ for ( OrganisationUnit ancestor : source.getAncestors() )
+ {
+ if ( mayApprove( ancestor, user, mayApproveAtSameLevel, mayApproveAtLowerLevels ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
=== added directory 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate'
=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java 2013-12-25 15:01:48 +0000
@@ -0,0 +1,90 @@
+package org.hisp.dhis.dataapproval.hibernate;
+
+/*
+ * Copyright (c) 2004-2013, 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 org.hibernate.Criteria;
+import org.hibernate.criterion.Restrictions;
+import org.hisp.dhis.dataapproval.DataApproval;
+import org.hisp.dhis.dataapproval.DataApprovalStore;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.hibernate.HibernateGenericStore;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.period.Period;
+import org.hisp.dhis.period.PeriodService;
+
+/**
+ * @author Jim Grace
+ * @version $Id$
+ */
+public class HibernateDataApprovalStore
+ extends HibernateGenericStore<DataApproval>
+ implements DataApprovalStore
+{
+ // -------------------------------------------------------------------------
+ // Dependencies
+ // -------------------------------------------------------------------------
+
+ private PeriodService periodService;
+
+ public void setPeriodService( PeriodService periodService )
+ {
+ this.periodService = periodService;
+ }
+
+ // -------------------------------------------------------------------------
+ // DataApproval
+ // -------------------------------------------------------------------------
+
+ public void addDataApproval( DataApproval dataApproval )
+ {
+ dataApproval.setPeriod( periodService.reloadPeriod( dataApproval.getPeriod() ) );
+
+ save( dataApproval );
+ }
+
+ public void deleteDataApproval( DataApproval dataApproval )
+ {
+ delete( dataApproval );
+ }
+
+ public DataApproval getDataApproval( DataSet dataSet, Period period,
+ OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo )
+ {
+ Period storedPeriod = periodService.reloadPeriod( period );
+
+ Criteria criteria = getCriteria();
+ criteria.add( Restrictions.eq( "dataSet", dataSet ) );
+ criteria.add( Restrictions.eq( "period", storedPeriod ) );
+ criteria.add( Restrictions.eq( "organisationUnit", organisationUnit ) );
+ criteria.add( Restrictions.eq( "attributeOptionCombo", attributeOptionCombo ) );
+
+ return (DataApproval) criteria.uniqueResult();
+ }
+}
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java 2013-12-22 21:08:30 +0000
@@ -410,6 +410,7 @@
executeSql( "update dataset set allowfutureperiods = false where allowfutureperiods is null" );
executeSql( "update dataset set validcompleteonly = false where validcompleteonly is null" );
executeSql( "update dataset set notifycompletinguser = false where notifycompletinguser is null" );
+ executeSql( "update dataset set approvedata = false where approvedata is null" );
executeSql( "update dataelement set zeroissignificant = false where zeroissignificant is null" );
executeSql( "update organisationunit set haspatients = false where haspatients is null" );
executeSql( "update dataset set expirydays = 0 where expirydays is null" );
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2013-12-23 09:13:02 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2013-12-25 15:01:48 +0000
@@ -56,6 +56,13 @@
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
+ <bean id="org.hisp.dhis.dataapproval.DataApprovalStore" class="org.hisp.dhis.dataapproval.hibernate.HibernateDataApprovalStore">
+ <property name="clazz" value="org.hisp.dhis.dataapproval.DataApproval" />
+ <property name="sessionFactory" ref="sessionFactory" />
+ <property name="periodService" ref="org.hisp.dhis.period.PeriodService" />
+ </bean>
+
+ <!--@author Ovidiu Rosu <rosu.ovi@xxxxxxxxx>-->
<bean id="org.hisp.dhis.filter.MetaDataFilterStore" class="org.hisp.dhis.metadatafilter.hibernate.HibernateMetaDataFilterStore">
<property name="clazz" value="org.hisp.dhis.filter.MetaDataFilter" />
<property name="sessionFactory" ref="sessionFactory" />
@@ -375,6 +382,10 @@
<property name="dataValueAuditStore" ref="org.hisp.dhis.datavalue.DataValueAuditStore" />
</bean>
+ <bean id="org.hisp.dhis.dataapproval.DataApprovalService" class="org.hisp.dhis.dataapproval.DefaultDataApprovalService">
+ <property name="dataApprovalStore" ref="org.hisp.dhis.dataapproval.DataApprovalStore" />
+ </bean>
+
<bean id="org.hisp.dhis.dataelement.DataElementService" class="org.hisp.dhis.dataelement.DefaultDataElementService">
<property name="dataElementStore" ref="org.hisp.dhis.dataelement.DataElementStore" />
<property name="dataElementGroupStore" ref="org.hisp.dhis.dataelement.DataElementGroupStore" />
=== added directory 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval'
=== added directory 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate'
=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/DataApproval.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/DataApproval.hbm.xml 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/DataApproval.hbm.xml 2013-12-25 15:01:48 +0000
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"
+ [<!ENTITY identifiableProperties SYSTEM "classpath://org/hisp/dhis/common/identifiableProperties.hbm">]
+ >
+<hibernate-mapping>
+ <class name="org.hisp.dhis.dataapproval.DataApproval" table="dataapproval">
+
+ <id name="id" column="dataapprovalid">
+ <generator class="native" />
+ </id>
+
+ <properties name="dataapproval_dataset_period_orgunit_unique_key" unique="true">
+ <many-to-one name="dataSet" class="org.hisp.dhis.dataset.DataSet" column="datasetid" foreign-key="fk_dataapproval_datasetid" />
+ <many-to-one name="period" class="org.hisp.dhis.period.Period" column="periodid" foreign-key="fk_dataapproval_periodid" />
+ <many-to-one name="organisationUnit" class="org.hisp.dhis.organisationunit.OrganisationUnit" column="organisationunitid" foreign-key="fk_dataapproval_organisationunitid" />
+ <many-to-one name="attributeOptionCombo" class="org.hisp.dhis.dataelement.DataElementCategoryOptionCombo" column="attributeoptioncomboid" foreign-key="fK_dataapproval_attributeoptioncomboid" />
+ </properties>
+
+ <property name="created" column="created" type="timestamp" />
+
+ <many-to-one name="creator" class="org.hisp.dhis.user.User" column="creator" foreign-key="fk_dataapproval_creator" />
+
+ </class>
+</hibernate-mapping>
=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataset/hibernate/DataSet.hbm.xml 2013-12-22 21:08:30 +0000
@@ -83,9 +83,11 @@
<many-to-one name="notificationRecipients" class="org.hisp.dhis.user.UserGroup"
foreign-key="fk_dataset_notificationrecipients" />
- <property name="notifyCompletingUser" />
-
- <!-- Form properties -->
+ <property name="notifyCompletingUser" />
+
+ <property name="approveData" />
+
+ <!-- Form properties -->
<property name="allowFuturePeriods" />
=== added directory 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval'
=== added 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 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java 2013-12-25 15:01:48 +0000
@@ -0,0 +1,379 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2013, 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.util.Date;
+
+import org.hisp.dhis.DhisSpringTest;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.dataset.DataSetService;
+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.User;
+import org.hisp.dhis.user.UserService;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author Jim Grace
+ * @version $Id$
+ */
+public class DataApprovalServiceTest
+ extends DhisSpringTest
+{
+ @Autowired
+ private DataApprovalService dataApprovalService;
+
+ @Autowired
+ private PeriodService periodService;
+
+ @Autowired
+ private DataElementCategoryService categoryService;
+
+ @Autowired
+ private DataSetService dataSetService;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private OrganisationUnitService organisationUnitService;
+
+ // -------------------------------------------------------------------------
+ // Supporting data
+ // -------------------------------------------------------------------------
+
+ private DataSet dataSetA;
+
+ private DataSet dataSetB;
+
+ private Period periodA;
+
+ private Period periodB;
+
+ private OrganisationUnit organisationUnitA;
+
+ private OrganisationUnit organisationUnitB;
+
+ private OrganisationUnit organisationUnitC;
+
+ private OrganisationUnit organisationUnitD;
+
+ private User userA;
+
+ private User userB;
+
+ private DataElementCategoryOptionCombo attributeOptionCombo;
+
+ // -------------------------------------------------------------------------
+ // Set up/tear down
+ // -------------------------------------------------------------------------
+
+ @Override
+ public void setUpTest() throws Exception
+ {
+ // ---------------------------------------------------------------------
+ // Add supporting data
+ // ---------------------------------------------------------------------
+
+ PeriodType periodType = PeriodType.getPeriodTypeByName( "Monthly" );
+
+ dataSetA = createDataSet( 'A', periodType );
+ dataSetB = createDataSet( 'B', periodType );
+
+ dataSetService.addDataSet( dataSetA );
+ dataSetService.addDataSet( dataSetB );
+
+ periodA = createPeriod( getDay( 5 ), getDay( 6 ) );
+ periodB = createPeriod( getDay( 6 ), getDay( 7 ) );
+
+ periodService.addPeriod( periodA );
+ periodService.addPeriod( periodB );
+
+ organisationUnitA = createOrganisationUnit( 'A' );
+ organisationUnitB = createOrganisationUnit( 'B', organisationUnitA );
+ organisationUnitC = createOrganisationUnit( 'C', organisationUnitB );
+ organisationUnitD = createOrganisationUnit( 'D', organisationUnitC );
+
+ organisationUnitService.addOrganisationUnit( organisationUnitA );
+ organisationUnitService.addOrganisationUnit( organisationUnitB );
+ organisationUnitService.addOrganisationUnit( organisationUnitC );
+ organisationUnitService.addOrganisationUnit( organisationUnitD );
+
+ userA = createUser( 'A' );
+ userB = createUser( 'B' );
+
+ userService.addUser( userA );
+ userService.addUser( userB );
+
+ attributeOptionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
+ }
+
+ // -------------------------------------------------------------------------
+ // Basic DataApproval
+ // -------------------------------------------------------------------------
+
+ @Test
+ public void testAddAndGetDataApproval() throws Exception
+ {
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalB = new DataApproval( dataSetA, periodA, organisationUnitB, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalC = new DataApproval( dataSetA, periodB, organisationUnitA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalD = new DataApproval( dataSetB, periodA, organisationUnitA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalE;
+
+ dataApprovalService.addDataApproval( dataApprovalA );
+ dataApprovalService.addDataApproval( dataApprovalB );
+ dataApprovalService.addDataApproval( dataApprovalC );
+ dataApprovalService.addDataApproval( dataApprovalD );
+
+ dataApprovalA = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo );
+ assertNotNull( dataApprovalA );
+ assertEquals( dataSetA.getId(), dataApprovalA.getDataSet().getId() );
+ assertEquals( periodA, dataApprovalA.getPeriod() );
+ assertEquals( organisationUnitA.getId(), dataApprovalA.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalA.getCreated() );
+ assertEquals( userA.getId(), dataApprovalA.getCreator().getId() );
+
+ dataApprovalB = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitB, attributeOptionCombo );
+ assertNotNull( dataApprovalB );
+ assertEquals( dataSetA.getId(), dataApprovalB.getDataSet().getId() );
+ assertEquals( periodA, dataApprovalB.getPeriod() );
+ assertEquals( organisationUnitB.getId(), dataApprovalB.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalB.getCreated() );
+ assertEquals( userA.getId(), dataApprovalB.getCreator().getId() );
+
+ dataApprovalC = dataApprovalService.getDataApproval( dataSetA, periodB, organisationUnitA, attributeOptionCombo );
+ assertNotNull( dataApprovalC );
+ assertEquals( dataSetA.getId(), dataApprovalC.getDataSet().getId() );
+ assertEquals( periodB, dataApprovalC.getPeriod() );
+ assertEquals( organisationUnitA.getId(), dataApprovalC.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalC.getCreated() );
+ assertEquals( userA.getId(), dataApprovalC.getCreator().getId() );
+
+ dataApprovalD = dataApprovalService.getDataApproval( dataSetB, periodA, organisationUnitA, attributeOptionCombo );
+ assertNotNull( dataApprovalD );
+ assertEquals( dataSetB.getId(), dataApprovalD.getDataSet().getId() );
+ assertEquals( periodA, dataApprovalD.getPeriod() );
+ assertEquals( organisationUnitA.getId(), dataApprovalD.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalD.getCreated() );
+ assertEquals( userA.getId(), dataApprovalD.getCreator().getId() );
+
+ dataApprovalE = dataApprovalService.getDataApproval( dataSetB, periodB, organisationUnitB, attributeOptionCombo );
+ assertNull( dataApprovalE );
+ }
+
+ @Test
+ public void testAddDuplicateDataApproval() throws Exception
+ {
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalB = new DataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo, date, userA );
+
+ dataApprovalService.addDataApproval( dataApprovalA );
+
+ try
+ {
+ dataApprovalService.addDataApproval( dataApprovalB );
+ fail("Should give unique constraint violation");
+ }
+ catch ( Exception e )
+ {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testDeleteDataApproval() throws Exception
+ {
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalB = new DataApproval( dataSetA, periodA, organisationUnitB, attributeOptionCombo, date, userB );
+ DataApproval testA;
+ DataApproval testB;
+
+ dataApprovalService.addDataApproval( dataApprovalA );
+ dataApprovalService.addDataApproval( dataApprovalB );
+
+ testA = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo );
+ assertNotNull( testA );
+
+ testB = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitB, attributeOptionCombo );
+ assertNotNull( testB );
+
+ dataApprovalService.deleteDataApproval( dataApprovalA ); // Only A should be deleted.
+
+ testA = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo );
+ assertNull( testA );
+
+ testB = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitB, attributeOptionCombo );
+ assertNotNull( testB );
+
+ dataApprovalService.addDataApproval( dataApprovalA );
+ dataApprovalService.deleteDataApproval( dataApprovalB ); // A and B should both be deleted.
+
+ testA = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo );
+ assertNull( testA );
+
+ testB = dataApprovalService.getDataApproval( dataSetA, periodA, organisationUnitB, attributeOptionCombo );
+ assertNull( testB );
+ }
+
+ @Test
+ public void testGetDataApprovalState() throws Exception
+ {
+ // Not enabled.
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitA, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitB, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitC, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitD, attributeOptionCombo ) );
+
+ // Enabled for data set, but data set not associated with organisation unit.
+ dataSetA.setApproveData( true );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitA, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitB, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitC, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitD, attributeOptionCombo ) );
+
+ // Enabled for data set, and associated with organisation unit C.
+ organisationUnitC.addDataSet( dataSetA );
+ assertEquals( DataApprovalState.WAITING_FOR_LOWER_LEVEL_APPROVAL, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitA, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.WAITING_FOR_LOWER_LEVEL_APPROVAL, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitB, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.READY_FOR_APPROVAL, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitC, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitD, attributeOptionCombo ) );
+
+ // Approved for sourceC
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, organisationUnitC, attributeOptionCombo, date, userA );
+ dataApprovalService.addDataApproval( dataApprovalA );
+ assertEquals( DataApprovalState.WAITING_FOR_LOWER_LEVEL_APPROVAL, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitA, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.READY_FOR_APPROVAL, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitB, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitC, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitD, attributeOptionCombo ) );
+
+ // Disable approval for dataset.
+ dataSetA.setApproveData( false );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitA, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitB, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitC, attributeOptionCombo ) );
+ assertEquals( DataApprovalState.APPROVAL_NOT_NEEDED, dataApprovalService.getDataApprovalState( dataSetA, periodA, organisationUnitD, attributeOptionCombo ) );
+ }
+
+ @Test
+ public void testMayApprove() throws Exception
+ {
+ userB.addOrganisationUnit( organisationUnitB );
+
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitA, userB, false, false ) );
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitB, userB, false, false ) );
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitC, userB, false, false ) );
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitD, userB, false, false ) );
+
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitA, userB, false, true ) );
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitB, userB, false, true ) );
+ assertEquals( true, dataApprovalService.mayApprove( organisationUnitC, userB, false, true ) );
+ assertEquals( true, dataApprovalService.mayApprove( organisationUnitD, userB, false, true ) );
+
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitA, userB, true, false ) );
+ assertEquals( true, dataApprovalService.mayApprove( organisationUnitB, userB, true, false ) );
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitC, userB, true, false ) );
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitD, userB, true, false ) );
+
+ assertEquals( false, dataApprovalService.mayApprove( organisationUnitA, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayApprove( organisationUnitB, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayApprove( organisationUnitC, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayApprove( organisationUnitD, userB, true, true ) );
+ }
+
+ @Test
+ public void testMayUnapprove() throws Exception
+ {
+ userA.addOrganisationUnit( organisationUnitA );
+ userB.addOrganisationUnit( organisationUnitB );
+
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, organisationUnitA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalB = new DataApproval( dataSetA, periodA, organisationUnitB, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalC = new DataApproval( dataSetA, periodA, organisationUnitC, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalD = new DataApproval( dataSetA, periodA, organisationUnitD, attributeOptionCombo, date, userA );
+
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userB, false, false ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalB, userB, false, false ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalC, userB, false, false ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalD, userB, false, false ) );
+
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userB, false, true ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalB, userB, false, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalC, userB, false, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalD, userB, false, true ) );
+
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userB, true, false ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalB, userB, true, false ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalC, userB, true, false ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalD, userB, true, false ) );
+
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalB, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalC, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalD, userB, true, true ) );
+
+ // If the organisation unit has no parent:
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userA, false, false ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userA, false, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalA, userA, true, false ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalA, userA, true, true ) );
+
+ dataApprovalService.addDataApproval( dataApprovalB );
+ dataApprovalService.addDataApproval( dataApprovalC );
+ dataApprovalService.addDataApproval( dataApprovalD );
+
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalB, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalC, userB, true, true ) );
+ assertEquals( true, dataApprovalService.mayUnapprove( dataApprovalD, userB, true, true ) );
+
+ dataApprovalService.addDataApproval( dataApprovalA );
+
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalA, userB, true, true ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalB, userB, true, true ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalC, userB, true, true ) );
+ assertEquals( false, dataApprovalService.mayUnapprove( dataApprovalD, userB, true, true ) );
+ }
+}
=== added file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalStoreTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalStoreTest.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalStoreTest.java 2013-12-25 15:01:48 +0000
@@ -0,0 +1,255 @@
+package org.hisp.dhis.dataapproval;
+
+/*
+ * Copyright (c) 2004-2013, 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.util.Date;
+
+import org.hisp.dhis.DhisSpringTest;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.dataset.DataSetService;
+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.User;
+import org.hisp.dhis.user.UserService;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author Jim Grace
+ * @version $Id$
+ */
+public class DataApprovalStoreTest
+ extends DhisSpringTest
+{
+ @Autowired
+ private DataApprovalStore dataApprovalStore;
+
+ @Autowired
+ private PeriodService periodService;
+
+ @Autowired
+ private DataElementCategoryService categoryService;
+
+ @Autowired
+ private DataSetService dataSetService;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private OrganisationUnitService organisationUnitService;
+
+ // -------------------------------------------------------------------------
+ // Supporting data
+ // -------------------------------------------------------------------------
+
+ private DataSet dataSetA;
+
+ private DataSet dataSetB;
+
+ private Period periodA;
+
+ private Period periodB;
+
+ private OrganisationUnit sourceA;
+
+ private OrganisationUnit sourceB;
+
+ private OrganisationUnit sourceC;
+
+ private OrganisationUnit sourceD;
+
+ private User userA;
+
+ private User userB;
+
+ private DataElementCategoryOptionCombo attributeOptionCombo;
+
+ // -------------------------------------------------------------------------
+ // Set up/tear down
+ // -------------------------------------------------------------------------
+
+ @Override
+ public void setUpTest() throws Exception
+ {
+ // ---------------------------------------------------------------------
+ // Add supporting data
+ // ---------------------------------------------------------------------
+
+ PeriodType periodType = PeriodType.getPeriodTypeByName( "Monthly" );
+
+ dataSetA = createDataSet( 'A', periodType );
+ dataSetB = createDataSet( 'B', periodType );
+
+ dataSetService.addDataSet( dataSetA );
+ dataSetService.addDataSet( dataSetB );
+
+ periodA = createPeriod( getDay( 5 ), getDay( 6 ) );
+ periodB = createPeriod( getDay( 6 ), getDay( 7 ) );
+
+ periodService.addPeriod( periodA );
+ periodService.addPeriod( periodB );
+
+ sourceA = createOrganisationUnit( 'A' );
+ sourceB = createOrganisationUnit( 'B', sourceA );
+ sourceC = createOrganisationUnit( 'C', sourceB );
+ sourceD = createOrganisationUnit( 'D', sourceC );
+
+ organisationUnitService.addOrganisationUnit( sourceA );
+ organisationUnitService.addOrganisationUnit( sourceB );
+ organisationUnitService.addOrganisationUnit( sourceC );
+ organisationUnitService.addOrganisationUnit( sourceD );
+
+ userA = createUser( 'A' );
+ userB = createUser( 'B' );
+
+ userService.addUser( userA );
+ userService.addUser( userB );
+
+ attributeOptionCombo = categoryService.getDefaultDataElementCategoryOptionCombo();
+ }
+
+ // -------------------------------------------------------------------------
+ // Basic DataApproval
+ // -------------------------------------------------------------------------
+
+ @Test
+ public void testAddAndGetDataApproval() throws Exception
+ {
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, sourceA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalB = new DataApproval( dataSetA, periodA, sourceB, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalC = new DataApproval( dataSetA, periodB, sourceA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalD = new DataApproval( dataSetB, periodA, sourceA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalE;
+
+ dataApprovalStore.addDataApproval( dataApprovalA );
+ dataApprovalStore.addDataApproval( dataApprovalB );
+ dataApprovalStore.addDataApproval( dataApprovalC );
+ dataApprovalStore.addDataApproval( dataApprovalD );
+
+ dataApprovalA = dataApprovalStore.getDataApproval( dataSetA, periodA, sourceA, attributeOptionCombo );
+ assertNotNull( dataApprovalA );
+ assertEquals( dataSetA.getId(), dataApprovalA.getDataSet().getId() );
+ assertEquals( periodA, dataApprovalA.getPeriod() );
+ assertEquals( sourceA.getId(), dataApprovalA.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalA.getCreated() );
+ assertEquals( userA.getId(), dataApprovalA.getCreator().getId() );
+
+ dataApprovalB = dataApprovalStore.getDataApproval( dataSetA, periodA, sourceB, attributeOptionCombo );
+ assertNotNull( dataApprovalB );
+ assertEquals( dataSetA.getId(), dataApprovalB.getDataSet().getId() );
+ assertEquals( periodA, dataApprovalB.getPeriod() );
+ assertEquals( sourceB.getId(), dataApprovalB.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalB.getCreated() );
+ assertEquals( userA.getId(), dataApprovalB.getCreator().getId() );
+
+ dataApprovalC = dataApprovalStore.getDataApproval( dataSetA, periodB, sourceA, attributeOptionCombo );
+ assertNotNull( dataApprovalC );
+ assertEquals( dataSetA.getId(), dataApprovalC.getDataSet().getId() );
+ assertEquals( periodB, dataApprovalC.getPeriod() );
+ assertEquals( sourceA.getId(), dataApprovalC.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalC.getCreated() );
+ assertEquals( userA.getId(), dataApprovalC.getCreator().getId() );
+
+ dataApprovalD = dataApprovalStore.getDataApproval( dataSetB, periodA, sourceA, attributeOptionCombo );
+ assertNotNull( dataApprovalD );
+ assertEquals( dataSetB.getId(), dataApprovalD.getDataSet().getId() );
+ assertEquals( periodA, dataApprovalD.getPeriod() );
+ assertEquals( sourceA.getId(), dataApprovalD.getOrganisationUnit().getId() );
+ assertEquals( date, dataApprovalD.getCreated() );
+ assertEquals( userA.getId(), dataApprovalD.getCreator().getId() );
+
+ dataApprovalE = dataApprovalStore.getDataApproval( dataSetB, periodB, sourceB, attributeOptionCombo );
+ assertNull( dataApprovalE );
+ }
+
+ @Test
+ public void testAddDuplicateDataApproval() throws Exception
+ {
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, sourceA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalB = new DataApproval( dataSetA, periodA, sourceA, attributeOptionCombo, date, userA );
+
+ dataApprovalStore.addDataApproval( dataApprovalA );
+
+ try
+ {
+ dataApprovalStore.addDataApproval( dataApprovalB );
+ fail("Should give unique constraint violation");
+ }
+ catch ( Exception e )
+ {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testDeleteDataApproval() throws Exception
+ {
+ Date date = new Date();
+ DataApproval dataApprovalA = new DataApproval( dataSetA, periodA, sourceA, attributeOptionCombo, date, userA );
+ DataApproval dataApprovalB = new DataApproval( dataSetB, periodB, sourceB, attributeOptionCombo, date, userB );
+
+ dataApprovalStore.addDataApproval( dataApprovalA );
+ dataApprovalStore.addDataApproval( dataApprovalB );
+
+ dataApprovalA = dataApprovalStore.getDataApproval( dataSetA, periodA, sourceA, attributeOptionCombo );
+ assertNotNull( dataApprovalA );
+
+ dataApprovalB = dataApprovalStore.getDataApproval( dataSetB, periodB, sourceB, attributeOptionCombo );
+ assertNotNull( dataApprovalB );
+
+ dataApprovalStore.deleteDataApproval( dataApprovalA );
+
+ dataApprovalA = dataApprovalStore.getDataApproval( dataSetA, periodA, sourceA, attributeOptionCombo );
+ assertNull( dataApprovalA );
+
+ dataApprovalB = dataApprovalStore.getDataApproval( dataSetB, periodB, sourceB, attributeOptionCombo );
+ assertNotNull( dataApprovalB );
+
+ dataApprovalStore.deleteDataApproval( dataApprovalB );
+
+ dataApprovalA = dataApprovalStore.getDataApproval( dataSetA, periodA, sourceA, attributeOptionCombo );
+ assertNull( dataApprovalA );
+
+ dataApprovalB = dataApprovalStore.getDataApproval( dataSetB, periodB, sourceB, attributeOptionCombo );
+ assertNull( dataApprovalB );
+ }
+}
=== modified file 'dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/batchhandler/DataSetBatchHandler.java'
--- dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/batchhandler/DataSetBatchHandler.java 2013-09-30 11:02:47 +0000
+++ dhis-2/dhis-support/dhis-support-jdbc/src/main/java/org/hisp/dhis/jdbc/batchhandler/DataSetBatchHandler.java 2013-12-21 01:36:12 +0000
@@ -103,6 +103,7 @@
statementBuilder.setColumn( "expirydays" );
statementBuilder.setColumn( "timelydays" );
statementBuilder.setColumn( "notifycompletinguser" );
+ statementBuilder.setColumn( "approvedata" );
statementBuilder.setColumn( "skipaggregation" );
statementBuilder.setColumn( "fieldcombinationrequired" );
statementBuilder.setColumn( "validcompleteonly" );
@@ -126,6 +127,7 @@
statementBuilder.setValue( dataSet.getExpiryDays() );
statementBuilder.setValue( dataSet.getTimelyDays() );
statementBuilder.setValue( dataSet.isNotifyCompletingUser() );
+ statementBuilder.setValue( dataSet.isApproveData() );
statementBuilder.setValue( dataSet.isSkipAggregation() );
statementBuilder.setValue( dataSet.isFieldCombinationRequired() );
statementBuilder.setValue( dataSet.isValidCompleteOnly() );
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/AddDataSetAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/AddDataSetAction.java 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/AddDataSetAction.java 2013-12-22 21:08:30 +0000
@@ -168,6 +168,13 @@
this.notifyCompletingUser = notifyCompletingUser;
}
+ private boolean approveData;
+
+ public void setApproveData( boolean approveData )
+ {
+ this.approveData = approveData;
+ }
+
private boolean skipAggregation;
public void setSkipAggregation( boolean skipAggregation )
@@ -310,6 +317,7 @@
dataSet.setFieldCombinationRequired( fieldCombinationRequired );
dataSet.setValidCompleteOnly( validCompleteOnly );
dataSet.setNotifyCompletingUser( notifyCompletingUser );
+ dataSet.setApproveData( approveData );
dataSet.setSkipOffline( skipOffline );
dataSet.setDataElementDecoration( dataElementDecoration );
dataSet.setRenderAsTabs( renderAsTabs );
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/UpdateDataSetAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/UpdateDataSetAction.java 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/java/org/hisp/dhis/dataset/action/UpdateDataSetAction.java 2013-12-22 21:08:30 +0000
@@ -178,6 +178,13 @@
this.notifyCompletingUser = notifyCompletingUser;
}
+ private boolean approveData;
+
+ public void setApproveData( boolean approveData )
+ {
+ this.approveData = approveData;
+ }
+
private boolean skipAggregation;
public void setSkipAggregation( boolean skipAggregation )
@@ -335,6 +342,7 @@
dataSet.setFieldCombinationRequired( fieldCombinationRequired );
dataSet.setValidCompleteOnly( validCompleteOnly );
dataSet.setNotifyCompletingUser( notifyCompletingUser );
+ dataSet.setApproveData( approveData );
dataSet.setSkipOffline( skipOffline );
dataSet.setDataElementDecoration( dataElementDecoration );
dataSet.setRenderAsTabs( renderAsTabs );
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/org/hisp/dhis/dataset/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/org/hisp/dhis/dataset/i18n_module.properties 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/resources/org/hisp/dhis/dataset/i18n_module.properties 2013-12-22 21:08:30 +0000
@@ -106,6 +106,7 @@
object_not_deleted_associated_by_objects=Object not deleted because it is associated by objects of type
auto_save_data_entry_forms=Auto-save data entry forms
notify_completing_user=Send notification to completing user
+approve_data=Approve data
insert_images=Insert images
dataelementdecoration=Data element decoration
pdf_data_entry_form=Get PDF for Data Entry
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/addDataSet.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/addDataSet.vm 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/addDataSet.vm 2013-12-22 21:08:30 +0000
@@ -126,6 +126,15 @@
</td>
</tr>
<tr>
+ <td><label>$i18n.getString( "approve_data" )</label></td>
+ <td>
+ <select id="approveData" name="approveData">
+ <option value="false">$i18n.getString( "no" )</option>
+ <option value="true">$i18n.getString( "yes" )</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
<td><label>$i18n.getString( "skip_aggregation" )</label></td>
<td>
<select id="skipAggregation" name="skipAggregation">
=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/editDataSet.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/editDataSet.vm 2013-12-20 14:53:40 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataset/src/main/webapp/dhis-web-maintenance-dataset/editDataSet.vm 2013-12-22 21:08:30 +0000
@@ -126,6 +126,15 @@
</td>
</tr>
<tr>
+ <td><label>$i18n.getString( "approve_data" )</label></td>
+ <td>
+ <select id="approveData" name="approveData">
+ <option value="false">$i18n.getString( "no" )</option>
+ <option value="true"#if( $dataSet.approveData == true ) selected="selected"#end>$i18n.getString( "yes" )</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
<td><label>$i18n.getString( "skip_aggregation" )</label></td>
<td>
<select id="skipAggregation" name="skipAggregation">