← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 14533: DataApproval testing and fixes

 

------------------------------------------------------------
revno: 14533
committer: Jim Grace <jimgrace@xxxxxxxxx>
branch nick: dhis2
timestamp: Sun 2014-03-30 00:37:39 -0400
message:
  DataApproval testing and fixes
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalLevel.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/DefaultDataApprovalLevelService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalLevelStore.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/dataapproval/hibernate/DataApprovalLevel.hbm.xml
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalLevelServiceTest.java
  dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataApprovalController.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/AddApprovalLevelAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/struts.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemApprovalSettings.vm
  dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataSetReport.js


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

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalLevel.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalLevel.java	2014-02-23 13:08:31 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataapproval/DataApprovalLevel.java	2014-03-30 04:37:39 +0000
@@ -58,7 +58,7 @@
     /**
      * The organisation unit level for this data approval level.
      */
-    private OrganisationUnitLevel organisationUnitLevel;
+    private int orgUnitLevel;
 
     /**
      * The category option group set (optional) for this data approval level.
@@ -75,6 +75,11 @@
      */
     private Date updated;
 
+    /**
+     * The name of the organisation unit level (derived through the service.)
+     */
+    private String orgUnitLevelName;
+
     // -------------------------------------------------------------------------
     // Constructors
     // -------------------------------------------------------------------------
@@ -83,19 +88,19 @@
     {
     }
 
-    public DataApprovalLevel( OrganisationUnitLevel organisationUnitLevel,
+    public DataApprovalLevel( int orgUnitLevel,
                               CategoryOptionGroupSet categoryOptionGroupSet )
     {
-        this.organisationUnitLevel = organisationUnitLevel;
+        this.orgUnitLevel = orgUnitLevel;
         this.categoryOptionGroupSet = categoryOptionGroupSet;
     }
 
-    public DataApprovalLevel( int level, OrganisationUnitLevel organisationUnitLevel,
+    public DataApprovalLevel( int level, int orgUnitLevel,
                               CategoryOptionGroupSet categoryOptionGroupSet,
                               Date created, Date updated )
     {
         this.level = level;
-        this.organisationUnitLevel = organisationUnitLevel;
+        this.orgUnitLevel = orgUnitLevel;
         this.categoryOptionGroupSet = categoryOptionGroupSet;
         this.created = created;
         this.updated = updated;
@@ -112,7 +117,7 @@
      */
     public String getName()
     {
-        String name = organisationUnitLevel.getName()
+        String name = orgUnitLevel
                 + ( categoryOptionGroupSet == null ? "" : ( " - " + categoryOptionGroupSet.getName() ) );
 
         return name;
@@ -155,14 +160,14 @@
         this.level = level;
     }
 
-    public OrganisationUnitLevel getOrganisationUnitLevel()
+    public int getOrgUnitLevel()
     {
-        return organisationUnitLevel;
+        return orgUnitLevel;
     }
 
-    public void setOrganisationUnitLevel( OrganisationUnitLevel organisationUnitLevel )
+    public void setOrgUnitLevel( int orgUnitLevel )
     {
-        this.organisationUnitLevel = organisationUnitLevel;
+        this.orgUnitLevel = orgUnitLevel;
     }
 
     public CategoryOptionGroupSet getCategoryOptionGroupSet()
@@ -194,4 +199,15 @@
     {
         this.updated = updated;
     }
+
+    public String getOrgUnitLevelName()
+    {
+        return orgUnitLevelName;
+    }
+
+    public void setOrgUnitLevelName( String orgUnitLevelName )
+    {
+        this.orgUnitLevelName = orgUnitLevelName;
+    }
+
 }

=== 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-03-28 10:13:01 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalSelection.java	2014-03-30 04:37:39 +0000
@@ -33,8 +33,10 @@
 import org.hisp.dhis.dataelement.*;
 import org.hisp.dhis.dataset.DataSet;
 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.springframework.util.CollectionUtils;
 
 import java.util.*;
@@ -52,6 +54,8 @@
  */
 class DataApprovalSelection
 {
+    private final static Log log = LogFactory.getLog( DataApprovalSelection.class );
+
     // -------------------------------------------------------------------------
     // Data selection parameters
     // -------------------------------------------------------------------------
@@ -74,14 +78,18 @@
 
     private DataApprovalLevelService dataApprovalLevelService;
 
+    private OrganisationUnitService organisationUnitService;
+
     private DataElementCategoryService categoryService;
 
     private PeriodService periodService;
 
     // -------------------------------------------------------------------------
-    // Internal variables
+    // Internal instance variables
     // -------------------------------------------------------------------------
 
+    private int organisationUnitLevel;
+
     private Map<CategoryOptionGroupSet, Set<CategoryOptionGroup>> dataGroups = null;
 
     private List<DataApprovalLevel> matchingApprovalLevels;
@@ -106,8 +114,6 @@
 
     private int foundThisOrHigherIndex;
 
-    private final static Log log = LogFactory.getLog( DataApprovalSelection.class );
-
     // -------------------------------------------------------------------------
     // Preconstructed Status object
     // -------------------------------------------------------------------------
@@ -125,6 +131,7 @@
                            Set<DataElementCategoryOption> dataElementCategoryOptions,
                            DataApprovalStore dataApprovalStore,
                            DataApprovalLevelService dataApprovalLevelService,
+                           OrganisationUnitService organisationUnitService,
                            DataElementCategoryService categoryService,
                            PeriodService periodService )
     {
@@ -136,6 +143,7 @@
         this.dataApprovalStore = dataApprovalStore;
         this.dataApprovalLevelService = dataApprovalLevelService;
         this.categoryService = categoryService;
+        this.organisationUnitService = organisationUnitService;
         this.periodService = periodService;
     }
 
@@ -145,11 +153,15 @@
 
     DataApprovalStatus getDataApprovalStatus()
     {
-        log.trace( "\n" + logSelection() + " starting." );
+        organisationUnitLevel = organisationUnit.getLevel() != 0 ?
+                organisationUnit.getLevel() :
+                organisationUnitService.getLevelOfOrganisationUnit( organisationUnit.getUid() );
+
+        log.info( logSelection() + " starting." );
 
         if ( !dataSet.isApproveData() )
         {
-            log.trace( logSelection() + " returning UNAPPROVABLE (dataSet not marked for approval)" );
+            log.info( logSelection() + " returning UNAPPROVABLE (dataSet not marked for approval)" );
 
             return STATUS_UNAPPROVABLE;
         }
@@ -158,7 +170,7 @@
 
         if ( matchingApprovalLevels.size() == 0 )
         {
-            log.trace( logSelection() + " returning UNAPPROVABLE (no matching approval levels)" );
+            log.info( logSelection() + " returning UNAPPROVABLE (no matching approval levels)" );
 
             return STATUS_UNAPPROVABLE;
         }
@@ -167,12 +179,12 @@
 
         if ( lowerIndex == 0 )
         {
-            log.trace( logSelection() + " returning UNAPPROVABLE because org unit is above all approval levels" );
+            log.info( logSelection() + " returning UNAPPROVABLE because org unit is above all approval levels" );
 
             return STATUS_UNAPPROVABLE;
         }
 
-        if ( period.getPeriodType() != dataSet.getPeriodType() )
+        if ( !period.getPeriodType().equals( dataSet.getPeriodType() ) )
         {
             if ( period.getPeriodType().getFrequencyOrder() > dataSet.getPeriodType().getFrequencyOrder() )
             {
@@ -180,7 +192,7 @@
             }
             else
             {
-                log.trace( logSelection() + " returning UNAPPROVABLE (period type too short)" );
+                log.info( logSelection() + " returning UNAPPROVABLE (period type too short)" );
 
                 return STATUS_UNAPPROVABLE;
             }
@@ -192,7 +204,7 @@
 
         DataApprovalStatus status = new DataApprovalStatus( state, dataApproval, dataApprovalLevel );
 
-        log.trace( logSelection() + " returning " + state.name() );
+        log.info( logSelection() + " returning " + state.name() );
 
         return status;
     }
@@ -219,7 +231,7 @@
         }
 
         return "getDataApprovalStatus( " + dataSet.getName() + ", " + period.getPeriodType().getName() + ":" + period.getShortName()
-                + ", " + organisationUnit.getName() + " (level " + organisationUnit.getLevel() + "), "
+                + ", " + organisationUnit.getName() + " (level " + organisationUnitLevel + "), "
                 + ( categoryOptionGroup == null ? "null" : categoryOptionGroup.getName() ) + ", "
                 + ( categoryOptionsString.isEmpty() ? "null" : ( "[" + categoryOptionsString + "]" ) ) + " )";
     }
@@ -332,65 +344,62 @@
     {
         if ( isApprovedAtThisOrHigherLevel() )
         {
-            log.trace( "getState() - isApprovedAtThisOrHigherLevel() true." );
+            log.info( "getState() - approved at this or higher level " + foundThisOrHigherIndex + ", this index is " + thisIndex );
 
             if ( foundThisOrHigherIndex == thisIndex )
             {
-                if ( dataElementCategoryOptions == null || dataElementCategoryOptions.size() == 0 )
-                {
-                    if ( dataApproval.isAccepted() )
-                    {
-                        log.trace( "getState() - accepted here." );
-
-                        return DataApprovalState.ACCEPTED_HERE;
-                    }
-                    else
-                    {
-                        log.trace( "getState() - approved here." );
-
-                        return DataApprovalState.APPROVED_HERE;
-                    }
+                if ( dataApproval.isAccepted() )
+                {
+                    log.info( "getState() - accepted here." );
+
+                    return DataApprovalState.ACCEPTED_HERE;
+                }
+                else
+                {
+                    log.info( "getState() - approved here." );
+
+                    return DataApprovalState.APPROVED_HERE;
                 }
             }
 
             if ( dataApproval.isAccepted() )
             {
-                log.trace( "getState() - accepted for a wider selection of category options, or at higher level." );
+                log.info( "getState() - accepted for a wider selection of category options, or at higher level." );
 
                 return DataApprovalState.ACCEPTED_ELSEWHERE;
             }
             else
             {
-                log.trace( "getState() - approved for a wider selection of category options, or at higher level." );
+                log.info( "getState() - approved for a wider selection of category options, or at higher level." );
 
                 return DataApprovalState.APPROVED_ELSEWHERE;
             }
         }
 
-        boolean unapprovedBelow = isUnapprovedBelow( organisationUnit );
+        boolean unapprovedBelow = isUnapprovedBelow( organisationUnit, organisationUnitLevel );
 
         if ( approvableAtLevel )
         {
             if ( !unapprovedBelow )
             {
-                log.trace( "getState() - not unapproved below." );
+                log.info( "getState() - not unapproved below." );
 
                 return DataApprovalState.UNAPPROVED_READY;
             }
 
-            log.trace( "getState() - waiting." );
+            log.info( "getState() - waiting." );
 
             return DataApprovalState.UNAPPROVED_WAITING;
         }
 
         if ( dataSetAssignedAtOrBelowLevel )
         {
-            log.trace( "getState() - waiting for higher-level approval at a higher level for data at or below this level." );
+            log.info( "getState() - waiting for higher-level approval at a higher level for data at or below this level." );
 
             return DataApprovalState.UNAPPROVED_ELSEWHERE;
         }
 
-        log.trace( "getState() - unapprovable because not approvable at level or below, and no dataset assignment." );
+        log.info( "getState() - unapprovable because not approvable at level or below, and no dataset assignment." );
 
         return DataApprovalState.UNAPPROVABLE;
     }
@@ -420,8 +429,8 @@
             {
                 if ( level.getCategoryOptionGroupSet() == null )
                 {
-                    log.trace( "findMatchingApprovalLevels() adding org unit level "
-                            + level.getOrganisationUnitLevel().getLevel()
+                    log.info( "findMatchingApprovalLevels() adding org unit level "
+                            + level.getOrgUnitLevel()
                             + " with no category option groups." );
 
                     matchingApprovalLevels.add( level );
@@ -444,7 +453,7 @@
             }
         }
 
-        log.trace( "findMatchingApprovalLevels() " + allDataApprovalLevels.size() + " -> " +  matchingApprovalLevels.size() );
+        log.info( "findMatchingApprovalLevels() " + allDataApprovalLevels.size() + " -> " +  matchingApprovalLevels.size() );
     }
 
     /**
@@ -462,12 +471,12 @@
             {
                 addDataGroup( categoryOptionGroup.getGroupSet(), categoryOptionGroup );
 
-                log.trace( "initDataGroups() adding categoryOptionGroupSet "
+                log.info( "initDataGroups() adding categoryOptionGroupSet "
                         + categoryOptionGroup.getGroupSet().getName()
                         + ", group " + categoryOptionGroup.getName() );
             }
 
-            else log.trace( "initDataGroups() - not adding categoryOptionGroup "
+            else log.info( "initDataGroups() - not adding categoryOptionGroup "
                     + ( categoryOptionGroup == null ? "null" : categoryOptionGroup.getName() ) );
 
             if ( dataElementCategoryOptions != null )
@@ -477,7 +486,7 @@
 
             if ( log.isInfoEnabled() )
             {
-                log.trace("initDataGroups() returning " + dataGroups.size() + " group sets:");
+                log.info("initDataGroups() returning " + dataGroups.size() + " group sets:");
 
                 for ( Map.Entry<CategoryOptionGroupSet,Set<CategoryOptionGroup>> entry : dataGroups.entrySet() )
                 {
@@ -490,7 +499,7 @@
                             s += ": " + group.getName();
                         }
 
-                        log.trace( "Group set " + entry.getKey().getName() + " (" + + entry.getValue().size() + ")" + s );
+                        log.info( "Group set " + entry.getKey().getName() + " (" + + entry.getValue().size() + ")" + s );
                     }
                 }
             }
@@ -513,7 +522,7 @@
                 s += (s.isEmpty() ? "" : ", ") + option.getName();
             }
 
-            log.trace( "addDataGroups() looking for options " + s );
+            log.info( "addDataGroups() looking for options " + s );
         }
 
         Collection<CategoryOptionGroup> allGroups = categoryService.getAllCategoryOptionGroups();
@@ -529,17 +538,17 @@
                     s += (s.isEmpty() ? "" : ", ") + option.getName();
                 }
 
-                log.trace( "addDataGroups() looking in group " + group.getName() + ", options " + s );
+                log.info( "addDataGroups() looking in group " + group.getName() + ", options " + s );
             }
 
             if ( group.getGroupSet() != null && CollectionUtils.containsAny( group.getMembers(), dataElementCategoryOptions ) )
             {
                 addDataGroup( group.getGroupSet(), group );
 
-                log.trace( "addDataGroups(): Adding " + group.getGroupSet().getName() + ", " + group.getName() );
+                log.info( "addDataGroups(): Adding " + group.getGroupSet().getName() + ", " + group.getName() );
             }
 
-            else log.trace( "addDataGroups(): Not adding " + group.getName() + " (group set "
+            else log.info( "addDataGroups(): Not adding " + group.getName() + " (group set "
                     + ( group.getGroupSet() == null ? "null" : group.getGroupSet().getName() ) + ")" );
         }
     }
@@ -572,15 +581,15 @@
      */
     private void findThisLevel()
     {
-        log.trace( "findThisLevel() - matchingApprovalLevels.size() = " + matchingApprovalLevels.size() );
+        log.info( "findThisLevel() - matchingApprovalLevels.size() = " + matchingApprovalLevels.size() );
 
         for ( int i = matchingApprovalLevels.size() - 1; i >= 0; i-- )
         {
-            log.trace( "findThisLevel() - testing index " + i
-                    + " org level " + organisationUnit.getLevel()
-                    + " approval level " + matchingApprovalLevels.get( i ).getOrganisationUnitLevel().getLevel() );
+            log.info( "findThisLevel() - testing index " + i
+                    + " org level " + organisationUnitLevel
+                    + " approval level " + matchingApprovalLevels.get( i ).getOrgUnitLevel() );
 
-            if ( organisationUnit.getLevel() == matchingApprovalLevels.get( i ).getOrganisationUnitLevel().getLevel() )
+            if ( organisationUnitLevel == matchingApprovalLevels.get( i ).getOrgUnitLevel() )
             {
                 approvableAtLevel = true;
 
@@ -588,11 +597,11 @@
                 thisOrHigherIndex = i;
                 lowerIndex = i + 1;
 
-                log.trace( "findThisLevel() - approvable at " + thisIndex );
+                log.info( "findThisLevel() - approvable at " + thisIndex );
 
                 return;
             }
-            else if ( organisationUnit.getLevel() > matchingApprovalLevels.get( i ).getOrganisationUnitLevel().getLevel() )
+            else if ( organisationUnitLevel > matchingApprovalLevels.get( i ).getOrgUnitLevel() )
             {
                 approvableAtLevel = false;
 
@@ -600,7 +609,7 @@
                 thisOrHigherIndex = i;
                 lowerIndex = i+1;
 
-                log.trace( "findThisLevel() - org lower than level, thisOrHigher=" + thisOrHigherIndex + ", lower=" + lowerIndex );
+                log.info( "findThisLevel() - org lower than level, thisOrHigher=" + thisOrHigherIndex + ", lower=" + lowerIndex );
 
                 return;
             }
@@ -612,7 +621,7 @@
         thisOrHigherIndex = -1;
         lowerIndex = 0;
 
-        log.trace( "findThisLevel() - org higher than all levels, thisOrHigher=" + thisOrHigherIndex + ", lower=" + lowerIndex );
+        log.info( "findThisLevel() - org higher than all levels, thisOrHigher=" + thisOrHigherIndex + ", lower=" + lowerIndex );
     }
 
     /**
@@ -629,15 +638,15 @@
         {
             OrganisationUnit orgUnit = organisationUnit;
 
+            int orgLevel = organisationUnitLevel;
+
             for (int i = thisOrHigherIndex; i >= 0; i-- )
             {
-                int orgLevel = orgUnit.getLevel();
-
-                while ( orgLevel > matchingApprovalLevels.get( i ).getOrganisationUnitLevel().getLevel() )
+                while ( orgLevel > matchingApprovalLevels.get( i ).getOrgUnitLevel() )
                 {
-                    log.trace( "isApprovedAtHigherLevel() moving up from " + orgUnit.getName() + " " + orgLevel
+                    log.info( "isApprovedAtHigherLevel() moving up from " + orgUnit.getName() + " " + orgLevel
                             + " to " + orgUnit.getParent().getName() + " " + ( orgLevel - 1 ) + " towards "
-                            + matchingApprovalLevels.get( i ).getOrganisationUnitLevel().getLevel() );
+                            + matchingApprovalLevels.get( i ).getOrgUnitLevel() );
 
                     orgUnit = orgUnit.getParent();
 
@@ -654,14 +663,14 @@
 
                     dataApprovalLevel = matchingApprovalLevels.get ( i );
 
-                    log.trace( "isApprovedAtHigherLevel() found approval at level " + dataApprovalLevel.getLevel() );
+                    log.info( "isApprovedAtHigherLevel() found approval at level " + dataApprovalLevel.getLevel() );
 
                     // (Keep looping to see if selection is also approved at a higher level.)
                 }
             }
         }
 
-        log.trace( "isApprovedAtHigherLevel() returning " + ( foundThisOrHigherIndex >= 0 ) );
+        log.info( "isApprovedAtHigherLevel() returning " + ( foundThisOrHigherIndex >= 0 ) );
 
         return ( foundThisOrHigherIndex >= 0 );
     }
@@ -682,7 +691,7 @@
         {
             DataApproval d = dataApprovalStore.getDataApproval( dataSet, period, orgUnit, null );
 
-            log.trace("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (no groups)" );
+            log.info("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (no groups)" );
 
             return d;
         }
@@ -691,7 +700,7 @@
         {
             DataApproval d = dataApprovalStore.getDataApproval( dataSet, period, orgUnit, group );
 
-            log.trace("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (group: " + group.getName() + ")" );
+            log.info("getDataApproval( " + orgUnit.getName() + " ) = " + ( d != null ) + " (group: " + group.getName() + ")" );
 
             if ( d != null )
             {
@@ -699,7 +708,7 @@
             }
         }
 
-        log.trace("getDataApproval( " + orgUnit.getName() + " ) = false (none of " + groups.size() + " groups matched)" );
+        log.info("getDataApproval( " + orgUnit.getName() + " ) = false (none of " + groups.size() + " groups matched)" );
 
         return null;
     }
@@ -717,12 +726,13 @@
      * if there is lower-level data to be entered or not for this data set.
      *
      * @param orgUnit Organisation unit to test
+     * @param orgUnitLevel The corresponding organisation unit level
      * @return true if we find an approval level and org unit for which
      * an approval object does not exist, else false
      */
-    private boolean isUnapprovedBelow ( OrganisationUnit orgUnit )
+    private boolean isUnapprovedBelow ( OrganisationUnit orgUnit, int orgUnitLevel )
     {
-        log.trace( "isUnapprovedBelow( " + orgUnit.getName() + " )" );
+        log.info( "isUnapprovedBelow( " + orgUnit.getName() + " )" );
 
         if ( dataSetAssignedAtOrBelowLevel == false && orgUnit.getAllDataSets().contains( dataSet ) )
         {
@@ -731,44 +741,44 @@
 
         if ( lowerIndex < matchingApprovalLevels.size() )
         {
-            if ( orgUnit.getLevel() == matchingApprovalLevels.get( lowerIndex ).getLevel() )
+            if ( orgUnitLevel == matchingApprovalLevels.get( lowerIndex ).getLevel() )
             {
-                log.trace( "isUnapprovedBelow() orgUnit level " + orgUnit.getLevel() + " matches approval level." );
+                log.info( "isUnapprovedBelow() orgUnit level " + orgUnitLevel + " matches approval level." );
 
                 DataApproval d = getDataApproval( lowerIndex, orgUnit );
 
-                log.trace( "isUnapprovedBelow() returns " + ( d == null ) + " after looking for approval for this orgUnit." );
+                log.info( "isUnapprovedBelow() returns " + ( d == null ) + " after looking for approval for this orgUnit." );
 
                 return ( d == null );
             }
         }
         else if ( dataSetAssignedAtOrBelowLevel )
         {
-            log.trace( "isUnapprovedBelow() returns false with data set assigned at or below level." );
+            log.info( "isUnapprovedBelow() returns false with data set assigned at or below level." );
 
             return false;
         }
 
         if ( orgUnit.getChildren() == null || orgUnit.getChildren().size() == 0 )
         {
-            log.trace( "isUnapprovedBelow() returns false with no more children." );
+            log.info( "isUnapprovedBelow() returns false with no more children." );
 
             return false;
         }
 
-        log.trace( "+++ isUnapprovedBelow( " + orgUnit.getName() + " ) is recursing..." );
+        log.info( "+++ isUnapprovedBelow( " + orgUnit.getName() + " ) is recursing..." );
 
         for ( OrganisationUnit child : orgUnit.getChildren() )
         {
-            if ( isUnapprovedBelow( child ) )
+            if ( isUnapprovedBelow( child, orgUnitLevel + 1 ) )
             {
-                log.trace( "--- isUnapprovedBelow( " + orgUnit.getName() + " ) returns true because unapproved from below." );
+                log.info( "--- isUnapprovedBelow( " + orgUnit.getName() + " ) returns true because unapproved from below." );
 
                 return true;
             }
         }
 
-        log.trace( "--- isUnapprovedBelow( " + orgUnit.getName() + " ) returns false after recursing" );
+        log.info( "--- isUnapprovedBelow( " + orgUnit.getName() + " ) returns false after recursing" );
 
         return false;
     }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalLevelService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalLevelService.java	2014-03-28 17:08:12 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalLevelService.java	2014-03-30 04:37:39 +0000
@@ -29,6 +29,8 @@
  */
 
 import org.hisp.dhis.dataelement.CategoryOptionGroup;
+import org.hisp.dhis.organisationunit.OrganisationUnitLevel;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.security.SecurityService;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -53,6 +55,13 @@
         this.dataApprovalLevelStore = dataApprovalLevelStore;
     }
 
+    private OrganisationUnitService organisationUnitService;
+
+    public void setOrganisationUnitService( OrganisationUnitService organisationUnitService )
+    {
+        this.organisationUnitService = organisationUnitService;
+    }
+
     private SecurityService securityService;
 
     public void setSecurityService( SecurityService securityService )
@@ -66,7 +75,29 @@
 
     public List<DataApprovalLevel> getAllDataApprovalLevels()
     {
-        return dataApprovalLevelStore.getAllDataApprovalLevels();
+        List<DataApprovalLevel> dataApprovalLevels = dataApprovalLevelStore.getAllDataApprovalLevels();
+
+        for ( DataApprovalLevel dataApprovalLevel : dataApprovalLevels)
+        {
+            String ouLevelName;
+
+            int ouLevelNumber = dataApprovalLevel.getOrgUnitLevel();
+
+            OrganisationUnitLevel ouLevel = organisationUnitService.getOrganisationUnitLevelByLevel( ouLevelNumber );
+
+            if ( ouLevel != null )
+            {
+                ouLevelName = ouLevelNumber + " " + ouLevel.getName();
+            }
+            else
+            {
+                ouLevelName = "Organization unit level " + ouLevelNumber;
+            }
+
+            dataApprovalLevel.setOrgUnitLevelName( ouLevelName );
+        }
+
+        return dataApprovalLevels;
     }
 
     public boolean canDataApprovalLevelMoveDown( int level )
@@ -83,7 +114,7 @@
         DataApprovalLevel test = dataApprovalLevels.get( index );
         DataApprovalLevel next = dataApprovalLevels.get( index + 1 );
 
-        if ( test.getOrganisationUnitLevel().getLevel() == next.getOrganisationUnitLevel().getLevel()
+        if ( test.getOrgUnitLevel() == next.getOrgUnitLevel()
                 && test.getCategoryOptionGroupSet() != null )
         {
             return true;
@@ -108,7 +139,7 @@
         DataApprovalLevel test = dataApprovalLevels.get( index );
         DataApprovalLevel previous = dataApprovalLevels.get( index - 1 );
 
-        if ( test.getOrganisationUnitLevel().getLevel() == previous.getOrganisationUnitLevel().getLevel()
+        if ( test.getOrgUnitLevel() == previous.getOrgUnitLevel()
                 && previous.getCategoryOptionGroupSet() != null )
         {
             return true;
@@ -141,7 +172,7 @@
 
         for ( DataApprovalLevel dataApprovalLevel : dataApprovalLevels )
         {
-            if ( testLevel.getOrganisationUnitLevel() == dataApprovalLevel.getOrganisationUnitLevel()
+            if ( testLevel.getOrgUnitLevel() == dataApprovalLevel.getOrgUnitLevel()
                     && testLevel.getCategoryOptionGroupSet() == dataApprovalLevel.getCategoryOptionGroupSet() )
             {
                 return true;
@@ -155,7 +186,7 @@
     {
         List<DataApprovalLevel> dataApprovalLevels = getAllDataApprovalLevels();
 
-        if ( newLevel.getOrganisationUnitLevel() == null )
+        if ( newLevel.getOrgUnitLevel() <= 0 )
         {
             return false;
         }
@@ -289,7 +320,7 @@
         {
             DataApprovalLevel test = dataApprovalLevels.get( i );
 
-            int orgLevelDifference = newLevel.getOrganisationUnitLevel().getLevel() - test.getOrganisationUnitLevel().getLevel();
+            int orgLevelDifference = newLevel.getOrgUnitLevel() - test.getOrgUnitLevel();
 
             if ( orgLevelDifference > 0 )
             {

=== 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-03-28 10:13:01 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java	2014-03-30 04:37:39 +0000
@@ -31,12 +31,15 @@
 import java.util.Set;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.dataelement.DataElementCategoryOption;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.dataset.DataSet;
 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.security.SecurityService;
@@ -51,6 +54,8 @@
 public class DefaultDataApprovalService
     implements DataApprovalService
 {
+    private final static Log log = LogFactory.getLog( DefaultDataApprovalService.class );
+
     // -------------------------------------------------------------------------
     // Dependencies
     // -------------------------------------------------------------------------
@@ -69,6 +74,13 @@
         this.dataApprovalLevelService = dataApprovalLevelService;
     }
 
+    private OrganisationUnitService organisationUnitService;
+
+    public void setOrganisationUnitService( OrganisationUnitService organisationUnitService )
+    {
+        this.organisationUnitService = organisationUnitService;
+    }
+
     private CurrentUserService currentUserService;
 
     public void setCurrentUserService( CurrentUserService currentUserService )
@@ -103,22 +115,38 @@
 
     public void addDataApproval( DataApproval dataApproval )
     {
-        dataApprovalStore.addDataApproval( dataApproval );
+        if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
+                && mayApprove( dataApproval.getOrganisationUnit() ) )
+        {
+            dataApprovalStore.addDataApproval( dataApproval );
+        }
+        else
+        {
+            warnNotPermitted( dataApproval, "approve", mayApprove( dataApproval.getOrganisationUnit() ) );
+        }
     }
 
     public void deleteDataApproval( DataApproval dataApproval )
     {
-        dataApprovalStore.deleteDataApproval( dataApproval );
-
-        for ( OrganisationUnit ancestor : dataApproval.getOrganisationUnit().getAncestors() )
+        if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
+                && mayUnapprove( dataApproval.getOrganisationUnit(), dataApproval.isAccepted() ))
         {
-            DataApproval ancestorApproval = dataApprovalStore.getDataApproval(
-                    dataApproval.getDataSet(), dataApproval.getPeriod(), ancestor, dataApproval.getCategoryOptionGroup() );
-
-            if ( ancestorApproval != null ) {
-                dataApprovalStore.deleteDataApproval ( ancestorApproval );
+            dataApprovalStore.deleteDataApproval( dataApproval );
+
+            for ( OrganisationUnit ancestor : dataApproval.getOrganisationUnit().getAncestors() )
+            {
+                DataApproval ancestorApproval = dataApprovalStore.getDataApproval(
+                        dataApproval.getDataSet(), dataApproval.getPeriod(), ancestor, dataApproval.getCategoryOptionGroup() );
+
+                if ( ancestorApproval != null ) {
+                    dataApprovalStore.deleteDataApproval ( ancestorApproval );
+                }
             }
         }
+        else
+        {
+            warnNotPermitted( dataApproval, "unapprove", mayUnapprove( dataApproval.getOrganisationUnit(), dataApproval.isAccepted() ) );
+        }
     }
 
     public DataApprovalStatus getDataApprovalStatus( DataSet dataSet, Period period, OrganisationUnit organisationUnit, DataElementCategoryOptionCombo attributeOptionCombo )
@@ -135,7 +163,7 @@
         DataApprovalSelection dataApprovalSelection = new DataApprovalSelection( dataSet, period, organisationUnit,
                 categoryOptionGroup, dataElementCategoryOptions,
                 dataApprovalStore, dataApprovalLevelService,
-                categoryService, periodService);
+                organisationUnitService, categoryService, periodService);
 
         return dataApprovalSelection.getDataApprovalStatus();
     }
@@ -156,47 +184,71 @@
 
         DataApprovalPermissions permissions = new DataApprovalPermissions();
 
+        log.info( "getDataApprovalPermissions() getting permissions." );
+
         permissions.setDataApprovalStatus( status );
 
         if ( canReadCategoryOptionGroups( categoryOptionGroup, dataElementCategoryOptions ) )
         {
+            boolean accepted = false;
+
             switch ( status.getDataApprovalState() )
             {
+                case APPROVED_HERE:
+                case ACCEPTED_HERE:
+                    accepted = status.getDataApproval().isAccepted();
                 case UNAPPROVED_READY:
                     permissions.setMayApprove( mayApprove( organisationUnit ) );
-                    break;
-
-                case APPROVED_HERE:
-                    permissions.setMayUnapprove( mayUnapprove( status ) );
-                    permissions.setMayAccept( mayAcceptOrUnaccept( status ) );
-                    break;
-
-                case ACCEPTED_HERE:
-                    permissions.setMayUnapprove( mayUnapprove( status ) );
-                    permissions.setMayUnaccept( mayAcceptOrUnaccept( status ) );
+                    permissions.setMayUnapprove( mayUnapprove( organisationUnit, accepted ) );
+                    permissions.setMayAccept( mayAcceptOrUnaccept( organisationUnit ) );
+                    permissions.setMayUnaccept( permissions.isMayAccept() );
                     break;
             }
         }
+
+        log.info( "Returning permissions for " + organisationUnit.getName()
+                + " " + status.getDataApprovalState().name()
+                + " may approve = " + permissions.isMayApprove()
+                + " may unapprove = " + permissions.isMayUnapprove()
+                + " may accept = " + permissions.isMayAccept()
+                + " may unaccept = " + permissions.isMayUnaccept() );
+
         return permissions;
     }
 
     public void accept( DataApproval dataApproval )
     {
-        if ( !dataApproval.isAccepted() )
+        if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
+                && mayAcceptOrUnaccept( dataApproval.getOrganisationUnit() ) )
         {
-            dataApproval.setAccepted( true );
+            if ( !dataApproval.isAccepted() )
+            {
+                dataApproval.setAccepted( true );
 
-            dataApprovalStore.updateDataApproval( dataApproval );
+                dataApprovalStore.updateDataApproval( dataApproval );
+            }
+        }
+        else
+        {
+            warnNotPermitted( dataApproval, "accept", mayAcceptOrUnaccept( dataApproval.getOrganisationUnit() ) );
         }
     }
 
     public void unaccept( DataApproval dataApproval )
     {
-        if ( dataApproval.isAccepted() )
+        if ( ( dataApproval.getCategoryOptionGroup() == null || securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
+                && mayAcceptOrUnaccept( dataApproval.getOrganisationUnit() ) )
         {
-            dataApproval.setAccepted( false );
+            if ( dataApproval.isAccepted() )
+            {
+                dataApproval.setAccepted( false );
 
-            dataApprovalStore.updateDataApproval( dataApproval );
+                dataApprovalStore.updateDataApproval( dataApproval );
+            }
+        }
+        else
+        {
+            warnNotPermitted( dataApproval, "unaccept", mayAcceptOrUnaccept( dataApproval.getOrganisationUnit() ) );
         }
     }
 
@@ -224,6 +276,8 @@
     {
         if ( categoryOptionGroup != null && !securityService.canRead( categoryOptionGroup ) )
         {
+            log.info( "User cannot read categoryOptionGroup " + categoryOptionGroup.getName() + " for approval." );
+
             return false;
         }
 
@@ -231,26 +285,36 @@
         {
             for ( DataElementCategoryOption option : dataElementCategoryOptions )
             {
-                boolean canReadGroup = false;
-
-                for ( CategoryOptionGroup group : option.getGroups() )
-                {
-                    if ( securityService.canRead( group ) )
-                    {
-                        canReadGroup = true;
-
-                        break;
-                    }
-
-                }
-
-                if ( !canReadGroup )
-                {
-                    return false;
+                if ( !securityService.canRead( option ) )
+                {
+                    boolean canReadGroup = false;
+
+                    for ( CategoryOptionGroup group : option.getGroups() )
+                    {
+                        log.info( "User " + ( securityService.canRead( group ) ? "can" : "cannot" )
+                                + " read option group" + group.getName()
+                                + " for option " + option.getName() );
+
+                        if ( securityService.canRead( group ) )
+                        {
+                            canReadGroup = true;
+
+                            break;
+                        }
+                    }
+
+                    if ( !canReadGroup && option.getGroups().size() != 0 )
+                    {
+                        log.info( "User cannot read option " + option.getName() );
+
+                        return false;
+                    }
                 }
             }
         }
 
+        log.info( "User can read categoryOptionGroup and/or dataElementCategoryOptions" );
+
         return true;
     }
 
@@ -271,6 +335,9 @@
 
             if ( mayApprove && user.getOrganisationUnits().contains( organisationUnit ) )
             {
+                log.info( "mayApprove = true because organisation unit " + organisationUnit.getName()
+                        + " is assigned to user and user may approve at same level." );
+
                 return true;
             }
 
@@ -279,15 +346,20 @@
             if ( mayApproveAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(),
                     organisationUnit.getAncestors() ) )
             {
+                log.info( "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() );
+
         return false;
     }
 
     /**
-     * Checks to see whether a user may unapprove a given data approval.
+     * Checks to see whether a user may unapprove for a given organisation unit.
      * <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
@@ -301,46 +373,56 @@
      * 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 status The data approval status to check for permission.
+     * @param organisationUnit The data approval status to check for permission.
+     * @param accepted Whether selection is accepted.
+     * @return true if the user may unapprove, otherwise false
      */
-    private boolean mayUnapprove( DataApprovalStatus status )
+    private boolean mayUnapprove( OrganisationUnit organisationUnit, boolean accepted )
     {
-        DataApproval dataApproval = status.getDataApproval();
-
-        if ( dataApproval != null && isAuthorizedToUnapprove( dataApproval.getOrganisationUnit() ) )
+        if ( isAuthorizedToUnapprove( organisationUnit ) )
         {
-            if ( !dataApproval.isAccepted() || mayAcceptOrUnaccept( status ) )
+            if ( !accepted || mayAcceptOrUnaccept( organisationUnit ) )
             {
+                log.info( "mayUnapprove = true for organisation unit " + organisationUnit.getName() );
+
                 return true;
             }
         }
 
+        log.info( "mayUnapprove = false for organisation unit " + organisationUnit.getName() );
+
         return false;
     }
 
     /**
-     * Checks to see whether a user may accept or unaccept a given data approval.
+     * Checks to see whether a user may accept or unaccept for a given
+     * organisation unit.
      *
-     * @param status The data approval status to check for permission.
-     * @return true if the user may accept or unaccept it, otherwise false.
+     * @param organisationUnit The organisation unit to check for permission.
+     * @return true if the user may accept or unaccept, otherwise false.
      */
-    private boolean mayAcceptOrUnaccept ( DataApprovalStatus status )
+    private boolean mayAcceptOrUnaccept ( OrganisationUnit organisationUnit )
     {
         User user = currentUserService.getCurrentUser();
 
-        DataApproval dataApproval = status.getDataApproval();
-
-        if ( user != null && dataApproval != null )
+        if ( user != null )
         {
             boolean mayAcceptAtLowerLevels = user.getUserCredentials().isAuthorized( DataApproval.AUTH_ACCEPT_LOWER_LEVELS );
 
             if ( mayAcceptAtLowerLevels && CollectionUtils.containsAny( user.getOrganisationUnits(),
-                    dataApproval.getOrganisationUnit().getAncestors() ) )
+                    organisationUnit.getAncestors() ) )
             {
+                log.info( "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 )
+                + " with " + user.getOrganisationUnits().size() + " org units"
+                + " may not accept or unaccept for organisation unit " + organisationUnit.getName()
+                + " with " + organisationUnit.getAncestors().size() + " ancestors.");
+
         return false;
     }
 
@@ -357,8 +439,12 @@
      */
     private boolean isAuthorizedToUnapprove( OrganisationUnit organisationUnit )
     {
+        log.info( "isAuthorizedToUnapprove( " + organisationUnit.getName() + ")" );
+
         if ( mayApprove( organisationUnit ) )
         {
+            log.info( "User may unapprove at " + organisationUnit.getName() );
+
             return true;
         }
 
@@ -366,10 +452,47 @@
         {
             if ( mayApprove( ancestor ) )
             {
+                log.info( "User may unapprove at " + ancestor.getName() );
+
                 return true;
             }
         }
 
+        log.info( "User may not unapprove at " + organisationUnit.getName() );
+
         return false;
     }
+
+    /**
+     * Warns if the user is not permitted to make a data approval operation.
+     * If the UI is working correctly, the user should never be able to choose
+     * an operation for which they are not permitted. So this should happen
+     * only if there is a programming error, or if the user is trying to perform
+     * an operation that the UI would not normally offer.
+     *
+     * @param dataApproval the data approval object for the attempted operation.
+     * @param operation the name of the operation attempted.
+     * @param mayOperate whether the user may perform this operation.
+     */
+    private void warnNotPermitted( DataApproval dataApproval, String operation, boolean mayOperate )
+    {
+        String warning = "User " + currentUserService.getCurrentUsername() + " tried to " + operation
+                + " data for (org unit " + dataApproval.getOrganisationUnit().getName()
+                + ", period " + dataApproval.getPeriod().getName()
+                + ", data set " + dataApproval.getDataSet().getName()
+                + ", COG " + ( dataApproval.getCategoryOptionGroup() == null ? "[null]" : dataApproval.getCategoryOptionGroup().getName() )
+                + ")";
+
+        if ( dataApproval.getCategoryOptionGroup() != null && !securityService.canRead( dataApproval.getCategoryOptionGroup() ) )
+        {
+            warning += " but couldn't read COG";
+        }
+
+        if ( !mayOperate )
+        {
+            warning += " but couldn't " + operation;
+        }
+
+        log.warn( warning + "." );
+    }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalLevelStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalLevelStore.java	2014-03-28 17:08:12 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalLevelStore.java	2014-03-30 04:37:39 +0000
@@ -31,6 +31,7 @@
 import java.util.List;
 
 import org.hibernate.criterion.Order;
+import org.hibernate.proxy.HibernateProxy;
 import org.hisp.dhis.dataapproval.DataApprovalLevel;
 import org.hisp.dhis.dataapproval.DataApprovalLevelStore;
 import org.hisp.dhis.hibernate.HibernateGenericStore;

=== 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	2014-03-28 08:30:22 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java	2014-03-30 04:37:39 +0000
@@ -707,7 +707,10 @@
         // update attribute.code, set to null if code=''
         executeSql( "UPDATE attribute SET code=NULL WHERE code=''" );
 
-        // validation rule group, new column alertbyorgunits needs values
+        // data approval, new column accepted
+        executeSql( "UPDATE dataapproval SET accepted=false WHERE accepted IS NULL" );
+
+        // validation rule group, new column alertbyorgunits
         executeSql( "UPDATE validationrulegroup SET alertbyorgunits=false WHERE alertbyorgunits IS NULL" );
 
         upgradeDataValuesWithAttributeOptionCombo();

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-03-28 01:53:11 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml	2014-03-30 04:37:39 +0000
@@ -411,6 +411,7 @@
   <bean id="org.hisp.dhis.dataapproval.DataApprovalService" class="org.hisp.dhis.dataapproval.DefaultDataApprovalService">
     <property name="dataApprovalStore" ref="org.hisp.dhis.dataapproval.DataApprovalStore" />
     <property name="dataApprovalLevelService" ref="org.hisp.dhis.dataapproval.DataApprovalLevelService" />
+    <property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
     <property name="currentUserService" ref="org.hisp.dhis.user.CurrentUserService" />
     <property name="categoryService" ref="org.hisp.dhis.dataelement.DataElementCategoryService" />
     <property name="periodService" ref="org.hisp.dhis.period.PeriodService" />
@@ -419,6 +420,7 @@
 
   <bean id="org.hisp.dhis.dataapproval.DataApprovalLevelService" class="org.hisp.dhis.dataapproval.DefaultDataApprovalLevelService">
     <property name="dataApprovalLevelStore" ref="org.hisp.dhis.dataapproval.DataApprovalLevelStore" />
+    <property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
     <property name="securityService" ref="org.hisp.dhis.security.SecurityService" />
   </bean>
 

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/DataApprovalLevel.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/DataApprovalLevel.hbm.xml	2014-02-23 13:08:31 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataapproval/hibernate/DataApprovalLevel.hbm.xml	2014-03-30 04:37:39 +0000
@@ -14,7 +14,7 @@
     <property name="level" column="level" not-null="true" />
 
     <properties name="dataapprovallevel_orgunitlevel_categoryoptiongroupset_unique_key" unique="true">
-      <many-to-one name="organisationUnitLevel" class="org.hisp.dhis.organisationunit.OrganisationUnitLevel" not-null="true" column="organisationunitlevelid" foreign-key="fk_dataapprovallevel_organisationunitlevelid" />
+      <property name="orgUnitLevel" not-null="true" column="orgunitlevel" />
       <many-to-one name="categoryOptionGroupSet" class="org.hisp.dhis.dataelement.CategoryOptionGroupSet" column="categoryoptiongroupsetid" foreign-key="fK_dataapprovallevel_categoryoptiongroupsetid" />
     </properties>
 

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalLevelServiceTest.java'
--- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalLevelServiceTest.java	2014-03-28 10:13:01 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalLevelServiceTest.java	2014-03-30 04:37:39 +0000
@@ -64,11 +64,6 @@
     // Supporting data
     // -------------------------------------------------------------------------
 
-    private OrganisationUnitLevel orgUnitLevel1;
-    private OrganisationUnitLevel orgUnitLevel2;
-    private OrganisationUnitLevel orgUnitLevel3;
-    private OrganisationUnitLevel orgUnitLevel4;
-
     private CategoryOptionGroupSet setA;
     private CategoryOptionGroupSet setB;
     private CategoryOptionGroupSet setC;
@@ -110,16 +105,6 @@
         // Add supporting data
         // ---------------------------------------------------------------------
 
-        orgUnitLevel1 = new OrganisationUnitLevel( 1, "Level 1");
-        orgUnitLevel2 = new OrganisationUnitLevel( 2, "Level 2");
-        orgUnitLevel3 = new OrganisationUnitLevel( 3, "Level 3");
-        orgUnitLevel4 = new OrganisationUnitLevel( 4, "Level 4");
-
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel1 );
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel2 );
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel3 );
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel4 );
-
         setA = new CategoryOptionGroupSet( "Set A" );
         setB = new CategoryOptionGroupSet( "Set B" );
         setC = new CategoryOptionGroupSet( "Set C" );
@@ -132,29 +117,29 @@
 
         Date now = new Date();
 
-        level1 = new DataApprovalLevel( orgUnitLevel1, null );
-        level1A = new DataApprovalLevel( orgUnitLevel1, setA );
-        level1B = new DataApprovalLevel( orgUnitLevel1, setB );
-        level1C = new DataApprovalLevel( orgUnitLevel1, setC );
-        level1D = new DataApprovalLevel( orgUnitLevel1, setD );
-
-        level2 = new DataApprovalLevel( orgUnitLevel2, null );
-        level2A = new DataApprovalLevel( orgUnitLevel2, setA );
-        level2B = new DataApprovalLevel( orgUnitLevel2, setB );
-        level2C = new DataApprovalLevel( orgUnitLevel2, setC );
-        level2D = new DataApprovalLevel( orgUnitLevel2, setD );
-
-        level3 = new DataApprovalLevel( orgUnitLevel3, null );
-        level3A = new DataApprovalLevel( orgUnitLevel3, setA );
-        level3B = new DataApprovalLevel( orgUnitLevel3, setB );
-        level3C = new DataApprovalLevel( orgUnitLevel3, setC );
-        level3D = new DataApprovalLevel( orgUnitLevel3, setD );
-
-        level4 = new DataApprovalLevel( orgUnitLevel4, null );
-        level4A = new DataApprovalLevel( orgUnitLevel4, setA );
-        level4B = new DataApprovalLevel( orgUnitLevel4, setB );
-        level4C = new DataApprovalLevel( orgUnitLevel4, setC );
-        level4D = new DataApprovalLevel( orgUnitLevel4, setD );
+        level1 = new DataApprovalLevel( 1, null );
+        level1A = new DataApprovalLevel( 1, setA );
+        level1B = new DataApprovalLevel( 1, setB );
+        level1C = new DataApprovalLevel( 1, setC );
+        level1D = new DataApprovalLevel( 1, setD );
+
+        level2 = new DataApprovalLevel( 2, null );
+        level2A = new DataApprovalLevel( 2, setA );
+        level2B = new DataApprovalLevel( 2, setB );
+        level2C = new DataApprovalLevel( 2, setC );
+        level2D = new DataApprovalLevel( 2, setD );
+
+        level3 = new DataApprovalLevel( 3, null );
+        level3A = new DataApprovalLevel( 3, setA );
+        level3B = new DataApprovalLevel( 3, setB );
+        level3C = new DataApprovalLevel( 3, setC );
+        level3D = new DataApprovalLevel( 3, setD );
+
+        level4 = new DataApprovalLevel( 4, null );
+        level4A = new DataApprovalLevel( 4, setA );
+        level4B = new DataApprovalLevel( 4, setB );
+        level4C = new DataApprovalLevel( 4, setC );
+        level4D = new DataApprovalLevel( 4, setD );
     }
 
     // -------------------------------------------------------------------------
@@ -173,57 +158,57 @@
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 1, levels.size() );
 
-        assertEquals( "Level 3", levels.get( 0 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 3, levels.get( 0 ).getOrgUnitLevel() );
         assertEquals( "Set B", levels.get( 0 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 3 - Set B", levels.get( 0 ).getName() );
+        assertEquals( "3 - Set B", levels.get( 0 ).getName() );
 
         dataApprovalLevelService.addDataApprovalLevel( level2C );
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 2, levels.size() );
 
-        assertEquals( "Level 2", levels.get( 0 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 2, levels.get( 0 ).getOrgUnitLevel() );
         assertEquals( "Set C", levels.get( 0 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 2 - Set C", levels.get( 0 ).getName() );
+        assertEquals( "2 - Set C", levels.get( 0 ).getName() );
 
-        assertEquals( "Level 3", levels.get( 1 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 3, levels.get( 1 ).getOrgUnitLevel() );
         assertEquals( "Set B", levels.get( 1 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 3 - Set B", levels.get( 1 ).getName() );
+        assertEquals( "3 - Set B", levels.get( 1 ).getName() );
 
         dataApprovalLevelService.addDataApprovalLevel( level3 );
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 3, levels.size() );
 
-        assertEquals( "Level 2", levels.get( 0 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 2, levels.get( 0 ).getOrgUnitLevel() );
         assertEquals( "Set C", levels.get( 0 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 2 - Set C", levels.get( 0 ).getName() );
+        assertEquals( "2 - Set C", levels.get( 0 ).getName() );
 
-        assertEquals( "Level 3", levels.get( 1 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 3, levels.get( 1 ).getOrgUnitLevel() );
         assertNull( levels.get( 1 ).getCategoryOptionGroupSet() );
-        assertEquals( "Level 3", levels.get( 1 ).getName() );
+        assertEquals( "3", levels.get( 1 ).getName() );
 
-        assertEquals( "Level 3", levels.get( 2 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 3, levels.get( 2 ).getOrgUnitLevel() );
         assertEquals( "Set B", levels.get( 2 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 3 - Set B", levels.get( 2 ).getName() );
+        assertEquals( "3 - Set B", levels.get( 2 ).getName() );
 
         dataApprovalLevelService.addDataApprovalLevel( level4A );
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 4, levels.size() );
 
-        assertEquals( "Level 2", levels.get( 0 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 2, levels.get( 0 ).getOrgUnitLevel() );
         assertEquals( "Set C", levels.get( 0 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 2 - Set C", levels.get( 0 ).getName() );
+        assertEquals( "2 - Set C", levels.get( 0 ).getName() );
 
-        assertEquals( "Level 3", levels.get( 1 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 3, levels.get( 1 ).getOrgUnitLevel() );
         assertNull( levels.get( 1 ).getCategoryOptionGroupSet() );
-        assertEquals( "Level 3", levels.get( 1 ).getName() );
+        assertEquals( "3", levels.get( 1 ).getName() );
 
-        assertEquals( "Level 3", levels.get( 2 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 3, levels.get( 2 ).getOrgUnitLevel() );
         assertEquals( "Set B", levels.get( 2 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 3 - Set B", levels.get( 2 ).getName() );
+        assertEquals( "3 - Set B", levels.get( 2 ).getName() );
 
-        assertEquals( "Level 4", levels.get( 3 ).getOrganisationUnitLevel().getName() );
+        assertEquals( 4, levels.get( 3 ).getOrgUnitLevel() );
         assertEquals( "Set A", levels.get( 3 ).getCategoryOptionGroupSet().getName() );
-        assertEquals( "Level 4 - Set A", levels.get( 3 ).getName() );
+        assertEquals( "4 - Set A", levels.get( 3 ).getName() );
     }
 
     @Test
@@ -238,31 +223,31 @@
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 4, levels.size() );
-        assertEquals( "Level 1 - Set A", levels.get( 0 ).getName() );
-        assertEquals( "Level 2 - Set B", levels.get( 1 ).getName() );
-        assertEquals( "Level 3 - Set C", levels.get( 2 ).getName() );
-        assertEquals( "Level 4 - Set D", levels.get( 3 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 0 ).getName() );
+        assertEquals( "2 - Set B", levels.get( 1 ).getName() );
+        assertEquals( "3 - Set C", levels.get( 2 ).getName() );
+        assertEquals( "4 - Set D", levels.get( 3 ).getName() );
 
         dataApprovalLevelService.deleteDataApprovalLevel( 2 );
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 3, levels.size() );
-        assertEquals( "Level 1 - Set A", levels.get( 0 ).getName() );
-        assertEquals( "Level 3 - Set C", levels.get( 1 ).getName() );
-        assertEquals( "Level 4 - Set D", levels.get( 2 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 0 ).getName() );
+        assertEquals( "3 - Set C", levels.get( 1 ).getName() );
+        assertEquals( "4 - Set D", levels.get( 2 ).getName() );
 
         dataApprovalLevelService.deleteDataApprovalLevel( 3 );
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 2, levels.size() );
-        assertEquals( "Level 1 - Set A", levels.get( 0 ).getName() );
-        assertEquals( "Level 3 - Set C", levels.get( 1 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 0 ).getName() );
+        assertEquals( "3 - Set C", levels.get( 1 ).getName() );
 
         dataApprovalLevelService.deleteDataApprovalLevel( 1 );
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 1, levels.size() );
-        assertEquals( "Level 3 - Set C", levels.get( 0 ).getName() );
+        assertEquals( "3 - Set C", levels.get( 0 ).getName() );
 
         dataApprovalLevelService.deleteDataApprovalLevel( 1 );
 
@@ -364,31 +349,31 @@
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 5, levels.size() );
-        assertEquals( "Level 1", levels.get( 0 ).getName() );
-        assertEquals( "Level 1 - Set A", levels.get( 1 ).getName() );
-        assertEquals( "Level 1 - Set B", levels.get( 2 ).getName() );
-        assertEquals( "Level 1 - Set C", levels.get( 3 ).getName() );
-        assertEquals( "Level 1 - Set D", levels.get( 4 ).getName() );
+        assertEquals( "1", levels.get( 0 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 1 ).getName() );
+        assertEquals( "1 - Set B", levels.get( 2 ).getName() );
+        assertEquals( "1 - Set C", levels.get( 3 ).getName() );
+        assertEquals( "1 - Set D", levels.get( 4 ).getName() );
 
         dataApprovalLevelService.moveDataApprovalLevelDown( 2 );
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 5, levels.size() );
-        assertEquals( "Level 1", levels.get( 0 ).getName() );
-        assertEquals( "Level 1 - Set B", levels.get( 1 ).getName() );
-        assertEquals( "Level 1 - Set A", levels.get( 2 ).getName() );
-        assertEquals( "Level 1 - Set C", levels.get( 3 ).getName() );
-        assertEquals( "Level 1 - Set D", levels.get( 4 ).getName() );
+        assertEquals( "1", levels.get( 0 ).getName() );
+        assertEquals( "1 - Set B", levels.get( 1 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 2 ).getName() );
+        assertEquals( "1 - Set C", levels.get( 3 ).getName() );
+        assertEquals( "1 - Set D", levels.get( 4 ).getName() );
 
         dataApprovalLevelService.moveDataApprovalLevelDown( 3 );
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 5, levels.size() );
-        assertEquals( "Level 1", levels.get( 0 ).getName() );
-        assertEquals( "Level 1 - Set B", levels.get( 1 ).getName() );
-        assertEquals( "Level 1 - Set C", levels.get( 2 ).getName() );
-        assertEquals( "Level 1 - Set A", levels.get( 3 ).getName() );
-        assertEquals( "Level 1 - Set D", levels.get( 4 ).getName() );
+        assertEquals( "1", levels.get( 0 ).getName() );
+        assertEquals( "1 - Set B", levels.get( 1 ).getName() );
+        assertEquals( "1 - Set C", levels.get( 2 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 3 ).getName() );
+        assertEquals( "1 - Set D", levels.get( 4 ).getName() );
     }
 
     @Test
@@ -404,30 +389,30 @@
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 5, levels.size() );
-        assertEquals( "Level 1", levels.get( 0 ).getName() );
-        assertEquals( "Level 1 - Set A", levels.get( 1 ).getName() );
-        assertEquals( "Level 1 - Set B", levels.get( 2 ).getName() );
-        assertEquals( "Level 1 - Set C", levels.get( 3 ).getName() );
-        assertEquals( "Level 1 - Set D", levels.get( 4 ).getName() );
+        assertEquals( "1", levels.get( 0 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 1 ).getName() );
+        assertEquals( "1 - Set B", levels.get( 2 ).getName() );
+        assertEquals( "1 - Set C", levels.get( 3 ).getName() );
+        assertEquals( "1 - Set D", levels.get( 4 ).getName() );
 
         dataApprovalLevelService.moveDataApprovalLevelUp( 5 );
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 5, levels.size() );
-        assertEquals( "Level 1", levels.get( 0 ).getName() );
-        assertEquals( "Level 1 - Set A", levels.get( 1 ).getName() );
-        assertEquals( "Level 1 - Set B", levels.get( 2 ).getName() );
-        assertEquals( "Level 1 - Set D", levels.get( 3 ).getName() );
-        assertEquals( "Level 1 - Set C", levels.get( 4 ).getName() );
+        assertEquals( "1", levels.get( 0 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 1 ).getName() );
+        assertEquals( "1 - Set B", levels.get( 2 ).getName() );
+        assertEquals( "1 - Set D", levels.get( 3 ).getName() );
+        assertEquals( "1 - Set C", levels.get( 4 ).getName() );
 
         dataApprovalLevelService.moveDataApprovalLevelUp( 4 );
 
         levels = dataApprovalLevelService.getAllDataApprovalLevels();
         assertEquals( 5, levels.size() );
-        assertEquals( "Level 1", levels.get( 0 ).getName() );
-        assertEquals( "Level 1 - Set A", levels.get( 1 ).getName() );
-        assertEquals( "Level 1 - Set D", levels.get( 2 ).getName() );
-        assertEquals( "Level 1 - Set B", levels.get( 3 ).getName() );
-        assertEquals( "Level 1 - Set C", levels.get( 4 ).getName() );
+        assertEquals( "1", levels.get( 0 ).getName() );
+        assertEquals( "1 - Set A", levels.get( 1 ).getName() );
+        assertEquals( "1 - Set D", levels.get( 2 ).getName() );
+        assertEquals( "1 - Set B", levels.get( 3 ).getName() );
+        assertEquals( "1 - Set C", levels.get( 4 ).getName() );
     }
 }

=== 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-03-28 01:53:11 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceTest.java	2014-03-30 04:37:39 +0000
@@ -62,6 +62,9 @@
     private DataApprovalService dataApprovalService;
 
     @Autowired
+    private DataApprovalStore dataApprovalStore;
+
+    @Autowired
     private DataApprovalLevelService dataApprovalLevelService;
 
     @Autowired
@@ -112,14 +115,6 @@
 
     private OrganisationUnit organisationUnitF;
 
-    private OrganisationUnitLevel orgUnitLevel1;
-
-    private OrganisationUnitLevel orgUnitLevel2;
-
-    private OrganisationUnitLevel orgUnitLevel3;
-
-    private OrganisationUnitLevel orgUnitLevel4;
-
     private DataApprovalLevel dataApprovalLevel1;
 
     private DataApprovalLevel dataApprovalLevel2;
@@ -246,16 +241,6 @@
         periodService.addPeriod( periodC );
         periodService.addPeriod( periodD );
 
-        orgUnitLevel1 = new OrganisationUnitLevel( 1, "Level 1");
-        orgUnitLevel2 = new OrganisationUnitLevel( 2, "Level 2");
-        orgUnitLevel3 = new OrganisationUnitLevel( 3, "Level 3");
-        orgUnitLevel4 = new OrganisationUnitLevel( 4, "Level 4");
-
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel1 );
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel2 );
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel3 );
-        organisationUnitService.addOrganisationUnitLevel( orgUnitLevel4 );
-
         //
         // Organisation unit hierarchy:
         //
@@ -289,10 +274,10 @@
         organisationUnitService.addOrganisationUnit( organisationUnitE );
         organisationUnitService.addOrganisationUnit( organisationUnitF );
 
-        dataApprovalLevel1 = new DataApprovalLevel( orgUnitLevel1, null );
-        dataApprovalLevel2 = new DataApprovalLevel( orgUnitLevel2, null );
-        dataApprovalLevel3 = new DataApprovalLevel( orgUnitLevel3, null );
-        dataApprovalLevel4 = new DataApprovalLevel( orgUnitLevel4, null );
+        dataApprovalLevel1 = new DataApprovalLevel( 1, null );
+        dataApprovalLevel2 = new DataApprovalLevel( 2, null );
+        dataApprovalLevel3 = new DataApprovalLevel( 3, null );
+        dataApprovalLevel4 = new DataApprovalLevel( 4, null );
 
         userA = createUser( 'A' );
         userB = createUser( 'B' );
@@ -381,20 +366,25 @@
         categoryService.saveCategoryOptionGroup( groupC );
         categoryService.saveCategoryOptionGroup( groupD );
 
-        groupSetA = createCategoryOptionGroupSet( 'A', groupA, groupB );
-        groupSetB = createCategoryOptionGroupSet( 'B', groupC, groupD );
+        groupSetA = new CategoryOptionGroupSet( "GroupSetA" );
+        groupSetB = new CategoryOptionGroupSet( "GroupSetB" );
 
         categoryService.saveCategoryOptionGroupSet( groupSetA );
         categoryService.saveCategoryOptionGroupSet( groupSetB );
 
-        dataApprovalLevel1A = new DataApprovalLevel( orgUnitLevel1, groupSetA );
-        dataApprovalLevel1B = new DataApprovalLevel( orgUnitLevel1, groupSetB );
-        dataApprovalLevel2A = new DataApprovalLevel( orgUnitLevel2, groupSetA );
-        dataApprovalLevel2B = new DataApprovalLevel( orgUnitLevel2, groupSetB );
-        dataApprovalLevel3A = new DataApprovalLevel( orgUnitLevel3, groupSetA );
-        dataApprovalLevel3B = new DataApprovalLevel( orgUnitLevel3, groupSetB );
-        dataApprovalLevel4A = new DataApprovalLevel( orgUnitLevel4, groupSetA );
-        dataApprovalLevel4B = new DataApprovalLevel( orgUnitLevel4, groupSetB );
+        groupSetA.addCategoryOptionGroup( groupA );
+        groupSetA.addCategoryOptionGroup( groupB );
+        groupSetB.addCategoryOptionGroup( groupC );
+        groupSetB.addCategoryOptionGroup( groupD );
+
+        dataApprovalLevel1A = new DataApprovalLevel( 1, groupSetA );
+        dataApprovalLevel1B = new DataApprovalLevel( 1, groupSetB );
+        dataApprovalLevel2A = new DataApprovalLevel( 2, groupSetA );
+        dataApprovalLevel2B = new DataApprovalLevel( 2, groupSetB );
+        dataApprovalLevel3A = new DataApprovalLevel( 3, groupSetA );
+        dataApprovalLevel3B = new DataApprovalLevel( 3, groupSetB );
+        dataApprovalLevel4A = new DataApprovalLevel( 4, groupSetA );
+        dataApprovalLevel4B = new DataApprovalLevel( 4, groupSetB );
     }
 
     // -------------------------------------------------------------------------
@@ -404,6 +394,10 @@
     @Test
     public void testAddAndGetDataApproval() throws Exception
     {
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS );
+
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel1 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel2 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel3 );
@@ -489,6 +483,10 @@
     @Test
     public void testAddDuplicateDataApproval() throws Exception
     {
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS );
+
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel1 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel2 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel3 );
@@ -514,6 +512,10 @@
     @Test
     public void testDeleteDataApproval() throws Exception
     {
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS );
+
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel1 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel2 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel3 );
@@ -557,6 +559,10 @@
     @Test
     public void testGetDataApprovalState() throws Exception
     {
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS );
+
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel1 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel2 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel3 );
@@ -643,6 +649,10 @@
     @Test
     public void testGetDataApprovalStateWithMultipleChildren() throws Exception
     {
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS );
+
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel1 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel2 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel3 );
@@ -697,6 +707,10 @@
     @Test
     public void testGetDataApprovalStateOtherPeriodTypes() throws Exception
     {
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS );
+
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel1 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel2 );
         dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel3 );
@@ -738,14 +752,14 @@
 
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayApprove());
 
-        dataApprovalService.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitD, NO_GROUP, NOT_ACCEPTED, date, userA ) );
+        dataApprovalStore.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitD, NO_GROUP, NOT_ACCEPTED, date, userA ) );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayApprove());
 
-        dataApprovalService.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitC, NO_GROUP, NOT_ACCEPTED, date, userA ) );
-        dataApprovalService.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitE, NO_GROUP, NOT_ACCEPTED, date, userA ) );
+        dataApprovalStore.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitC, NO_GROUP, NOT_ACCEPTED, date, userA ) );
+        dataApprovalStore.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitE, NO_GROUP, NOT_ACCEPTED, date, userA ) );
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayApprove());
 
-        dataApprovalService.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitB, NO_GROUP, NOT_ACCEPTED, date, userA ) );
+        dataApprovalStore.addDataApproval( new DataApproval( dataSetA, periodA, organisationUnitB, NO_GROUP, NOT_ACCEPTED, date, userA ) );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayApprove());
     }
 
@@ -873,26 +887,26 @@
         DataApproval dataApprovalD = new DataApproval( dataSetA, periodA, organisationUnitD, NO_GROUP, NOT_ACCEPTED, date, userA );
         DataApproval dataApprovalE = new DataApproval( dataSetA, periodA, organisationUnitE, NO_GROUP, NOT_ACCEPTED, date, userA );
 
-        dataApprovalService.addDataApproval( dataApprovalD );
+        dataApprovalStore.addDataApproval( dataApprovalD );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalC );
-        dataApprovalService.addDataApproval( dataApprovalE );
+        dataApprovalStore.addDataApproval( dataApprovalC );
+        dataApprovalStore.addDataApproval( dataApprovalE );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalB );
+        dataApprovalStore.addDataApproval( dataApprovalB );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalA );
+        dataApprovalStore.addDataApproval( dataApprovalA );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
@@ -921,26 +935,26 @@
         DataApproval dataApprovalD = new DataApproval( dataSetA, periodA, organisationUnitD, NO_GROUP, NOT_ACCEPTED, date, userA );
         DataApproval dataApprovalE = new DataApproval( dataSetA, periodA, organisationUnitE, NO_GROUP, NOT_ACCEPTED, date, userA );
 
-        dataApprovalService.addDataApproval( dataApprovalD );
+        dataApprovalStore.addDataApproval( dataApprovalD );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalC );
-        dataApprovalService.addDataApproval( dataApprovalE );
+        dataApprovalStore.addDataApproval( dataApprovalC );
+        dataApprovalStore.addDataApproval( dataApprovalE );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalB );
+        dataApprovalStore.addDataApproval( dataApprovalB );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalA );
+        dataApprovalStore.addDataApproval( dataApprovalA );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
@@ -969,26 +983,26 @@
         DataApproval dataApprovalD = new DataApproval( dataSetA, periodA, organisationUnitD, NO_GROUP, NOT_ACCEPTED, date, userA );
         DataApproval dataApprovalE = new DataApproval( dataSetA, periodA, organisationUnitE, NO_GROUP, NOT_ACCEPTED, date, userA );
 
-        dataApprovalService.addDataApproval( dataApprovalD );
+        dataApprovalStore.addDataApproval( dataApprovalD );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalC );
-        dataApprovalService.addDataApproval( dataApprovalE );
+        dataApprovalStore.addDataApproval( dataApprovalC );
+        dataApprovalStore.addDataApproval( dataApprovalE );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalB );
+        dataApprovalStore.addDataApproval( dataApprovalB );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( true, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
 
-        dataApprovalService.addDataApproval( dataApprovalA );
+        dataApprovalStore.addDataApproval( dataApprovalA );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
@@ -1017,26 +1031,26 @@
         DataApproval dataApprovalD = new DataApproval( dataSetA, periodA, organisationUnitD, NO_GROUP, NOT_ACCEPTED, date, userA );
         DataApproval dataApprovalE = new DataApproval( dataSetA, periodA, organisationUnitE, NO_GROUP, NOT_ACCEPTED, date, userA );
 
-        dataApprovalService.addDataApproval( dataApprovalD );
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-
-        dataApprovalService.addDataApproval( dataApprovalC );
-        dataApprovalService.addDataApproval( dataApprovalE );
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-
-        dataApprovalService.addDataApproval( dataApprovalB );
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
-
-        dataApprovalService.addDataApproval( dataApprovalA );
+        dataApprovalStore.addDataApproval( dataApprovalD );
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+
+        dataApprovalStore.addDataApproval( dataApprovalC );
+        dataApprovalStore.addDataApproval( dataApprovalE );
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+
+        dataApprovalStore.addDataApproval( dataApprovalB );
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+        assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitD, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
+
+        dataApprovalStore.addDataApproval( dataApprovalA );
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitA, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitB, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
         assertEquals( false, dataApprovalService.getDataApprovalPermissions( dataSetA, periodA, organisationUnitC, NO_GROUP, NO_OPTIONS ).isMayUnapprove());
@@ -1052,6 +1066,10 @@
     {
         setUpCategories();
 
+        Set<OrganisationUnit> units = new HashSet<OrganisationUnit>();
+        units.add( organisationUnitA );
+        createUserAndInjectSecurityContext( units, false, DataApproval.AUTH_APPROVE, DataApproval.AUTH_APPROVE_LOWER_LEVELS );
+
         dataSetA.setApproveData( true );
 
         organisationUnitA.addDataSet( dataSetA );
@@ -1113,7 +1131,7 @@
         assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, groupA, NO_OPTIONS ).getDataApprovalState() );
 
         assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboA ).getDataApprovalState() );
-        assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboB ).getDataApprovalState() );
+        assertEquals( DataApprovalState.APPROVED_HERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitB, optionComboB ).getDataApprovalState() );
         assertEquals( DataApprovalState.APPROVED_ELSEWHERE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitC, optionComboC ).getDataApprovalState() );
 
         assertEquals( DataApprovalState.UNAPPROVABLE, dataApprovalService.getDataApprovalStatus( dataSetA, periodA, organisationUnitA, optionComboI ).getDataApprovalState() );

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataApprovalController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataApprovalController.java	2014-03-28 01:53:11 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/DataApprovalController.java	2014-03-30 04:37:39 +0000
@@ -35,9 +35,12 @@
 
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.api.utils.ContextUtils;
 import org.hisp.dhis.api.utils.InputUtils;
 import org.hisp.dhis.dataapproval.*;
+import org.hisp.dhis.dataelement.CategoryOptionGroup;
 import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.dataset.DataSet;
@@ -65,6 +68,8 @@
 @RequestMapping(value = DataApprovalController.RESOURCE_PATH)
 public class DataApprovalController
 {
+    private final static Log log = LogFactory.getLog( DataApprovalController.class );
+
     public static final String RESOURCE_PATH = "/dataApprovals";
     public static final String ACCEPTANCES_PATH = "/acceptances";
 
@@ -100,6 +105,8 @@
         @RequestParam( required = false ) String cc, 
         @RequestParam( required = false ) String cp, HttpServletResponse response ) throws IOException
     {
+        log.info( "getApprovalState called." );
+
         DataSet dataSet = dataSetService.getDataSet( ds );
         
         if ( dataSet == null )
@@ -152,6 +159,8 @@
         @RequestParam( required = false ) String cc, 
         @RequestParam( required = false ) String cp, HttpServletResponse response )
     {
+        log.info( "saveApproval called." );
+
         DataSet dataSet = dataSetService.getDataSet( ds );
         
         if ( dataSet == null )
@@ -200,10 +209,11 @@
         User user = currentUserService.getCurrentUser();
 
         //TODO: FIX. We need to know what CategoryOptionGroup if any was selected, to use when constructing the data approval object.
-
-        //TODO: FIX. DataApproval approval = new DataApproval( dataSet, period, organisationUnit, attributeOptionGroup, new Date(), user );
-
-        //TODO: FIX. dataApprovalService.addDataApproval( approval );
+        CategoryOptionGroup attributeOptionGroup = null;
+
+        DataApproval approval = new DataApproval( dataSet, period, organisationUnit, attributeOptionGroup, false, new Date(), user );
+
+        dataApprovalService.addDataApproval( approval );
     }
 
     @PreAuthorize( "hasRole('ALL') or hasRole('F_APPROVE_DATA') or hasRole('F_APPROVE_DATA_LOWER_LEVELS')" )
@@ -216,6 +226,8 @@
         @RequestParam( required = false ) String cc, 
         @RequestParam( required = false ) String cp, HttpServletResponse response )
     {
+        log.info( "removeApproval called." );
+
         DataSet dataSet = dataSetService.getDataSet( ds );
         
         if ( dataSet == null )
@@ -274,6 +286,8 @@
             @RequestParam( required = false ) String cc,
             @RequestParam( required = false ) String cp, HttpServletResponse response )
     {
+        log.info( "acceptApproval called." );
+
         DataSet dataSet = dataSetService.getDataSet( ds );
 
         if ( dataSet == null )
@@ -333,6 +347,8 @@
             @RequestParam( required = false ) String cc,
             @RequestParam( required = false ) String cp, HttpServletResponse response )
     {
+        log.info( "unacceptApproval called." );
+
         DataSet dataSet = dataSetService.getDataSet( ds );
 
         if ( dataSet == null )
@@ -390,7 +406,7 @@
     {
         return "dataSet " + dataSet.getName()
                 + ", period " + period.getName()
-                + ", org unit " + organisationUnit.getName() + "(" + organisationUnit.getLevel() + ")"
+                + ", org unit " + organisationUnit.getName()
                 + ", attributeOptionCombo " + ( attributeOptionCombo == null ? "null" : attributeOptionCombo.getName() );
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/AddApprovalLevelAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/AddApprovalLevelAction.java	2014-03-28 17:08:12 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/java/org/hisp/dhis/settings/action/system/AddApprovalLevelAction.java	2014-03-30 04:37:39 +0000
@@ -111,8 +111,6 @@
 
     public String execute()
     {
-        OrganisationUnitLevel orgUnitLevel = organisationUnitService.getOrganisationUnitLevelByLevel( organisationUnitLevel );
-
         CategoryOptionGroupSet catOptGroupSet = null;
 
         if ( categoryOptionGroupSet != 0 )
@@ -120,7 +118,7 @@
             catOptGroupSet = dataElementCategoryService.getCategoryOptionGroupSet( categoryOptionGroupSet );
         }
 
-        DataApprovalLevel dataApprovalLevel = new DataApprovalLevel( orgUnitLevel, catOptGroupSet );
+        DataApprovalLevel dataApprovalLevel = new DataApprovalLevel( organisationUnitLevel, catOptGroupSet );
 
         boolean added = dataApprovalLevelService.addDataApprovalLevel( dataApprovalLevel );
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/struts.xml	2014-03-28 17:58:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/resources/struts.xml	2014-03-30 04:37:39 +0000
@@ -87,7 +87,7 @@
 
     <action name="addApprovalLevel" class="org.hisp.dhis.settings.action.system.AddApprovalLevelAction">
       <result name="success" type="redirect">systemApprovalSettings.action</result>
-      <result name="input" type="velocity-xml">/dhis-web-commons/ajax/xmlResponseInput.vm</result>
+      <result name="input" type="velocity-json">/dhis-web-commons/ajax/jsonResponseInput.vm</result>
       <param name="requiredAuthorities">F_SYSTEM_SETTING</param>
     </action>
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemApprovalSettings.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemApprovalSettings.vm	2014-02-19 06:32:40 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-settings/src/main/webapp/dhis-web-maintenance-settings/systemApprovalSettings.vm	2014-03-30 04:37:39 +0000
@@ -46,7 +46,7 @@
                     <tr id="tr${level.level}" data-id="$!level.level" data-name="$encoder.htmlEncode( $!level.getName() )"
                             data-can-move-up="$approvalLevelService.canMoveUp( $level.level )"
                             data-can-move-down="$approvalLevelService.canMoveDown( $level.level )">
-                        <td>$encoder.htmlEncode( $!level.organisationUnitLevel.name )</td>
+                        <td>$encoder.htmlEncode( $!level.orgUnitLevelName )</td>
                         <td>$encoder.htmlEncode( $!level.getCategoryOptionGroupSetName() )</td>
                     </tr>
                     #end

=== modified file 'dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataSetReport.js'
--- dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataSetReport.js	2014-03-28 01:53:11 +0000
+++ dhis-2/dhis-web/dhis-web-reporting/src/main/webapp/dhis-web-reporting/javascript/dataSetReport.js	2014-03-30 04:37:39 +0000
@@ -4,6 +4,7 @@
 dhis2.dsr.currentPeriodOffset = 0;
 dhis2.dsr.periodTypeFactory = new PeriodType();
 dhis2.dsr.currentDataSetReport = null;
+dhis2.dsr.permissions = null;
 
 //------------------------------------------------------------------------------
 // Get and set methods
@@ -356,12 +357,12 @@
 	var dataSetReport = dhis2.dsr.currentDataSetReport;
 	
 	var approval = $( "#dataSetId :selected" ).data( "approval" );
-	var attributesSelected = dhis2.dsr.attributesSelected( dataSetReport );
+	// var attributesSelected = dhis2.dsr.attributesSelected( dataSetReport );
 
 	$( "#approvalNotification" ).hide();
     $( "#approvalDiv" ).hide();
 
-	if ( !approval || !attributesSelected ) {
+	if ( !approval /* || !attributesSelected */ ) {
 		return;
 	}
 	
@@ -371,13 +372,15 @@
 		if ( !json || !json.state ) {
 			return;
 		}
+
+        dhis2.dsr.permissions = json;
 		
 		var state = json.state;
 
-        $( "#approveButton" ).prop( "disabled", true );
-        $( "#unapproveButton" ).prop( "disabled", true );
-        $( "#acceptButton" ).prop( "disabled", true );
-        $( "#unacceptButton" ).prop( "disabled", true );
+        $( "#approveButton" ).hide();
+        $( "#unapproveButton" ).hide();
+        $( "#acceptButton" ).hide();
+        $( "#unacceptButton" ).hide();
 
         switch (state)
         {
@@ -389,7 +392,7 @@
                 $( "#approvalNotification" ).show().html( i18n_ready_for_approval );
                 if ( json.mayApprove ) {
                     $( "#approvalDiv" ).show();
-                    $( "#approveButton" ).prop( "disabled", false );
+                    $( "#approveButton" ).show();
                 }
                 break;
 
@@ -397,12 +400,11 @@
                 $( "#approvalNotification" ).show().html( i18n_approved );
                 if ( json.mayUnapprove ) {
                     $( "#approvalDiv" ).show();
-                    $( "#unapproveButton" ).prop( "disabled", false );
+                    $( "#unapproveButton" ).show();
                 }
-
                 if ( json.mayAccept ) {
                     $( "#approvalDiv" ).show();
-                    $( "#acceptButton" ).prop( "disabled", false );
+                    $( "#acceptButton" ).show();
                 }
                 break;
 
@@ -410,12 +412,11 @@
                 $( "#approvalNotification" ).show().html( i18n_approved );
                 if ( json.mayUnapprove ) {
                     $( "#approvalDiv" ).show();
-                    $( "#unapproveButton" ).prop( "disabled", false );
+                    $( "#unapproveButton" ).show();
                 }
-
                 if ( json.mayUnccept ) {
                     $( "#approvalDiv" ).show();
-                    $( "#unacceptButton" ).prop( "disabled", false );
+                    $( "#unacceptButton" ).show();
                 }
                 break;
         }
@@ -439,9 +440,17 @@
 		url: url,
 		type: "post",
 		success: function() {
-			$( "#approveButton" ).prop( "disabled", true );
-			$( "#unapproveButton" ).prop( "disabled", false );
-			$( "#approvalNotification" ).show().html( i18n_approved );
+            $( "#approvalNotification" ).show().html( i18n_approved );
+            $( "#approvalDiv" ).hide();
+			$( "#approveButton" ).hide();
+            if ( dhis2.dsr.permissions.mayUnapprove ) {
+                $( "#approvalDiv" ).show();
+                $( "#unapproveButton" ).show();
+            }
+            if ( dhis2.dsr.permissions.mayAccept ) {
+                $( "#approvalDiv" ).show();
+                $( "#acceptButton" ).show();
+            }
 		},
 		error: function( xhr, status, error ) {
 			alert( xhr.responseText );
@@ -462,9 +471,15 @@
 		url: url,
 		type: "delete",
 		success: function() {
-			$( "#approveButton" ).prop( "disabled", false );
-			$( "#unapproveButton" ).prop( "disabled", true );
-			$( "#approvalNotification" ).show().html( i18n_ready_for_approval );
+            $( "#approvalNotification" ).show().html( i18n_ready_for_approval );
+            $( "#approvalDiv" ).hide();
+            $( "#unapproveButton" ).hide();
+            $( "#acceptButton" ).hide();
+            $( "#unacceptButton" ).hide();
+            if ( dhis2.dsr.permissions.mayApprove ) {
+                $( "#approvalDiv" ).show();
+                $( "#approveButton" ).show();
+            }
 		},
 		error: function( xhr, status, error ) {
 			alert( xhr.responseText );
@@ -485,9 +500,17 @@
         url: url,
         type: "post",
         success: function() {
-            $( "#acceptButton" ).prop( "disabled", true );
-            $( "#unacceptButton" ).prop( "disabled", false );
             $( "#approvalNotification" ).show().html( i18n_approved_and_accepted );
+            $( "#approvalDiv" ).hide();
+            $( "#acceptButton" ).hide();
+            if ( dhis2.dsr.permissions.mayUnapprove ) {
+                $( "#approvalDiv" ).show();
+                $( "#unapproveButton" ).show();
+            }
+            if ( dhis2.dsr.permissions.mayUnaccept ) {
+                $( "#approvalDiv" ).show();
+                $( "#unacceptButton" ).show();
+            }
         },
         error: function( xhr, status, error ) {
             alert( xhr.responseText );
@@ -508,9 +531,17 @@
         url: url,
         type: "delete",
         success: function() {
-            $( "#acceptButton" ).prop( "disabled", false );
-            $( "#unacceptButton" ).prop( "disabled", true );
             $( "#approvalNotification" ).show().html( i18n_approved );
+            $( "#approvalDiv" ).hide();
+            $( "#unacceptButton" ).hide();
+            if ( dhis2.dsr.permissions.mayUnapprove ) {
+                $( "#approvalDiv" ).show();
+                $( "#unapproveButton" ).show();
+            }
+            if ( dhis2.dsr.permissions.mayAccept ) {
+                $( "#approvalDiv" ).show();
+                $( "#acceptButton" ).show();
+            }
         },
         error: function( xhr, status, error ) {
             alert( xhr.responseText );