← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 18427: Approval, code style fixes

 

------------------------------------------------------------
revno: 18427
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2015-02-26 12:19:31 +0100
message:
  Approval, code style fixes
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectUtils.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalPermissionsEvaluator.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/HibernateDataApprovalStore.java


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

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectUtils.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectUtils.java	2015-01-17 07:41:26 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/IdentifiableObjectUtils.java	2015-02-26 11:19:31 +0000
@@ -52,8 +52,8 @@
  */
 public class IdentifiableObjectUtils
 {
+    public static final String SEPARATOR = "-";
     private static final String SEPARATOR_JOIN = ", ";
-    private static final String SEPARATOR = "-";
     private static final SimpleDateFormat LONG_DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss" );
 
     public static final Map<String, String> CLASS_ALIAS = new HashMap<String, String>()

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalPermissionsEvaluator.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalPermissionsEvaluator.java	2015-02-13 10:11:37 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DataApprovalPermissionsEvaluator.java	2015-02-26 11:19:31 +0000
@@ -77,8 +77,8 @@
     }
 
     private static Cache<String, DataApprovalLevel> USER_APPROVAL_LEVEL_CACHE = CacheBuilder.newBuilder()
-            .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 10000 )
-            .maximumSize( 50000 ).build();
+        .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 10000 )
+        .maximumSize( 50000 ).build();
 
     /**
      * Allocates and populates the context for determining user permissions
@@ -109,9 +109,9 @@
         ev.maxApprovalLevel = dataApprovalLevelService.getAllDataApprovalLevels().size();
 
         log.debug( "makePermissionsEvaluator acceptanceRequiredForApproval " + ev.acceptanceRequiredForApproval
-                + " hideUnapprovedData " + ev.hideUnapprovedData + " authorizedToApprove " + ev.authorizedToApprove
-                + " authorizedToAcceptAtLowerLevels " + ev.authorizedToAcceptAtLowerLevels
-                + " authorizedToViewUnapprovedData " + ev.authorizedToViewUnapprovedData + " maxApprovalLevel " + ev.maxApprovalLevel );
+            + " hideUnapprovedData " + ev.hideUnapprovedData + " authorizedToApprove " + ev.authorizedToApprove
+            + " authorizedToAcceptAtLowerLevels " + ev.authorizedToAcceptAtLowerLevels
+            + " authorizedToViewUnapprovedData " + ev.authorizedToViewUnapprovedData + " maxApprovalLevel " + ev.maxApprovalLevel );
 
         return ev;
     }
@@ -175,10 +175,10 @@
         int nextApproveDataLevel = s.isApproved() ? dataLevel - 1 : dataLevel;
 
         boolean mayApproveOrUnapproveAtLevel = ( authorizedToApprove && userLevel == dataLevel && !da.isAccepted() ) ||
-                        ( authorizedToApproveAtLowerLevels && userLevel < dataLevel );
+            ( authorizedToApproveAtLowerLevels && userLevel < dataLevel );
 
-        boolean mayApproveAtNextLevel = ( s == DataApprovalState.ACCEPTED_HERE || ( s == DataApprovalState.APPROVED_HERE && ! acceptanceRequiredForApproval ) )
-                && ( ( authorizedToApprove && userLevel == nextApproveDataLevel ) || ( authorizedToApproveAtLowerLevels && userLevel < nextApproveDataLevel ) );
+        boolean mayApproveAtNextLevel = ( s == DataApprovalState.ACCEPTED_HERE || ( s == DataApprovalState.APPROVED_HERE && ! acceptanceRequiredForApproval ) ) && 
+            ( ( authorizedToApprove && userLevel == nextApproveDataLevel ) || ( authorizedToApproveAtLowerLevels && userLevel < nextApproveDataLevel ) );
 
         // TODO More testing needed
         
@@ -198,14 +198,14 @@
                 || userLevel >= dataLevel;
 
         log.debug( "getPermissions orgUnit " + ( da.getOrganisationUnit() == null ? "(null)" : da.getOrganisationUnit().getName() )
-                + " combo " + da.getAttributeOptionCombo().getName() + " state " + s.name()
-                + " isApproved " + s.isApproved() + " isApprovable " + s.isApprovable() + " isUnapprovable " + s.isUnapprovable()
-                + " isAccepted " + s.isAccepted() + " isAcceptable " + s.isAcceptable() + " isUnacceptable " + s.isUnacceptable()
-                + " userLevel " + userLevel + " dataLevel " + dataLevel
-                + " mayApproveOrUnapproveAtLevel " + mayApproveOrUnapproveAtLevel + " mayAcceptOrUnacceptAtLevel " + mayAcceptOrUnacceptAtLevel
-                + " mayApprove " + mayApprove + " mayUnapprove " + mayUnapprove
-                + " mayAccept " + mayAccept + " mayUnaccept " + mayUnaccept
-                + " mayReadData " + mayReadData );
+            + " combo " + da.getAttributeOptionCombo().getName() + " state " + s.name()
+            + " isApproved " + s.isApproved() + " isApprovable " + s.isApprovable() + " isUnapprovable " + s.isUnapprovable()
+            + " isAccepted " + s.isAccepted() + " isAcceptable " + s.isAcceptable() + " isUnacceptable " + s.isUnacceptable()
+            + " userLevel " + userLevel + " dataLevel " + dataLevel
+            + " mayApproveOrUnapproveAtLevel " + mayApproveOrUnapproveAtLevel + " mayAcceptOrUnacceptAtLevel " + mayAcceptOrUnacceptAtLevel
+            + " mayApprove " + mayApprove + " mayUnapprove " + mayUnapprove
+            + " mayAccept " + mayAccept + " mayUnaccept " + mayUnaccept
+            + " mayReadData " + mayReadData );
 
         permissions.setMayApprove( mayApprove );
         permissions.setMayUnapprove( mayUnapprove );

=== 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	2015-02-22 20:02:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalLevelService.java	2015-02-26 11:19:31 +0000
@@ -683,13 +683,13 @@
         for ( DataApprovalLevel level : getAllDataApprovalLevels() )
         {
             tracePrint("userApprovalLevel( " + orgUnit.getName() + "-" + orgUnitLevel + " ) approval level "
-                    + level.getName() + " " + securityService.canRead( level )
-                    + " COGS " + ( level.getCategoryOptionGroupSet() == null ? "(null)" : level.getCategoryOptionGroupSet().getName() )
-                    + " canReadCOGS " + canReadCOGS( user, level.getCategoryOptionGroupSet() ) );
+                + level.getName() + " " + securityService.canRead( level )
+                + " COGS " + ( level.getCategoryOptionGroupSet() == null ? "(null)" : level.getCategoryOptionGroupSet().getName() )
+                + " canReadCOGS " + canReadCOGS( user, level.getCategoryOptionGroupSet() ) );
 
             if ( level.getOrgUnitLevel() >= orgUnitLevel
-                    && securityService.canRead( level )
-                    && canReadCOGS( user, level.getCategoryOptionGroupSet() ) )
+                && securityService.canRead( level )
+                && canReadCOGS( user, level.getCategoryOptionGroupSet() ) )
             {
                 userLevel = level;
                 break;

=== 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	2015-02-22 20:02:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/DefaultDataApprovalService.java	2015-02-26 11:19:31 +0000
@@ -38,6 +38,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.common.IdentifiableObjectUtils;
 import org.hisp.dhis.common.ListMap;
 import org.hisp.dhis.dataapproval.exceptions.DataMayNotBeAcceptedException;
 import org.hisp.dhis.dataapproval.exceptions.DataMayNotBeApprovedException;
@@ -50,6 +51,7 @@
 import org.hisp.dhis.period.PeriodService;
 import org.hisp.dhis.setting.SystemSettingManager;
 import org.hisp.dhis.system.util.CollectionUtils;
+import org.hisp.dhis.system.util.TextUtils;
 import org.hisp.dhis.user.CurrentUserService;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -120,12 +122,12 @@
         {
             DataApprovalStatus status = getStatus( da, statusMap );
 
-            if ( da.getDataApprovalLevel() == null ) // Determine the approval level.
+            if ( da.getDataApprovalLevel() == null ) // Determine the approval level
             {
-                if ( status.getState().isApproved() ) // If approved already, approve at next level up (lower level number).
+                if ( status.getState().isApproved() ) // If approved already, approve at next level up (lower level number)
                 {
                     da.setDataApprovalLevel( dataApprovalLevelService.getDataApprovalLevelByLevelNumber(
-                            status.getDataApproval().getDataApprovalLevel().getLevel() - 1 ) );
+                        status.getDataApproval().getDataApprovalLevel().getLevel() - 1 ) );
                 }
                 else
                 {
@@ -134,7 +136,7 @@
             }
 
             if ( status != null && status.getState().isApproved() &&
-                    da.getDataApprovalLevel().getLevel() >= status.getDataApprovalLevel().getLevel() )
+                da.getDataApprovalLevel().getLevel() >= status.getDataApprovalLevel().getLevel() )
             {
                 continue; // Already approved at or above this level
             }
@@ -142,7 +144,7 @@
             if ( status == null || !status.getPermissions().isMayApprove() )
             {
                 log.warn( "approveData: data may not be approved, state " +
-                        ( status == null ? "(null)" : status.getState().name() ) + " " + da );
+                    ( status == null ? TextUtils.EMPTY : status.getState().name() ) + " " + da );
 
                 throw new DataMayNotBeApprovedException();
             }
@@ -181,7 +183,7 @@
             }
 
             if ( status == null || !status.getState().isApproved() ||
-                    da.getDataApprovalLevel().getLevel() < status.getDataApprovalLevel().getLevel() )
+                da.getDataApprovalLevel().getLevel() < status.getDataApprovalLevel().getLevel() )
             {
                 continue; // Already unapproved at or below this level
             }
@@ -201,7 +203,7 @@
             log.debug( "unapproving " + da );
 
             DataApproval d = dataApprovalStore.getDataApproval( da.getDataApprovalLevel(), da.getDataSet(),
-                    da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
+                da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
 
             if ( d == null )
             {
@@ -236,16 +238,15 @@
                 da.setDataApprovalLevel( status.getDataApproval().getDataApprovalLevel() );
             }
 
-            if ( status != null &&
-                    ( status.getState().isAccepted() && da.getDataApprovalLevel().getLevel() == status.getDataApprovalLevel().getLevel()
-                    || da.getDataApprovalLevel().getLevel() > status.getDataApprovalLevel().getLevel() ) )
+            if ( status != null && ( status.getState().isAccepted() && da.getDataApprovalLevel().getLevel() == status.getDataApprovalLevel().getLevel() || 
+                da.getDataApprovalLevel().getLevel() > status.getDataApprovalLevel().getLevel() ) )
             {
                 continue; // Already accepted at, or approved above, this level
             }
 
             if ( status == null || !status.getPermissions().isMayAccept() )
             {
-                log.warn( "acceptData: data may not be accepted, state " + ( status == null ? "(null)" : status.getState().name() ) + " " + da );
+                log.warn( "acceptData: data may not be accepted, state " + ( status == null ? TextUtils.EMPTY : status.getState().name() ) + " " + da );
 
                 throw new DataMayNotBeAcceptedException();
             }
@@ -259,8 +260,8 @@
 
             log.debug( "accepting " + da );
 
-            DataApproval d = dataApprovalStore.getDataApproval( da.getDataApprovalLevel(), da.getDataSet(),
-                    da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
+            DataApproval d = dataApprovalStore.getDataApproval( da.getDataApprovalLevel(), da.getDataSet(), 
+                da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
 
             if ( d == null )
             {
@@ -297,10 +298,10 @@
                 da.setDataApprovalLevel( status.getDataApproval().getDataApprovalLevel() );
             }
 
-            if ( status == null || ( !status.getState().isAccepted() && da.getDataApprovalLevel().getLevel() == status.getDataApprovalLevel().getLevel() )
-                || da.getDataApprovalLevel().getLevel() < status.getDataApprovalLevel().getLevel() )
+            if ( status == null || ( !status.getState().isAccepted() && da.getDataApprovalLevel().getLevel() == status.getDataApprovalLevel().getLevel() ) || 
+                da.getDataApprovalLevel().getLevel() < status.getDataApprovalLevel().getLevel() )
             {
-                continue; // Already unaccepted at, or not approved up to, this level
+                continue; // Already unaccepted at or not approved up to this level
             }
 
             if ( !status.getPermissions().isMayUnaccept() )
@@ -318,7 +319,7 @@
             log.debug( "unaccepting " + da );
 
             DataApproval d = dataApprovalStore.getDataApproval( da.getDataApprovalLevel(), da.getDataSet(),
-                    da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
+                da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
 
             if ( d == null )
             {
@@ -340,14 +341,12 @@
         DataElementCategoryOptionCombo attributeOptionCombo )
     {
         log.debug( "getDataApprovalStatus( " + dataSet.getName() + ", "
-                + period.getPeriodType().getName() + " " + period.getName() + " " + period + ", "
-                + organisationUnit.getName() + ", "
-                + ( attributeOptionCombo == null ? "(null)" : attributeOptionCombo.getName() ) + " )" );
-
-        period = periodService.reloadPeriod( period );
+            + period.getPeriodType().getName() + " " + period.getName() + " " + period + ", "
+            + organisationUnit.getName() + ", "
+            + ( attributeOptionCombo == null ? TextUtils.EMPTY : attributeOptionCombo.getName() ) + " )" );
 
         List<DataApprovalStatus> statuses = dataApprovalStore.getDataApprovals( CollectionUtils.asSet( dataSet ),
-                period, organisationUnit, attributeOptionCombo );
+            periodService.reloadPeriod( period ), organisationUnit, attributeOptionCombo );
 
         if ( statuses != null && !statuses.isEmpty() )
         {
@@ -355,11 +354,12 @@
 
             DataApproval da = status.getDataApproval();
 
-            da = dataApprovalStore.getDataApproval( da.getDataApprovalLevel(), da.getDataSet(), da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
+            da = dataApprovalStore.getDataApproval( da.getDataApprovalLevel(), da.getDataSet(), 
+                da.getPeriod(), da.getOrganisationUnit(), da.getAttributeOptionCombo() );
 
             if ( da != null )
             {
-                status.setDataApproval( da ); // Includes created and creator from database.
+                status.setDataApproval( da ); // Includes created and creator from database
             }
 
             return status;
@@ -468,7 +468,7 @@
             DataApproval da0 = dataApprovals.get( 0 );
 
             List<DataApprovalStatus> statuses = dataApprovalStore.getDataApprovals( dataSets,
-                    da0.getPeriod(), da0.getOrganisationUnit(), da0.getAttributeOptionCombo() );
+                da0.getPeriod(), da0.getOrganisationUnit(), da0.getAttributeOptionCombo() );
 
             for ( DataApprovalStatus status : statuses )
             {
@@ -498,9 +498,9 @@
 
         for ( DataApproval approval : dataApprovalList )
         {
-            String key = approval == null ? null : approval.getOrganisationUnit().getId()
-                    + "-" + approval.getPeriod().getId()
-                    + "-" + ( approval.getAttributeOptionCombo() == null ? "null" : approval.getAttributeOptionCombo().getId() );
+            String key = approval == null ? null : approval.getOrganisationUnit().getId() + 
+                IdentifiableObjectUtils.SEPARATOR + approval.getPeriod().getId() + 
+                IdentifiableObjectUtils.SEPARATOR + ( approval.getAttributeOptionCombo() == null ? "null" : approval.getAttributeOptionCombo().getId() );
             
             map.putValue( key, approval );
         }

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java	2015-02-24 23:43:23 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java	2015-02-26 11:19:31 +0000
@@ -327,14 +327,14 @@
                 boolean acceptanceRequiredForApproval = (Boolean) systemSettingManager.getSystemSetting( KEY_ACCEPTANCE_REQUIRED_FOR_APPROVAL, false );
 
                 readyBelowSubquery = "not exists (select 1 from _orgunitstructure ous " +
-                        "join dataset ds on ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
-                        "left join dataapproval da on da.organisationunitid = ous.organisationunitid " +
-                        "and da.dataapprovallevelid = " + dal.getId() + " and da.periodid in (" + periodIds + ") " +
-                        "and da.datasetid = ds.datasetid " +
-                        "and da.attributeoptioncomboid = a.categoryoptioncomboid " +
-                        "where ous.idlevel" + orgUnitLevel + " = a.organisationunitid " +
-                        "and ous.level = " + dal.getOrgUnitLevel() + " " +
-                        "and ( da.dataapprovalid is null " + ( acceptanceRequiredForApproval ? "or not da.accepted " : "" ) + ") )";
+                    "join dataset ds on ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
+                    "left join dataapproval da on da.organisationunitid = ous.organisationunitid " +
+                    "and da.dataapprovallevelid = " + dal.getId() + " and da.periodid in (" + periodIds + ") " +
+                    "and da.datasetid = ds.datasetid " +
+                    "and da.attributeoptioncomboid = a.categoryoptioncomboid " +
+                    "where ous.idlevel" + orgUnitLevel + " = a.organisationunitid " +
+                    "and ous.level = " + dal.getOrgUnitLevel() + " " +
+                    "and ( da.dataapprovalid is null " + ( acceptanceRequiredForApproval ? "or not da.accepted " : "" ) + ") )";
                 break;
             }
         }
@@ -344,48 +344,48 @@
         if ( orgUnitLevelAbove > 0 )
         {
             approvedAboveSubquery = "exists(select 1 from dataapproval da " +
-                    "join dataapprovallevel dal on dal.dataapprovallevelid = da.dataapprovallevelid " +
-                    "join dataset ds on ds.datasetid = da.datasetid and ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
-                    "join _orgunitstructure ou on ou.organisationunitid = a.organisationunitid and ou.idlevel" + orgUnitLevelAbove + " = da.organisationunitid " +
-                    "where da.periodid in (" + periodIds + ") and da.attributeoptioncomboid = a.categoryoptioncomboid) ";
+                "join dataapprovallevel dal on dal.dataapprovallevelid = da.dataapprovallevelid " +
+                "join dataset ds on ds.datasetid = da.datasetid and ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
+                "join _orgunitstructure ou on ou.organisationunitid = a.organisationunitid and ou.idlevel" + orgUnitLevelAbove + " = da.organisationunitid " +
+                "where da.periodid in (" + periodIds + ") and da.attributeoptioncomboid = a.categoryoptioncomboid) ";
         }
 
         final String sql =
-                "select a.categoryoptioncomboid, a.organisationunitid, " +
-                "(select min(coalesce(dal.level, 0)) from period p " +
-                    "join dataset ds on ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
-                    "left join dataapproval da on da.datasetid = ds.datasetid and da.periodid = p.periodid " +
-                        "and da.attributeoptioncomboid = a.categoryoptioncomboid and da.organisationunitid = a.organisationunitid " +
-                    "left join dataapprovallevel dal on dal.dataapprovallevelid = da.dataapprovallevelid " +
-                    "where p.periodid in (" + periodIds + ") " +
-                ") as highest_approved_level, " +
-                "(select substring(min(concat(100000 + coalesce(dal.level, 0), coalesce(da.accepted, FALSE))) from 7) from period p " +
-                    "join dataset ds on ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
-                    "left join dataapproval da on da.datasetid = ds.datasetid and da.periodid = p.periodid " +
-                        "and da.attributeoptioncomboid = a.categoryoptioncomboid and da.organisationunitid = a.organisationunitid " +
-                    "left join dataapprovallevel dal on dal.dataapprovallevelid = da.dataapprovallevelid " +
-                    "where p.periodid in (" + periodIds + ") " +
-                ") as accepted_at_highest_level, " +
-                readyBelowSubquery + " as ready_below, " +
-                approvedAboveSubquery + " as approved_above " +
-                "from ( " + // subquery to get combinations of organisation unit and category option combo
-                    "select distinct cocco.categoryoptioncomboid, ccoc.categorycomboid, coalesce(coo.organisationunitid, o.organisationunitid) as organisationunitid " +
-                    "from categoryoptioncombos_categoryoptions cocco " +
-                    "join categorycombos_optioncombos ccoc on ccoc.categoryoptioncomboid = cocco.categoryoptioncomboid and ccoc.categorycomboid in (" + categoryComboIds + ") " +
-                    "join dataelementcategoryoption co on co.categoryoptionid = cocco.categoryoptionid " +
-                        "and (co.startdate is null or co.startdate <= '" + maxDate + "') and (co.enddate is null or co.enddate >= '" + minDate + "') " +
-                    "join _orgunitstructure o on " + orgUnitJoinOn + " " +
-                    "left join categoryoption_organisationunits coo on coo.categoryoptionid = co.categoryoptionid " +
-                    "left join _orgunitstructure ous on ous.idlevel" + orgUnitLevel + " = o.organisationunitid and ous.organisationunitid = coo.organisationunitid " +
-                    joinAncestors +
-                    "left join dataelementcategoryoptionusergroupaccesses couga on couga.categoryoptionid = cocco.categoryoptionid " +
-                    "left join usergroupaccess uga on uga.usergroupaccessid = couga.usergroupaccessid " +
-                    "left join usergroupmembers ugm on ugm.usergroupid = uga.usergroupid " +
-                    "where ( coo.categoryoptionid is null or ous.organisationunitid is not null " + testAncestors + ") " +
-                     ( isSuperUser || user == null ? "" : "and ( ugm.userid = " + user.getId() + " or co.userid = " + user.getId() + " " +
-                             "or co.publicaccess is null or left(co.publicaccess, 1) = 'r' ) " ) +
-                     ( attributeOptionCombo == null ? "" : "and cocco.categoryoptioncomboid = " + attributeOptionCombo.getId() + " " ) +
-                ") as a";
+            "select a.categoryoptioncomboid, a.organisationunitid, " +
+            "(select min(coalesce(dal.level, 0)) from period p " +
+                "join dataset ds on ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
+                "left join dataapproval da on da.datasetid = ds.datasetid and da.periodid = p.periodid " +
+                    "and da.attributeoptioncomboid = a.categoryoptioncomboid and da.organisationunitid = a.organisationunitid " +
+                "left join dataapprovallevel dal on dal.dataapprovallevelid = da.dataapprovallevelid " +
+                "where p.periodid in (" + periodIds + ") " +
+            ") as highest_approved_level, " +
+            "(select substring(min(concat(100000 + coalesce(dal.level, 0), coalesce(da.accepted, FALSE))) from 7) from period p " +
+                "join dataset ds on ds.datasetid in (" + dataSetIds + ") " + dsCategoryComboIdMatches +
+                "left join dataapproval da on da.datasetid = ds.datasetid and da.periodid = p.periodid " +
+                    "and da.attributeoptioncomboid = a.categoryoptioncomboid and da.organisationunitid = a.organisationunitid " +
+                "left join dataapprovallevel dal on dal.dataapprovallevelid = da.dataapprovallevelid " +
+                "where p.periodid in (" + periodIds + ") " +
+            ") as accepted_at_highest_level, " +
+            readyBelowSubquery + " as ready_below, " +
+            approvedAboveSubquery + " as approved_above " +
+            "from ( " + // subquery to get combinations of organisation unit and category option combo
+                "select distinct cocco.categoryoptioncomboid, ccoc.categorycomboid, coalesce(coo.organisationunitid, o.organisationunitid) as organisationunitid " +
+                "from categoryoptioncombos_categoryoptions cocco " +
+                "join categorycombos_optioncombos ccoc on ccoc.categoryoptioncomboid = cocco.categoryoptioncomboid and ccoc.categorycomboid in (" + categoryComboIds + ") " +
+                "join dataelementcategoryoption co on co.categoryoptionid = cocco.categoryoptionid " +
+                    "and (co.startdate is null or co.startdate <= '" + maxDate + "') and (co.enddate is null or co.enddate >= '" + minDate + "') " +
+                "join _orgunitstructure o on " + orgUnitJoinOn + " " +
+                "left join categoryoption_organisationunits coo on coo.categoryoptionid = co.categoryoptionid " +
+                "left join _orgunitstructure ous on ous.idlevel" + orgUnitLevel + " = o.organisationunitid and ous.organisationunitid = coo.organisationunitid " +
+                joinAncestors +
+                "left join dataelementcategoryoptionusergroupaccesses couga on couga.categoryoptionid = cocco.categoryoptionid " +
+                "left join usergroupaccess uga on uga.usergroupaccessid = couga.usergroupaccessid " +
+                "left join usergroupmembers ugm on ugm.usergroupid = uga.usergroupid " +
+                "where ( coo.categoryoptionid is null or ous.organisationunitid is not null " + testAncestors + ") " +
+                 ( isSuperUser || user == null ? "" : "and ( ugm.userid = " + user.getId() + " or co.userid = " + user.getId() + " " +
+                         "or co.publicaccess is null or left(co.publicaccess, 1) = 'r' ) " ) +
+                 ( attributeOptionCombo == null ? "" : "and cocco.categoryoptioncomboid = " + attributeOptionCombo.getId() + " " ) +
+            ") as a";
 
         log.debug( "Get approval SQL: " + sql );