diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/feedback/ErrorCode.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/feedback/ErrorCode.java index dea0cc65ed49..1c1cf44d0afe 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/feedback/ErrorCode.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/feedback/ErrorCode.java @@ -67,6 +67,8 @@ public enum ErrorCode { E1120("Update cannot be applied as it would make existing data values inaccessible"), E1121("Data element `{0}` value type cannot be changed as it has associated data values"), + E1122("Category option combo {0} cannot be associated with the default category combo"), + E1125("Category option combo {0} contains options not associated with category combo {1}"), /* Org unit merge */ E1500("At least two source orgs unit must be specified"), E1501("Target org unit must be specified"), diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/CategoryOptionComboObjectBundleHook.java b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/CategoryOptionComboObjectBundleHook.java new file mode 100644 index 000000000000..8347f96b4e88 --- /dev/null +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/CategoryOptionComboObjectBundleHook.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2004-2024, 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.dxf2.metadata.objectbundle.hooks; + +import java.util.function.Consumer; +import lombok.AllArgsConstructor; +import org.hisp.dhis.category.CategoryCombo; +import org.hisp.dhis.category.CategoryOptionCombo; +import org.hisp.dhis.category.CategoryService; +import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle; +import org.hisp.dhis.feedback.ErrorCode; +import org.hisp.dhis.feedback.ErrorReport; +import org.springframework.stereotype.Component; + +@Component +@AllArgsConstructor +public class CategoryOptionComboObjectBundleHook + extends AbstractObjectBundleHook { + private final CategoryService categoryService; + + private void checkNonStandardDefaultCatOptionCombo( + CategoryOptionCombo categoryOptionCombo, Consumer addReports) { + + CategoryCombo categoryCombo = categoryOptionCombo.getCategoryCombo(); + CategoryCombo defaultCombo = categoryService.getDefaultCategoryCombo(); + if (!categoryCombo.getUid().equals(defaultCombo.getUid())) { + return; + } + + CategoryOptionCombo defaultCatOptionCombo = categoryService.getDefaultCategoryOptionCombo(); + + if (!categoryOptionCombo.getUid().equals(defaultCatOptionCombo.getUid())) { + addReports.accept( + new ErrorReport( + CategoryOptionCombo.class, ErrorCode.E1122, categoryOptionCombo.getName())); + } + } + + @Override + public void validate( + CategoryOptionCombo categoryOptionCombo, + ObjectBundle bundle, + Consumer addReports) { + + checkNonStandardDefaultCatOptionCombo(categoryOptionCombo, addReports); + } +} diff --git a/dhis-2/dhis-test-e2e/src/test/resources/tracker/idSchemesMetadata.json b/dhis-2/dhis-test-e2e/src/test/resources/tracker/idSchemesMetadata.json index 195b156af94c..216c33d1dca1 100644 --- a/dhis-2/dhis-test-e2e/src/test/resources/tracker/idSchemesMetadata.json +++ b/dhis-2/dhis-test-e2e/src/test/resources/tracker/idSchemesMetadata.json @@ -742,6 +742,7 @@ ], "categoryCombos": [ { + "code": "TA_CATEGORY_COMBO_ATTRIBUTE", "name": "TA Category combo attribute", "created": "2022-05-30T11:40:03.717", diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/validation/EventImportValidationTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/validation/EventImportValidationTest.java index 646276e5e0ec..5394088d2d09 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/validation/EventImportValidationTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/validation/EventImportValidationTest.java @@ -161,12 +161,20 @@ void testTrackerAndProgramEventUpdateSuccess() throws IOException { @Test void testCantWriteAccessCatCombo() throws IOException { - TrackerObjects trackerObjects = fromJson("tracker/validations/events-cat-write-access.json"); + TrackerObjects trackerObjects = + fromJson("tracker/validations/enrollments-cat-write-access.json"); TrackerImportParams params = new TrackerImportParams(); - injectSecurityContextUser(userService.getUser(USER_6)); ImportReport importReport = trackerImportService.importTracker(params, trackerObjects); + assertNoErrors(importReport); + + trackerObjects = fromJson("tracker/validations/events-cat-write-access.json"); + params = new TrackerImportParams(); + injectSecurityContextUser(userService.getUser(USER_6)); + + importReport = trackerImportService.importTracker(params, trackerObjects); + assertHasOnlyErrors( importReport, ValidationCode.E1096, diff --git a/dhis-2/dhis-test-integration/src/test/resources/tracker/tracker_basic_metadata.json b/dhis-2/dhis-test-integration/src/test/resources/tracker/tracker_basic_metadata.json index 66db4ea628af..41715dd25d9d 100644 --- a/dhis-2/dhis-test-integration/src/test/resources/tracker/tracker_basic_metadata.json +++ b/dhis-2/dhis-test-integration/src/test/resources/tracker/tracker_basic_metadata.json @@ -559,7 +559,7 @@ "ignoreOverdueEvents": false, "programSections": [], "created": "2019-03-29T12:41:33.001", - "shortName": "Tracker Program", + "shortName": "Tracker Program no default CC", "incidentDateLabel": "IncidentDate", "translations": [], "style": { @@ -571,10 +571,75 @@ }, "programStages": [ { - "id": "Qmqxq907VNz" + "id": "OilWH8Cj6QU" + } + ], + "selectEnrollmentDatesInFuture": false, + "categoryCombo": { + "id": "WG3syvpSE9o" + }, + "notificationTemplates": [], + "displayIncidentDate": true, + "accessLevel": "OPEN", + "featureType": "POLYGON", + "id": "qiHs9hD2Opf", + "lastUpdatedBy": { + "id": "tTgjgobT1oS" + }, + "completeEventsExpiryDays": 10, + "organisationUnits": [ + { + "id": "QfUVllTs6cS" }, { - "id": "OilWH8Cj6QU" + "id": "QfUVllTs6cZ" + }, + { + "id": "QfUVllTs6cW" + } + ], + "onlyEnrollOnce": false, + "lastUpdated": "2019-03-29T12:41:33.039", + "trackedEntityType": { + "id": "bPJ0FMtcnEh" + }, + "name": "Tracker Program no default CC", + "enrollmentDateLabel": "EnrollmentDate", + "maxTeiCountToReturn": 0, + "attributeValues": [], + "programTrackedEntityAttributes": [], + "useFirstStageDuringRegistration": false, + "minAttributesRequiredToSearch": 1, + "skipOffline": false, + "version": 0, + "programType": "WITH_REGISTRATION", + "selectIncidentDatesInFuture": false, + "displayFrontPageList": false, + "sharing": { + "public": "rw------", + "external": false, + "owner": "tTgjgobT1oS", + "users": {}, + "userGroups": {} + } + }, + { + "ignoreOverdueEvents": false, + "programSections": [], + "created": "2019-03-29T12:41:33.001", + "shortName": "Tracker Program", + "incidentDateLabel": "IncidentDate", + "translations": [], + "style": { + "color": "#d32f2f" + }, + "expiryDays": 0, + "user": { + "id": "tTgjgobT1oS" + }, + "programStages": [ + { + "id": "Qmqxq907VNz" }, { "id": "m7HlXaMvgX2" @@ -2672,10 +2737,10 @@ ], "categoryOptions": [ { - "id": "xYerKDKCefk", - "code": "default", - "name": "default", - "shortName": "default", + "id": "WAFwwid9TzE", + "code": "default2", + "name": "default2", + "shortName": "default2", "startDate": "2019-01-01T00:00:00.000", "attributeValues": [], "lastUpdated": "2019-03-25T13:40:24.783", @@ -2812,14 +2877,14 @@ ], "categories": [ { - "id": "GLevLNI9wkl", - "name": "default", - "shortName": "default", - "code": "default", + "id": "Vk8PHR8HBAe", + "name": "default2", + "shortName": "default2", + "code": "default2", "dataDimensionType": "DISAGGREGATION", "categoryOptions": [ { - "id": "xYerKDKCefk" + "id": "WAFwwid9TzE" } ], "dataDimension": false, @@ -2886,13 +2951,13 @@ ], "categoryCombos": [ { - "id": "bjDvmb4bfuf", - "code": "default", - "name": "default", + "id": "WG3syvpSE9o", + "code": "default2", + "name": "default2", "dataDimensionType": "DISAGGREGATION", "categories": [ { - "id": "GLevLNI9wkl" + "id": "Vk8PHR8HBAe" } ], "created": "2019-03-25T13:40:24.771", @@ -2978,25 +3043,6 @@ } ], "categoryOptionCombos": [ - { - "id": "HllvX50cXC0", - "code": "default", - "name": "default", - "categoryOptions": [ - { - "id": "xYerKDKCefk" - } - ], - "categoryCombo": { - "id": "bjDvmb4bfuf" - }, - "translations": [], - "startDate": "2019-01-01T00:00:00.000", - "lastUpdated": "2019-03-25T13:40:24.779", - "ignoreApproval": false, - "attributeValues": [], - "created": "2019-03-25T13:40:24.775" - }, { "id": "KKKKX50cXC0", "name": "accesstest1", @@ -3007,7 +3053,7 @@ } ], "categoryCombo": { - "id": "bjDvmb4bfuf" + "id": "WG3syvpSE9o" }, "translations": [], "startDate": "2019-01-01T00:00:00.000", diff --git a/dhis-2/dhis-test-integration/src/test/resources/tracker/validations/enrollments-cat-write-access.json b/dhis-2/dhis-test-integration/src/test/resources/tracker/validations/enrollments-cat-write-access.json new file mode 100644 index 000000000000..7a18012a347d --- /dev/null +++ b/dhis-2/dhis-test-integration/src/test/resources/tracker/validations/enrollments-cat-write-access.json @@ -0,0 +1,29 @@ +{ + "trackedEntities": [], + "enrollments": [ + { + "enrollment": "CzXv1fa1kbX", + "trackedEntity": "Kj6vYde4LHh", + "program": { + "idScheme": "UID", + "identifier": "qiHs9hD2Opf" + }, + "status": "COMPLETED", + "orgUnit": { + "idScheme": "UID", + "identifier": "QfUVllTs6cS" + }, + "enrolledAt": "2019-08-19T00:00:00.000", + "occurredAt": "2019-08-19T00:00:00.000", + "followUp": false, + "deleted": false, + "storedBy": "admin", + "events": [], + "relationships": [], + "attributes": [], + "notes": [] + } + ], + "events": [], + "relationships": [] +} \ No newline at end of file diff --git a/dhis-2/dhis-test-integration/src/test/resources/tracker/validations/events-cat-write-access.json b/dhis-2/dhis-test-integration/src/test/resources/tracker/validations/events-cat-write-access.json index 254eda322691..d4c1aef6ca99 100644 --- a/dhis-2/dhis-test-integration/src/test/resources/tracker/validations/events-cat-write-access.json +++ b/dhis-2/dhis-test-integration/src/test/resources/tracker/validations/events-cat-write-access.json @@ -1,35 +1,4 @@ { - "importMode": "COMMIT", - "idSchemes": { - "dataElementIdScheme": { - "idScheme": "UID" - }, - "orgUnitIdScheme": { - "idScheme": "UID" - }, - "programIdScheme": { - "idScheme": "UID" - }, - "programStageIdScheme": { - "idScheme": "UID" - }, - "idScheme": { - "idScheme": "UID" - }, - "categoryOptionComboIdScheme": { - "idScheme": "UID" - }, - "categoryOptionIdScheme": { - "idScheme": "UID" - } - }, - "importStrategy": "CREATE", - "atomicMode": "ALL", - "flushMode": "AUTO", - "validationMode": "FULL", - "skipPatternValidation": false, - "skipSideEffects": false, - "skipRuleEngine": false, "trackedEntities": [], "enrollments": [], "events": [ @@ -38,13 +7,13 @@ "status": "ACTIVE", "program": { "idScheme": "UID", - "identifier": "E8o1E9tAppy" + "identifier": "qiHs9hD2Opf" }, "programStage": { "idScheme": "UID", "identifier": "OilWH8Cj6QU" }, - "enrollment": "MNWZ6hnuhSw", + "enrollment": "CzXv1fa1kbX", "orgUnit": { "idScheme": "UID", "identifier": "QfUVllTs6cS" @@ -64,6 +33,5 @@ "notes": [] } ], - "relationships": [], - "username": "system-process" + "relationships": [] } \ No newline at end of file diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/CategoryOptionComboControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/CategoryOptionComboControllerTest.java index ab13aa6564e4..dcd627964017 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/CategoryOptionComboControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/CategoryOptionComboControllerTest.java @@ -27,19 +27,26 @@ */ package org.hisp.dhis.webapi.controller; +import static org.hisp.dhis.http.HttpAssertions.assertStatus; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import org.hisp.dhis.category.CategoryCombo; import org.hisp.dhis.category.CategoryOption; import org.hisp.dhis.category.CategoryOptionCombo; import org.hisp.dhis.category.CategoryService; +import org.hisp.dhis.feedback.ErrorCode; import org.hisp.dhis.http.HttpStatus; import org.hisp.dhis.jsontree.JsonArray; +import org.hisp.dhis.jsontree.JsonList; +import org.hisp.dhis.jsontree.JsonObject; import org.hisp.dhis.test.webapi.H2ControllerIntegrationTestBase; import org.hisp.dhis.test.webapi.json.domain.JsonCategoryOptionCombo; +import org.hisp.dhis.test.webapi.json.domain.JsonErrorReport; import org.hisp.dhis.test.webapi.json.domain.JsonIdentifiableObject; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -115,4 +122,57 @@ void catOptionCombosExcludingDefaultTest() { assertFalse( catOptionComboNames.contains("default"), "default catOptionCombo is not in payload"); } + + @Test + @DisplayName("Duplicate default category option combos should not be allowed") + void catOptionCombosDuplicatedDefaultTest() { + JsonObject response = + GET("/categoryOptionCombos?filter=name:eq:default&fields=id,categoryCombo[id],categoryOptions[id]") + .content(); + JsonList catOptionCombos = + response.getList("categoryOptionCombos", JsonCategoryOptionCombo.class); + String defaultCatOptionComboOptions = + catOptionCombos.get(0).getCategoryOptions().get(0).getId(); + String defaultCatOptionComboCatComboId = catOptionCombos.get(0).getCategoryCombo().getId(); + response = + POST( + "/categoryOptionCombos/", + """ + { "name": "Not default", + "categoryOptions" : [{"id" : "%s"}], + "categoryCombo" : {"id" : "%s"} } + """ + .formatted(defaultCatOptionComboOptions, defaultCatOptionComboCatComboId)) + .content(HttpStatus.CONFLICT); + + JsonErrorReport error = + response.find(JsonErrorReport.class, report -> report.getErrorCode() == ErrorCode.E1122); + assertNotNull(error); + assertEquals( + "Category option combo Not default cannot be associated with the default category combo", + error.getMessage()); + } + + @Test + @DisplayName("Can delete a duplicate default COC") + void canAllowDeleteDuplicatedDefaultCOC() { + // Revert to the service layer as the API should not allow us to create a duplicate default COC + CategoryOptionCombo defaultCOC = categoryService.getDefaultCategoryOptionCombo(); + CategoryCombo categoryCombo = + categoryService.getCategoryCombo(defaultCOC.getCategoryCombo().getUid()); + CategoryOptionCombo existingCategoryOptionCombo = + categoryService.getCategoryOptionCombo(defaultCOC.getUid()); + CategoryOptionCombo categoryOptionComboDuplicate = new CategoryOptionCombo(); + categoryOptionComboDuplicate.setAutoFields(); + categoryOptionComboDuplicate.setCategoryCombo(categoryCombo); + Set newCategoryOptions = + new HashSet<>(existingCategoryOptionCombo.getCategoryOptions()); + categoryOptionComboDuplicate.setCategoryOptions(newCategoryOptions); + categoryOptionComboDuplicate.setName("dupDefault"); + categoryService.addCategoryOptionCombo(categoryOptionComboDuplicate); + + // Can delete the duplicated default COC + assertStatus( + HttpStatus.OK, DELETE("/categoryOptionCombos/" + categoryOptionComboDuplicate.getUid())); + } } diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/dataintegrity/DataIntegrityCategoryOptionComboDuplicatedTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/dataintegrity/DataIntegrityCategoryOptionComboDuplicatedTest.java index 66016541b3c3..f7e4ed3a7022 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/dataintegrity/DataIntegrityCategoryOptionComboDuplicatedTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/dataintegrity/DataIntegrityCategoryOptionComboDuplicatedTest.java @@ -28,8 +28,14 @@ package org.hisp.dhis.webapi.controller.dataintegrity; import static org.hisp.dhis.http.HttpAssertions.assertStatus; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.HashSet; import java.util.Set; +import org.hisp.dhis.category.CategoryCombo; +import org.hisp.dhis.category.CategoryOption; +import org.hisp.dhis.category.CategoryOptionCombo; import org.hisp.dhis.http.HttpStatus; import org.hisp.dhis.jsontree.JsonList; import org.hisp.dhis.jsontree.JsonObject; @@ -48,8 +54,6 @@ class DataIntegrityCategoryOptionComboDuplicatedTest extends AbstractDataIntegri private final String check = "category_option_combos_have_duplicates"; - private String cocWithOptionsA; - private String categoryOptionRed; @Test @@ -80,44 +84,40 @@ void testCategoryOptionCombosDuplicated() { + categoryColor + "'}]} ")); - cocWithOptionsA = - assertStatus( - HttpStatus.CREATED, - POST( - "/categoryOptionCombos", - """ - { "name": "Reddish", - "categoryOptions" : [{"id" : "%s"}], - "categoryCombo" : {"id" : "%s"} } - """ - .formatted(categoryOptionRed, testCatCombo))); + HttpResponse response = GET("/categoryOptionCombos?fields=id,name&filter=name:eq:Red"); + assertStatus(HttpStatus.OK, response); + JsonObject responseContent = response.content(); - assertStatus( - HttpStatus.CREATED, - POST( - "/categoryOptionCombos", - """ - { "name": "Not Red", - "categoryOptions" : [{"id" : "%s"}]}, - "categoryCombo" : {"id" : "%s"} } - """ - .formatted(categoryOptionRed, testCatCombo))); + JsonList catOptionCombos = + responseContent.getList("categoryOptionCombos", JsonCategoryOptionCombo.class); + assertEquals(1, catOptionCombos.size()); + String redCategoryOptionComboId = catOptionCombos.get(0).getId(); + + /*We must resort to the service layer as the API will not allow us to create a duplicate*/ + CategoryCombo categoryCombo = categoryService.getCategoryCombo(testCatCombo); + CategoryOptionCombo existingCategoryOptionCombo = + categoryService.getCategoryOptionCombo(redCategoryOptionComboId); + CategoryOptionCombo categoryOptionComboDuplicate = new CategoryOptionCombo(); + categoryOptionComboDuplicate.setAutoFields(); + categoryOptionComboDuplicate.setCategoryCombo(categoryCombo); + Set newCategoryOptions = + new HashSet<>(existingCategoryOptionCombo.getCategoryOptions()); + categoryOptionComboDuplicate.setCategoryOptions(newCategoryOptions); + categoryOptionComboDuplicate.setName("Reddish"); + manager.persist(categoryOptionComboDuplicate); + dbmsManager.clearSession(); + String categoryOptionComboDuplicatedID = categoryOptionComboDuplicate.getUid(); + assertNotNull(categoryOptionComboDuplicatedID); assertNamedMetadataObjectExists("categoryOptionCombos", "default"); assertNamedMetadataObjectExists("categoryOptionCombos", "Red"); assertNamedMetadataObjectExists("categoryOptionCombos", "Reddish"); - assertNamedMetadataObjectExists("categoryOptionCombos", "Not Red"); - /*We need to get the Red category option combo to be able to check the data integrity issues*/ + /* There are three total category option combos, so we expect 33% */ + checkDataIntegritySummary(check, 1, 33, true); - JsonObject response = GET("/categoryOptionCombos?fields=id,name&filter=name:eq:Red").content(); - JsonList catOptionCombos = - response.getList("categoryOptionCombos", JsonCategoryOptionCombo.class); - String redCategoryOptionComboId = catOptionCombos.get(0).getId(); - /* There are four total category option combos, so we expect 25% */ - checkDataIntegritySummary(check, 1, 25, true); - - Set expectedCategoryOptCombos = Set.of(cocWithOptionsA, redCategoryOptionComboId); + Set expectedCategoryOptCombos = + Set.of(categoryOptionComboDuplicatedID, redCategoryOptionComboId); Set expectedMessages = Set.of("Red", "Reddish"); checkDataIntegrityDetailsIssues( check, expectedCategoryOptCombos, expectedMessages, Set.of(), "categoryOptionCombos"); @@ -135,27 +135,27 @@ void testCategoryOptionCombosNotDuplicated() { HttpStatus.CREATED, POST("/categoryOptions", "{ 'name': 'Blue', 'shortName': 'Blue' }")); - cocWithOptionsA = + String categoryColor = assertStatus( HttpStatus.CREATED, POST( - "/categoryOptionCombos", - """ - { "name": "Color", - "categoryOptions" : [{"id" : "%s"} ] } - """ - .formatted(categoryOptionRed))); + "/categories", + "{ 'name': 'Color', 'shortName': 'Color', 'dataDimensionType': 'DISAGGREGATION' ," + + "'categoryOptions' : [{'id' : '" + + categoryOptionRed + + "'}, {'id' : '" + + categoryOptionBlue + + "'} ] }")); assertStatus( HttpStatus.CREATED, POST( - "/categoryOptionCombos", - """ - { "name": "Colour", - "categoryOptions" : [{"id" : "%s"} ] } - """ - .formatted(categoryOptionBlue))); - + "/categoryCombos", + "{ 'name' : 'Color', " + + "'dataDimensionType' : 'DISAGGREGATION', 'categories' : [" + + "{'id' : '" + + categoryColor + + "'}]} ")); assertHasNoDataIntegrityIssues("categoryOptionCombos", check, true); }