diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityOperationParams.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityOperationParams.java index 5d4a34da6513..3c5d23e77c57 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityOperationParams.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityOperationParams.java @@ -105,7 +105,8 @@ public class TrackedEntityOperationParams { /** Tracked entity type to fetch. */ private UID trackedEntityType; - private OrganisationUnitSelectionMode orgUnitMode; + @Builder.Default + private OrganisationUnitSelectionMode orgUnitMode = OrganisationUnitSelectionMode.ACCESSIBLE; @Getter @Builder.Default private AssignedUserQueryParam assignedUserQueryParam = AssignedUserQueryParam.ALL; diff --git a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/utils/Assertions.java b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/utils/Assertions.java index b072a24aa164..763e989f1a05 100644 --- a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/utils/Assertions.java +++ b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/utils/Assertions.java @@ -191,24 +191,59 @@ public static void assertNotEmpty(Collection actual, String message) { assertFalse(actual.isEmpty(), message); } + /** + * Asserts that the given collection is not null and not empty. + * + * @param actual the collection. + * @param messageSupplier fails with this supplied message + */ + public static void assertNotEmpty(Collection actual, Supplier messageSupplier) { + assertNotNull(actual, messageSupplier); + assertFalse(actual.isEmpty(), messageSupplier); + } + /** * Asserts that the given collection contains the expected number of elements. * * @param actual the collection. */ public static void assertHasSize(int expected, Collection actual) { - assert expected > 0 : "use assertIsEmpty"; - - assertNotEmpty(actual); - assertEquals( + assertHasSize( expected, - actual.size(), + actual, () -> String.format( "expected collection to contain %d elements, it has %d instead: '%s'", expected, actual.size(), actual)); } + /** + * Asserts that the given collection contains the expected number of elements. + * + * @param actual the collection. + * @param messageSupplier fails with this supplied message + */ + public static void assertHasSize( + int expected, Collection actual, Supplier messageSupplier) { + assert expected > 0 : "use assertIsEmpty"; + + assertNotEmpty(actual); + assertEquals(expected, actual.size(), messageSupplier); + } + + /** + * Asserts that the given collection contains the expected number of elements. + * + * @param actual the collection. + * @param message fails with this message + */ + public static void assertHasSize(int expected, Collection actual, String message) { + assert expected > 0 : "use assertIsEmpty"; + + assertNotEmpty(actual); + assertEquals(expected, actual.size(), message); + } + /** * Asserts that the given string starts with the expected prefix. * diff --git a/dhis-2/dhis-support/dhis-support-test/src/main/resources/tracker/simple_metadata.json b/dhis-2/dhis-support/dhis-support-test/src/main/resources/tracker/simple_metadata.json index 2b61abbb750d..24a0f27d194f 100644 --- a/dhis-2/dhis-support/dhis-support-test/src/main/resources/tracker/simple_metadata.json +++ b/dhis-2/dhis-support/dhis-support-test/src/main/resources/tracker/simple_metadata.json @@ -1070,7 +1070,7 @@ "attribute": { "id": "j45AR9cBQKc" }, - "value": "programStage qLZC0lvvxQH" + "value": "multi-program-stage-attribute" } ], "autoGenerateEvent": true, @@ -1126,15 +1126,7 @@ } ], "validationStrategy": "ON_UPDATE_AND_INSERT", - "featureType": "POINT", - "attributeValues": [ - { - "attribute": { - "id": "j45AR9cBQKc" - }, - "value": "multi-program-stage-attribute" - } - ] + "featureType": "POINT" }, { "id": "SKNvpoLioON", @@ -1851,6 +1843,29 @@ }, "relationshipEntity": "PROGRAM_STAGE_INSTANCE" } + }, + { + "id": "m1575931405", + "displayFromToName": "Parent Of", + "displayName": "Parent to Child", + "fromConstraint": { + "relationshipEntity": "TRACKED_ENTITY_INSTANCE", + "trackedEntityType": { + "id": "ja8NY4PW7Xm" + } + }, + "fromToName": "Child Of", + "name": "Tracked entity to tracked entity", + "sharing": { + "owner": null, + "public": "r-------" + }, + "toConstraint": { + "relationshipEntity": "TRACKED_ENTITY_INSTANCE", + "trackedEntityType": { + "id": "ja8NY4PW7Xm" + } + } } ], "trackedEntityAttributes": [ @@ -2230,6 +2245,41 @@ ], "username": "trackeradmin" }, + { + "id": "Z7870757a75", + "access": { + "delete": true, + "externalize": true, + "manage": true, + "read": true, + "update": true, + "write": true + }, + "dataViewOrganisationUnits": [ + { + "id": "h4w96yEMlzO" + } + ], + "displayName": "basicuser", + "email": "basic@dhis2.org", + "firstName": "basic", + "name": "user", + "organisationUnits": [ + { + "id": "h4w96yEMlzO" + } + ], + "password": "Test123###...", + "passwordLastUpdated": "2020-05-31T08:57:59.060", + "phoneNumber": "+4740332255", + "surname": "basic", + "userRoles": [ + { + "id": "UbhT3bXWUyb" + } + ], + "username": "basicuser" + }, { "id": "o1HMTIzBGo7", "access": { diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityServiceTest.java index 1ead5c13e1b2..6e99d46da1c8 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/export/trackedentity/TrackedEntityServiceTest.java @@ -724,7 +724,7 @@ void shouldReturnEnrollmentsFromSpecifiedProgramWhenRequestingSingleTrackedEntit trackedEntityService.getTrackedEntity( UID.of(trackedEntityA), UID.of(programA), TrackedEntityParams.TRUE); - assertContainsOnly(Set.of(enrollmentA), trackedEntity.getEnrollments()); + assertContainsOnly(Set.of(enrollmentA), trackedEntity.getEnrollments(), Enrollment::getUid); } @Test @@ -740,7 +740,9 @@ void shouldReturnAllEnrollmentsWhenRequestingSingleTrackedEntityAndNoProgramSpec UID.of(trackedEntityA), null, TrackedEntityParams.TRUE); assertContainsOnly( - Set.of(enrollmentA, enrollmentB, enrollmentProgramB), trackedEntity.getEnrollments()); + Set.of(enrollmentA, enrollmentB, enrollmentProgramB), + trackedEntity.getEnrollments(), + Enrollment::getUid); } @Test diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntitiesExportControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntitiesExportControllerTest.java index 2491f75e691d..89cea37bf476 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntitiesExportControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntitiesExportControllerTest.java @@ -29,6 +29,10 @@ import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ACCESSIBLE; import static org.hisp.dhis.http.HttpClientAdapter.Accept; +import static org.hisp.dhis.test.utils.Assertions.assertContains; +import static org.hisp.dhis.test.utils.Assertions.assertHasSize; +import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; +import static org.hisp.dhis.test.utils.Assertions.assertNotEmpty; import static org.hisp.dhis.test.utils.Assertions.assertStartsWith; import static org.hisp.dhis.webapi.controller.tracker.JsonAssertions.assertContainsAll; import static org.hisp.dhis.webapi.controller.tracker.JsonAssertions.assertFirstRelationship; @@ -41,69 +45,129 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.IOException; import java.time.LocalDate; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; -import org.hisp.dhis.category.CategoryOptionCombo; -import org.hisp.dhis.category.CategoryService; +import java.util.function.Supplier; import org.hisp.dhis.common.CodeGenerator; +import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.common.IdentifiableObjectManager; import org.hisp.dhis.common.ValueType; -import org.hisp.dhis.dataelement.DataElement; -import org.hisp.dhis.eventdatavalue.EventDataValue; +import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle; +import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleMode; +import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleParams; +import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleService; +import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleValidationService; +import org.hisp.dhis.dxf2.metadata.objectbundle.feedback.ObjectBundleValidationReport; import org.hisp.dhis.feedback.ConflictException; import org.hisp.dhis.fileresource.FileResource; import org.hisp.dhis.fileresource.FileResourceService; import org.hisp.dhis.fileresource.FileResourceStorageStatus; import org.hisp.dhis.http.HttpStatus; +import org.hisp.dhis.importexport.ImportStrategy; import org.hisp.dhis.jsontree.JsonList; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.program.Enrollment; import org.hisp.dhis.program.Event; import org.hisp.dhis.program.Program; import org.hisp.dhis.program.ProgramStage; -import org.hisp.dhis.program.UserInfoSnapshot; import org.hisp.dhis.relationship.Relationship; import org.hisp.dhis.relationship.RelationshipEntity; import org.hisp.dhis.relationship.RelationshipItem; import org.hisp.dhis.relationship.RelationshipType; +import org.hisp.dhis.render.RenderFormat; +import org.hisp.dhis.render.RenderService; import org.hisp.dhis.security.acl.AccessStringHelper; -import org.hisp.dhis.test.webapi.H2ControllerIntegrationTestBase; +import org.hisp.dhis.test.webapi.PostgresControllerIntegrationTestBase; import org.hisp.dhis.trackedentity.TrackedEntity; import org.hisp.dhis.trackedentity.TrackedEntityAttribute; import org.hisp.dhis.trackedentity.TrackedEntityType; import org.hisp.dhis.trackedentity.TrackedEntityTypeAttribute; import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue; +import org.hisp.dhis.tracker.imports.TrackerImportParams; +import org.hisp.dhis.tracker.imports.TrackerImportService; +import org.hisp.dhis.tracker.imports.domain.TrackerObjects; +import org.hisp.dhis.tracker.imports.report.ImportReport; +import org.hisp.dhis.tracker.imports.report.Status; +import org.hisp.dhis.tracker.imports.report.ValidationReport; import org.hisp.dhis.user.User; import org.hisp.dhis.user.sharing.UserAccess; import org.hisp.dhis.util.DateUtils; import org.hisp.dhis.webapi.controller.tracker.JsonAttribute; -import org.hisp.dhis.webapi.controller.tracker.JsonDataValue; import org.hisp.dhis.webapi.controller.tracker.JsonEnrollment; import org.hisp.dhis.webapi.controller.tracker.JsonEvent; import org.hisp.dhis.webapi.controller.tracker.JsonRelationship; import org.hisp.dhis.webapi.controller.tracker.JsonRelationshipItem; import org.hisp.dhis.webapi.controller.tracker.JsonTrackedEntity; import org.hisp.dhis.webapi.utils.ContextUtils; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; import org.springframework.transaction.annotation.Transactional; @Transactional -class TrackedEntitiesExportControllerTest extends H2ControllerIntegrationTestBase { +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TrackedEntitiesExportControllerTest extends PostgresControllerIntegrationTestBase { // Used to generate unique chars for creating test objects like TEA, ... private static final String UNIQUE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - private static final String EVENT_OCCURRED_AT = "2023-03-23T12:23:00.000"; + + @Autowired private RenderService renderService; + + @Autowired private ObjectBundleService objectBundleService; + + @Autowired private ObjectBundleValidationService objectBundleValidationService; + + @Autowired private TrackerImportService trackerImportService; @Autowired private IdentifiableObjectManager manager; - @Autowired private FileResourceService fileResourceService; + private User importUser; + + protected ObjectBundle setUpMetadata(String path) throws IOException { + Map, List> metadata = + renderService.fromMetadata(new ClassPathResource(path).getInputStream(), RenderFormat.JSON); + ObjectBundleParams params = new ObjectBundleParams(); + params.setObjectBundleMode(ObjectBundleMode.COMMIT); + params.setImportStrategy(ImportStrategy.CREATE); + params.setObjects(metadata); + ObjectBundle bundle = objectBundleService.create(params); + assertNoErrors(objectBundleValidationService.validate(bundle)); + objectBundleService.commit(bundle); + return bundle; + } + + protected TrackerObjects fromJson(String path) throws IOException { + return renderService.fromJson( + new ClassPathResource(path).getInputStream(), TrackerObjects.class); + } + + @BeforeAll + void setUp() throws IOException { + setUpMetadata("tracker/simple_metadata.json"); - @Autowired private CategoryService categoryService; + importUser = userService.getUser("tTgjgobT1oS"); + injectSecurityContextUser(importUser); - private CategoryOptionCombo coc; + TrackerImportParams params = TrackerImportParams.builder().build(); + assertNoErrors( + trackerImportService.importTracker(params, fromJson("tracker/event_and_enrollment.json"))); + + manager.flush(); + manager.clear(); + } + + @BeforeEach + void setUpUser() { + switchContextToUser(importUser); + } + + @Autowired private FileResourceService fileResourceService; private OrganisationUnit orgUnit; @@ -115,8 +179,6 @@ class TrackedEntitiesExportControllerTest extends H2ControllerIntegrationTestBas private TrackedEntityType trackedEntityType; - private DataElement dataElement; - private User owner; private User user; @@ -127,11 +189,9 @@ class TrackedEntitiesExportControllerTest extends H2ControllerIntegrationTestBas private int uniqueAttributeCharCounter = 0; @BeforeEach - void setUp() { + void setUpToBeMigrated() { owner = makeUser("owner"); - coc = categoryService.getDefaultCategoryOptionCombo(); - orgUnit = createOrganisationUnit('A'); orgUnit.getSharing().setOwner(owner); manager.save(orgUnit, false); @@ -167,8 +227,6 @@ void setUp() { @Test void getTrackedEntitiesNeedsProgramOrType() { - injectSecurityContextUser(user); - assertEquals( "Either `program`, `trackedEntityType` or `trackedEntities` should be specified", GET("/tracker/trackedEntities").error(HttpStatus.BAD_REQUEST).getMessage()); @@ -176,8 +234,6 @@ void getTrackedEntitiesNeedsProgramOrType() { @Test void getTrackedEntitiesNeedsProgramOrTrackedEntityType() { - this.switchContextToUser(user); - assertEquals( "Either `program`, `trackedEntityType` or `trackedEntities` should be specified", GET("/tracker/trackedEntities?orgUnit={ou}", orgUnit.getUid()) @@ -188,7 +244,7 @@ void getTrackedEntitiesNeedsProgramOrTrackedEntityType() { @Test void shouldReturnEmptyListWhenGettingTrackedEntitiesWithNoMatchingParams() { LocalDate futureDate = LocalDate.now().plusYears(1); - JsonList instances = + JsonList trackedEntities = GET("/tracker/trackedEntities?trackedEntityType=" + trackedEntityType.getUid() + "&ouMode=ALL" @@ -198,13 +254,12 @@ void shouldReturnEmptyListWhenGettingTrackedEntitiesWithNoMatchingParams() { .content(HttpStatus.OK) .getList("trackedEntities", JsonTrackedEntity.class); - assertEquals(0, instances.size()); + assertEquals(0, trackedEntities.size()); } @Test void getTrackedEntityById() { - TrackedEntity te = trackedEntity(); - this.switchContextToUser(user); + TrackedEntity te = get(TrackedEntity.class, "QS6w44flWAf"); JsonTrackedEntity json = GET("/tracker/trackedEntities/{id}", te.getUid()) @@ -226,8 +281,7 @@ void getTrackedEntityById() { @Test void getTrackedEntityByIdWithFields() { - TrackedEntity te = trackedEntity(); - this.switchContextToUser(user); + TrackedEntity te = get(TrackedEntity.class, "QS6w44flWAf"); JsonTrackedEntity json = GET("/tracker/trackedEntities/{id}?fields=trackedEntityType,orgUnit", te.getUid()) @@ -241,77 +295,75 @@ void getTrackedEntityByIdWithFields() { @Test void getTrackedEntityByIdWithAttributesReturnsTrackedEntityTypeAttributesOnly() { - TrackedEntity trackedEntity = trackedEntity(); - enroll(trackedEntity, program, orgUnit); - - TrackedEntityAttribute tea = - addTrackedEntityTypeAttributeValue(trackedEntity, ValueType.NUMBER, "12"); - addProgramAttributeValue(trackedEntity, program, ValueType.NUMBER, "24"); + TrackedEntity te = get(TrackedEntity.class, "dUE514NMOlo"); + // TETA + TrackedEntityAttribute tea1 = get(TrackedEntityAttribute.class, "numericAttr"); + TrackedEntityAttribute tea2 = get(TrackedEntityAttribute.class, "toUpdate000"); JsonList attributes = - GET( - "/tracker/trackedEntities/{id}?fields=attributes[attribute,value]", - trackedEntity.getUid()) + GET("/tracker/trackedEntities/{id}?fields=attributes[attribute,value]", te.getUid()) .content(HttpStatus.OK) .getList("attributes", JsonAttribute.class); - assertAll( - "include tracked entity type attributes only if no program query param is given", - () -> - assertEquals( - 1, - attributes.size(), - () -> String.format("expected 1 attribute instead got %s", attributes)), - () -> assertEquals(tea.getUid(), attributes.get(0).getAttribute()), - () -> assertEquals("12", attributes.get(0).getValue())); + assertContainsAll( + List.of(tea1.getUid(), tea2.getUid()), attributes, JsonAttribute::getAttribute); + assertContainsAll(List.of("rainy day", "70"), attributes, JsonAttribute::getValue); } @Test void getTrackedEntityByIdWithAttributesReturnsAllAttributes() { - TrackedEntity trackedEntity = trackedEntity(); - enroll(trackedEntity, program, orgUnit); - - TrackedEntityAttribute tea = - addTrackedEntityTypeAttributeValue(trackedEntity, ValueType.NUMBER, "12"); - TrackedEntityAttribute tea2 = - addProgramAttributeValue(trackedEntity, program, ValueType.NUMBER, "24"); + TrackedEntity te = get(TrackedEntity.class, "dUE514NMOlo"); + assertNotEmpty(te.getEnrollments(), "test expects a tracked entity with an enrollment"); + String program = te.getEnrollments().iterator().next().getProgram().getUid(); + // TETA + TrackedEntityAttribute tea1 = get(TrackedEntityAttribute.class, "numericAttr"); + TrackedEntityAttribute tea2 = get(TrackedEntityAttribute.class, "toUpdate000"); + // PTEA + TrackedEntityAttribute tea3 = get(TrackedEntityAttribute.class, "dIVt4l5vIOa"); JsonList attributes = GET( "/tracker/trackedEntities/{id}?program={id}&fields=attributes[attribute,value]", - trackedEntity.getUid(), - program.getUid()) + te.getUid(), + program) .content(HttpStatus.OK) .getList("attributes", JsonAttribute.class); assertContainsAll( - List.of(tea.getUid(), tea2.getUid()), attributes, JsonAttribute::getAttribute); - assertContainsAll(List.of("12", "24"), attributes, JsonAttribute::getValue); + List.of(tea1.getUid(), tea2.getUid(), tea3.getUid()), + attributes, + JsonAttribute::getAttribute); + assertContainsAll( + List.of("rainy day", "70", "Frank PTEA"), attributes, JsonAttribute::getValue); } @Test void getTrackedEntityByIdWithFieldsRelationships() { - TrackedEntity from = trackedEntity(); - TrackedEntity to = trackedEntity(); - Relationship r = relationship(from, to); - this.switchContextToUser(user); + TrackedEntity from = get(TrackedEntity.class, "mHWCacsGYYn"); + assertHasSize( + 1, from.getRelationshipItems(), "test expects a tracked entity with one relationship"); + RelationshipItem relItem = from.getRelationshipItems().iterator().next(); + Relationship r = get(Relationship.class, relItem.getRelationship().getUid()); + Event to = r.getTo().getEvent(); JsonList rels = GET("/tracker/trackedEntities/{id}?fields=relationships", from.getUid()) .content(HttpStatus.OK) .getList("relationships", JsonRelationship.class); - assertEquals(1, rels.size()); JsonRelationship relationship = assertFirstRelationship(r, rels); assertTrackedEntityWithinRelationship(from, relationship.getFrom()); assertTrackedEntityWithinRelationship(to, relationship.getTo()); } @Test - void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToRelationshipType() { - TrackedEntity from = trackedEntity(); - TrackedEntity to = trackedEntity(); - relationship(relationshipTypeNotAccessible(), fromTrackedEntity(from), toTrackedEntity(to)); + void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToRelationshipItemTo() { + TrackedEntity from = get(TrackedEntity.class, "mHWCacsGYYn"); + assertNotEmpty( + from.getRelationshipItems(), + "test expects a tracked entity with at least one relationship"); + + User user = userService.getUser("Z7870757a75"); this.switchContextToUser(user); JsonList relationships = @@ -322,18 +374,20 @@ void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToRelationshipType() { assertEquals( 0, relationships.size(), - "user needs access to relationship type to access the relationship"); + "user needs access to from and to items to access the relationship"); } @Test - void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToRelationshipItemTo() { - TrackedEntity from = trackedEntity(); - TrackedEntity to = trackedEntityNotInSearchScope(); - relationship(from, to); + void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToRelationshipItemFrom() { + TrackedEntity to = get(TrackedEntity.class, "QesgJkTyTCk"); + assertNotEmpty( + to.getRelationshipItems(), "test expects a tracked entity with at least one relationship"); + + User user = userService.getUser("Z7870757a75"); this.switchContextToUser(user); JsonList relationships = - GET("/tracker/trackedEntities/{id}?fields=relationships", from.getUid()) + GET("/tracker/trackedEntities/{id}?fields=relationships", to.getUid()) .content(HttpStatus.OK) .getList("relationships", JsonRelationship.class); @@ -343,34 +397,6 @@ void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToRelationshipItemTo() { "user needs access to from and to items to access the relationship"); } - @Test - void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToBothRelationshipItems() { - TrackedEntity from = trackedEntityNotInSearchScope(); - TrackedEntity to = trackedEntityNotInSearchScope(); - relationship(from, to); - this.switchContextToUser(user); - - assertTrue( - GET("/tracker/trackedEntities/{id}?fields=relationships", from.getUid()) - .error(HttpStatus.FORBIDDEN) - .getMessage() - .contains("User has no access to TrackedEntity")); - } - - @Test - void getTrackedEntityByIdWithFieldsRelationshipsNoAccessToRelationshipItemFrom() { - TrackedEntity from = trackedEntityNotInSearchScope(); - TrackedEntity to = trackedEntity(); - relationship(from, to); - this.switchContextToUser(user); - - assertTrue( - GET("/tracker/trackedEntities/{id}?fields=relationships", from.getUid()) - .error(HttpStatus.FORBIDDEN) - .getMessage() - .contains("User has no access to TrackedEntity")); - } - @Test void getTrackedEntityByIdyWithFieldsRelationshipsNoAccessToTrackedEntityType() { TrackedEntityType type = trackedEntityTypeNotAccessible(); @@ -379,11 +405,8 @@ void getTrackedEntityByIdyWithFieldsRelationshipsNoAccessToTrackedEntityType() { relationship(from, to); this.switchContextToUser(user); - assertTrue( - GET("/tracker/trackedEntities/{id}?fields=relationships", from.getUid()) - .error(HttpStatus.FORBIDDEN) - .getMessage() - .contains("User has no access to TrackedEntity")); + GET("/tracker/trackedEntities/{id}?fields=relationships", from.getUid()) + .error(HttpStatus.FORBIDDEN); } @Test @@ -402,7 +425,7 @@ void shouldReturnNotFoundWhenGettingASoftDeletedTrackedEntityById() { @Test void getTrackedEntityReturnsCsvFormat() { - injectSecurityContextUser(user); + Program program = get(Program.class, "BFcipDERJnf"); HttpResponse response = GET( @@ -423,8 +446,15 @@ void getTrackedEntityReturnsCsvFormat() { @Test void getTrackedEntityCsvById() { - TrackedEntity te = trackedEntity(); - this.switchContextToUser(user); + TrackedEntity te = get(TrackedEntity.class, "QS6w44flWAf"); + List trackedEntityTypeAttributeValues = + te.getTrackedEntityAttributeValues().stream() + .filter(teav -> !"toDelete000".equals(teav.getAttribute().getUid())) + .toList(); + assertHasSize( + 2, + trackedEntityTypeAttributeValues, + "test expects the tracked entity to have 2 tracked entity type attribute values"); HttpResponse response = GET("/tracker/trackedEntities/{id}", te.getUid(), Accept(ContextUtils.CONTENT_TYPE_CSV)); @@ -433,27 +463,45 @@ void getTrackedEntityCsvById() { assertTrue(response.header("content-type").contains(ContextUtils.CONTENT_TYPE_CSV)); assertTrue(response.header("content-disposition").contains("filename=trackedEntity.csv")); - assertEquals(trackedEntityToCsv(te), csvResponse); - } - - String trackedEntityToCsv(TrackedEntity te) { - return """ - trackedEntity,trackedEntityType,createdAt,createdAtClient,updatedAt,updatedAtClient,orgUnit,inactive,deleted,potentialDuplicate,geometry,latitude,longitude,storedBy,createdBy,updatedBy,attrCreatedAt,attrUpdatedAt,attribute,displayName,value,valueType - """ - .concat( - String.join( - ",", - te.getUid(), - te.getTrackedEntityType().getUid(), - DateUtils.instantFromDate(te.getCreated()).toString(), - DateUtils.instantFromDate(te.getCreatedAtClient()).toString(), - DateUtils.instantFromDate(te.getLastUpdated()).toString(), - DateUtils.instantFromDate(te.getLastUpdatedAtClient()).toString(), - te.getOrganisationUnit().getUid(), - Boolean.toString(te.isInactive()), - Boolean.toString(te.isDeleted()), - Boolean.toString(te.isPotentialDuplicate()), - ",,,,,,,,,,," + "\n")); + assertStartsWith( + """ +trackedEntity,trackedEntityType,createdAt,createdAtClient,updatedAt,updatedAtClient,orgUnit,inactive,deleted,potentialDuplicate,geometry,latitude,longitude,storedBy,createdBy,updatedBy,attrCreatedAt,attrUpdatedAt,attribute,displayName,value,valueType +""", + csvResponse); + // TEAV order is not deterministic + assertContains(trackedEntityToCsv(te, trackedEntityTypeAttributeValues.get(0)), csvResponse); + assertContains(trackedEntityToCsv(te, trackedEntityTypeAttributeValues.get(1)), csvResponse); + } + + String trackedEntityToCsv(TrackedEntity te, TrackedEntityAttributeValue attributeValue) { + String value = attributeValue.getValue(); + if (attributeValue.getAttribute().getValueType() == ValueType.TEXT) { + value = "\"" + value + "\""; + } + return String.join( + ",", + te.getUid(), + te.getTrackedEntityType().getUid(), + DateUtils.instantFromDate(te.getCreated()).toString(), + DateUtils.instantFromDate(te.getCreatedAtClient()).toString(), + DateUtils.instantFromDate(te.getLastUpdated()).toString(), + DateUtils.instantFromDate(te.getLastUpdatedAtClient()).toString(), + te.getOrganisationUnit().getUid(), + Boolean.toString(te.isInactive()), + Boolean.toString(te.isDeleted()), + Boolean.toString(te.isPotentialDuplicate()), + ",,,", + importUser.getUsername(), + importUser.getUsername()) + + "," + + String.join( + ",", + DateUtils.instantFromDate(attributeValue.getCreated()).toString(), + DateUtils.instantFromDate(attributeValue.getLastUpdated()).toString(), + attributeValue.getAttribute().getUid(), + attributeValue.getAttribute().getDisplayName(), + value, + attributeValue.getAttribute().getValueType().name()); } @Test @@ -503,105 +551,97 @@ void getTrackedEntityReturnsCsvGZipFormat() { @Test void shouldGetEnrollmentWhenFieldsHasEnrollments() { - TrackedEntity trackedEntity = trackedEntity(); - Enrollment enrollment = enroll(trackedEntity, program, orgUnit); + TrackedEntity te = get(TrackedEntity.class, "dUE514NMOlo"); + assertHasSize(1, te.getEnrollments(), "test expects a tracked entity with one enrollment"); + Enrollment enrollment = te.getEnrollments().iterator().next(); JsonList json = - GET("/tracker/trackedEntities/{id}?fields=enrollments", trackedEntity.getUid()) + GET("/tracker/trackedEntities/{id}?fields=enrollments", te.getUid()) .content(HttpStatus.OK) .getList("enrollments", JsonEnrollment.class); - JsonEnrollment jsonEnrollment = assertDefaultEnrollmentResponse(json, enrollment); - - assertTrue(jsonEnrollment.getArray("relationships").isEmpty()); - assertTrue(jsonEnrollment.getAttributes().isEmpty()); - assertTrue(jsonEnrollment.getEvents().isEmpty()); + assertDefaultEnrollmentResponse(json, enrollment); } @Test void shouldGetNoEventRelationshipsWhenEventsHasNoRelationshipsAndFieldsIncludeAll() { - TrackedEntity trackedEntity = trackedEntity(); - - Enrollment enrollment = enroll(trackedEntity, program, orgUnit); - - Event event = eventWithDataValue(enrollment); - - enrollment.getEvents().add(event); - manager.update(enrollment); + TrackedEntity te = get(TrackedEntity.class, "mHWCacsGYYn"); + assertHasSize(1, te.getEnrollments(), "test expects a tracked entity with one enrollment"); + Enrollment enrollment = te.getEnrollments().iterator().next(); + assertHasSize(1, enrollment.getEvents(), "test expects an enrollment with one event"); + Event event = enrollment.getEvents().iterator().next(); + assertIsEmpty(event.getRelationshipItems(), "test expects an event with no relationships"); JsonList json = - GET("/tracker/trackedEntities/{id}?fields=enrollments", trackedEntity.getUid()) + GET("/tracker/trackedEntities/{id}?fields=enrollments", te.getUid()) .content(HttpStatus.OK) .getList("enrollments", JsonEnrollment.class); JsonEnrollment jsonEnrollment = assertDefaultEnrollmentResponse(json, enrollment); - assertTrue(jsonEnrollment.getArray("relationships").isEmpty()); - assertTrue(jsonEnrollment.getAttributes().isEmpty()); - JsonEvent jsonEvent = assertDefaultEventResponse(jsonEnrollment, event); - assertTrue(jsonEvent.getRelationships().isEmpty()); } - @Disabled( - "TODO(DHIS2-18541) test fixtures will be fixed in next PR: org.hisp.dhis.feedback.ForbiddenException: User needs to be assigned either search or data capture org units") @Test void shouldGetEventRelationshipsWhenEventHasRelationshipsAndFieldsIncludeEventRelationships() { - TrackedEntity trackedEntity = trackedEntity(); - - Enrollment enrollment = enroll(trackedEntity, program, orgUnit); - - Event event = eventWithDataValue(enrollment); - enrollment.getEvents().add(event); - manager.update(enrollment); - - Relationship teToEventRelationship = relationship(trackedEntity, event); + TrackedEntity te = get(TrackedEntity.class, "QS6w44flWAf"); + Enrollment enrollment = get(Enrollment.class, "nxP7UnKhomJ"); + assertHasSize(1, enrollment.getEvents(), "test expects an enrollment with one event"); + Event event = enrollment.getEvents().iterator().next(); + assertNotEmpty( + event.getRelationshipItems(), "test expects an event with at least one relationship"); + RelationshipItem relItem = te.getRelationshipItems().iterator().next(); + Relationship r = get(Relationship.class, relItem.getRelationship().getUid()); JsonList json = - GET("/tracker/trackedEntities/{id}?fields=enrollments", trackedEntity.getUid()) + GET("/tracker/trackedEntities/{id}?fields=enrollments", te.getUid()) .content(HttpStatus.OK) .getList("enrollments", JsonEnrollment.class); - JsonEnrollment jsonEnrollment = assertDefaultEnrollmentResponse(json, enrollment); - assertTrue(jsonEnrollment.getAttributes().isEmpty()); - assertTrue(jsonEnrollment.getArray("relationships").isEmpty()); + List enrollments = + json.stream().filter(en -> "nxP7UnKhomJ".equals(en.getEnrollment())).toList(); + assertNotEmpty( + enrollments, + () -> String.format("Expected enrollment \"nxP7UnKhomJ\" instead got %s", enrollments)); + JsonEnrollment jsonEnrollment = enrollments.get(0); + assertDefaultEnrollmentResponse(enrollment, jsonEnrollment); JsonEvent jsonEvent = assertDefaultEventResponse(jsonEnrollment, event); - - JsonRelationship relationship = jsonEvent.getRelationships().get(0); - - assertEquals(teToEventRelationship.getUid(), relationship.getRelationship()); - assertEquals( - trackedEntity.getUid(), relationship.getFrom().getTrackedEntity().getTrackedEntity()); - assertEquals(event.getUid(), relationship.getTo().getEvent().getEvent()); + assertTrue( + jsonEvent + .getRelationships() + .contains(JsonRelationship::getRelationship, actual -> r.getUid().equals(actual)), + () -> + String.format( + "Expected event to have relationship to TE instead got %s", + jsonEvent.getRelationships().toJson())); } @Test void shouldGetNoEventRelationshipsWhenEventHasRelationshipsAndFieldsExcludeEventRelationships() { - TrackedEntity trackedEntity = trackedEntity(); - - Enrollment enrollment = enroll(trackedEntity, program, orgUnit); - - Event event = eventWithDataValue(enrollment); - - enrollment.getEvents().add(event); - manager.update(enrollment); - - relationship(trackedEntity, event); + TrackedEntity te = get(TrackedEntity.class, "QS6w44flWAf"); + Enrollment enrollment = get(Enrollment.class, "nxP7UnKhomJ"); + assertHasSize(1, enrollment.getEvents(), "test expects an enrollment with one event"); + Event event = enrollment.getEvents().iterator().next(); + assertNotEmpty( + event.getRelationshipItems(), "test expects an event with at least one relationship"); JsonList json = GET( "/tracker/trackedEntities/{id}?fields=enrollments[*,events[!relationships]]", - trackedEntity.getUid()) + te.getUid()) .content(HttpStatus.OK) .getList("enrollments", JsonEnrollment.class); - JsonEnrollment jsonEnrollment = assertDefaultEnrollmentResponse(json, enrollment); - assertTrue(jsonEnrollment.getAttributes().isEmpty()); - assertTrue(jsonEnrollment.getArray("relationships").isEmpty()); + List enrollments = + json.stream().filter(en -> "nxP7UnKhomJ".equals(en.getEnrollment())).toList(); + assertNotEmpty( + enrollments, + () -> String.format("Expected enrollment \"nxP7UnKhomJ\" instead got %s", enrollments)); + JsonEnrollment jsonEnrollment = enrollments.get(0); + assertDefaultEnrollmentResponse(enrollment, jsonEnrollment); JsonEvent jsonEvent = assertDefaultEventResponse(jsonEnrollment, event); - assertHasNoMember(jsonEvent, "relationships"); } @@ -946,39 +986,24 @@ void getAttributeValuesImageByProgramAttribute() throws ConflictException { assertEquals("file content", response.content("image/png")); } - private Event eventWithDataValue(Enrollment enrollment) { - Event event = new Event(enrollment, programStage, enrollment.getOrganisationUnit(), coc); - event.setAutoFields(); - event.setOccurredDate(DateUtils.parseDate(EVENT_OCCURRED_AT)); - - dataElement = createDataElement('A'); - dataElement.setValueType(ValueType.TEXT); - manager.save(dataElement); - - EventDataValue eventDataValue = new EventDataValue(); - eventDataValue.setValue("value"); - eventDataValue.setDataElement(dataElement.getUid()); - eventDataValue.setCreatedByUserInfo(UserInfoSnapshot.from(user)); - eventDataValue.setLastUpdatedByUserInfo(UserInfoSnapshot.from(user)); - Set eventDataValues = Set.of(eventDataValue); - event.setEventDataValues(eventDataValues); - - manager.save(event); - return event; - } - private JsonEnrollment assertDefaultEnrollmentResponse( JsonList enrollments, Enrollment enrollment) { assertFalse(enrollments.isEmpty()); JsonEnrollment jsonEnrollment = enrollments.get(0); - assertHasMember(jsonEnrollment, "enrollment"); + assertDefaultEnrollmentResponse(enrollment, jsonEnrollment); + return jsonEnrollment; + } + + private static void assertDefaultEnrollmentResponse( + Enrollment enrollment, JsonEnrollment jsonEnrollment) { + assertHasMember(jsonEnrollment, "enrollment"); assertEquals(enrollment.getUid(), jsonEnrollment.getEnrollment()); assertEquals(enrollment.getTrackedEntity().getUid(), jsonEnrollment.getTrackedEntity()); - assertEquals(program.getUid(), jsonEnrollment.getProgram()); - assertEquals("ACTIVE", jsonEnrollment.getStatus()); - assertEquals(orgUnit.getUid(), jsonEnrollment.getOrgUnit()); + assertEquals(enrollment.getProgram().getUid(), jsonEnrollment.getProgram()); + assertEquals(enrollment.getStatus().name(), jsonEnrollment.getStatus()); + assertEquals(enrollment.getOrganisationUnit().getUid(), jsonEnrollment.getOrgUnit()); assertFalse(jsonEnrollment.getBoolean("deleted").booleanValue()); assertHasMember(jsonEnrollment, "enrolledAt"); assertHasMember(jsonEnrollment, "occurredAt"); @@ -987,8 +1012,6 @@ private JsonEnrollment assertDefaultEnrollmentResponse( assertHasMember(jsonEnrollment, "updatedAt"); assertHasMember(jsonEnrollment, "notes"); assertHasMember(jsonEnrollment, "followUp"); - - return jsonEnrollment; } private JsonEvent assertDefaultEventResponse(JsonEnrollment enrollment, Event event) { @@ -1000,27 +1023,15 @@ private JsonEvent assertDefaultEventResponse(JsonEnrollment enrollment, Event ev assertEquals(event.getUid(), jsonEvent.getEvent()); assertEquals(event.getProgramStage().getUid(), jsonEvent.getProgramStage()); assertEquals(event.getEnrollment().getUid(), jsonEvent.getEnrollment()); - assertEquals(program.getUid(), jsonEvent.getProgram()); - assertEquals("ACTIVE", jsonEvent.getStatus()); - assertEquals(orgUnit.getUid(), jsonEvent.getOrgUnit()); + assertEquals(event.getProgramStage().getProgram().getUid(), jsonEvent.getProgram()); + assertEquals(event.getStatus().name(), jsonEvent.getStatus()); + assertEquals(event.getOrganisationUnit().getUid(), jsonEvent.getOrgUnit()); assertFalse(jsonEvent.getDeleted()); assertHasMember(jsonEvent, "createdAt"); assertHasMember(jsonEvent, "occurredAt"); - assertEquals(EVENT_OCCURRED_AT, jsonEvent.getString("occurredAt").string()); - assertHasMember(jsonEvent, "createdAtClient"); assertHasMember(jsonEvent, "updatedAt"); assertHasMember(jsonEvent, "notes"); assertHasMember(jsonEvent, "followUp"); - assertHasMember(jsonEvent, "followup"); - - JsonDataValue dataValue = jsonEvent.getDataValues().get(0); - - assertEquals(dataElement.getUid(), dataValue.getDataElement()); - assertEquals(event.getEventDataValues().iterator().next().getValue(), dataValue.getValue()); - assertHasMember(dataValue, "createdAt"); - assertHasMember(dataValue, "updatedAt"); - assertHasMember(dataValue, "createdBy"); - assertHasMember(dataValue, "updatedBy"); return jsonEvent; } @@ -1053,12 +1064,6 @@ private TrackedEntity trackedEntity() { return te; } - private TrackedEntity trackedEntityNotInSearchScope() { - TrackedEntity te = trackedEntity(anotherOrgUnit); - manager.save(te, false); - return te; - } - private TrackedEntity trackedEntity(TrackedEntityType trackedEntityType) { TrackedEntity te = trackedEntity(orgUnit, trackedEntityType); manager.save(te, false); @@ -1103,11 +1108,6 @@ private RelationshipType relationshipTypeAccessible( return type; } - private RelationshipType relationshipTypeNotAccessible() { - return relationshipType( - RelationshipEntity.TRACKED_ENTITY_INSTANCE, RelationshipEntity.TRACKED_ENTITY_INSTANCE); - } - private RelationshipType relationshipType(RelationshipEntity from, RelationshipEntity to) { RelationshipType type = createRelationshipType('A'); type.getFromConstraint().setRelationshipEntity(from); @@ -1125,21 +1125,6 @@ private Relationship relationship(TrackedEntity from, TrackedEntity to) { return relationship(type, fromTrackedEntity(from), toTrackedEntity(to)); } - private Relationship relationship(TrackedEntity from, Event to) { - RelationshipType type = - relationshipTypeAccessible( - RelationshipEntity.TRACKED_ENTITY_INSTANCE, RelationshipEntity.PROGRAM_STAGE_INSTANCE); - RelationshipItem fromItem = fromTrackedEntity(from); - RelationshipItem toItem = toEvent(to); - Relationship relationship = relationship(type, fromItem, toItem); - fromItem.setRelationship(relationship); - toItem.setRelationship(relationship); - to.getRelationshipItems().add(toItem); - manager.save(to, false); - manager.save(relationship, false); - return relationship; - } - private Relationship relationship( RelationshipType type, RelationshipItem fromItem, RelationshipItem toItem) { Relationship r = new Relationship(); @@ -1173,13 +1158,6 @@ private RelationshipItem toTrackedEntity(TrackedEntity to) { return toItem; } - private RelationshipItem toEvent(Event to) { - RelationshipItem toItem = new RelationshipItem(); - toItem.setEvent(to); - to.getRelationshipItems().add(toItem); - return toItem; - } - private void assertTrackedEntityWithinRelationship( TrackedEntity expected, JsonRelationshipItem json) { JsonRelationshipItem.JsonTrackedEntity jsonTe = json.getTrackedEntity(); @@ -1190,7 +1168,20 @@ private void assertTrackedEntityWithinRelationship( assertHasNoMember(json, "relationships"); // relationships are not // returned within // relationships - assertTrue(jsonTe.getArray("attributes").isEmpty()); + assertEquals( + expected.getTrackedEntityAttributeValues().isEmpty(), + jsonTe.getArray("attributes").isEmpty()); + } + + private void assertTrackedEntityWithinRelationship(Event expected, JsonRelationshipItem json) { + JsonRelationshipItem.JsonEvent jsonEvent = json.getEvent(); + assertFalse(jsonEvent.isEmpty(), "event should not be empty"); + assertEquals(expected.getUid(), jsonEvent.getEvent()); + assertHasNoMember(json, "trackedEntityType"); + assertHasNoMember(json, "orgUnit"); + assertHasNoMember(json, "relationships"); // relationships are not + // returned within + // relationships } private TrackedEntityAttribute addTrackedEntityTypeAttributeValue( @@ -1253,4 +1244,47 @@ private FileResource storeFile(String contentType, String content, char uniqueCh fr.setStorageStatus(FileResourceStorageStatus.STORED); return fr; } + + private T get(Class type, String uid) { + T t = manager.get(type, uid); + assertNotNull( + t, + () -> + String.format( + "'%s' with uid '%s' should have been created", type.getSimpleName(), uid)); + return t; + } + + public static void assertNoErrors(ImportReport report) { + assertNotNull(report); + assertEquals( + Status.OK, + report.getStatus(), + errorMessage( + "Expected import with status OK, instead got:%n", report.getValidationReport())); + } + + private static Supplier errorMessage(String errorTitle, ValidationReport report) { + return () -> { + StringBuilder msg = new StringBuilder(errorTitle); + report + .getErrors() + .forEach( + e -> { + msg.append(e.getErrorCode()); + msg.append(": "); + msg.append(e.getMessage()); + msg.append('\n'); + }); + return msg.toString(); + }; + } + + public static void assertNoErrors(ObjectBundleValidationReport report) { + assertNotNull(report); + List errors = new ArrayList<>(); + report.forEachErrorReport(err -> errors.add(err.toString())); + assertFalse( + report.hasErrorReports(), String.format("Expected no errors, instead got: %s%n", errors)); + } } diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntityFieldsParamMapperTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntityFieldsParamMapperTest.java index d1ede1162508..82f631b469c8 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntityFieldsParamMapperTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/trackedentity/TrackedEntityFieldsParamMapperTest.java @@ -129,11 +129,12 @@ void mapWithExcludedSubFields() { map("enrollments[!uid,!relationships],relationships[relationship]"); assertTrue(params.isIncludeRelationships()); + assertFalse(params.isIncludeProgramOwners()); + assertTrue(params.isIncludeEnrollments()); assertTrue(params.getEnrollmentParams().isIncludeEvents()); assertTrue(params.getEnrollmentParams().isIncludeAttributes()); assertFalse(params.getEnrollmentParams().isIncludeRelationships()); - assertFalse(params.isIncludeProgramOwners()); } @Test @@ -141,9 +142,12 @@ void mapOnlyIncludeIfFieldIsRoot() { TrackedEntityParams params = map("enrollments[events,relationships]"); assertFalse(params.isIncludeRelationships()); + assertFalse(params.isIncludeProgramOwners()); + assertTrue(params.isIncludeEnrollments()); assertTrue(params.getTeEnrollmentParams().isIncludeEvents()); - assertFalse(params.isIncludeProgramOwners()); + assertTrue(params.getTeEnrollmentParams().isIncludeRelationships()); + assertFalse(params.getTeEnrollmentParams().isIncludeAttributes()); } @Test @@ -152,9 +156,10 @@ void mapOnlyIncludeIfNotAlsoExcluded() { TrackedEntityParams params = map("relationships,!relationships"); assertFalse(params.isIncludeRelationships()); + assertFalse(params.isIncludeProgramOwners()); + assertFalse(params.isIncludeEnrollments()); assertFalse(params.getTeEnrollmentParams().isIncludeEvents()); - assertFalse(params.isIncludeProgramOwners()); params = map("!relationships,relationships"); @@ -169,9 +174,12 @@ void mapRootInclusionPrecedesSubfieldExclusion() { TrackedEntityParams params = map("enrollments,enrollments[!status]"); assertFalse(params.isIncludeRelationships()); + assertFalse(params.isIncludeProgramOwners()); + assertTrue(params.isIncludeEnrollments()); assertTrue(params.getTeEnrollmentParams().isIncludeEvents()); - assertFalse(params.isIncludeProgramOwners()); + assertTrue(params.getTeEnrollmentParams().isIncludeAttributes()); + assertTrue(params.getTeEnrollmentParams().isIncludeRelationships()); } static Stream mapEnrollmentsAndEvents() { diff --git a/dhis-2/dhis-test-web-api/src/test/resources/tracker/event_and_enrollment.json b/dhis-2/dhis-test-web-api/src/test/resources/tracker/event_and_enrollment.json index 12a75f2722c6..24248d000bc0 100644 --- a/dhis-2/dhis-test-web-api/src/test/resources/tracker/event_and_enrollment.json +++ b/dhis-2/dhis-test-web-api/src/test/resources/tracker/event_and_enrollment.json @@ -42,10 +42,8 @@ "identifier": "h4w96yEMlzO" }, "inactive": true, - "deleted": false, - "potentialDuplicate": false, "createdAtClient": "2018-10-01T12:17:30.163", - "relationships": [], + "updatedAtClient": "2018-10-07T12:17:30.163", "attributes": [ { "valueType": "TEXT", @@ -71,8 +69,7 @@ }, "value": "88" } - ], - "enrollments": [] + ] }, { "trackedEntity": "dUE514NMOlo", @@ -84,11 +81,7 @@ "idScheme": "UID", "identifier": "h4w96yEMlzO" }, - "inactive": false, - "deleted": false, - "potentialDuplicate": false, "createdAtClient": "2018-11-01T12:17:30.163", - "relationships": [], "attributes": [ { "valueType": "TEXT", @@ -122,8 +115,7 @@ }, "value": "70" } - ], - "enrollments": [] + ] }, { "trackedEntity": "mHWCacsGYYn", @@ -135,10 +127,6 @@ "idScheme": "UID", "identifier": "h4w96yEMlzO" }, - "inactive": false, - "deleted": false, - "potentialDuplicate": false, - "relationships": [], "attributes": [ { "valueType": "TEXT", @@ -164,8 +152,7 @@ }, "value": "72" } - ], - "enrollments": [] + ] }, { "trackedEntity": "QesgJkTyTCk", @@ -177,10 +164,6 @@ "idScheme": "UID", "identifier": "h4w96yEMlzO" }, - "inactive": false, - "deleted": false, - "potentialDuplicate": false, - "relationships": [], "attributes": [ { "valueType": "TEXT", @@ -206,8 +189,7 @@ }, "value": "89" } - ], - "enrollments": [] + ] }, { "trackedEntity": "guVNoAerxWo", @@ -219,10 +201,6 @@ "idScheme": "UID", "identifier": "tSsGrtfRzjY" }, - "inactive": false, - "deleted": false, - "potentialDuplicate": false, - "relationships": [], "attributes": [ { "valueType": "TEXT", @@ -248,8 +226,7 @@ }, "value": "91" } - ], - "enrollments": [] + ] }, { "trackedEntity": "woitxQbWYNq", @@ -261,10 +238,6 @@ "idScheme": "UID", "identifier": "RojfDTBhoGC" }, - "inactive": false, - "deleted": false, - "potentialDuplicate": false, - "relationships": [], "attributes": [ { "valueType": "TEXT", @@ -290,8 +263,7 @@ }, "value": "90" } - ], - "enrollments": [] + ] }, { "trackedEntity": "XUitxQbWYNq", @@ -302,12 +274,18 @@ "orgUnit": { "idScheme": "UID", "identifier": "DiszpKrYNg8" + } + }, + { + "trackedEntity": "H8732208127", + "trackedEntityType": { + "idScheme": "UID", + "identifier": "ja8NY4PW7Xm" }, - "inactive": false, - "deleted": false, - "potentialDuplicate": false, - "relationships": [], - "enrollments": [] + "orgUnit": { + "idScheme": "UID", + "identifier": "DiszpKrYNg8" + } } ], "enrollments": [ @@ -324,16 +302,9 @@ "idScheme": "UID", "identifier": "h4w96yEMlzO" }, - "orgUnitName": "Mbokie CHP", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" }, { "enrollment": "nxP8UnKhomJ", @@ -350,13 +321,7 @@ }, "enrolledAt": "2021-04-28T12:05:00.000", "occurredAt": "2021-04-28T12:05:00.000", - "scheduledAt": "2021-04-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-04-28T12:05:00.000" }, { "enrollment": "TvctPPhpD8z", @@ -371,16 +336,18 @@ "idScheme": "UID", "identifier": "h4w96yEMlzO" }, - "orgUnitName": "Mbokie CHP", "enrolledAt": "2021-03-28T12:05:00.000", "occurredAt": "2021-03-28T12:05:00.000", "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "attributes": [ + { + "attribute": { + "idScheme": "UID", + "identifier": "dIVt4l5vIOa" + }, + "value": "Frank PTEA" + } + ] }, { "enrollment": "JuioKiICQqI", @@ -395,16 +362,9 @@ "idScheme": "UID", "identifier": "uoNW0E3xXUy" }, - "orgUnitName": "test-orgunit-2", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" }, { "enrollment": "iHFHfPKTSYP", @@ -419,16 +379,9 @@ "idScheme": "UID", "identifier": "uoNW0E3xXUy" }, - "orgUnitName": "test-orgunit-2", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" }, { "enrollment": "ipBifypAQTo", @@ -443,16 +396,9 @@ "idScheme": "UID", "identifier": "tSsGrtfRzjY" }, - "orgUnitName": "test-orgunit-3", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" }, { "enrollment": "qxOSXoEZkOA", @@ -467,16 +413,9 @@ "idScheme": "UID", "identifier": "RojfDTBhoGC" }, - "orgUnitName": "test-orgunit-3", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" }, { "enrollment": "HDWTYSYkICe", @@ -491,16 +430,9 @@ "idScheme": "UID", "identifier": "DiszpKrYNg8" }, - "orgUnitName": "test-orgunit-3", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" }, { "enrollment": "FXWSSZunTLk", @@ -515,16 +447,9 @@ "idScheme": "UID", "identifier": "lbDXJBlvtZe" }, - "orgUnitName": "test-orgunit-3", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" }, { "enrollment": "GYWSSZunTLk", @@ -539,16 +464,9 @@ "idScheme": "UID", "identifier": "DiszpKrYNg8" }, - "orgUnitName": "test-orgunit-3", "enrolledAt": "2021-02-28T12:05:00.000", "occurredAt": "2021-02-28T12:05:00.000", - "scheduledAt": "2021-02-28T12:05:00.000", - "followUp": false, - "deleted": false, - "events": [], - "relationships": [], - "attributes": [], - "notes": [] + "scheduledAt": "2021-02-28T12:05:00.000" } ], "events": [ @@ -568,14 +486,12 @@ "idScheme": "UID", "identifier": "h4w96yEMlzO" }, - "relationships": [], "occurredAt": "2019-01-25T12:10:38.100", "scheduledAt": "2019-01-28T12:32:38.100", "createdAtClient": "2020-01-25T12:10:38.100", "updatedAtClient": "2020-01-26T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" @@ -595,8 +511,7 @@ }, "value": "value00001", "createdAt": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null }, { "dataElement": { @@ -605,8 +520,7 @@ }, "value": "option1", "createdAt": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null }, { "dataElement": { @@ -615,8 +529,7 @@ }, "value": "88", "createdAt": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null } ], "notes": [ @@ -648,14 +561,12 @@ "idScheme": "UID", "identifier": "h4w96yEMlzO" }, - "relationships": [], "occurredAt": "2020-01-28T00:00:00.000", "scheduledAt": "2019-01-28T12:10:38.100", "createdAtClient": "2019-01-25T12:10:38.100", "updatedAtClient": "2021-01-26T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" @@ -674,8 +585,7 @@ }, "value": "value00002", "created": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null }, { "dataElement": { @@ -684,8 +594,7 @@ }, "value": "value00002", "created": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null }, { "dataElement": { @@ -694,8 +603,7 @@ }, "value": "option2", "created": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null }, { "dataElement": { @@ -704,8 +612,7 @@ }, "value": "70", "created": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null }, { "dataElement": { @@ -714,11 +621,9 @@ }, "value": "70", "created": "2021-07-01T12:05:00", - "storedBy": null, - "providedElsewhere": false + "storedBy": null } ], - "notes": [], "assignedUser": { "uid": "xE7jOejl9FI", "firstName": "John", @@ -747,7 +652,6 @@ "scheduledAt": "2019-01-28T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" @@ -757,8 +661,7 @@ "idScheme": "UID", "identifier": "xYerKDKCefk" } - ], - "notes": [] + ] }, { "event": "JaRDIvcEcEx", @@ -781,7 +684,6 @@ "scheduledAt": "2019-01-28T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" @@ -791,8 +693,7 @@ "idScheme": "UID", "identifier": "xYerKDKCefk" } - ], - "notes": [] + ] }, { "event": "QRYjLTiJTrA", @@ -827,7 +728,6 @@ "identifier": "DiszpKrYNg8" }, "status": "ACTIVE", - "deleted": false, "dataValues": [ { "created": "2022-04-22T06:00:38.339", @@ -835,20 +735,16 @@ "idScheme": "UID", "identifier": "GieVkTxp4HH" }, - "value": "15", - "providedElsewhere": false + "value": "15" }, { "dataElement": { "idScheme": "UID", "identifier": "GieVkTxp4HG" }, - "value": "1.5", - "providedElsewhere": false + "value": "1.5" } - ], - "notes": [], - "relationships": [] + ] }, { "event": "kWjSezkXHVp", @@ -883,7 +779,6 @@ "identifier": "DiszpKrYNg8" }, "status": "ACTIVE", - "deleted": false, "dataValues": [ { "created": "2022-04-22T06:00:34.319", @@ -891,12 +786,9 @@ "idScheme": "UID", "identifier": "GieVkTxp4HH" }, - "value": "14", - "providedElsewhere": false + "value": "14" } - ], - "notes": [], - "relationships": [] + ] }, { "event": "OTmjvJDn0Fu", @@ -931,7 +823,6 @@ "identifier": "DiszpKrYNg8" }, "status": "ACTIVE", - "deleted": false, "dataValues": [ { "created": "2022-04-22T06:00:30.559", @@ -939,12 +830,9 @@ "idScheme": "UID", "identifier": "GieVkTxp4HH" }, - "value": "13", - "providedElsewhere": false + "value": "13" } - ], - "notes": [], - "relationships": [] + ] }, { "event": "ck7DzdxqLqA", @@ -979,7 +867,6 @@ "identifier": "DiszpKrYNg8" }, "status": "ACTIVE", - "deleted": false, "dataValues": [ { "created": "2022-04-22T06:00:14.224", @@ -987,12 +874,9 @@ "idScheme": "UID", "identifier": "GieVkTxp4HH" }, - "value": "12", - "providedElsewhere": false + "value": "12" } - ], - "notes": [], - "relationships": [] + ] }, { "event": "lumVtWwwy0O", @@ -1078,17 +962,14 @@ "idScheme": "UID", "identifier": "tSsGrtfRzjY" }, - "relationships": [], "occurredAt": "2019-01-28T00:00:00.000", "scheduledAt": "2019-01-28T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" - }, - "notes": [] + } }, { "event": "SbUJzkxKYAG", @@ -1106,12 +987,10 @@ "idScheme": "UID", "identifier": "RojfDTBhoGC" }, - "relationships": [], "occurredAt": "2019-01-28T00:00:00.000", "scheduledAt": "2019-01-28T11:10:38.100", "storedBy": "tracker", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" @@ -1133,17 +1012,14 @@ "idScheme": "UID", "identifier": "DiszpKrYNg8" }, - "relationships": [], "occurredAt": "2019-01-28T00:00:00.000", "scheduledAt": "2019-01-28T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" - }, - "notes": [] + } }, { "event": "YKmfzHdjUDL", @@ -1161,17 +1037,14 @@ "idScheme": "UID", "identifier": "lbDXJBlvtZe" }, - "relationships": [], "occurredAt": "2019-01-28T00:00:00.000", "scheduledAt": "2019-01-28T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" - }, - "notes": [] + } }, { "event": "G9PbzJY8bJG", @@ -1188,17 +1061,14 @@ "idScheme": "UID", "identifier": "g4w96yEMlzO" }, - "relationships": [], "occurredAt": "2019-01-28T00:00:00.000", "scheduledAt": "2019-01-28T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" - }, - "notes": [] + } }, { "event": "H0PbzJY8bJG", @@ -1216,17 +1086,14 @@ "idScheme": "UID", "identifier": "DiszpKrYNg8" }, - "relationships": [], "occurredAt": "2019-01-28T00:00:00.000", "scheduledAt": "2019-01-28T12:10:38.100", "storedBy": "admin", "followUp": true, - "deleted": false, "attributeOptionCombo": { "idScheme": "UID", "identifier": "HllvX50cXC0" - }, - "notes": [] + } } ], "relationships": [ @@ -1237,8 +1104,6 @@ "identifier": "TV9oB9LT3sh" }, "createdAtClient": "2018-10-01T12:17:30.163", - "bidirectional": false, - "deleted": false, "from": { "trackedEntity": "QS6w44flWAf" }, @@ -1253,14 +1118,38 @@ "identifier": "TV9oB9LT3sh" }, "createdAtClient": "2018-11-01T13:24:37.118", - "bidirectional": false, - "deleted": false, "from": { "trackedEntity": "dUE514NMOlo" }, "to": { "event": "pTzf9KYMk72" } + }, + { + "relationship": "x8919212736", + "relationshipType": { + "idScheme": "UID", + "identifier": "TV9oB9LT3sh" + }, + "from": { + "trackedEntity": "mHWCacsGYYn" + }, + "to": { + "event": "QRYjLTiJTrA" + } + }, + { + "relationship": "N8800829a58", + "relationshipType": { + "idScheme": "UID", + "identifier": "m1575931405" + }, + "from": { + "trackedEntity": "H8732208127" + }, + "to": { + "trackedEntity": "QesgJkTyTCk" + } } ], "username": "system-process"