diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java index a2f525bf7be1..ccea4b057bd4 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java @@ -234,6 +234,8 @@ public class EventQueryParams extends DataQueryParams { @Getter protected boolean multipleQueries = false; + @Getter protected List userOrgUnits = new ArrayList<>(); + // ------------------------------------------------------------------------- // Constructors // ------------------------------------------------------------------------- @@ -303,6 +305,7 @@ protected EventQueryParams instance() { params.endpointAction = this.endpointAction; params.rowContext = this.rowContext; params.multipleQueries = this.multipleQueries; + params.userOrgUnits = this.userOrgUnits; return params; } @@ -1352,5 +1355,10 @@ public Builder withMultipleQueries(boolean multipleQueries) { this.params.multipleQueries = multipleQueries; return this; } + + public Builder withUserOrgUnits(List userOrgUnits) { + this.params.userOrgUnits = userOrgUnits; + return this; + } } } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsService.java index 9c14b98e1770..6f21e024a42a 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsService.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsService.java @@ -104,6 +104,8 @@ public abstract class AbstractAnalyticsService { protected final SchemaIdResponseMapper schemaIdResponseMapper; + protected final OrganisationUnitResolver organisationUnitResolver; + /** * Returns a grid based on the given query. * @@ -503,6 +505,8 @@ private Map getMetadataItems(EventQueryParams params) { new MetadataItem( item.getItem().getDisplayName(), includeDetails ? item.getItem() : null))); + metadataItemMap.putAll(organisationUnitResolver.getMetadataItemsForOrgUnitDataElements(params)); + return metadataItemMap; } @@ -685,7 +689,10 @@ private Map> getDimensionItems( for (QueryItem item : params.getItems()) { String itemUid = getItemUid(item); - if (item.hasOptionSet()) { + if (item.getValueType().isOrganisationUnit()) { + List items = organisationUnitResolver.resolveOrgUnis(params, item); + dimensionItems.put(itemUid, items); + } else if (item.hasOptionSet()) { if (itemOptions.isPresent()) { Map> itemOptionsMap = itemOptions.get(); diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManager.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManager.java index 2804c6260dad..08104a1ed49e 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManager.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManager.java @@ -166,6 +166,8 @@ public abstract class AbstractJdbcEventAnalyticsManager { protected final ExecutionPlanStore executionPlanStore; + private final OrganisationUnitResolver organisationUnitResolver; + /** * Returns a SQL paging clause. * @@ -1236,9 +1238,14 @@ public String toSql(QueryItem item, QueryFilter filter, EventQueryParams params) ? getSelectSql(filter, item, params) : getSelectSql(filter, item, params.getEarliestStartDate(), params.getLatestEndDate()); + String filterString = + item.getValueType() == ValueType.ORGANISATION_UNIT + ? organisationUnitResolver.resolveOrgUnits(filter, params.getUserOrgUnits()) + : filter.getFilter(); + if (IN.equals(filter.getOperator())) { InQueryFilter inQueryFilter = - new InQueryFilter(field, encode(filter.getFilter(), false), !item.isNumeric()); + new InQueryFilter(field, encode(filterString, false), !item.isNumeric()); return inQueryFilter.getSqlFilter(); } else { diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEnrollmentAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEnrollmentAnalyticsService.java index a21c623cf959..dabf960d7fa8 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEnrollmentAnalyticsService.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEnrollmentAnalyticsService.java @@ -98,8 +98,9 @@ public DefaultEnrollmentAnalyticsService( AnalyticsSecurityManager securityManager, EventQueryPlanner queryPlanner, EventQueryValidator queryValidator, - SchemaIdResponseMapper schemaIdResponseMapper) { - super(securityManager, queryValidator, schemaIdResponseMapper); + SchemaIdResponseMapper schemaIdResponseMapper, + OrganisationUnitResolver organisationUnitResolver) { + super(securityManager, queryValidator, schemaIdResponseMapper, organisationUnitResolver); checkNotNull(enrollmentAnalyticsManager); checkNotNull(queryPlanner); diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java index ae87214cd78e..dde7052ad52c 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java @@ -197,8 +197,9 @@ public DefaultEventAnalyticsService( DatabaseInfo databaseInfo, AnalyticsCache analyticsCache, EnrollmentAnalyticsManager enrollmentAnalyticsManager, - SchemaIdResponseMapper schemaIdResponseMapper) { - super(securityManager, queryValidator, schemaIdResponseMapper); + SchemaIdResponseMapper schemaIdResponseMapper, + OrganisationUnitResolver organisationUnitResolver) { + super(securityManager, queryValidator, schemaIdResponseMapper, organisationUnitResolver); checkNotNull(dataElementService); checkNotNull(trackedEntityAttributeService); diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventDataQueryService.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventDataQueryService.java index f8081bf734ac..29715ec57650 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventDataQueryService.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventDataQueryService.java @@ -48,12 +48,10 @@ import static org.hisp.dhis.analytics.event.data.DefaultEventDataQueryService.SortableItems.translateItemIfNecessary; import static org.hisp.dhis.analytics.util.AnalyticsUtils.throwIllegalQueryEx; import static org.hisp.dhis.common.DimensionalObject.DIMENSION_NAME_SEP; -import static org.hisp.dhis.common.DimensionalObject.OPTION_SEP; import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID; import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionFromParam; import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionItemsFromParam; import static org.hisp.dhis.common.DimensionalObjectUtils.getDimensionalItemIds; -import static org.hisp.dhis.common.ValueType.ORGANISATION_UNIT; import java.util.ArrayList; import java.util.Arrays; @@ -68,7 +66,6 @@ import java.util.stream.Collectors; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.hisp.dhis.analytics.AnalyticsAggregationType; import org.hisp.dhis.analytics.DataQueryService; @@ -229,7 +226,8 @@ public EventQueryParams getFromRequest(EventDataQueryRequest request, boolean an .withEnhancedConditions(request.isEnhancedConditions()) .withEndpointItem(request.getEndpointItem()) .withEndpointAction(request.getEndpointAction()) - .withRowContext(request.isRowContext()); + .withRowContext(request.isRowContext()) + .withUserOrgUnits(userOrgUnits); if (analyzeOnly) { builder = builder.withSkipData(true).withAnalyzeOrderId(); @@ -344,7 +342,7 @@ private void addDimensionsToParams( if (groupableItem != null) { params.addDimension((DimensionalObject) groupableItem); } else { - groupableItem = getQueryItem(dim, pr, request.getOutputType(), userOrgUnits); + groupableItem = getQueryItem(dim, pr, request.getOutputType()); params.addItem((QueryItem) groupableItem); } @@ -511,14 +509,6 @@ private QueryItem getQueryItem( @Override public QueryItem getQueryItem(String dimensionString, Program program, EventOutputType type) { - return getQueryItem(dimensionString, program, type, Collections.emptyList()); - } - - private QueryItem getQueryItem( - String dimensionString, - Program program, - EventOutputType type, - List userOrgUnits) { String[] split = dimensionString.split(DIMENSION_NAME_SEP); if (split.length % 2 != 1) { @@ -535,7 +525,6 @@ private QueryItem getQueryItem( // FE uses HH.MM time format instead of HH:MM. This is not // compatible with db table/cell values modifyFilterWhenTimeQueryItem(queryItem, filter); - resolveOrgUnitDimensionIfNecessary(queryItem, filter, userOrgUnits); queryItem.addFilter(filter); } } @@ -543,17 +532,6 @@ private QueryItem getQueryItem( return queryItem; } - @SneakyThrows - private void resolveOrgUnitDimensionIfNecessary( - QueryItem queryItem, QueryFilter queryFilter, List userOrgUnits) { - if (queryItem.getValueType().equals(ORGANISATION_UNIT)) { - List filterItem = QueryFilter.getFilterItems(queryFilter.getFilter()); - List orgUnitDimensionUid = - dataQueryService.getOrgUnitDimensionUid(filterItem, userOrgUnits); - queryFilter.setFilter(String.join(OPTION_SEP, orgUnitDimensionUid)); - } - } - private static void modifyFilterWhenTimeQueryItem(QueryItem queryItem, QueryFilter filter) { if (queryItem.getItem() instanceof DataElement && ((DataElement) queryItem.getItem()).getValueType() == ValueType.TIME) { diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java index 09e08a77197b..22ea1805b665 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEnrollmentAnalyticsManager.java @@ -124,9 +124,14 @@ public JdbcEnrollmentAnalyticsManager( ProgramIndicatorService programIndicatorService, ProgramIndicatorSubqueryBuilder programIndicatorSubqueryBuilder, EnrollmentTimeFieldSqlRenderer timeFieldSqlRenderer, - ExecutionPlanStore executionPlanStore) { + ExecutionPlanStore executionPlanStore, + OrganisationUnitResolver organisationUnitResolver) { super( - jdbcTemplate, programIndicatorService, programIndicatorSubqueryBuilder, executionPlanStore); + jdbcTemplate, + programIndicatorService, + programIndicatorSubqueryBuilder, + executionPlanStore, + organisationUnitResolver); this.timeFieldSqlRenderer = timeFieldSqlRenderer; } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEventAnalyticsManager.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEventAnalyticsManager.java index 0bbbe0340477..80e3a2591f0a 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEventAnalyticsManager.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEventAnalyticsManager.java @@ -117,9 +117,14 @@ public JdbcEventAnalyticsManager( ProgramIndicatorService programIndicatorService, ProgramIndicatorSubqueryBuilder programIndicatorSubqueryBuilder, EventTimeFieldSqlRenderer timeFieldSqlRenderer, - ExecutionPlanStore executionPlanStore) { + ExecutionPlanStore executionPlanStore, + OrganisationUnitResolver organisationUnitResolver) { super( - jdbcTemplate, programIndicatorService, programIndicatorSubqueryBuilder, executionPlanStore); + jdbcTemplate, + programIndicatorService, + programIndicatorSubqueryBuilder, + executionPlanStore, + organisationUnitResolver); this.timeFieldSqlRenderer = timeFieldSqlRenderer; } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/OrganisationUnitResolver.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/OrganisationUnitResolver.java new file mode 100644 index 000000000000..2f56c2484dee --- /dev/null +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/OrganisationUnitResolver.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2004-2025, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.analytics.event.data; + +import static org.hisp.dhis.common.DimensionalObject.OPTION_SEP; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.hisp.dhis.analytics.data.DimensionalObjectProducer; +import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.common.MetadataItem; +import org.hisp.dhis.common.QueryFilter; +import org.hisp.dhis.common.QueryItem; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.organisationunit.OrganisationUnitService; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class OrganisationUnitResolver { + + private final DimensionalObjectProducer dimensionalObjectProducer; + + private final OrganisationUnitService organisationUnitService; + + /** + * Resolve organisation units like ou:USER_ORGUNIT;USER_ORGUNIT_CHILDREN;LEVEL-XXX;OUGROUP-XXX + * into a list of organisation unit dimension uids. + * + * @param queryFilter the query filter containing the organisation unit filter + * @param userOrgUnits the user organisation units + * @return the organisation unit dimension uids + */ + public String resolveOrgUnits(QueryFilter queryFilter, List userOrgUnits) { + List filterItem = QueryFilter.getFilterItems(queryFilter.getFilter()); + List orgUnitDimensionUid = + dimensionalObjectProducer.getOrgUnitDimensionUid(filterItem, userOrgUnits); + return String.join(OPTION_SEP, orgUnitDimensionUid); + } + + /** + * Returns a map of metadata item identifiers and {@link MetadataItem} for organisation unit data + * elements. + * + * @param params the {@link EventQueryParams}. + * @return a map. + */ + public Map getMetadataItemsForOrgUnitDataElements(EventQueryParams params) { + List orgUnitIds = new ArrayList<>(); + for (QueryItem queryItem : params.getItems()) { + if (queryItem.getValueType().isOrganisationUnit()) { + for (QueryFilter queryFilter : queryItem.getFilters()) { + String resolveOrgUnits = resolveOrgUnits(queryFilter, params.getUserOrgUnits()); + if (StringUtils.isNotBlank(resolveOrgUnits)) { + orgUnitIds.addAll(Arrays.asList(resolveOrgUnits.split(OPTION_SEP))); + } + } + } + } + + if (orgUnitIds.isEmpty()) { + return Map.of(); + } + + return organisationUnitService.getOrganisationUnitsByUid(orgUnitIds).stream() + .collect( + Collectors.toMap(OrganisationUnit::getUid, orgUnit -> toMetadataItem(orgUnit, params))); + } + + /** + * Returns a {@link MetadataItem} based on the given organisation unit and query parameters. + * + * @param orgUnit the {@link OrganisationUnit}. + * @param params the {@link EventQueryParams}. + * @return a {@link MetadataItem}. + */ + private MetadataItem toMetadataItem(OrganisationUnit orgUnit, EventQueryParams params) { + return new MetadataItem( + orgUnit.getDisplayProperty(params.getDisplayProperty()), + params.isIncludeMetadataDetails() ? orgUnit.getUid() : null, + orgUnit.getCode()); + } + + /** + * Resolve organisation units like ou:USER_ORGUNIT;USER_ORGUNIT_CHILDREN;LEVEL-XXX;OUGROUP-XXX + * into a list of organisation unit dimension uids. + * + * @param params the event query parameters + * @param item the query item + * @return the list of organisation unit dimension uids + */ + public List resolveOrgUnis(EventQueryParams params, QueryItem item) { + return item.getFilters().stream() + .map(queryFilter -> resolveOrgUnits(queryFilter, params.getUserOrgUnits())) + .map(s -> s.split(OPTION_SEP)) + .flatMap(Arrays::stream) + .distinct() + .collect(Collectors.toList()); + } +} diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsServiceTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsServiceTest.java index fe5f48c0e8fa..c013a6b2ee7c 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractAnalyticsServiceTest.java @@ -90,10 +90,13 @@ class AbstractAnalyticsServiceTest { @Mock private SchemaIdResponseMapper schemaIdResponseMapper; + @Mock private OrganisationUnitResolver organisationUnitResolver; + @BeforeEach public void setUp() { dummyAnalyticsService = - new DummyAnalyticsService(securityManager, eventQueryValidator, schemaIdResponseMapper); + new DummyAnalyticsService( + securityManager, eventQueryValidator, schemaIdResponseMapper, organisationUnitResolver); peA = MonthlyPeriodType.getPeriodFromIsoString("201701"); ouA = createOrganisationUnit('A'); @@ -249,8 +252,9 @@ class DummyAnalyticsService extends AbstractAnalyticsService { public DummyAnalyticsService( AnalyticsSecurityManager securityManager, EventQueryValidator queryValidator, - SchemaIdResponseMapper schemaIdResponseMapper) { - super(securityManager, queryValidator, schemaIdResponseMapper); + SchemaIdResponseMapper schemaIdResponseMapper, + OrganisationUnitResolver organisationUnitResolver) { + super(securityManager, queryValidator, schemaIdResponseMapper, organisationUnitResolver); } @Override diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java index 2489e42e392e..185a792d6d9e 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java @@ -54,6 +54,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -117,6 +118,8 @@ class AbstractJdbcEventAnalyticsManagerTest extends EventAnalyticsTest { @Mock private ExecutionPlanStore executionPlanStore; + @Mock private OrganisationUnitResolver organisationUnitResolver; + private JdbcEventAnalyticsManager eventSubject; private Program programA; @@ -140,7 +143,8 @@ public void setUp() { programIndicatorService, programIndicatorSubqueryBuilder, new EventTimeFieldSqlRenderer(statementBuilder), - executionPlanStore); + executionPlanStore, + organisationUnitResolver); programA = createProgram('A'); @@ -804,6 +808,7 @@ void testItemsInFilterAreQuotedForOrganisationUnit() { new EventQueryParams.Builder().withStartDate(new Date()).withEndDate(new Date()).build(); when(queryItem.getItemName()).thenReturn("anyItem"); when(queryItem.getValueType()).thenReturn(ValueType.ORGANISATION_UNIT); + when(organisationUnitResolver.resolveOrgUnits(any(), any())).thenReturn("A;B;C"); // When String sql = eventSubject.toSql(queryItem, queryFilter, params).trim(); diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsServiceTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsServiceTest.java index 94380004749c..33cb1895ec78 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsServiceTest.java @@ -92,6 +92,8 @@ class DefaultEventAnalyticsServiceTest { @Mock private SchemaIdResponseMapper schemaIdResponseMapper; + @Mock private OrganisationUnitResolver organisationUnitResolver; + @BeforeEach public void setUp() { defaultEventAnalyticsService = @@ -106,7 +108,8 @@ public void setUp() { databaseInfo, analyticsCache, enrollmentAnalyticsManager, - schemaIdResponseMapper); + schemaIdResponseMapper, + organisationUnitResolver); } @Test diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EnrollmentAnalyticsManagerTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EnrollmentAnalyticsManagerTest.java index f87ad7b51ad9..60f844b5e74a 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EnrollmentAnalyticsManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EnrollmentAnalyticsManagerTest.java @@ -107,6 +107,8 @@ class EnrollmentAnalyticsManagerTest extends EventAnalyticsTest { @Mock private ProgramIndicatorService programIndicatorService; + @Mock private OrganisationUnitResolver organisationUnitResolver; + @Captor private ArgumentCaptor sql; private String DEFAULT_COLUMNS = @@ -132,7 +134,8 @@ public void setUp() { programIndicatorService, programIndicatorSubqueryBuilder, new EnrollmentTimeFieldSqlRenderer(statementBuilder), - executionPlanStore); + executionPlanStore, + organisationUnitResolver); } @Test diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsManagerTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsManagerTest.java index 0547659a422c..ca396d8ca008 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsManagerTest.java @@ -108,6 +108,8 @@ class EventAnalyticsManagerTest extends EventAnalyticsTest { @Mock private ExecutionPlanStore executionPlanStore; + @Mock private OrganisationUnitResolver organisationUnitResolver; + private JdbcEventAnalyticsManager subject; @Captor private ArgumentCaptor sql; @@ -137,7 +139,8 @@ public void setUp() { programIndicatorService, programIndicatorSubqueryBuilder, timeCoordinateSelector, - executionPlanStore); + executionPlanStore, + organisationUnitResolver); when(jdbcTemplate.queryForRowSet(anyString())).thenReturn(this.rowSet); } diff --git a/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/analytics/event/query/EventQueryTest.java b/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/analytics/event/query/EventQueryTest.java index 2ceeb1260c4f..50c4cd2a1474 100644 --- a/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/analytics/event/query/EventQueryTest.java +++ b/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/analytics/event/query/EventQueryTest.java @@ -1043,7 +1043,7 @@ public void queryWithOrgUnitDataElement() throws JSONException { // Assert metaData. String expectedMetaData = - "{\"pager\":{\"isLastPage\":true,\"pageSize\":100,\"page\":1},\"items\":{\"ImspTQPwCqd\":{\"uid\":\"ImspTQPwCqd\",\"code\":\"OU_525\",\"valueType\":\"TEXT\",\"name\":\"Sierra Leone\",\"dimensionItemType\":\"ORGANISATION_UNIT\",\"totalAggregationType\":\"SUM\"},\"ou\":{\"uid\":\"ou\",\"dimensionType\":\"ORGANISATION_UNIT\",\"name\":\"Organisation unit\"},\"Ge7Eo3FNnbl\":{\"uid\":\"Ge7Eo3FNnbl\",\"name\":\"XX MAL RDT - Case Registration\"},\"Ge7Eo3FNnbl.rypjN8CV02V\":{\"uid\":\"rypjN8CV02V\",\"aggregationType\":\"SUM\",\"valueType\":\"TEXT\",\"name\":\"XX MAL RDT TRK - Village of Residence\",\"style\":{\"icon\":\"nullapi\\/icons\\/star_medium_positive\\/icon.svg\"},\"dimensionItemType\":\"DATA_ELEMENT\",\"totalAggregationType\":\"SUM\"},\"MoUd5BTQ3lY\":{\"uid\":\"MoUd5BTQ3lY\",\"name\":\"XX MAL RDT - Case Registration\"},\"rypjN8CV02V\":{\"uid\":\"rypjN8CV02V\",\"aggregationType\":\"SUM\",\"valueType\":\"TEXT\",\"name\":\"XX MAL RDT TRK - Village of Residence\",\"style\":{\"icon\":\"nullapi\\/icons\\/star_medium_positive\\/icon.svg\"},\"dimensionItemType\":\"DATA_ELEMENT\",\"totalAggregationType\":\"SUM\"},\"LAST_12_MONTHS\":{\"name\":\"Last 12 months\"}},\"dimensions\":{\"pe\":[],\"ou\":[\"ImspTQPwCqd\"],\"Ge7Eo3FNnbl.rypjN8CV02V\":[]}}"; + "{\"pager\":{\"isLastPage\":true,\"pageSize\":100,\"page\":1},\"items\":{\"ImspTQPwCqd\":{\"uid\":\"ImspTQPwCqd\",\"code\":\"OU_525\",\"valueType\":\"TEXT\",\"name\":\"Sierra Leone\",\"dimensionItemType\":\"ORGANISATION_UNIT\",\"totalAggregationType\":\"SUM\"},\"ou\":{\"uid\":\"ou\",\"dimensionType\":\"ORGANISATION_UNIT\",\"name\":\"Organisation unit\"},\"Ge7Eo3FNnbl\":{\"uid\":\"Ge7Eo3FNnbl\",\"name\":\"XX MAL RDT - Case Registration\"},\"Ge7Eo3FNnbl.rypjN8CV02V\":{\"uid\":\"rypjN8CV02V\",\"aggregationType\":\"SUM\",\"valueType\":\"TEXT\",\"name\":\"XX MAL RDT TRK - Village of Residence\",\"style\":{\"icon\":\"nullapi\\/icons\\/star_medium_positive\\/icon.svg\"},\"dimensionItemType\":\"DATA_ELEMENT\",\"totalAggregationType\":\"SUM\"},\"MoUd5BTQ3lY\":{\"uid\":\"MoUd5BTQ3lY\",\"name\":\"XX MAL RDT - Case Registration\"},\"rypjN8CV02V\":{\"uid\":\"rypjN8CV02V\",\"aggregationType\":\"SUM\",\"valueType\":\"TEXT\",\"name\":\"XX MAL RDT TRK - Village of Residence\",\"style\":{\"icon\":\"nullapi\\/icons\\/star_medium_positive\\/icon.svg\"},\"dimensionItemType\":\"DATA_ELEMENT\",\"totalAggregationType\":\"SUM\"},\"LAST_12_MONTHS\":{\"name\":\"Last 12 months\"}},\"dimensions\":{\"pe\":[],\"ou\":[\"ImspTQPwCqd\"],\"Ge7Eo3FNnbl.rypjN8CV02V\":[\"DiszpKrYNg8\",\"g8upMTyEZGZ\",\"ImspTQPwCqd\",\"O6uvpzGd5pu\",\"fdc6uOvgoji\",\"lc3eMKXaEfw\",\"jUb8gELQApl\",\"PMa2VCrupOd\",\"kJq2mPyFEHo\",\"qhqAxPSTUXp\",\"Vth0fbpFcsO\",\"jmIPBj66vD6\",\"TEQlaapDQoK\",\"bL4ooGhyHRQ\",\"eIQbndfxQMb\",\"at6UHUQatSo\",\"YuQRtpLP10I\",\"vWbkYPRmKyS\",\"dGheVylzol6\",\"zFDYIgyGmXG\",\"BGGmAwx33dj\",\"YmmeuGbqOwR\",\"daJPPxtIrQn\",\"U6Kr7Gtpidn\",\"JdhagCUEMbj\",\"kU8vhUkAGaT\",\"I4jWcnFmgEC\",\"KctpIIucige\",\"sxRd2XOzFbz\",\"npWGUj37qDe\",\"ARZ4y5i4reU\",\"fwH9ipvXde9\",\"KKkLOTpMXGV\",\"e1eIKM1GIF3\",\"BXJdOLvUrZB\",\"hRZOIgQ0O1m\",\"eV4cuxniZgP\",\"lY93YpCxJqf\",\"L8iA6eLwKNb\",\"XG8HGAbrbbL\",\"WXnNDWTiE9r\",\"UhHipWG7J8b\",\"j43EZb15rjI\",\"Qhmi8IZyPyD\",\"ENHOJz3UH5L\",\"EB1zRKdYjdY\",\"iUauWFeH8Qp\",\"DNRAeXT9IwS\",\"XEyIRFd9pct\",\"VCtF1DbspR5\",\"aWQTfvgPA5v\",\"HV8RTzgcFH3\",\"VP397wRvePm\",\"g8DdBm7EmUt\",\"cgOy0hRMGu9\",\"CG4QD1HC3h4\",\"lYIM1MXbSYS\",\"KSdZwrU7Hh6\",\"JsxnA2IywRo\",\"j0Mtr3xTMjM\",\"hjpHnHZIniP\",\"cM2BKSrj9F9\",\"GE25DpSrqpB\",\"yu4N82FFeLm\",\"ERmBhYkhV6Y\",\"DxAPPqXvwLy\",\"pmxZm7klXBy\",\"bQiBfA2j5cw\",\"LfTkc0S4b5k\",\"byp7w6Xd9Df\",\"kbPmt60yi0L\",\"qIRCo0MfuGb\",\"QywkxFudXrC\",\"xGMGhjA3y6J\",\"FlBemv1NfEC\",\"r06ohri9wA9\",\"y5X4mP5XylL\",\"myQ4q1W6B4y\",\"QlCIp2S9NHs\",\"eROJsBwxQHt\",\"KXSqt7jv6DU\",\"K1r3uF6eZ8n\",\"EYt6ThQDagn\",\"jWSIbtKfURj\",\"hdEuw2ugkVF\",\"x4HaBHHwBML\",\"uKC54fzxRzO\",\"U09TSwIjG0s\",\"KIUCimTXf8Q\",\"A3Fh37HWBWE\",\"vzup1f6ynON\",\"l7pFejMtUoF\",\"X7dWcGerQIm\",\"Mr4au3jR9bt\",\"Lt8U7GVWvSR\",\"iEkBZnMDarP\",\"vEvs2ckGNQj\",\"OTFepb1k9Db\",\"GFk45MOxzJJ\",\"J4GiUImJZoE\",\"VGAFxBXz16y\",\"PaqugoqjRIj\",\"XrF5AvaGcuw\",\"EZPwuUTeIIG\",\"CF243RPvNY7\",\"ajILkI0cfxn\",\"Zoy23SSHCPs\",\"TQkG0sX9nca\",\"GWTIxJO9pRo\",\"kvkDWg42lHR\",\"LhaAPLxdSFH\",\"EjnIQNVAXGp\",\"DmaLM8WYmWv\",\"qgQ49DH9a0v\",\"g5ptsn0SFX8\",\"iGHlidSFdpu\",\"M2qEv692lS6\",\"FRxcUEwktoV\",\"jPidqyo7cpF\",\"nOYt1LtFSyU\",\"RndxKqQGzUl\",\"vULnao2hV5v\",\"USQdmvrHh1Q\",\"LsYpCyYxSLY\",\"Z9QaI6sxTwW\",\"Jiyc4ekaMMh\",\"nV3OkyzF4US\",\"xIKjidMrico\",\"W5fN3G6y1VI\",\"gy8rmvYT4cj\",\"AovmOHadayb\",\"DBs6e2Oxaj1\",\"TA7NvKjsn4A\",\"Pc3JTyqnsmL\",\"ZiOVcrSjSYe\",\"vn9KJsLyP5f\",\"pRHGAROvuyI\",\"fRLX08WHWpL\",\"JdqfYTIFZXN\",\"RWvG1aFrr0r\",\"EfWCa0Cc8WW\",\"HWjrSuoNPte\",\"PrJQHI6q7w2\",\"RzKeCma9qb1\",\"eNtRuQrrZeo\",\"zSNUViKdkk3\",\"QwMiPiME3bA\",\"YpVol7asWvd\",\"BD9gU0GKlr2\",\"DfUfwjM9am5\",\"nlt6j60tCHF\",\"N233eZJZ1bh\",\"d9iMR1MpuIO\",\"NqWaKXcg01b\",\"pk7bUK5c1Uf\",\"P69SId31eDp\",\"BmYyh9bZ0sr\",\"smoyi1iYNK6\",\"fwxkctgmffZ\",\"PQZJPIpTepd\",\"l0ccv2yzfF3\",\"rXLor9Knq6l\",\"EVkm2xYcf6Z\",\"r1RUyfVBkLp\",\"xhyjU2SVewz\",\"NNE0YMCDZkO\",\"C9uduqDZr9d\",\"qtr8GGlm4gg\"]}}"; String actualMetaData = new JSONObject((Map) response.extract("metaData")).toString(); assertEquals(expectedMetaData, actualMetaData, false);