From 255a89d52b772c00948aa75440876d4fd6a31626 Mon Sep 17 00:00:00 2001 From: Enrico Date: Mon, 21 Oct 2024 11:59:00 +0200 Subject: [PATCH 1/4] chore: Validate completedAt for Event and Enrollment [DHIS2-18222] --- .../imports/validation/ValidationCode.java | 8 ++--- .../imports/bundle/TrackerObjectsMapper.java | 11 +++++-- .../tracker/imports/domain/Enrollment.java | 2 ++ .../dhis/tracker/imports/domain/Event.java | 2 -- .../validator/enrollment/DateValidator.java | 16 ++++++++-- .../validator/event/DateValidator.java | 23 ++++++++------- .../enrollment/DateValidatorTest.java | 29 +++++++++++++++---- .../validator/event/DateValidatorTest.java | 11 ++++--- ...TrackerNotificationHandlerServiceTest.java | 1 - 9 files changed, 70 insertions(+), 33 deletions(-) diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java index 7e1270969f1a..4f8dd0e49343 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java @@ -58,9 +58,8 @@ public enum ValidationCode { E1020("Enrollment date: `{0}`, cannot be a future date."), E1021("Incident date: `{0}`, cannot be a future date."), E1022("TrackedEntity: `{0}`, must have same TrackedEntityType as Program `{1}`."), - E1023( - "DisplayIncidentDate is true but property occurredAt is null or has an invalid format: `{0}`."), - E1025("Property enrolledAt is null or has an invalid format: `{0}`."), + E1023("DisplayIncidentDate is true but property occurredAt is null."), + E1025("Property enrolledAt is null."), E1029("Event OrganisationUnit: `{0}`, and Program: `{1}`, don't match."), E1030("Event: `{0}`, already exists."), E1031("Event occurredAt date is missing."), @@ -69,7 +68,6 @@ public enum ValidationCode { E1035("Event: `{0}`, ProgramStage value is null."), E1039("ProgramStage: `{0}`, is not repeatable and an event already exists."), E1041("Enrollment OrganisationUnit: `{0}`, and Program: `{1}`, don't match."), - E1042("Event: `{0}`, needs to have completed date."), E1043("Event: `{0}`, completeness date has expired. Not possible to make changes to this event."), E1044("Event: `{0}`, needs to have event date."), E1045( @@ -80,6 +78,8 @@ public enum ValidationCode { E1048("Object: `{0}`, uid: `{1}`, has an invalid uid format."), E1049("Could not find OrganisationUnit: `{0}`, linked to Tracked Entity."), E1050("Event ScheduledAt date is missing."), + E1051("Event: `{0}`, completedAt must be null when status is `{1}`"), + E1052("Enrollment: `{0}`, completedAt must be null when status is `{1}`"), E1054("AttributeOptionCombo `{0}` is not in the event programs category combo `{1}`."), E1055("Default AttributeOptionCombo is not allowed since program has non-default CategoryCombo."), E1056("Event date: `{0}`, is before start date: `{1}`, for AttributeOption: `{2}`."), diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java index 37c0cb4e510f..807cfe166389 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java @@ -144,17 +144,21 @@ private TrackerObjectsMapper() { if (enrollment.getStatus() != dbEnrollment.getStatus()) { dbEnrollment.setStatus(enrollment.getStatus()); + Date completedDate = + enrollment.getCompletedAt() == null + ? now + : DateUtils.fromInstant(enrollment.getCompletedAt()); switch (dbEnrollment.getStatus()) { case ACTIVE -> { dbEnrollment.setCompletedDate(null); dbEnrollment.setCompletedBy(null); } case COMPLETED -> { - dbEnrollment.setCompletedDate(now); + dbEnrollment.setCompletedDate(completedDate); dbEnrollment.setCompletedBy(user.getUsername()); } case CANCELLED -> { - dbEnrollment.setCompletedDate(now); + dbEnrollment.setCompletedDate(completedDate); dbEnrollment.setCompletedBy(null); } } @@ -211,7 +215,8 @@ private TrackerObjectsMapper() { EventStatus currentStatus = event.getStatus(); EventStatus previousStatus = dbEvent.getStatus(); if (currentStatus != previousStatus && currentStatus == EventStatus.COMPLETED) { - dbEvent.setCompletedDate(now); + dbEvent.setCompletedDate( + event.getCompletedAt() == null ? now : DateUtils.fromInstant(event.getCompletedAt())); dbEvent.setCompletedBy(user.getUsername()); } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Enrollment.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Enrollment.java index 9fc015c798d8..8af77cdcec24 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Enrollment.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Enrollment.java @@ -70,6 +70,8 @@ public class Enrollment implements TrackerDto, Serializable { @JsonProperty private String storedBy; + @JsonProperty private Instant completedAt; + @JsonProperty private Geometry geometry; @JsonProperty @Builder.Default private List attributes = new ArrayList<>(); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Event.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Event.java index d5232846f0cc..ca526d080edf 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Event.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/domain/Event.java @@ -78,8 +78,6 @@ public class Event implements TrackerDto, Serializable { @JsonProperty @Builder.Default private Set attributeCategoryOptions = new HashSet<>(); - @JsonProperty private String completedBy; - @JsonProperty private Instant completedAt; @JsonProperty private Geometry geometry; diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java index 3018ef48020e..c0b70919a1fe 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java @@ -31,10 +31,12 @@ import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1021; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1023; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1025; +import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1052; import java.time.LocalDate; import java.time.ZoneOffset; import java.util.Objects; +import org.hisp.dhis.program.EnrollmentStatus; import org.hisp.dhis.program.Program; import org.hisp.dhis.tracker.imports.bundle.TrackerBundle; import org.hisp.dhis.tracker.imports.domain.Enrollment; @@ -55,13 +57,23 @@ public void validate(Reporter reporter, TrackerBundle bundle, Enrollment enrollm if (Boolean.TRUE.equals(program.getDisplayIncidentDate()) && Objects.isNull(enrollment.getOccurredAt())) { - reporter.addError(enrollment, E1023, enrollment.getOccurredAt()); + reporter.addError(enrollment, E1023); + } + + validateCompletedDateIsSetOnlyForSupportedStatus(reporter, enrollment); + } + + private void validateCompletedDateIsSetOnlyForSupportedStatus( + Reporter reporter, Enrollment enrollment) { + if (enrollment.getCompletedAt() != null + && EnrollmentStatus.COMPLETED != enrollment.getStatus()) { + reporter.addError(enrollment, E1052, enrollment, enrollment.getStatus()); } } private void validateMandatoryDates(Reporter reporter, Enrollment enrollment) { if (Objects.isNull(enrollment.getEnrolledAt())) { - reporter.addError(enrollment, E1025, enrollment.getEnrolledAt()); + reporter.addError(enrollment, E1025); } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java index 38756479b321..881d20846dfa 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java @@ -30,11 +30,11 @@ import static java.time.Duration.ofDays; import static java.time.Instant.now; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1031; -import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1042; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1043; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1046; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1047; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1050; +import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1051; import java.time.Instant; import java.util.Date; @@ -70,25 +70,28 @@ public void validate(Reporter reporter, TrackerBundle bundle, Event event) { return; } + validateCompletedDateIsSetOnlyForSupportedStatus(reporter, event); validateExpiryDays(reporter, event, program, bundle.getUser()); validatePeriodType(reporter, event, program); } + private void validateCompletedDateIsSetOnlyForSupportedStatus(Reporter reporter, Event event) { + if (event.getCompletedAt() != null && EventStatus.COMPLETED != event.getStatus()) { + reporter.addError(event, E1051, event, event.getStatus()); + } + } + private void validateExpiryDays( Reporter reporter, Event event, Program program, UserDetails user) { - if (user.isAuthorized(Authorities.F_EDIT_EXPIRED.name())) { + if (user.isAuthorized(Authorities.F_EDIT_EXPIRED.name()) || event.getCompletedAt() == null) { return; } - if ((program.getCompleteEventsExpiryDays() > 0 && EventStatus.COMPLETED == event.getStatus())) { - if (event.getCompletedAt() == null) { - reporter.addError(event, E1042, event); - } else { - if (now() + if (program.getCompleteEventsExpiryDays() > 0 + && EventStatus.COMPLETED == event.getStatus() + && now() .isAfter(event.getCompletedAt().plus(ofDays(program.getCompleteEventsExpiryDays())))) { - reporter.addError(event, E1043, event); - } - } + reporter.addError(event, E1043, event); } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java index 3b89470f8558..c19c7628e8f9 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java @@ -27,11 +27,13 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.enrollment; +import static java.time.Instant.now; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1020; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1021; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1023; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1025; +import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1052; import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertHasError; import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.Mockito.when; @@ -39,6 +41,7 @@ import java.time.Duration; import java.time.Instant; import org.hisp.dhis.common.CodeGenerator; +import org.hisp.dhis.program.EnrollmentStatus; import org.hisp.dhis.program.Program; import org.hisp.dhis.tracker.imports.TrackerIdSchemeParams; import org.hisp.dhis.tracker.imports.bundle.TrackerBundle; @@ -82,7 +85,7 @@ void testMandatoryDatesMustBePresent() { Enrollment.builder() .enrollment(CodeGenerator.generateUid()) .program(MetadataIdentifier.ofUid(CodeGenerator.generateUid())) - .occurredAt(Instant.now()) + .occurredAt(now()) .build(); when(preheat.getProgram(enrollment.getProgram())).thenReturn(new Program()); @@ -94,7 +97,7 @@ void testMandatoryDatesMustBePresent() { @Test void testDatesMustNotBeInTheFuture() { - final Instant dateInTheFuture = Instant.now().plus(Duration.ofDays(2)); + final Instant dateInTheFuture = now().plus(Duration.ofDays(2)); Enrollment enrollment = Enrollment.builder() .enrollment(CodeGenerator.generateUid()) @@ -114,7 +117,7 @@ void testDatesMustNotBeInTheFuture() { @Test void testDatesShouldBeAllowedOnSameDayIfFutureDatesAreNotAllowed() { - final Instant today = Instant.now().plus(Duration.ofMinutes(1)); + final Instant today = now().plus(Duration.ofMinutes(1)); Enrollment enrollment = Enrollment.builder() .enrollment(CodeGenerator.generateUid()) @@ -132,7 +135,7 @@ void testDatesShouldBeAllowedOnSameDayIfFutureDatesAreNotAllowed() { @Test void testDatesCanBeInTheFuture() { - final Instant dateInTheFuture = Instant.now().plus(Duration.ofDays(2)); + final Instant dateInTheFuture = now().plus(Duration.ofDays(2)); Enrollment enrollment = Enrollment.builder() .enrollment(CodeGenerator.generateUid()) @@ -157,7 +160,7 @@ void testFailOnMissingOccurredAtDate() { Enrollment.builder() .enrollment(CodeGenerator.generateUid()) .program(MetadataIdentifier.ofUid(CodeGenerator.generateUid())) - .enrolledAt(Instant.now()) + .enrolledAt(now()) .build(); Program program = new Program(); @@ -168,4 +171,20 @@ void testFailOnMissingOccurredAtDate() { assertHasError(reporter, enrollment, E1023); } + + @Test + void shouldFailWhenCompletedAtIsPresentAndStatusIsNotCompleted() { + Enrollment enrollment = new Enrollment(); + enrollment.setEnrollment(CodeGenerator.generateUid()); + enrollment.setProgram(MetadataIdentifier.ofUid(CodeGenerator.generateUid())); + enrollment.setOccurredAt(now()); + enrollment.setCompletedAt(now()); + enrollment.setStatus(EnrollmentStatus.ACTIVE); + + when(preheat.getProgram(enrollment.getProgram())).thenReturn(new Program()); + + validator.validate(reporter, bundle, enrollment); + + assertHasError(reporter, enrollment, E1052); + } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidatorTest.java index 9445f3203162..52eca791b667 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidatorTest.java @@ -29,11 +29,11 @@ import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1031; -import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1042; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1043; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1046; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1047; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1050; +import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1051; import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertHasError; import static org.mockito.Mockito.when; @@ -174,7 +174,7 @@ void testEventIsNotValidWhenScheduledDateIsNotPresentAndEventIsSchedule() { } @Test - void testEventIsNotValidWhenCompletedAtIsNotPresentAndEventIsCompleted() { + void shouldFailWhenCompletedAtIsPresentAndStatusIsNotCompleted() { // given when(preheat.getProgram(MetadataIdentifier.ofUid(PROGRAM_WITH_REGISTRATION_ID))) .thenReturn(getProgramWithRegistration()); @@ -182,13 +182,12 @@ void testEventIsNotValidWhenCompletedAtIsNotPresentAndEventIsCompleted() { event.setEvent(CodeGenerator.generateUid()); event.setProgram(MetadataIdentifier.ofUid(PROGRAM_WITH_REGISTRATION_ID)); event.setOccurredAt(now()); - event.setStatus(EventStatus.COMPLETED); + event.setCompletedAt(now()); + event.setStatus(EventStatus.ACTIVE); - // when validator.validate(reporter, bundle, event); - // then - assertHasError(reporter, event, E1042); + assertHasError(reporter, event, E1051); } @Test diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/bundle/TrackerNotificationHandlerServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/bundle/TrackerNotificationHandlerServiceTest.java index 13b10de7c07c..aa46c5c8564f 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/bundle/TrackerNotificationHandlerServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/tracker/imports/bundle/TrackerNotificationHandlerServiceTest.java @@ -210,7 +210,6 @@ void shouldSendTrackerNotificationAtEnrollmentCompletionAndThenEventCompletion() .programStage(MetadataIdentifier.ofUid(programStageA.getUid())) .status(EventStatus.ACTIVE) .attributeOptionCombo(MetadataIdentifier.EMPTY_UID) - .completedAt(Instant.now()) .occurredAt(Instant.now()) .build(); From 8042285587da2d3efca3a7e0b09e9f355ff7c547 Mon Sep 17 00:00:00 2001 From: Enrico Date: Tue, 22 Oct 2024 09:00:29 +0200 Subject: [PATCH 2/4] chore: Validate completedAt for Event and Enrollment [DHIS2-18222] --- .../imports/bundle/TrackerObjectsMapper.java | 2 +- .../validator/enrollment/DateValidator.java | 3 +-- .../enrollment/DateValidatorTest.java | 22 +++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java index 807cfe166389..d5bd7f744c0b 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/bundle/TrackerObjectsMapper.java @@ -148,7 +148,7 @@ private TrackerObjectsMapper() { enrollment.getCompletedAt() == null ? now : DateUtils.fromInstant(enrollment.getCompletedAt()); - switch (dbEnrollment.getStatus()) { + switch (enrollment.getStatus()) { case ACTIVE -> { dbEnrollment.setCompletedDate(null); dbEnrollment.setCompletedBy(null); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java index c0b70919a1fe..374106599c16 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java @@ -65,8 +65,7 @@ public void validate(Reporter reporter, TrackerBundle bundle, Enrollment enrollm private void validateCompletedDateIsSetOnlyForSupportedStatus( Reporter reporter, Enrollment enrollment) { - if (enrollment.getCompletedAt() != null - && EnrollmentStatus.COMPLETED != enrollment.getStatus()) { + if (enrollment.getCompletedAt() != null && EnrollmentStatus.ACTIVE == enrollment.getStatus()) { reporter.addError(enrollment, E1052, enrollment, enrollment.getStatus()); } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java index c19c7628e8f9..b85f1a618769 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidatorTest.java @@ -35,6 +35,7 @@ import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1025; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1052; import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertHasError; +import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertHasNoError; import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.Mockito.when; @@ -52,6 +53,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -187,4 +190,23 @@ void shouldFailWhenCompletedAtIsPresentAndStatusIsNotCompleted() { assertHasError(reporter, enrollment, E1052); } + + @ParameterizedTest + @EnumSource( + value = EnrollmentStatus.class, + names = {"COMPLETED", "CANCELLED"}) + void shouldValidateWhenCompletedAtIsPresentAndStatusAcceptCompletedAt(EnrollmentStatus status) { + Enrollment enrollment = new Enrollment(); + enrollment.setEnrollment(CodeGenerator.generateUid()); + enrollment.setProgram(MetadataIdentifier.ofUid(CodeGenerator.generateUid())); + enrollment.setOccurredAt(now()); + enrollment.setCompletedAt(now()); + enrollment.setStatus(status); + + when(preheat.getProgram(enrollment.getProgram())).thenReturn(new Program()); + + validator.validate(reporter, bundle, enrollment); + + assertHasNoError(reporter, enrollment, E1052); + } } From 81a8e7c377dbe9b03d1554df61abe6ae0b7d1a8a Mon Sep 17 00:00:00 2001 From: Enrico Date: Tue, 22 Oct 2024 12:00:08 +0200 Subject: [PATCH 3/4] Fix review comments --- .../validation/validator/enrollment/DateValidator.java | 6 ++++-- .../imports/validation/validator/event/DateValidator.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java index 374106599c16..d0466dff876d 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.enrollment; +import static org.hisp.dhis.program.EnrollmentStatus.*; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1020; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1021; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1023; @@ -36,7 +37,6 @@ import java.time.LocalDate; import java.time.ZoneOffset; import java.util.Objects; -import org.hisp.dhis.program.EnrollmentStatus; import org.hisp.dhis.program.Program; import org.hisp.dhis.tracker.imports.bundle.TrackerBundle; import org.hisp.dhis.tracker.imports.domain.Enrollment; @@ -65,7 +65,9 @@ public void validate(Reporter reporter, TrackerBundle bundle, Enrollment enrollm private void validateCompletedDateIsSetOnlyForSupportedStatus( Reporter reporter, Enrollment enrollment) { - if (enrollment.getCompletedAt() != null && EnrollmentStatus.ACTIVE == enrollment.getStatus()) { + if (enrollment.getCompletedAt() != null + && enrollment.getStatus() != COMPLETED + && enrollment.getStatus() != CANCELLED) { reporter.addError(enrollment, E1052, enrollment, enrollment.getStatus()); } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java index 881d20846dfa..935ca01f35fc 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/event/DateValidator.java @@ -83,7 +83,7 @@ private void validateCompletedDateIsSetOnlyForSupportedStatus(Reporter reporter, private void validateExpiryDays( Reporter reporter, Event event, Program program, UserDetails user) { - if (user.isAuthorized(Authorities.F_EDIT_EXPIRED.name()) || event.getCompletedAt() == null) { + if (event.getCompletedAt() == null || user.isAuthorized(Authorities.F_EDIT_EXPIRED.name())) { return; } From ab975aab1c6e2c12170c3e175c9ddf01d97084e4 Mon Sep 17 00:00:00 2001 From: Enrico Date: Tue, 22 Oct 2024 13:21:17 +0200 Subject: [PATCH 4/4] Fix review comments --- .../imports/validation/validator/enrollment/DateValidator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java index d0466dff876d..f541434cdc55 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/DateValidator.java @@ -27,7 +27,8 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.enrollment; -import static org.hisp.dhis.program.EnrollmentStatus.*; +import static org.hisp.dhis.program.EnrollmentStatus.CANCELLED; +import static org.hisp.dhis.program.EnrollmentStatus.COMPLETED; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1020; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1021; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1023;