diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java index 3aa083968793..dcbf053901a6 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java @@ -33,7 +33,9 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.Calendar; @@ -109,6 +111,9 @@ public class DateUtils { ObjectArrays.concat( SUPPORTED_DATE_ONLY_PARSERS, SUPPORTED_DATE_TIME_FORMAT_PARSERS, DateTimeParser.class); + private static final DateTimeFormatter ONLY_DATE_FORMATTER = + new DateTimeFormatterBuilder().append(null, SUPPORTED_DATE_ONLY_PARSERS).toFormatter(); + private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder().append(null, SUPPORTED_DATE_FORMAT_PARSERS).toFormatter(); @@ -137,6 +142,9 @@ public class DateUtils { private static final DateTimeFormatter LONG_DATE_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss"); + private static final DateTimeFormatter LONG_DATE_FORMAT_WITH_MILLIS = + DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"); + private static final DateTimeFormatter HTTP_DATE_FORMAT = DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'").withLocale(Locale.ENGLISH); @@ -178,6 +186,16 @@ public static String getLongGmtDateString(Date date) { return date != null ? TIMESTAMP_UTC_TZ_FORMAT.print(new DateTime(date)) : null; } + /** + * Formats a Date to the format yyyy-MM-dd HH:mm:ss.SSS. + * + * @param date the Date to parse. + * @return A formatted date string. + */ + public static String toLongDateWithMillis(Date date) { + return date != null ? LONG_DATE_FORMAT_WITH_MILLIS.print(new DateTime(date)) : null; + } + /** * Formats a Date to the format yyyy-MM-dd HH:mm:ss. * @@ -648,8 +666,8 @@ public static String getPrettyInterval(Date start, Date end) { } /** - * Parses the given string into a Date using the supported date formats. Returns null if the - * string cannot be parsed. + * Parses the given string into a Date using the supported date formats. Add time at the beginning + * of the day if no time was provided. Returns null if the string cannot be parsed. * * @param dateString the date string. * @return a date. @@ -658,6 +676,29 @@ public static Date parseDate(String dateString) { return safeParseDateTime(dateString, DATE_FORMATTER); } + /** + * Parses the given string into a Date using the supported date formats. Add time at the end of + * the day if no time was provided. Returns null if the string cannot be parsed. + * + * @param dateString the date string. + * @return a date. + */ + public static Date parseDateEndOfTheDay(String dateString) { + if (StringUtils.isEmpty(dateString)) { + return null; + } + + try { + Date date = safeParseDateTime(dateString, ONLY_DATE_FORMATTER); + LocalDateTime localDateTime = + LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).with(LocalTime.MAX); + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } catch (IllegalArgumentException e) { + // dateString has time defined + } + return safeParseDateTime(dateString, DATE_FORMATTER); + } + /** * Parses the given string into a Date using the supported date formats. Returns null if the * string cannot be parsed. diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java index 13953c9e5c4d..289281cba16d 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java @@ -29,10 +29,13 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; /** @@ -168,4 +171,48 @@ public static T throwIfNull(T object, Supplier the function return type. + * @param the object type. + * @param function the function to be applied to non-null object. + */ + public static U applyIfNotNull(T object, Function function) { + if (object == null) { + return null; + } + + return function.apply(object); + } + + /** + * Util method that always returns a new Set, either instantiated from a non-null Set passed as an + * argument, or if a null arg is passed then returning an empty Set. This helps reduce possible + * NullPointerExceptions when trying to instantiate a Set with a null value. + * + * @param set + * @return + * @param + */ + @Nonnull + public static Set copyOf(Set set) { + return set != null ? new HashSet<>(set) : new HashSet<>(); + } + + /** + * Util method that always returns a new List, either instantiated from a non-null Set passed as + * an argument, or if a null arg is passed then returning an empty Set. This helps reduce possible + * NullPointerExceptions when trying to instantiate a Set with a null value. + * + * @param list + * @return + * @param + */ + @Nonnull + public static List copyOf(List list) { + return list != null ? new ArrayList<>(list) : new ArrayList<>(); + } } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java index 863251074ebc..9e4c5aeef6cb 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/hibernate/HibernateProgramInstanceStore.java @@ -30,9 +30,9 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids; import static org.hisp.dhis.commons.util.TextUtils.getQuotedCommaDelimitedString; -import static org.hisp.dhis.util.DateUtils.getLongDateString; import static org.hisp.dhis.util.DateUtils.getLongGmtDateString; import static org.hisp.dhis.util.DateUtils.nowMinusDuration; +import static org.hisp.dhis.util.DateUtils.toLongDateWithMillis; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -157,7 +157,10 @@ private QueryWithOrderBy buildProgramInstanceHql(ProgramInstanceQueryParams para + "'"; } else if (params.hasLastUpdated()) { hql += - hlp.whereAnd() + "pi.lastUpdated >= '" + getLongDateString(params.getLastUpdated()) + "'"; + hlp.whereAnd() + + "pi.lastUpdated >= '" + + toLongDateWithMillis(params.getLastUpdated()) + + "'"; } if (params.hasTrackedEntityInstance()) { @@ -211,7 +214,7 @@ private QueryWithOrderBy buildProgramInstanceHql(ProgramInstanceQueryParams para hql += hlp.whereAnd() + "pi.enrollmentDate >= '" - + getLongDateString(params.getProgramStartDate()) + + toLongDateWithMillis(params.getProgramStartDate()) + "'"; } @@ -219,7 +222,7 @@ private QueryWithOrderBy buildProgramInstanceHql(ProgramInstanceQueryParams para hql += hlp.whereAnd() + "pi.enrollmentDate <= '" - + getLongDateString(params.getProgramEndDate()) + + toLongDateWithMillis(params.getProgramEndDate()) + "'"; } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/hibernate/HibernateTrackedEntityInstanceStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/hibernate/HibernateTrackedEntityInstanceStore.java index 190cb2867005..aeefb5e1eb6b 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/hibernate/HibernateTrackedEntityInstanceStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/trackedentity/hibernate/HibernateTrackedEntityInstanceStore.java @@ -46,8 +46,8 @@ import static org.hisp.dhis.trackedentity.TrackedEntityInstanceQueryParams.PROGRAM_INSTANCE_ALIAS; import static org.hisp.dhis.trackedentity.TrackedEntityInstanceQueryParams.TRACKED_ENTITY_ID; import static org.hisp.dhis.trackedentity.TrackedEntityInstanceQueryParams.TRACKED_ENTITY_INSTANCE_ID; -import static org.hisp.dhis.util.DateUtils.getLongDateString; import static org.hisp.dhis.util.DateUtils.getLongGmtDateString; +import static org.hisp.dhis.util.DateUtils.toLongDateWithMillis; import com.google.common.collect.Lists; import java.util.ArrayList; @@ -647,14 +647,14 @@ private String getFromSubQueryTrackedEntityConditions( trackedEntity .append(whereAnd.whereAnd()) .append(" TEI.lastupdated >= '") - .append(getLongDateString(params.getLastUpdatedStartDate())) + .append(toLongDateWithMillis(params.getLastUpdatedStartDate())) .append(SINGLE_QUOTE); } if (params.hasLastUpdatedEndDate()) { trackedEntity .append(whereAnd.whereAnd()) .append(" TEI.lastupdated <= '") - .append(getLongDateString(params.getLastUpdatedEndDate())) + .append(toLongDateWithMillis(params.getLastUpdatedEndDate())) .append(SINGLE_QUOTE); } } @@ -663,7 +663,7 @@ private String getFromSubQueryTrackedEntityConditions( if (params.getSkipChangedBefore() != null) { trackedEntity .append(" AND TEI.lastupdated >= '") - .append(getLongDateString(params.getSkipChangedBefore())) + .append(toLongDateWithMillis(params.getSkipChangedBefore())) .append(SINGLE_QUOTE); } } @@ -985,28 +985,28 @@ private String getFromSubQueryProgramInstanceConditions( if (params.hasProgramEnrollmentStartDate()) { program .append("AND PI.enrollmentdate >= '") - .append(getLongDateString(params.getProgramEnrollmentStartDate())) + .append(toLongDateWithMillis(params.getProgramEnrollmentStartDate())) .append("' "); } if (params.hasProgramEnrollmentEndDate()) { program .append("AND PI.enrollmentdate <= '") - .append(getLongDateString(params.getProgramEnrollmentEndDate())) + .append(toLongDateWithMillis(params.getProgramEnrollmentEndDate())) .append("' "); } if (params.hasProgramIncidentStartDate()) { program .append("AND PI.incidentdate >= '") - .append(getLongDateString(params.getProgramIncidentStartDate())) + .append(toLongDateWithMillis(params.getProgramIncidentStartDate())) .append("' "); } if (params.hasProgramIncidentEndDate()) { program .append("AND PI.incidentdate <= '") - .append(getLongDateString(params.getProgramIncidentEndDate())) + .append(toLongDateWithMillis(params.getProgramIncidentEndDate())) .append("' "); } @@ -1047,8 +1047,8 @@ private String getFromSubQueryProgramStageInstance(TrackedEntityInstanceQueryPar } if (params.hasEventStatus()) { - String start = getLongDateString(params.getEventStartDate()); - String end = getLongDateString(params.getEventEndDate()); + String start = toLongDateWithMillis(params.getEventStartDate()); + String end = toLongDateWithMillis(params.getEventEndDate()); if (params.isEventStatus(EventStatus.COMPLETED)) { events diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/JdbcEventStore.java b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/JdbcEventStore.java index cf601199ce32..0e3b46b2bc90 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/JdbcEventStore.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/JdbcEventStore.java @@ -1284,7 +1284,7 @@ private StringBuilder getFromWhereClause( } if (params.getStartDate() != null) { - mapSqlParameterSource.addValue("startDate", params.getStartDate(), Types.DATE); + mapSqlParameterSource.addValue("startDate", params.getStartDate(), Types.TIMESTAMP); fromBuilder .append(hlp.whereAnd()) @@ -1706,7 +1706,7 @@ private String getFromWhereClause( } if (params.getStartDate() != null) { - mapSqlParameterSource.addValue("startDate", params.getStartDate(), Types.DATE); + mapSqlParameterSource.addValue("startDate", params.getStartDate(), Types.TIMESTAMP); sqlBuilder .append(hlp.whereAnd()) @@ -1745,7 +1745,7 @@ private String getFromWhereClause( } if (params.getDueDateStart() != null) { - mapSqlParameterSource.addValue("startDueDate", params.getDueDateStart(), Types.DATE); + mapSqlParameterSource.addValue("startDueDate", params.getDueDateStart(), Types.TIMESTAMP); sqlBuilder .append(hlp.whereAnd()) @@ -1755,7 +1755,7 @@ private String getFromWhereClause( } if (params.getDueDateEnd() != null) { - mapSqlParameterSource.addValue("endDueDate", params.getDueDateEnd(), Types.DATE); + mapSqlParameterSource.addValue("endDueDate", params.getDueDateEnd(), Types.TIMESTAMP); sqlBuilder .append(hlp.whereAnd()) diff --git a/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/tracker/export/TrackerExportTests.java b/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/tracker/export/TrackerExportTests.java index f3c1225892fc..fecd38a340ce 100644 --- a/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/tracker/export/TrackerExportTests.java +++ b/dhis-2/dhis-test-e2e/src/test/java/org/hisp/dhis/tracker/export/TrackerExportTests.java @@ -467,7 +467,7 @@ public void shouldNotReturnRelationshipsWhenEventHasRelationshipsAndFieldsExclud public void shouldReturnFilteredEvent() { trackerActions .get( - "events?enrollmentOccurredAfter=2019-08-16&enrollmentOccurredBefore=2019-08-20&event=ZwwuwNp6gVd") + "events?enrollmentOccurredAfter=2019-08-19&enrollmentOccurredBefore=2019-08-19&event=ZwwuwNp6gVd") .validate() .statusCode(200) .rootPath("instances[0]") diff --git a/dhis-2/dhis-test-e2e/src/test/resources/tracker/importer/teis/teisWithEnrollmentsAndEvents.json b/dhis-2/dhis-test-e2e/src/test/resources/tracker/importer/teis/teisWithEnrollmentsAndEvents.json index dfeba7e3c42c..aaba25109791 100644 --- a/dhis-2/dhis-test-e2e/src/test/resources/tracker/importer/teis/teisWithEnrollmentsAndEvents.json +++ b/dhis-2/dhis-test-e2e/src/test/resources/tracker/importer/teis/teisWithEnrollmentsAndEvents.json @@ -12,7 +12,7 @@ "enrollment": "MNWZ6hnuhSw", "enrolledAt": "2019-08-19T00:00:00.000", "deleted": false, - "occurredAt": "2019-08-19T00:00:00.000", + "occurredAt": "2019-08-19T12:00:00.000", "status": "ACTIVE", "notes": [], "relationships": [], diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteria.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteria.java index 62df1a4b25bf..458c351b376d 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteria.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteria.java @@ -29,7 +29,6 @@ import static org.hisp.dhis.webapi.controller.event.webrequest.tracker.FieldTranslatorSupport.translate; -import java.util.Date; import java.util.Optional; import lombok.Data; import lombok.Getter; @@ -38,6 +37,8 @@ import org.hisp.dhis.common.OrganisationUnitSelectionMode; import org.hisp.dhis.program.ProgramStatus; import org.hisp.dhis.webapi.controller.event.webrequest.PagingAndSortingCriteriaAdapter; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; /** Represents query parameters sent to {@link TrackerEnrollmentsExportController}. */ @Data @@ -53,13 +54,13 @@ public class TrackerEnrollmentCriteria extends PagingAndSortingCriteriaAdapter { private Boolean followUp; - private Date updatedAfter; + private StartDateTime updatedAfter; private String updatedWithin; - private Date enrolledAfter; + private StartDateTime enrolledAfter; - private Date enrolledBefore; + private EndDateTime enrolledBefore; private String trackedEntityType; diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteriaMapper.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteriaMapper.java index dd2a0696c125..f3858ba652ee 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteriaMapper.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEnrollmentCriteriaMapper.java @@ -30,6 +30,7 @@ import static org.apache.commons.lang3.BooleanUtils.toBooleanDefaultIfNull; import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; +import static org.hisp.dhis.util.ObjectUtils.applyIfNotNull; import static org.hisp.dhis.webapi.controller.event.mapper.OrderParamsHelper.toOrderParams; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamUtils.applyIfNonEmpty; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamUtils.parseUids; @@ -54,6 +55,8 @@ import org.hisp.dhis.trackedentity.TrackedEntityTypeService; import org.hisp.dhis.user.CurrentUserService; import org.hisp.dhis.user.User; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -101,10 +104,10 @@ public ProgramInstanceQueryParams map(TrackerEnrollmentCriteria criteria) params.setProgram(program); params.setProgramStatus(criteria.getProgramStatus()); params.setFollowUp(criteria.getFollowUp()); - params.setLastUpdated(criteria.getUpdatedAfter()); + params.setLastUpdated(applyIfNotNull(criteria.getUpdatedAfter(), StartDateTime::toDate)); params.setLastUpdatedDuration(criteria.getUpdatedWithin()); - params.setProgramStartDate(criteria.getEnrolledAfter()); - params.setProgramEndDate(criteria.getEnrolledBefore()); + params.setProgramStartDate(applyIfNotNull(criteria.getEnrolledAfter(), StartDateTime::toDate)); + params.setProgramEndDate(applyIfNotNull(criteria.getEnrolledBefore(), EndDateTime::toDate)); params.setTrackedEntityType(trackedEntityType); params.setTrackedEntityInstanceUid( Optional.ofNullable(trackedEntity).map(BaseIdentifiableObject::getUid).orElse(null)); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteria.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteria.java index 76daf262bd1a..d7384f0564d5 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteria.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteria.java @@ -29,7 +29,6 @@ import static org.hisp.dhis.webapi.controller.event.webrequest.tracker.FieldTranslatorSupport.translate; -import java.util.Date; import java.util.HashSet; import java.util.Optional; import java.util.Set; @@ -43,6 +42,8 @@ import org.hisp.dhis.event.EventStatus; import org.hisp.dhis.program.ProgramStatus; import org.hisp.dhis.webapi.controller.event.webrequest.PagingAndSortingCriteriaAdapter; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; /** * Represents query parameters sent to {@link TrackerEventsExportController}. @@ -70,27 +71,27 @@ class TrackerEventCriteria extends PagingAndSortingCriteriaAdapter { private String assignedUser; - private Date occurredAfter; + private StartDateTime occurredAfter; - private Date occurredBefore; + private EndDateTime occurredBefore; - private Date scheduledAfter; + private StartDateTime scheduledAfter; - private Date scheduledBefore; + private EndDateTime scheduledBefore; - private Date updatedAfter; + private StartDateTime updatedAfter; - private Date updatedBefore; + private EndDateTime updatedBefore; private String updatedWithin; - private Date enrollmentEnrolledBefore; + private EndDateTime enrollmentEnrolledBefore; - private Date enrollmentEnrolledAfter; + private StartDateTime enrollmentEnrolledAfter; - private Date enrollmentOccurredBefore; + private EndDateTime enrollmentOccurredBefore; - private Date enrollmentOccurredAfter; + private StartDateTime enrollmentOccurredAfter; private EventStatus status; diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapper.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapper.java index 8bb814a1496e..85549c5ef016 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapper.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapper.java @@ -28,6 +28,7 @@ package org.hisp.dhis.webapi.controller.tracker.export; import static org.apache.commons.lang3.BooleanUtils.toBooleanDefaultIfNull; +import static org.hisp.dhis.util.ObjectUtils.*; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamUtils.applyIfNonEmpty; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamUtils.parseAndFilterUids; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamUtils.parseAttributeQueryItems; @@ -82,6 +83,8 @@ import org.hisp.dhis.webapi.controller.event.mapper.OrderParamsHelper; import org.hisp.dhis.webapi.controller.event.mapper.SortDirection; import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; import org.springframework.stereotype.Component; /** @@ -207,17 +210,21 @@ public EventQueryParams map(TrackerEventCriteria criteria) .setFollowUp(criteria.getFollowUp()) .setOrgUnitSelectionMode(orgUnitMode) .setUserWithAssignedUsers(criteria.getAssignedUserMode(), user, assignedUserIds) - .setStartDate(criteria.getOccurredAfter()) - .setEndDate(criteria.getOccurredBefore()) - .setDueDateStart(criteria.getScheduledAfter()) - .setDueDateEnd(criteria.getScheduledBefore()) - .setLastUpdatedStartDate(criteria.getUpdatedAfter()) - .setLastUpdatedEndDate(criteria.getUpdatedBefore()) + .setStartDate(applyIfNotNull(criteria.getOccurredAfter(), StartDateTime::toDate)) + .setEndDate(applyIfNotNull(criteria.getOccurredBefore(), EndDateTime::toDate)) + .setDueDateStart(applyIfNotNull(criteria.getScheduledAfter(), StartDateTime::toDate)) + .setDueDateEnd(applyIfNotNull(criteria.getScheduledBefore(), EndDateTime::toDate)) + .setLastUpdatedStartDate(applyIfNotNull(criteria.getUpdatedAfter(), StartDateTime::toDate)) + .setLastUpdatedEndDate(applyIfNotNull(criteria.getUpdatedBefore(), EndDateTime::toDate)) .setLastUpdatedDuration(criteria.getUpdatedWithin()) - .setEnrollmentEnrolledBefore(criteria.getEnrollmentEnrolledBefore()) - .setEnrollmentEnrolledAfter(criteria.getEnrollmentEnrolledAfter()) - .setEnrollmentOccurredBefore(criteria.getEnrollmentOccurredBefore()) - .setEnrollmentOccurredAfter(criteria.getEnrollmentOccurredAfter()) + .setEnrollmentEnrolledBefore( + applyIfNotNull(criteria.getEnrollmentEnrolledBefore(), EndDateTime::toDate)) + .setEnrollmentEnrolledAfter( + applyIfNotNull(criteria.getEnrollmentEnrolledAfter(), StartDateTime::toDate)) + .setEnrollmentOccurredBefore( + applyIfNotNull(criteria.getEnrollmentOccurredBefore(), EndDateTime::toDate)) + .setEnrollmentOccurredAfter( + applyIfNotNull(criteria.getEnrollmentOccurredAfter(), StartDateTime::toDate)) .setEventStatus(criteria.getStatus()) .setCategoryOptionCombo(attributeOptionCombo) .setIdSchemes(criteria.getIdSchemes()) diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteria.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteria.java index 7b6e62c767a7..fdb66ea2ff72 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteria.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteria.java @@ -27,7 +27,6 @@ */ package org.hisp.dhis.webapi.controller.tracker.export; -import java.util.Date; import lombok.Data; import lombok.NoArgsConstructor; import org.hisp.dhis.common.AssignedUserSelectionMode; @@ -38,6 +37,8 @@ import org.hisp.dhis.program.ProgramStatus; import org.hisp.dhis.webapi.controller.event.webrequest.PagingAndSortingCriteriaAdapter; import org.hisp.dhis.webapi.controller.tracker.view.Attribute; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; /** * Represents query parameters sent to {@link TrackerTrackedEntitiesExportController}. @@ -74,25 +75,25 @@ class TrackerTrackedEntityCriteria extends PagingAndSortingCriteriaAdapter { private Boolean followUp; /** Start date for last updated. */ - private Date updatedAfter; + private StartDateTime updatedAfter; /** End date for last updated. */ - private Date updatedBefore; + private EndDateTime updatedBefore; /** The last updated duration filter. */ private String updatedWithin; /** The given Program start date. */ - private Date enrollmentEnrolledAfter; + private StartDateTime enrollmentEnrolledAfter; /** The given Program end date. */ - private Date enrollmentEnrolledBefore; + private EndDateTime enrollmentEnrolledBefore; /** Start date for incident in the given program. */ - private Date enrollmentOccurredAfter; + private StartDateTime enrollmentOccurredAfter; /** End date for incident in the given program. */ - private Date enrollmentOccurredBefore; + private EndDateTime enrollmentOccurredBefore; /** Only returns Tracked Entity Instances of this type. */ private String trackedEntityType; @@ -113,10 +114,10 @@ class TrackerTrackedEntityCriteria extends PagingAndSortingCriteriaAdapter { private EventStatus eventStatus; /** Start date for Event for the given Program. */ - private Date eventOccurredAfter; + private StartDateTime eventOccurredAfter; /** End date for Event for the given Program. */ - private Date eventOccurredBefore; + private EndDateTime eventOccurredBefore; /** Indicates whether not to include meta data in the response. */ private boolean skipMeta; diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapper.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapper.java index de49ec51307a..052f2837faf3 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapper.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapper.java @@ -30,6 +30,7 @@ import static org.apache.commons.lang3.BooleanUtils.toBooleanDefaultIfNull; import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; +import static org.hisp.dhis.util.ObjectUtils.applyIfNotNull; import static org.hisp.dhis.webapi.controller.event.mapper.OrderParamsHelper.toOrderParams; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamUtils.applyIfNonEmpty; import static org.hisp.dhis.webapi.controller.tracker.export.RequestParamUtils.parseAndFilterUids; @@ -72,6 +73,8 @@ import org.hisp.dhis.user.User; import org.hisp.dhis.webapi.controller.event.mapper.OrderParam; import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -166,19 +169,23 @@ public TrackedEntityInstanceQueryParams map(TrackerTrackedEntityCriteria criteri .setProgramStage(programStage) .setProgramStatus(criteria.getProgramStatus()) .setFollowUp(criteria.getFollowUp()) - .setLastUpdatedStartDate(criteria.getUpdatedAfter()) - .setLastUpdatedEndDate(criteria.getUpdatedBefore()) + .setLastUpdatedStartDate(applyIfNotNull(criteria.getUpdatedAfter(), StartDateTime::toDate)) + .setLastUpdatedEndDate(applyIfNotNull(criteria.getUpdatedBefore(), EndDateTime::toDate)) .setLastUpdatedDuration(criteria.getUpdatedWithin()) - .setProgramEnrollmentStartDate(criteria.getEnrollmentEnrolledAfter()) - .setProgramEnrollmentEndDate(criteria.getEnrollmentEnrolledBefore()) - .setProgramIncidentStartDate(criteria.getEnrollmentOccurredAfter()) - .setProgramIncidentEndDate(criteria.getEnrollmentOccurredBefore()) + .setProgramEnrollmentStartDate( + applyIfNotNull(criteria.getEnrollmentEnrolledAfter(), StartDateTime::toDate)) + .setProgramEnrollmentEndDate( + applyIfNotNull(criteria.getEnrollmentEnrolledBefore(), EndDateTime::toDate)) + .setProgramIncidentStartDate( + applyIfNotNull(criteria.getEnrollmentOccurredAfter(), StartDateTime::toDate)) + .setProgramIncidentEndDate( + applyIfNotNull(criteria.getEnrollmentOccurredBefore(), EndDateTime::toDate)) .setTrackedEntityType(trackedEntityType) .addOrganisationUnits(orgUnits) .setOrganisationUnitMode(criteria.getOuMode()) .setEventStatus(criteria.getEventStatus()) - .setEventStartDate(criteria.getEventOccurredAfter()) - .setEventEndDate(criteria.getEventOccurredBefore()) + .setEventStartDate(applyIfNotNull(criteria.getEventOccurredAfter(), StartDateTime::toDate)) + .setEventEndDate(applyIfNotNull(criteria.getEventOccurredBefore(), EndDateTime::toDate)) .setUserWithAssignedUsers(criteria.getAssignedUserMode(), user, assignedUserIds) .setTrackedEntityInstanceUids(trackedEntities) .setAttributes(attributeItems) diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/EndDateTime.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/EndDateTime.java new file mode 100644 index 000000000000..8a9a0c605830 --- /dev/null +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/EndDateTime.java @@ -0,0 +1,58 @@ +/* + * 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.webapi.webdomain; + +import java.util.Date; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.hisp.dhis.util.DateUtils; + +/** + * EndDateTime represents an upper limit date and time used to filter results in search APIs. + * + *

EndDateTime accepts any date and time in ISO8601 format. If no time is defined, then the time + * at the end of the day is used by default. + * + *

This behavior, combined with {@link StartDateTime}, allows to correctly implement an interval + * search including start and end dates. + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class EndDateTime { + private final Date date; + + public static EndDateTime of(String date) { + return new EndDateTime(DateUtils.parseDateEndOfTheDay(date)); + } + + public Date toDate() { + if (date == null) { + return null; + } + return new Date(date.getTime()); + } +} diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/StartDateTime.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/StartDateTime.java new file mode 100644 index 000000000000..4b52f917ba0a --- /dev/null +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/webdomain/StartDateTime.java @@ -0,0 +1,58 @@ +/* + * 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.webapi.webdomain; + +import java.util.Date; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.hisp.dhis.util.DateUtils; + +/** + * StartDateTime represents a lower limit date and time used to filter results in search APIs. + * + *

StartDateTime accepts any date and time in ISO8601 format. If no time is defined, then the + * time at the beginning of the day is used by default. + * + *

This behavior, combined with {@link EndDateTime}, allows to correctly implement an interval + * search including start and end dates. + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class StartDateTime { + private final Date date; + + public static StartDateTime of(String date) { + return new StartDateTime(DateUtils.parseDate(date)); + } + + public Date toDate() { + if (date == null) { + return null; + } + return new Date(date.getTime()); + } +} diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/DatesBindingTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/DatesBindingTest.java new file mode 100644 index 000000000000..d06a1d1f641c --- /dev/null +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/DatesBindingTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2004-2022, 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.webapi.controller; + +import static org.hisp.dhis.dxf2.webmessage.WebMessageUtils.ok; +import static org.hisp.dhis.util.ObjectUtils.applyIfNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Date; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hisp.dhis.dxf2.webmessage.WebMessage; +import org.hisp.dhis.util.DateUtils; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.stereotype.Controller; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +class DatesBindingTest { + private static final String ENDPOINT = "/binding"; + + private MockMvc mockMvc; + private Date actualStartDateTime; + private Date actualEndDateTime; + + @BeforeEach + public void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(new BindingController()).build(); + } + + @Test + void shouldReturnADateAtTheEndOfTheDayWhenAnEndDateIsPassedWithoutTime() throws Exception { + mockMvc.perform(get(ENDPOINT).param("end", "2001-06-17")).andExpect(status().isOk()); + + assertNull(actualStartDateTime); + assertEquals("2001-06-17T23:59:59.999", DateUtils.toLongDateWithMillis(actualEndDateTime)); + } + + @Test + void shouldReturnADateWithTimeWhenAnEndDateIsPassedWithTime() throws Exception { + mockMvc + .perform(get(ENDPOINT).param("end", "2001-06-17T16:45:34.324")) + .andExpect(status().isOk()); + + assertNull(actualStartDateTime); + assertEquals("2001-06-17T16:45:34.324", DateUtils.toLongDateWithMillis(actualEndDateTime)); + } + + @Test + void shouldReturnADateAtTheStartOfTheDayWhenAnStartDateIsPassedWithoutTime() throws Exception { + mockMvc.perform(get(ENDPOINT).param("start", "2001-06-17")).andExpect(status().isOk()); + + assertEquals("2001-06-17T00:00:00.000", DateUtils.toLongDateWithMillis(actualStartDateTime)); + assertNull(actualEndDateTime); + } + + @Test + void shouldReturnADateWithTimeWhenAnStartDateIsPassedWithTime() throws Exception { + mockMvc + .perform(get(ENDPOINT).param("start", "2001-06-17T16:45:34.324")) + .andExpect(status().isOk()); + + assertEquals("2001-06-17T16:45:34.324", DateUtils.toLongDateWithMillis(actualStartDateTime)); + assertNull(actualEndDateTime); + } + + @Controller + private class BindingController { + @GetMapping(value = ENDPOINT) + public @ResponseBody WebMessage getDefault(Params params) { + actualStartDateTime = applyIfNotNull(params.getStart(), StartDateTime::toDate); + actualEndDateTime = applyIfNotNull(params.getEnd(), EndDateTime::toDate); + return ok(); + } + } + + @NoArgsConstructor + @Data + private class Params { + private StartDateTime start; + + private EndDateTime end; + } +} diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java index f6c64559d514..faad4cee1608 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/OrderBindingTest.java @@ -58,10 +58,7 @@ class OrderBindingTest { @BeforeEach public void setUp() { - mockMvc = - MockMvcBuilders.standaloneSetup(new OrderingController()) - .setControllerAdvice(new CrudControllerAdvice()) - .build(); + mockMvc = MockMvcBuilders.standaloneSetup(new OrderingController()).build(); } @Test diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java index 4be723e2662d..cde43792bb6c 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/SpringBindingTest.java @@ -52,10 +52,7 @@ class SpringBindingTest { @BeforeEach public void setUp() { - mockMvc = - MockMvcBuilders.standaloneSetup(new BindingController()) - .setControllerAdvice(new CrudControllerAdvice()) - .build(); + mockMvc = MockMvcBuilders.standaloneSetup(new BindingController()).build(); } @Test diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapperTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapperTest.java index 5d6cfc35a645..2da0c7b74791 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapperTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerEventCriteriaMapperTest.java @@ -32,7 +32,6 @@ import static org.hisp.dhis.common.AccessLevel.PROTECTED; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ACCESSIBLE; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.SELECTED; -import static org.hisp.dhis.util.DateUtils.parseDate; import static org.hisp.dhis.utils.Assertions.assertContains; import static org.hisp.dhis.utils.Assertions.assertContainsOnly; import static org.hisp.dhis.utils.Assertions.assertIsEmpty; @@ -47,7 +46,6 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; @@ -87,6 +85,8 @@ import org.hisp.dhis.webapi.controller.event.mapper.OrderParam; import org.hisp.dhis.webapi.controller.event.mapper.SortDirection; import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -302,47 +302,47 @@ void shouldFailWithBadRequestExceptionWhenTrackedEntityDoesNotExist() { void testMappingOccurredAfterBefore() throws BadRequestException, ForbiddenException { TrackerEventCriteria criteria = new TrackerEventCriteria(); - Date occurredAfter = parseDate("2020-01-01"); + StartDateTime occurredAfter = StartDateTime.of("2020-01-01"); criteria.setOccurredAfter(occurredAfter); - Date occurredBefore = parseDate("2020-09-12"); + EndDateTime occurredBefore = EndDateTime.of("2020-09-12"); criteria.setOccurredBefore(occurredBefore); EventQueryParams params = mapper.map(criteria); - assertEquals(occurredAfter, params.getStartDate()); - assertEquals(occurredBefore, params.getEndDate()); + assertEquals(occurredAfter.toDate(), params.getStartDate()); + assertEquals(occurredBefore.toDate(), params.getEndDate()); } @Test void testMappingScheduledAfterBefore() throws BadRequestException, ForbiddenException { TrackerEventCriteria criteria = new TrackerEventCriteria(); - Date scheduledAfter = parseDate("2021-01-01"); + StartDateTime scheduledAfter = StartDateTime.of("2021-01-01"); criteria.setScheduledAfter(scheduledAfter); - Date scheduledBefore = parseDate("2021-09-12"); + EndDateTime scheduledBefore = EndDateTime.of("2021-09-12"); criteria.setScheduledBefore(scheduledBefore); EventQueryParams params = mapper.map(criteria); - assertEquals(scheduledAfter, params.getDueDateStart()); - assertEquals(scheduledBefore, params.getDueDateEnd()); + assertEquals(scheduledAfter.toDate(), params.getDueDateStart()); + assertEquals(scheduledBefore.toDate(), params.getDueDateEnd()); } @Test void testMappingUpdatedDates() throws BadRequestException, ForbiddenException { TrackerEventCriteria criteria = new TrackerEventCriteria(); - Date updatedAfter = parseDate("2022-01-01"); + StartDateTime updatedAfter = StartDateTime.of("2022-01-01"); criteria.setUpdatedAfter(updatedAfter); - Date updatedBefore = parseDate("2022-09-12"); + EndDateTime updatedBefore = EndDateTime.of("2022-09-12"); criteria.setUpdatedBefore(updatedBefore); String updatedWithin = "P6M"; criteria.setUpdatedWithin(updatedWithin); EventQueryParams params = mapper.map(criteria); - assertEquals(updatedAfter, params.getLastUpdatedStartDate()); - assertEquals(updatedBefore, params.getLastUpdatedEndDate()); + assertEquals(updatedAfter.toDate(), params.getLastUpdatedStartDate()); + assertEquals(updatedBefore.toDate(), params.getLastUpdatedEndDate()); assertEquals(updatedWithin, params.getLastUpdatedDuration()); } @@ -350,30 +350,30 @@ void testMappingUpdatedDates() throws BadRequestException, ForbiddenException { void testMappingEnrollmentEnrolledAtDates() throws BadRequestException, ForbiddenException { TrackerEventCriteria criteria = new TrackerEventCriteria(); - Date enrolledBefore = parseDate("2022-01-01"); + EndDateTime enrolledBefore = EndDateTime.of("2022-01-01"); criteria.setEnrollmentEnrolledBefore(enrolledBefore); - Date enrolledAfter = parseDate("2022-02-01"); + StartDateTime enrolledAfter = StartDateTime.of("2022-02-01"); criteria.setEnrollmentEnrolledAfter(enrolledAfter); EventQueryParams params = mapper.map(criteria); - assertEquals(enrolledBefore, params.getEnrollmentEnrolledBefore()); - assertEquals(enrolledAfter, params.getEnrollmentEnrolledAfter()); + assertEquals(enrolledBefore.toDate(), params.getEnrollmentEnrolledBefore()); + assertEquals(enrolledAfter.toDate(), params.getEnrollmentEnrolledAfter()); } @Test void testMappingEnrollmentOccurredAtDates() throws BadRequestException, ForbiddenException { TrackerEventCriteria criteria = new TrackerEventCriteria(); - Date enrolledBefore = parseDate("2022-01-01"); + EndDateTime enrolledBefore = EndDateTime.of("2022-01-01"); criteria.setEnrollmentOccurredBefore(enrolledBefore); - Date enrolledAfter = parseDate("2022-02-01"); + StartDateTime enrolledAfter = StartDateTime.of("2022-02-01"); criteria.setEnrollmentOccurredAfter(enrolledAfter); EventQueryParams params = mapper.map(criteria); - assertEquals(enrolledBefore, params.getEnrollmentOccurredBefore()); - assertEquals(enrolledAfter, params.getEnrollmentOccurredAfter()); + assertEquals(enrolledBefore.toDate(), params.getEnrollmentOccurredBefore()); + assertEquals(enrolledAfter.toDate(), params.getEnrollmentOccurredAfter()); } @Test diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapperTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapperTest.java index 7dc98a583252..83f1994566a1 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapperTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/export/TrackerTrackedEntityCriteriaMapperTest.java @@ -32,9 +32,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.containsString; -import static org.hisp.dhis.DhisConvenienceTest.getDate; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; -import static org.hisp.dhis.util.DateUtils.parseDate; import static org.hisp.dhis.utils.Assertions.assertContains; import static org.hisp.dhis.utils.Assertions.assertContainsOnly; import static org.hisp.dhis.utils.Assertions.assertIsEmpty; @@ -47,7 +45,6 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; @@ -80,6 +77,8 @@ import org.hisp.dhis.webapi.controller.event.mapper.OrderParam; import org.hisp.dhis.webapi.controller.event.mapper.SortDirection; import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria; +import org.hisp.dhis.webapi.webdomain.EndDateTime; +import org.hisp.dhis.webapi.webdomain.StartDateTime; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -201,15 +200,15 @@ void testMapping() throws BadRequestException, ForbiddenException { criteria.setOuMode(OrganisationUnitSelectionMode.DESCENDANTS); criteria.setProgramStatus(ProgramStatus.ACTIVE); criteria.setFollowUp(true); - criteria.setUpdatedAfter(getDate(2019, 1, 1)); - criteria.setUpdatedBefore(getDate(2020, 1, 1)); + criteria.setUpdatedAfter(StartDateTime.of("2019-01-01")); + criteria.setUpdatedBefore(EndDateTime.of("2020-01-01")); criteria.setUpdatedWithin("20"); - criteria.setEnrollmentOccurredAfter(getDate(2019, 5, 5)); - criteria.setEnrollmentOccurredBefore(getDate(2020, 5, 5)); + criteria.setEnrollmentOccurredAfter(StartDateTime.of("2019-05-05")); + criteria.setEnrollmentOccurredBefore(EndDateTime.of("2020-05-05")); criteria.setTrackedEntityType(TRACKED_ENTITY_TYPE_UID); criteria.setEventStatus(EventStatus.COMPLETED); - criteria.setEventOccurredAfter(getDate(2019, 7, 7)); - criteria.setEventOccurredBefore(getDate(2020, 7, 7)); + criteria.setEventOccurredAfter(StartDateTime.of("2019-07-07")); + criteria.setEventOccurredBefore(EndDateTime.of("2020-07-07")); criteria.setSkipMeta(true); criteria.setPage(1); criteria.setPageSize(50); @@ -229,13 +228,15 @@ void testMapping() throws BadRequestException, ForbiddenException { assertThat(params.isTotalPages(), is(false)); assertThat(params.getProgramStatus(), is(ProgramStatus.ACTIVE)); assertThat(params.getFollowUp(), is(true)); - assertThat(params.getLastUpdatedStartDate(), is(criteria.getUpdatedAfter())); - assertThat(params.getLastUpdatedEndDate(), is(criteria.getUpdatedBefore())); - assertThat(params.getProgramIncidentStartDate(), is(criteria.getEnrollmentOccurredAfter())); - assertThat(params.getProgramIncidentEndDate(), is(criteria.getEnrollmentOccurredBefore())); + assertThat(params.getLastUpdatedStartDate(), is(criteria.getUpdatedAfter().toDate())); + assertThat(params.getLastUpdatedEndDate(), is(criteria.getUpdatedBefore().toDate())); + assertThat( + params.getProgramIncidentStartDate(), is(criteria.getEnrollmentOccurredAfter().toDate())); + assertThat( + params.getProgramIncidentEndDate(), is(criteria.getEnrollmentOccurredBefore().toDate())); assertThat(params.getEventStatus(), is(EventStatus.COMPLETED)); - assertThat(params.getEventStartDate(), is(criteria.getEventOccurredAfter())); - assertThat(params.getEventEndDate(), is(criteria.getEventOccurredBefore())); + assertThat(params.getEventStartDate(), is(criteria.getEventOccurredAfter().toDate())); + assertThat(params.getEventEndDate(), is(criteria.getEventOccurredBefore().toDate())); assertThat( params.getAssignedUserQueryParam().getMode(), is(AssignedUserSelectionMode.PROVIDED)); assertThat(params.isIncludeDeleted(), is(true)); @@ -268,22 +269,22 @@ void testMappingDoesNotFetchOptionalEmptyQueryParametersFromDB() @Test void testMappingProgramEnrollmentStartDate() throws BadRequestException, ForbiddenException { - Date date = parseDate("2022-12-13"); + StartDateTime date = StartDateTime.of("2022-12-13"); criteria.setEnrollmentEnrolledAfter(date); TrackedEntityInstanceQueryParams params = mapper.map(criteria); - assertEquals(date, params.getProgramEnrollmentStartDate()); + assertEquals(date.toDate(), params.getProgramEnrollmentStartDate()); } @Test void testMappingProgramEnrollmentEndDate() throws BadRequestException, ForbiddenException { - Date date = parseDate("2022-12-13"); + EndDateTime date = EndDateTime.of("2022-12-13"); criteria.setEnrollmentEnrolledBefore(date); TrackedEntityInstanceQueryParams params = mapper.map(criteria); - assertEquals(date, params.getProgramEnrollmentEndDate()); + assertEquals(date.toDate(), params.getProgramEnrollmentEndDate()); } @Test