← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 14913: Approval testing logic fixes.

 

------------------------------------------------------------
revno: 14913
committer: Jim Grace <jimgrace@xxxxxxxxx>
branch nick: dhis2
timestamp: Sat 2014-04-19 20:18:20 -0400
message:
  Approval testing logic fixes.
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalSelection.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/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java


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

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java	2014-03-31 20:44:51 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalService.java	2014-04-20 00:18:20 +0000
@@ -88,10 +88,10 @@
      * @param dataElementCategoryOptions Selected category options (if any).
      * @return the data approval status.
      */
-    public DataApprovalStatus getDataApprovalStatus( DataSet dataSet, Period period,
-                                                     OrganisationUnit organisationUnit,
-                                                     Set<CategoryOptionGroup> categoryOptionGroups,
-                                                     Set<DataElementCategoryOption> dataElementCategoryOptions );
+    DataApprovalStatus getDataApprovalStatus( DataSet dataSet, Period period,
+                                              OrganisationUnit organisationUnit,
+                                              Set<CategoryOptionGroup> categoryOptionGroups,
+                                              Set<DataElementCategoryOption> dataElementCategoryOptions );
 
     /**
      * Returns the data approval status for a given data set, period,
@@ -105,8 +105,8 @@
      * @return the data approval status.
      */
     DataApprovalPermissions getDataApprovalPermissions( DataSet dataSet, Period period,
-                                              OrganisationUnit organisationUnit,
-                                              DataElementCategoryOptionCombo attributeOptionCombo );
+                                                        OrganisationUnit organisationUnit,
+                                                        DataElementCategoryOptionCombo attributeOptionCombo );
 
     /**
      * Returns the data approval permissions and status for a given data set,
@@ -121,10 +121,10 @@
      * @param dataElementCategoryOptions Selected category options (if any).
      * @return the data approval permissions (including status.)
      */
-    public DataApprovalPermissions getDataApprovalPermissions( DataSet dataSet, Period period,
-                                                     OrganisationUnit organisationUnit,
-                                                     Set<CategoryOptionGroup> categoryOptionGroups,
-                                                     Set<DataElementCategoryOption> dataElementCategoryOptions );
+    DataApprovalPermissions getDataApprovalPermissions( DataSet dataSet, Period period,
+                                                        OrganisationUnit organisationUnit,
+                                                        Set<CategoryOptionGroup> categoryOptionGroups,
+                                                        Set<DataElementCategoryOption> dataElementCategoryOptions );
 
     /**
      * Accepts an approval. This action is optional, and is usually done

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalSelection.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalSelection.java	2014-04-14 06:52:39 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalSelection.java	2014-04-20 00:18:20 +0000
@@ -52,7 +52,7 @@
 /**
  * This package-private class is used by the data approval service to
  * describe selected data from a data set, such as could appear in a data set
- * report, and to determine its data approval status.
+ * report or data approval report, to determine its data approval status.
  * <p>
  * The entire reason for this class is to make the code more readable.
  * The use of instance variables greatly reduces the need to pass parameters
@@ -102,7 +102,7 @@
 
     private Map<CategoryOptionGroupSet, Set<CategoryOptionGroup>> selectionGroups = null;
 
-    private List<DataApprovalLevel> matchingApprovalLevels;
+    private List<DataApprovalLevel> allApprovalLevels;
 
     private List<Set<CategoryOptionGroup>> categoryOptionGroupsByLevel;
 
@@ -165,29 +165,22 @@
                 organisationUnit.getLevel() :
                 organisationUnitService.getLevelOfOrganisationUnit( organisationUnit.getUid() );
 
-        log.info( logSelection() + " starting." );
+        log.debug( logSelection() + " starting." );
 
         if ( !dataSet.isApproveData() )
         {
-            log.info( logSelection() + " returning UNAPPROVABLE (dataSet not marked for approval)" );
-
-            return STATUS_UNAPPROVABLE;
-        }
-
-        findMatchingApprovalLevels();
-
-        if ( matchingApprovalLevels.size() == 0 )
-        {
-            log.info( logSelection() + " returning UNAPPROVABLE (no matching approval levels)" );
-
-            return STATUS_UNAPPROVABLE;
-        }
+            log.debug( logSelection() + " returning UNAPPROVABLE (dataSet not marked for approval)" );
+
+            return STATUS_UNAPPROVABLE;
+        }
+
+        findCategoryOptionGroupsByLevel();
 
         findThisLevel();
 
         if ( lowerIndex == 0 )
         {
-            log.info( logSelection() + " returning UNAPPROVABLE because org unit is above all approval levels" );
+            log.debug( logSelection() + " returning UNAPPROVABLE because org unit is above all approval levels" );
 
             return STATUS_UNAPPROVABLE;
         }
@@ -200,7 +193,7 @@
             }
             else
             {
-                log.info( logSelection() + " returning UNAPPROVABLE (period type too short)" );
+                log.debug( logSelection() + " returning UNAPPROVABLE (period type too short)" );
 
                 return STATUS_UNAPPROVABLE;
             }
@@ -212,7 +205,7 @@
 
         DataApprovalStatus status = new DataApprovalStatus( state, dataApproval, dataApprovalLevel );
 
-        log.info( logSelection() + " returning " + state.name() );
+        log.debug( logSelection() + " returning " + state.name() );
 
         return status;
     }
@@ -249,7 +242,7 @@
 
         return "getDataApprovalStatus( " + dataSet.getName() + ", " + period.getPeriodType().getName() + ":" + period.getShortName()
                 + ", " + organisationUnit.getName() + " (level " + organisationUnitLevel + "), "
-                + ( categoryOptionGroupsString.isEmpty() ? "null" : ( "[" + categoryOptionGroupsString + "]" ) ) + " )"
+                + ( categoryOptionGroupsString.isEmpty() ? "null" : ( "[" + categoryOptionGroupsString + "]" ) ) + ", "
                 + ( categoryOptionsString.isEmpty() ? "null" : ( "[" + categoryOptionsString + "]" ) ) + " )";
     }
 
@@ -360,19 +353,19 @@
     {
         if ( isApprovedAtThisOrHigherLevel() )
         {
-            log.info( "getState() - approved at this or higher level " + foundThisOrHigherIndex + ", this index is " + thisIndex );
+            log.debug( "getState() - approved at this or higher level " + foundThisOrHigherIndex + ", this index is " + thisIndex );
 
             if ( foundThisOrHigherIndex == thisIndex )
             {
                 if ( dataApproval.isAccepted() )
                 {
-                    log.info( "getState() - accepted here." );
+                    log.debug( "getState() - accepted here." );
 
                     return DataApprovalState.ACCEPTED_HERE;
                 }
                 else
                 {
-                    log.info( "getState() - approved here." );
+                    log.debug( "getState() - approved here." );
 
                     return DataApprovalState.APPROVED_HERE;
                 }
@@ -380,13 +373,13 @@
 
             if ( dataApproval.isAccepted() )
             {
-                log.info( "getState() - accepted for a wider selection of category options, or at higher level." );
+                log.debug( "getState() - accepted for a wider selection of category options, or at higher level." );
 
                 return DataApprovalState.ACCEPTED_ELSEWHERE;
             }
             else
             {
-                log.info( "getState() - approved for a wider selection of category options, or at higher level." );
+                log.debug( "getState() - approved for a wider selection of category options, or at higher level." );
 
                 return DataApprovalState.APPROVED_ELSEWHERE;
             }
@@ -398,61 +391,60 @@
         {
             if ( !unapprovedBelow )
             {
-                log.info( "getState() - unapproved ready." );
+                log.debug( "getState() - unapproved ready." );
 
-                dataApprovalLevel = matchingApprovalLevels.get( thisIndex );
+                dataApprovalLevel = allApprovalLevels.get( thisIndex );
 
                 return DataApprovalState.UNAPPROVED_READY;
             }
 
-            log.info( "getState() - waiting." );
+            log.debug( "getState() - waiting." );
 
             return DataApprovalState.UNAPPROVED_WAITING;
         }
 
         if ( dataSetAssignedAtOrBelowLevel )
         {
-            log.info( "getState() - waiting for higher-level approval at a higher level for data at or below this level." );
+            log.debug( "getState() - waiting for higher-level approval at a higher level for data at or below this level." );
 
             return DataApprovalState.UNAPPROVED_ELSEWHERE;
         }
 
-        log.info( "getState() - unapprovable because not approvable at level or below, and no dataset assignment." );
+        log.debug( "getState() - unapprovable because not approvable at level or below, and no dataset assignment." );
 
         return DataApprovalState.UNAPPROVABLE;
     }
 
     /**
-     * Find approval levels that apply to this selection, based on the
-     * approval level's category option groups. Approval levels without
-     * category option groups always apply. Approval levels with category
-     * option groups only apply if the category option group contains
-     * category options that apply to the selected data.
+     * Compares the approval levels with the data selection, to determine how
+     * the data selection might be approved at each levels.
      * <p>
-     * For each matching approval level, also remember the category
-     * option groups (if any) that apply to this data selection and
-     * match this level's category option group set.
+     * This is done for each level by finding the category option groups
+     * (if any) that satisfy both of these:
+     * <ul>
+     *     <li>Fall under the category option group set for this level</li>
+     *     <li>Describe the data selection</li>
+     * </ul>
+     * For levels with a category option group set, the data selection may be
+     * approved at that level only if the level's category option group set
+     * contains a category option group under which the data falls.
      */
-    private void findMatchingApprovalLevels()
+    private void findCategoryOptionGroupsByLevel()
     {
-        matchingApprovalLevels = new ArrayList<DataApprovalLevel>();
+        allApprovalLevels = dataApprovalLevelService.getAllDataApprovalLevels();
 
         categoryOptionGroupsByLevel = new ArrayList<Set<CategoryOptionGroup>>();
 
-        List<DataApprovalLevel> allDataApprovalLevels = dataApprovalLevelService.getAllDataApprovalLevels();
-
-        if ( allDataApprovalLevels != null )
+        if ( allApprovalLevels != null )
         {
-            for ( DataApprovalLevel level : allDataApprovalLevels )
+            for ( DataApprovalLevel level : allApprovalLevels )
             {
                 if ( level.getCategoryOptionGroupSet() == null )
                 {
-                    log.info( "findMatchingApprovalLevels() adding org unit level "
-                            + level.getOrgUnitLevel()
+                    log.debug( "findCategoryOptionGroupsByLevel() found level " + level.getLevel()
+                            + " org unit level " + level.getOrgUnitLevel()
                             + " with no category option groups." );
 
-                    matchingApprovalLevels.add( level );
-
                     categoryOptionGroupsByLevel.add ( null );
                 }
                 else
@@ -461,29 +453,22 @@
 
                     Set<CategoryOptionGroup> groups = selectionGroups.get( level.getCategoryOptionGroupSet() );
 
-                    if ( groups != null )
-                    {
-                        matchingApprovalLevels.add( level );
-
-                        categoryOptionGroupsByLevel.add ( groups );
-                    }
+                    categoryOptionGroupsByLevel.add ( groups );
                 }
             }
         }
-
-        log.info( "findMatchingApprovalLevels() " + allDataApprovalLevels.size() + " -> " +  matchingApprovalLevels.size() );
     }
 
     /**
      * Initializes the selection groups if they have not yet been initialized.
      * This is a "lazy" operation that is only done if we find approval
      * levels that contain category option group sets we need to compare with.
-     *
+     * <p>
      * selectionGroups are constructed by finding all the category option groups
      * (COGs) that contain COG and/or category options of the selection. The
      * selectionGroup map is indexed by category option group set (COGS). For
      * each COGS, it contains all the COGs that describe the data selection.
-     *
+     * <p>
      * We will then use this information when we encounter an approval level
      * with a COGS. The selectionGroups map will tell us which COGs, if any,
      * from the selected data set apply to the COGS of the approval level.
@@ -502,7 +487,7 @@
                     {
                         addDataGroup( group.getGroupSet(), group );
 
-                        log.info( "initSelectionGroups() adding categoryOptionGroupSet "
+                        log.debug( "initSelectionGroups() adding categoryOptionGroupSet "
                                 + group.getGroupSet().getName()
                                 + ", group " + group.getName() );
                     }
@@ -516,7 +501,7 @@
 
             if ( log.isInfoEnabled() )
             {
-                log.info("initSelectionGroups() returning " + selectionGroups.size() + " group sets:");
+                log.debug("initSelectionGroups() returning " + selectionGroups.size() + " group sets:");
 
                 for ( Map.Entry<CategoryOptionGroupSet,Set<CategoryOptionGroup>> entry : selectionGroups.entrySet() )
                 {
@@ -529,7 +514,7 @@
                             s += ": " + group.getName();
                         }
 
-                        log.info( "Group set " + entry.getKey().getName() + " (" + + entry.getValue().size() + ")" + s );
+                        log.debug( "Group set " + entry.getKey().getName() + " (" + + entry.getValue().size() + ")" + s );
                     }
                 }
             }
@@ -552,7 +537,7 @@
                 s += (s.isEmpty() ? "" : ", ") + option.getName();
             }
 
-            log.info( "addDataGroups() looking for options " + s );
+            log.debug( "addDataGroups() looking for options " + s );
         }
 
         Collection<CategoryOptionGroup> allGroups = categoryService.getAllCategoryOptionGroups();
@@ -568,17 +553,17 @@
                     s += (s.isEmpty() ? "" : ", ") + option.getName();
                 }
 
-                log.info( "addDataGroups() looking in group " + group.getName() + ", options " + s );
+                log.debug( "addDataGroups() looking in group " + group.getName() + ", options " + s );
             }
 
             if ( group.getGroupSet() != null && CollectionUtils.containsAny( group.getMembers(), dataElementCategoryOptions ) )
             {
                 addDataGroup( group.getGroupSet(), group );
 
-                log.info( "addDataGroups(): Adding " + group.getGroupSet().getName() + ", " + group.getName() );
+                log.debug( "addDataGroups(): Adding " + group.getGroupSet().getName() + ", " + group.getName() );
             }
 
-            else log.info( "addDataGroups(): Not adding " + group.getName() + " (group set "
+            else log.debug( "addDataGroups(): Not adding " + group.getName() + " (group set "
                     + ( group.getGroupSet() == null ? "null" : group.getGroupSet().getName() ) + ")" );
         }
     }
@@ -611,49 +596,27 @@
      */
     private void findThisLevel()
     {
-        log.info( "findThisLevel() - matchingApprovalLevels.size() = " + matchingApprovalLevels.size() );
-
-        for ( int i = matchingApprovalLevels.size() - 1; i >= 0; i-- )
-        {
-            log.info( "findThisLevel() - testing index " + i
-                    + " org level " + organisationUnitLevel
-                    + " approval level " + matchingApprovalLevels.get( i ).getOrgUnitLevel() );
-
-            if ( organisationUnitLevel == matchingApprovalLevels.get( i ).getOrgUnitLevel() )
-            {
-                if ( approvableAtLevel( i ) )
-                {
-                    thisIndex = i;
-                }
-                else
-                {
-                    thisIndex = INDEX_NOT_FOUND;
-                }
-
-                thisOrHigherIndex = i;
-                lowerIndex = i + 1;
-
-                log.info( "findThisLevel() - approvable at " + thisIndex );
-
-                return;
-            }
-            else if ( organisationUnitLevel > matchingApprovalLevels.get( i ).getOrgUnitLevel() )
-            {
-                thisIndex = INDEX_NOT_FOUND;
-                thisOrHigherIndex = i;
-                lowerIndex = i+1;
-
-                log.info( "findThisLevel() - org lower than level, thisOrHigher=" + thisOrHigherIndex + ", lower=" + lowerIndex );
-
-                return;
-            }
-        }
-
         thisIndex = INDEX_NOT_FOUND;
+
         thisOrHigherIndex = INDEX_NOT_FOUND;
+
         lowerIndex = 0;
 
-        log.info( "findThisLevel() - org higher than all levels, thisOrHigher=" + thisOrHigherIndex + ", lower=" + lowerIndex );
+        for ( int i = 0; i < allApprovalLevels.size() && organisationUnitLevel >= allApprovalLevels.get( i ).getOrgUnitLevel(); i++ )
+        {
+            thisOrHigherIndex = i;
+
+            lowerIndex = i + 1;
+
+            if ( approvableAtLevel( i ) )
+            {
+                thisIndex = i;
+
+                break;
+            }
+        }
+
+        log.debug( "findThisLevel() - returning thisOrHigher=" + thisOrHigherIndex + ", this=" + thisIndex + ", lower=" + lowerIndex );
     }
 
     /**
@@ -663,13 +626,13 @@
      * at index i. The job of this method is to determine whether the selected
      * category option groups and/or category options (if any) are compatible
      * with the category option group set (if any) defined for this level.
-     *
+     * <p>
      * If any category options were specified, then the data is not approvable
      * at any level.
-     *
+     * <p>
      * If the level contains no category option group set, then the selection
      * must contain no category option group.
-     *
+     * <p>
      * If the level contains a category option group set, then the selection
      * must contain one (only) category option group. (Previous logic has
      * determined that if this is the case, the group will be a member of
@@ -680,18 +643,56 @@
      */
     private boolean approvableAtLevel( int i )
     {
+        DataApprovalLevel level = allApprovalLevels.get( i );
+
+        if ( organisationUnitLevel != level.getOrgUnitLevel() )
+        {
+            log.debug( "approvableAtLevel( " + i + " ) = false: org unit level " + organisationUnitLevel + " not at approval org unit level " + level.getOrgUnitLevel() );
+
+            return false;
+        }
+
         if ( dataElementCategoryOptions != null && dataElementCategoryOptions.size() != 0 )
         {
+            log.debug( "approvableAtLevel( " + i + " ) = false: selection category options present." );
+
             return false;
         }
 
-        if ( matchingApprovalLevels.get( i ).getCategoryOptionGroupSet() == null )
+        if ( level.getCategoryOptionGroupSet() == null )
         {
-            return ( categoryOptionGroups == null || categoryOptionGroups.size() == 0 );
+            if ( categoryOptionGroups == null || categoryOptionGroups.size() == 0 )
+            {
+                log.debug( "approvableAtLevel( " + i + " ) = true: no COG in selection or COGS in level." );
+
+                return true;
+            }
+            else
+            {
+                log.debug( "approvableAtLevel( " + i + " ) = false: COG in selection but no COGS in level." );
+
+                return false;
+            }
         }
         else
         {
-            return ( categoryOptionGroups.size() == 1 );
+            if ( categoryOptionGroups != null && categoryOptionGroups.size() == 1
+                    && categoryOptionGroups.iterator().next().getGroupSet() == level.getCategoryOptionGroupSet() )
+            {
+                log.debug( "approvableAtLevel( " + i + " ) = true: COG in selection is a member of COGS in level." );
+
+                return true;
+            }
+            else
+            {
+                log.debug( "approvableAtLevel( " + i + " ) = false: COGS in level, "
+                        + ( categoryOptionGroups == null ? "no COG(s) in selection" :
+                        ( categoryOptionGroups.size() ) + " COG(s) in selection"
+                                + ( categoryOptionGroups.size() != 1 ? "" :
+                                ( " selected COG: " + categoryOptionGroups.iterator().next().getGroupSet().getName() ) ) ) );
+
+                return false;
+            }
         }
     }
 
@@ -713,11 +714,11 @@
 
             for (int i = thisOrHigherIndex; i >= 0; i-- )
             {
-                while ( orgLevel > matchingApprovalLevels.get( i ).getOrgUnitLevel() )
+                while ( orgLevel > allApprovalLevels.get( i ).getOrgUnitLevel() )
                 {
-                    log.info( "isApprovedAtHigherLevel() moving up from " + orgUnit.getName() + " " + orgLevel
-                            + " to " + orgUnit.getParent().getName() + " " + ( orgLevel - 1 ) + " towards "
-                            + matchingApprovalLevels.get( i ).getOrgUnitLevel() );
+                    log.debug( "isApprovedAtHigherLevel() moving up from " + orgUnit.getName() + "(" + orgLevel
+                            + ") to " + orgUnit.getParent().getName() + "(" + ( orgLevel - 1 ) + ") towards org unit level "
+                            + allApprovalLevels.get( i ).getOrgUnitLevel() );
 
                     orgUnit = orgUnit.getParent();
 
@@ -732,27 +733,27 @@
 
                     dataApproval = da;
 
-                    dataApprovalLevel = matchingApprovalLevels.get ( i );
+                    dataApprovalLevel = allApprovalLevels.get ( i );
 
-                    log.info( "isApprovedAtHigherLevel() found approval at level " + dataApprovalLevel.getLevel() );
+                    log.debug( "isApprovedAtHigherLevel() found approval at level " + dataApprovalLevel.getLevel() );
 
                     // (Keep looping to see if selection is also approved at a higher level.)
                 }
             }
         }
 
-        log.info( "isApprovedAtHigherLevel() returning " + ( foundThisOrHigherIndex >= 0 ) );
+        log.debug( "isApprovedAtHigherLevel() returning " + ( foundThisOrHigherIndex >= 0 ) );
 
         return ( foundThisOrHigherIndex >= 0 );
     }
 
     /**
      * Is this data selection approved at the given level index, for the
-     * given organisation unit and category option group(s)?
+     * given organisation unit?
      *
-     * @param index (matching) approval level index at which to test
-     * @param orgUnit organisation unit to tes.
-     * @return true if approved, otherwise false.
+     * @param index (matching) approval level index at which to test.
+     * @param orgUnit organisation unit to test.
+     * @return DataApproval if approved, otherwise null.
      */
     private DataApproval getDataApproval( int index, OrganisationUnit orgUnit )
     {
@@ -762,7 +763,7 @@
         {
             DataApproval d = dataApprovalStore.getDataApproval( dataSet, period, orgUnit, null );
 
-            log.info("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (no groups)" );
+            log.debug("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (no groups)" );
 
             return d;
         }
@@ -771,7 +772,7 @@
         {
             DataApproval d = dataApprovalStore.getDataApproval( dataSet, period, orgUnit, group );
 
-            log.info("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (group: " + group.getName() + ")" );
+            log.debug("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (group: " + group.getName() + ")" );
 
             if ( d != null )
             {
@@ -779,7 +780,7 @@
             }
         }
 
-        log.info("getDataApproval( " + orgUnit.getName() + " ) = false (none of " + groups.size() + " groups matched)" );
+        log.debug("getDataApproval( " + orgUnit.getName() + " ) = false (none of " + groups.size() + " groups matched)" );
 
         return null;
     }
@@ -810,9 +811,9 @@
             dataSetAssignedAtOrBelowLevel = true;
         }
 
-        if ( lowerIndex < matchingApprovalLevels.size() )
+        if ( lowerIndex < allApprovalLevels.size() )
         {
-            if ( orgUnitLevel == matchingApprovalLevels.get( lowerIndex ).getLevel() )
+            if ( orgUnitLevel == allApprovalLevels.get( lowerIndex ).getLevel() )
             {
                 log.info( "isUnapprovedBelow() orgUnit level " + orgUnitLevel + " matches approval level." );
 

=== 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-04-14 07:02:03 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java	2014-04-20 00:18:20 +0000
@@ -188,7 +188,7 @@
 
         DataApprovalPermissions permissions = new DataApprovalPermissions();
 
-        log.info( "getDataApprovalPermissions() getting permissions." );
+        log.debug( "getDataApprovalPermissions() getting permissions." );
 
         permissions.setDataApprovalStatus( status );
 
@@ -214,7 +214,7 @@
             }
         }
 
-        log.info( "Returning permissions for " + organisationUnit.getName()
+        log.debug( "Returning permissions for " + organisationUnit.getName()
                 + " " + status.getDataApprovalState().name()
                 + " may approve = " + permissions.isMayApprove()
                 + " may unapprove = " + permissions.isMayUnapprove()
@@ -259,7 +259,7 @@
             warnNotPermitted( dataApproval, "unaccept", mayAcceptOrUnaccept( dataApproval.getOrganisationUnit() ) );
         }
     }
-    
+
     // -------------------------------------------------------------------------
     // Supportive methods
     // -------------------------------------------------------------------------
@@ -303,7 +303,7 @@
 
             if ( mayApprove && user.getOrganisationUnits().contains( organisationUnit ) )
             {
-                log.info( "mayApprove = true because organisation unit " + organisationUnit.getName()
+                log.debug( "mayApprove = true because organisation unit " + organisationUnit.getName()
                         + " is assigned to user and user may approve at same level." );
 
                 return true;
@@ -314,14 +314,14 @@
             if ( mayApproveAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(),
                 organisationUnit.getAncestors() ) )
             {
-                log.info( "mayApprove = true because organisation unit " + organisationUnit.getName()
+                log.debug( "mayApprove = true because organisation unit " + organisationUnit.getName()
                         + " is under user and user may approve at lower levels." );
 
                 return true;
             }
         }
 
-        log.info( "mayApprove = false for organisation unit " + organisationUnit.getName() );
+        log.debug( "mayApprove = false for organisation unit " + organisationUnit.getName() );
 
         return false;
     }
@@ -351,13 +351,13 @@
         {
             if ( !accepted || mayAcceptOrUnaccept( organisationUnit ) )
             {
-                log.info( "mayUnapprove = true for organisation unit " + organisationUnit.getName() );
+                log.debug( "mayUnapprove = true for organisation unit " + organisationUnit.getName() );
 
                 return true;
             }
         }
 
-        log.info( "mayUnapprove = false for organisation unit " + organisationUnit.getName() );
+        log.debug( "mayUnapprove = false for organisation unit " + organisationUnit.getName() );
 
         return false;
     }
@@ -380,16 +380,16 @@
             if ( mayAcceptAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(),
                 organisationUnit.getAncestors() ) )
             {
-                log.info( "User may accept or unaccept for organisation unit " + organisationUnit.getName() );
+                log.debug( "User may accept or unaccept for organisation unit " + organisationUnit.getName() );
 
                 return true;
             }
         }
 
-        log.info( "User with AUTH_ACCEPT_LOWER_LEVELS " + user.getUserCredentials().isAuthorized( DataApproval.AUTH_ACCEPT_LOWER_LEVELS )
+        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.getName()
-                + " with " + organisationUnit.getAncestors().size() + " ancestors.");
+                + " with " + organisationUnit.getAncestors().size() + " ancestors." );
 
         return false;
     }
@@ -407,11 +407,11 @@
      */
     private boolean isAuthorizedToUnapprove( OrganisationUnit organisationUnit )
     {
-        log.info( "isAuthorizedToUnapprove( " + organisationUnit.getName() + ")" );
+        log.debug( "isAuthorizedToUnapprove( " + organisationUnit.getName() + ")" );
 
         if ( mayApprove( organisationUnit ) )
         {
-            log.info( "User may unapprove at " + organisationUnit.getName() );
+            log.debug( "User may unapprove at " + organisationUnit.getName() );
 
             return true;
         }
@@ -420,13 +420,13 @@
         {
             if ( mayApprove( ancestor ) )
             {
-                log.info( "User may unapprove at " + ancestor.getName() );
+                log.debug( "User may unapprove at " + ancestor.getName() );
 
                 return true;
             }
         }
 
-        log.info( "User may not unapprove at " + organisationUnit.getName() );
+        log.debug( "User may not unapprove at " + organisationUnit.getName() );
 
         return false;
     }
@@ -458,7 +458,7 @@
 
         if ( !mayOperate )
         {
-            warning += " but couldn't " + operation;
+            warning += " but couldn't " + operation  + " for " + dataApproval.getOrganisationUnit().getName();
         }
 
         log.warn( warning + "." );

=== 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-04-10 17:52:41 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java	2014-04-20 00:18:20 +0000
@@ -131,21 +131,11 @@
 
     private DataApprovalLevel level4;
 
-    private DataApprovalLevel level1A;
-
-    private DataApprovalLevel level2A;
-
-    private DataApprovalLevel level3A;
-
-    private DataApprovalLevel level4A;
-
-    private DataApprovalLevel level1B;
-
-    private DataApprovalLevel level2B;
-
-    private DataApprovalLevel level3B;
-
-    private DataApprovalLevel level4B;
+    private DataApprovalLevel level1ABCD;
+
+    private DataApprovalLevel level1EFGH;
+
+    private DataApprovalLevel level2ABCD;
 
     private User userA;
 
@@ -205,17 +195,17 @@
 
     private DataElementCategoryCombo categoryComboA;
 
-    private CategoryOptionGroup groupA;
-
-    private CategoryOptionGroup groupB;
-
-    private CategoryOptionGroup groupC;
-
-    private CategoryOptionGroup groupD;
-
-    private CategoryOptionGroupSet groupSetA;
-
-    private CategoryOptionGroupSet groupSetB;
+    private CategoryOptionGroup groupAB;
+
+    private CategoryOptionGroup groupCD;
+
+    private CategoryOptionGroup groupEF;
+
+    private CategoryOptionGroup groupGH;
+
+    private CategoryOptionGroupSet groupSetABCD;
+
+    private CategoryOptionGroupSet groupSetEFGH;
 
     // -------------------------------------------------------------------------
     // Set up/tear down
@@ -282,10 +272,10 @@
         organisationUnitService.addOrganisationUnit( organisationUnitE );
         organisationUnitService.addOrganisationUnit( organisationUnitF );
 
-        level1 = new DataApprovalLevel( "1", 1, null );
-        level2 = new DataApprovalLevel( "2", 2, null );
-        level3 = new DataApprovalLevel( "3", 3, null );
-        level4 = new DataApprovalLevel( "4", 4, null );
+        level1 = new DataApprovalLevel( "level1", 1, null );
+        level2 = new DataApprovalLevel( "level2", 2, null );
+        level3 = new DataApprovalLevel( "level3", 3, null );
+        level4 = new DataApprovalLevel( "level4", 4, null );
 
         userA = createUser( 'A' );
         userB = createUser( 'B' );
@@ -362,35 +352,30 @@
         categoryService.addDataElementCategoryOptionCombo( optionComboO );
         categoryService.addDataElementCategoryOptionCombo( optionComboP );
 
-        groupA = createCategoryOptionGroup( 'A', optionA, optionB );
-        groupB = createCategoryOptionGroup( 'B', optionC, optionD );
-        groupC = createCategoryOptionGroup( 'C', optionE, optionF );
-        groupD = createCategoryOptionGroup( 'D', optionG, optionH );
-
-        categoryService.saveCategoryOptionGroup( groupA );
-        categoryService.saveCategoryOptionGroup( groupB );
-        categoryService.saveCategoryOptionGroup( groupC );
-        categoryService.saveCategoryOptionGroup( groupD );
-
-        groupSetA = new CategoryOptionGroupSet( "GroupSetA" );
-        groupSetB = new CategoryOptionGroupSet( "GroupSetB" );
-
-        categoryService.saveCategoryOptionGroupSet( groupSetA );
-        categoryService.saveCategoryOptionGroupSet( groupSetB );
-
-        groupSetA.addCategoryOptionGroup( groupA );
-        groupSetA.addCategoryOptionGroup( groupB );
-        groupSetB.addCategoryOptionGroup( groupC );
-        groupSetB.addCategoryOptionGroup( groupD );
-
-        level1A = new DataApprovalLevel( "1A", 1, groupSetA );
-        level1B = new DataApprovalLevel( "1B",1, groupSetB );
-        level2A = new DataApprovalLevel( "2A", 2, groupSetA );
-        level2B = new DataApprovalLevel( "2B", 2, groupSetB );
-        level3A = new DataApprovalLevel( "3A", 3, groupSetA );
-        level3B = new DataApprovalLevel( "3B", 3, groupSetB );
-        level4A = new DataApprovalLevel( "4A", 4, groupSetA );
-        level4B = new DataApprovalLevel( "4B", 4, groupSetB );
+        groupAB = createCategoryOptionGroup( 'A', optionA, optionB );
+        groupCD = createCategoryOptionGroup( 'C', optionC, optionD );
+        groupEF = createCategoryOptionGroup( 'E', optionE, optionF );
+        groupGH = createCategoryOptionGroup( 'G', optionG, optionH );
+
+        categoryService.saveCategoryOptionGroup( groupAB );
+        categoryService.saveCategoryOptionGroup( groupCD );
+        categoryService.saveCategoryOptionGroup( groupEF );
+        categoryService.saveCategoryOptionGroup( groupGH );
+
+        groupSetABCD = new CategoryOptionGroupSet( "GroupSetABCD" );
+        groupSetEFGH = new CategoryOptionGroupSet( "GroupSetEFGH" );
+
+        categoryService.saveCategoryOptionGroupSet( groupSetABCD );
+        categoryService.saveCategoryOptionGroupSet( groupSetEFGH );
+
+        groupSetABCD.addCategoryOptionGroup( groupAB );
+        groupSetABCD.addCategoryOptionGroup( groupCD );
+        groupSetEFGH.addCategoryOptionGroup( groupEF );
+        groupSetEFGH.addCategoryOptionGroup( groupGH );
+
+        level1ABCD = new DataApprovalLevel( "level1ABCD", 1, groupSetABCD );
+        level1EFGH = new DataApprovalLevel( "level1EFGH", 1, groupSetEFGH );
+        level2ABCD = new DataApprovalLevel( "level2ABCD", 2, groupSetABCD );
     }
 
     // -------------------------------------------------------------------------
@@ -1067,7 +1052,7 @@
     // ---------------------------------------------------------------------
 
     @Test
-    public void testAddAndGetDataApprovalWithCategories() throws Exception
+    public void testApprovalStateWithCategories() throws Exception
     {
         setUpCategories();
 
@@ -1075,8 +1060,8 @@
         units.add( organisationUnitA );
         createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS, AUTH_APPR_LEVEL );
 
-        Set<CategoryOptionGroup> groupASet = new HashSet<CategoryOptionGroup>();
-        groupASet.add ( groupA );
+        Set<CategoryOptionGroup> groupABSet = new HashSet<CategoryOptionGroup>();
+        groupABSet.add( groupAB );
 
         dataSetA.setApproveData( true );
 
@@ -1087,13 +1072,13 @@
         Date date = new Date();
 
         //
-        // Group set A -> Groups A,B
-        // Group set B -> Groups C,D
+        // Group set ABCD -> Groups AB,CD
+        // Group set EFGH -> Groups EF,GH
         //
-        // Group A -> Options A,B
-        // Group B -> Options C,D
-        // Group C -> Options E,F
-        // Group D -> Options G,H
+        // Group AB -> Options A,B
+        // Group CD -> Options C,D
+        // Group EF -> Options E,F
+        // Group GH -> Options G,H
         //
         // Category A -> Options A,B,C,D
         // Category B -> Options E,F,G,H
@@ -1110,19 +1095,19 @@
         // Option combo J -> Options C,F -> Groups B,D
         // Option combo K -> Options C,G -> Groups B,D
 
-        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalState() );
-        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalState() );
-        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupABSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupABSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, groupABSet, NO_OPTIONS ).getDataApprovalState() );
 
         assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
         assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalState() );
         assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, optionComboA ).getDataApprovalState() );
 
-        dataApprovalLevelService.addDataApprovalLevel( level2A );
+        dataApprovalLevelService.addDataApprovalLevel( level2ABCD );
 
-        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalState() );
-        assertEquals( DataApprovalState.UNAPPROVED_READY, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalState() );
-        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupABSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_READY, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupABSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, groupABSet, NO_OPTIONS ).getDataApprovalState() );
 
         assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
         assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboB ).getDataApprovalState() );
@@ -1132,11 +1117,11 @@
         assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboJ ).getDataApprovalState() );
         assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, optionComboK ).getDataApprovalState() );
 
-        dataApprovalService.addDataApproval( new DataApproval( level2A, dataSetA, periodA, organisationUnitB, groupA, NOT_ACCEPTED, date, userA ) );
+        dataApprovalService.addDataApproval( new DataApproval( level2ABCD, dataSetA, periodA, organisationUnitB, groupAB, NOT_ACCEPTED, date, userA ) );
 
-        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalState() );
-        assertEquals( DataApprovalState.APPROVED_HERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalState() );
-        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupABSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_HERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupABSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, groupABSet, NO_OPTIONS ).getDataApprovalState() );
 
         assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
         assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboB ).getDataApprovalState() );
@@ -1146,4 +1131,159 @@
         assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboJ ).getDataApprovalState() );
         assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, optionComboK ).getDataApprovalState() );
     }
+
+    @Test
+    public void testApprovalLevelWithCategories() throws Exception
+    {
+        setUpCategories();
+
+        dataSetA.setApproveData( true );
+
+        organisationUnitA.addDataSet( dataSetA );
+        organisationUnitB.addDataSet( dataSetA );
+
+        Set<CategoryOptionGroup> groupASet = new HashSet<CategoryOptionGroup>();
+        groupASet.add( groupAB ); // GroupA is a member of DataSetA
+
+        Set<CategoryOptionGroup> groupBSet = new HashSet<CategoryOptionGroup>();
+        groupBSet.add ( groupCD );
+
+        Set<CategoryOptionGroup> groupCSet = new HashSet<CategoryOptionGroup>();
+        groupCSet.add ( groupEF );
+
+        Set<CategoryOptionGroup> groupXSet = new HashSet<CategoryOptionGroup>();
+        groupXSet.add ( groupAB );
+        groupXSet.add( groupEF );
+
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS, AUTH_APPR_LEVEL );
+
+        Date date = new Date();
+
+        DataApproval dab = new DataApproval( level1EFGH, dataSetA, periodA, organisationUnitA, groupCD, NOT_ACCEPTED, date, userA );
+
+        dataApprovalLevelService.addDataApprovalLevel( level1EFGH );
+        dataApprovalService.addDataApproval( dab );
+
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_READY, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
+
+        assertEquals( level1EFGH, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalLevel() );
+
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalState() );
+
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertNull( dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalLevel() );
+
+        dataApprovalLevelService.addDataApprovalLevel( level1ABCD );
+        dataApprovalService.addDataApproval( new DataApproval( level1ABCD, dataSetA, periodA, organisationUnitA, groupAB, NOT_ACCEPTED, date, userA ) );
+
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_HERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_HERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_READY, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
+
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1EFGH, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalLevel() );
+
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalState() );
+
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalLevel() );
+
+        dataApprovalService.deleteDataApproval( dab );
+
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_HERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_WAITING, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_READY, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
+
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1EFGH, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalLevel() );
+
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.UNAPPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalState() );
+
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( null, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1ABCD, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalLevel() );
+
+        dataApprovalLevelService.addDataApprovalLevel( level1 );
+        dataApprovalService.addDataApproval( new DataApproval( level1, dataSetA, periodA, organisationUnitA, NO_GROUP, NOT_ACCEPTED, date, userA ) );
+
+        assertEquals( DataApprovalState.APPROVED_HERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
+
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalLevel() );
+
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalState() );
+
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, NO_GROUPS, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupASet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupBSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupCSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, groupXSet, NO_OPTIONS ).getDataApprovalLevel() );
+        assertEquals( level1, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboA ).getDataApprovalLevel() );
+    }
 }