diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index ebcd4065d2e..f2438dcb32b 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -31,6 +31,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import javax.annotation.Nullable; import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; @@ -2345,7 +2346,9 @@ protected String getDeleteReferenceField(DeletionReference deletionReference) { return super.getDeleteReferenceField(deletionReference); } - public String getCaseUuidForAutomaticSampleAssignment(Set uuids, Disease disease, int threshold) { + public String getCaseUuidForAutomaticSampleAssignment(Set uuids, Disease disease, @Nullable Date sampleDateTime, int threshold) { + Date dateToCompareTo = sampleDateTime != null ? sampleDateTime : new Date(); + CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(String.class); Root caseRoot = cq.from(Case.class); @@ -2366,7 +2369,7 @@ public String getCaseUuidForAutomaticSampleAssignment(Set uuids, Disease ExtendedPostgreSQL94Dialect.DATE, Date.class, CriteriaBuilderHelper.coalesce(cb, Date.class, earliestSampleSq, caseRoot.get(Case.REPORT_DATE))), - cb.function(ExtendedPostgreSQL94Dialect.DATE, Date.class, cb.literal(new Date()))), + cb.function(ExtendedPostgreSQL94Dialect.DATE, Date.class, cb.literal(dateToCompareTo))), Long.valueOf(TimeUnit.DAYS.toSeconds(threshold)).doubleValue())); cq.orderBy(cb.desc(caseRoot.get(Case.REPORT_DATE))); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java index f660bce1805..763177459f2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessor.java @@ -16,7 +16,10 @@ package de.symeda.sormas.backend.externalmessage.labmessage; import java.text.Collator; +import java.util.Comparator; +import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -43,6 +46,7 @@ import de.symeda.sormas.api.event.EventParticipantDto; import de.symeda.sormas.api.event.SimilarEventParticipantDto; import de.symeda.sormas.api.externalmessage.ExternalMessageDto; +import de.symeda.sormas.api.externalmessage.labmessage.SampleReportDto; import de.symeda.sormas.api.externalmessage.processing.ExternalMessageMapper; import de.symeda.sormas.api.externalmessage.processing.ExternalMessageProcessingFacade; import de.symeda.sormas.api.externalmessage.processing.ExternalMessageProcessingResult; @@ -183,7 +187,14 @@ protected void handlePickOrCreateEntry( } Set similarCaseUuids = similarCases.stream().map(CaseSelectionDto::getUuid).collect(Collectors.toSet()); - String caseUuid = caseService.getCaseUuidForAutomaticSampleAssignment(similarCaseUuids, disease, automaticSampleAssignmentThreshold); + Date sampleDate = externalMessageDto.getSampleReports() + .stream() + .map(SampleReportDto::getSampleDateTime) + .filter(Objects::nonNull) + .min(Comparator.comparing(Date::getTime)) + .orElse(null); + String caseUuid = + caseService.getCaseUuidForAutomaticSampleAssignment(similarCaseUuids, disease, sampleDate, automaticSampleAssignmentThreshold); if (caseUuid == null) { logger.debug( diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java index e3e22f325c7..85da716cf6f 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/externalmessage/labmessage/AutomaticLabMessageProcessorTest.java @@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.CaseCriteria; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.externalmessage.ExternalMessageDto; import de.symeda.sormas.api.externalmessage.ExternalMessageStatus; @@ -46,6 +47,7 @@ import de.symeda.sormas.api.sample.PathogenTestDto; import de.symeda.sormas.api.sample.PathogenTestResultType; import de.symeda.sormas.api.sample.PathogenTestType; +import de.symeda.sormas.api.sample.SampleCriteria; import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SamplePurpose; @@ -213,6 +215,42 @@ public void testProcessWithExistingPersonAndCase() throws ExecutionException, In assertThat(samples, hasSize(2)); } + /** + * External message with sample date in the threshold period should generate a new sample to the existing case + * @throws ExecutionException + * @throws InterruptedException + */ + @Test + public void testThresholdAgainstSampleDate() throws ExecutionException, InterruptedException { + ExternalMessageDto externalMessage = createExternalMessage(e -> { + e.getSampleReports().get(0).setSampleDateTime(DateHelper.subtractDays(new Date(), 10)); + }); + + PersonDto person = + creator.createPerson(externalMessage.getPersonFirstName(), externalMessage.getPersonLastName(), externalMessage.getPersonSex(), p -> { + p.setNationalHealthId(externalMessage.getPersonNationalHealthId()); + }); + + CaseDataDto caze = creator.createCase(reportingUser.toReference(), person.toReference(), rdcf, c -> { + c.setDisease(externalMessage.getDisease()); + c.setReportDate(DateHelper.subtractDays(new Date(), 15)); + }); + creator.createSample(caze.toReference(), reportingUser.toReference(), rdcf.facility, s -> { + s.setSampleDateTime(DateHelper.subtractDays(new Date(), 15)); + }); + + // set the threshold + creator.updateDiseaseConfiguration(externalMessage.getDisease(), true, true, true, true, null, 10); + getBean(DiseaseConfigurationFacadeEjb.DiseaseConfigurationFacadeEjbLocal.class).loadData(); + + ProcessingResult result = runFlow(externalMessage); + assertThat(result.getStatus(), is(DONE)); + assertThat(externalMessage.getStatus(), is(ExternalMessageStatus.PROCESSED)); + + assertThat(getCaseFacade().count(new CaseCriteria().person(caze.getPerson())), is(1L)); + assertThat(getSampleFacade().count(new SampleCriteria().caze(caze.toReference())), is(2L)); + } + @Test public void testProcessWithExistingPersonAndCaseWithBySampleDate() throws ExecutionException, InterruptedException { ExternalMessageDto externalMessage = createExternalMessage(null);