Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#13207 - [LUX] Automatic case processing for Pertussis cases #13230

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@
import org.slf4j.LoggerFactory;

import de.symeda.sormas.api.CountryHelper;
import de.symeda.sormas.api.Disease;
import de.symeda.sormas.api.caze.CaseClassification;
import de.symeda.sormas.api.caze.CaseDataDto;
import de.symeda.sormas.api.caze.CaseOutcome;
import de.symeda.sormas.api.caze.InvestigationStatus;
import de.symeda.sormas.api.externalmessage.ExternalMessageDto;
import de.symeda.sormas.api.feature.FeatureType;
import de.symeda.sormas.api.infrastructure.facility.FacilityDto;
import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto;
import de.symeda.sormas.api.infrastructure.facility.FacilityType;
import de.symeda.sormas.api.person.PersonDto;
import de.symeda.sormas.api.sample.PathogenTestResultType;
import de.symeda.sormas.api.sample.PathogenTestType;
import de.symeda.sormas.api.user.UserDto;
import de.symeda.sormas.api.utils.dataprocessing.EntitySelection;
import de.symeda.sormas.api.utils.dataprocessing.HandlerCallback;
Expand Down Expand Up @@ -175,6 +181,18 @@ protected CaseDataDto buildCase(PersonDto person, ExternalMessageDto externalMes
caseDto.setHealthFacility(processingFacade.getFacilityReferenceByUuid(FacilityDto.NONE_FACILITY_UUID));
}

if (processingFacade.isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)) {
if (externalMessageDto.getDisease().equals(Disease.PERTUSSIS)
&& externalMessageDto.getSampleReports().get(0).getTestReports().get(0).getTestResult().equals(PathogenTestResultType.POSITIVE)) {
PathogenTestType testType = externalMessageDto.getSampleReports().get(0).getTestReports().get(0).getTestType();
if (testType.equals(PathogenTestType.CULTURE) || testType.equals(PathogenTestType.PCR_RT_PCR)) {
caseDto.setCaseClassification(CaseClassification.CONFIRMED);
}
}
caseDto.setInvestigationStatus(InvestigationStatus.PENDING);
caseDto.setOutcome(CaseOutcome.NO_OUTCOME);
}

caseDto.setVaccinationStatus(externalMessageDto.getVaccinationStatus());
caseDto.getHospitalization().setAdmittedToHealthFacility(externalMessageDto.getAdmittedToHealthFacility());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;

import java.util.Collections;
import java.util.Date;
Expand All @@ -31,8 +32,11 @@
import org.junit.jupiter.api.Test;

import de.symeda.sormas.api.Disease;
import de.symeda.sormas.api.caze.CaseClassification;
import de.symeda.sormas.api.caze.CaseCriteria;
import de.symeda.sormas.api.caze.CaseDataDto;
import de.symeda.sormas.api.caze.CaseOutcome;
import de.symeda.sormas.api.caze.InvestigationStatus;
import de.symeda.sormas.api.externalmessage.ExternalMessageDto;
import de.symeda.sormas.api.externalmessage.ExternalMessageStatus;
import de.symeda.sormas.api.externalmessage.ExternalMessageType;
Expand All @@ -58,7 +62,9 @@
import de.symeda.sormas.api.utils.DateHelper;
import de.symeda.sormas.api.utils.dataprocessing.ProcessingResult;
import de.symeda.sormas.backend.AbstractBeanTest;
import de.symeda.sormas.backend.MockProducer;
import de.symeda.sormas.backend.TestDataCreator;
import de.symeda.sormas.backend.common.ConfigFacadeEjb;
import de.symeda.sormas.backend.disease.DiseaseConfigurationFacadeEjb;

public class AutomaticLabMessageProcessorTest extends AbstractBeanTest {
Expand Down Expand Up @@ -217,6 +223,7 @@ public void testProcessWithExistingPersonAndCase() throws ExecutionException, In

/**
* External message with sample date in the threshold period should generate a new sample to the existing case
*
* @throws ExecutionException
* @throws InterruptedException
*/
Expand Down Expand Up @@ -410,6 +417,84 @@ public void testProcessMessageWithNoNationalHealthId() throws ExecutionException
assertThat(pathogenTests, hasSize(1));
}

@Test
public void testProcessPertussisMessageTestTypeCulture() throws ExecutionException, InterruptedException {
MockProducer.getProperties().setProperty(ConfigFacadeEjb.COUNTRY_LOCALE, "lu");
ExternalMessageDto cultureMessage = createExternalMessage((messageDto) -> {
messageDto.setDisease(Disease.PERTUSSIS);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestType(PathogenTestType.CULTURE);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestResult(PathogenTestResultType.POSITIVE);
});
ProcessingResult<ExternalMessageProcessingResult> result = runFlow(cultureMessage);
assertThat(result.getStatus(), is(DONE));
assertThat(cultureMessage.getStatus(), is(ExternalMessageStatus.PROCESSED));
assertThat(getExternalMessageFacade().getByUuid(cultureMessage.getUuid()).getStatus(), is(ExternalMessageStatus.PROCESSED));
CaseDataDto positiveCase = getCaseData();
assertThat(positiveCase, is(notNullValue()));
assertThat(positiveCase.getDisease(), is(cultureMessage.getDisease()));
assertThat(positiveCase.getCaseClassification(), is(CaseClassification.CONFIRMED));
assertThat(positiveCase.getInvestigationStatus(), is(InvestigationStatus.PENDING));
assertThat(positiveCase.getOutcome(), is(CaseOutcome.NO_OUTCOME));
}

@Test
public void testProcessPertussisTestTypePCR() throws ExecutionException, InterruptedException {
MockProducer.getProperties().setProperty(ConfigFacadeEjb.COUNTRY_LOCALE, "lu");
ExternalMessageDto pcrMessage = createExternalMessage((messageDto) -> {
messageDto.setDisease(Disease.PERTUSSIS);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestType(PathogenTestType.PCR_RT_PCR);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestResult(PathogenTestResultType.POSITIVE);
});
runFlow(pcrMessage);
assertThat(pcrMessage.getStatus(), is(ExternalMessageStatus.PROCESSED));
CaseDataDto pcrCase = getCaseData();
assertThat(pcrCase, is(notNullValue()));
assertThat(pcrCase.getDisease(), is(pcrMessage.getDisease()));
assertThat(pcrCase.getCaseClassification(), is(CaseClassification.CONFIRMED));
assertThat(pcrCase.getInvestigationStatus(), is(InvestigationStatus.PENDING));
assertThat(pcrCase.getOutcome(), is(CaseOutcome.NO_OUTCOME));
}

@Test
public void testProcessPertussisTestNegativeResult() throws ExecutionException, InterruptedException {
ExternalMessageDto negativeMessage = createExternalMessage((messageDto) -> {
messageDto.setDisease(Disease.PERTUSSIS);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestType(PathogenTestType.CULTURE);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestResult(PathogenTestResultType.NEGATIVE);
});
runFlow(negativeMessage);
assertThat(negativeMessage.getStatus(), is(ExternalMessageStatus.PROCESSED));
CaseDataDto negativeCase = getCaseData();
assertThat(negativeCase, is(notNullValue()));
assertThat(negativeCase.getDisease(), is(negativeMessage.getDisease()));
assertThat(negativeCase.getCaseClassification(), is(CaseClassification.NOT_CLASSIFIED));
assertThat(negativeCase.getInvestigationStatus(), is(InvestigationStatus.PENDING));
assertThat(negativeCase.getOutcome(), is(CaseOutcome.NO_OUTCOME));
}

@Test
public void testProcessPertussisOtherTestType() throws ExecutionException, InterruptedException {
ExternalMessageDto rapidTestMessage = createExternalMessage((messageDto) -> {
messageDto.setDisease(Disease.PERTUSSIS);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestType(PathogenTestType.RAPID_TEST);
messageDto.getSampleReports().get(0).getTestReports().get(0).setTestResult(PathogenTestResultType.POSITIVE);
});
runFlow(rapidTestMessage);
assertThat(rapidTestMessage.getStatus(), is(ExternalMessageStatus.PROCESSED));
CaseDataDto rapidTestcase = getCaseData();
assertThat(rapidTestcase, is(notNullValue()));
assertThat(rapidTestcase.getDisease(), is(rapidTestMessage.getDisease()));
assertThat(rapidTestcase.getCaseClassification(), is(CaseClassification.NOT_CLASSIFIED));
assertThat(rapidTestcase.getInvestigationStatus(), is(InvestigationStatus.PENDING));
assertThat(rapidTestcase.getOutcome(), is(CaseOutcome.NO_OUTCOME));
}

private CaseDataDto getCaseData() {
List<PersonDto> persons = getPersonFacade().getAllAfter(new Date(0));
List<CaseDataDto> cases = getCaseFacade().getByPersonUuids(persons.stream().map(PersonDto::getUuid).collect(Collectors.toList()));
return cases.get(0);
}

private ProcessingResult<ExternalMessageProcessingResult> runFlow(ExternalMessageDto labMessage) throws ExecutionException, InterruptedException {

return flow.processLabMessage(labMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import de.symeda.sormas.api.caze.CaseOutcome;
import de.symeda.sormas.backend.MockProducer;
import de.symeda.sormas.backend.common.ConfigFacadeEjb;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -2816,6 +2819,196 @@ public void testCaseSurveillanceReportUnknownFacility() throws ExecutionExceptio
assertThat(surveillanceReport.getFacilityDistrict(), is(nullValue()));
}

@Test
public void testCreateCaseWithPertusisTestTypeCultureForLuServers() throws ExecutionException, InterruptedException {
MockProducer.getProperties().setProperty(ConfigFacadeEjb.COUNTRY_LOCALE, "lu");
ArgumentCaptor<PersonDto> personCaptor = ArgumentCaptor.forClass(PersonDto.class);
doAnswer(invocation -> {
HandlerCallback<EntitySelection<PersonDto>> callback = invocation.getArgument(1);
PersonDto person = invocation.getArgument(0);

getPersonFacade().save(person);

callback.done(new EntitySelection<>(person, true));

return null;

}).when(handlePickOrCreatePerson).apply(personCaptor.capture(), any());

PickOrCreateEntryResult pickOrCreateEntryResult = new PickOrCreateEntryResult();
pickOrCreateEntryResult.setNewCase(true);
doAnswer(answerPickOrCreateEntry(pickOrCreateEntryResult)).when(handlePickOrCreateEntry).handle(any(), any(), any(), any());

ArgumentCaptor<CaseDataDto> caseCaptor = ArgumentCaptor.forClass(CaseDataDto.class);
doAnswer((invocation) -> {
CaseDataDto caze = invocation.getArgument(0);
caze.setResponsibleRegion(rdcf.region);
caze.setResponsibleDistrict(rdcf.district);
caze.setFacilityType(FacilityType.HOSPITAL);
caze.setHealthFacility(rdcf.facility);
getCaseFacade().save(caze);
getCallbackParam(invocation).done(caze);
return null;
}).when(handleCreateCase).handle(caseCaptor.capture(), any(), any());

doAnswer((invocation) -> {
SampleDto sample = invocation.getArgument(0);
sample.setSamplingReason(SamplingReason.PROFESSIONAL_REASON);

List<PathogenTestDto> pathogenTests = invocation.getArgument(1);
pathogenTests.get(0).setTestResultText("Dummy test result text");

getCallbackParam(invocation).done(new SampleAndPathogenTests(sample, pathogenTests));
return null;
}).when(handleCreateSampleAndPathogenTests).handle(any(), any(), any(), eq(true), any());

SampleReportDto sampleReport = SampleReportDto.build();
ExternalMessageDto labMessage = createLabMessage(Disease.PERTUSSIS, "test-report-id", ExternalMessageStatus.UNPROCESSED);
labMessage.addSampleReport(sampleReport);
sampleReport.setSampleDateTime(new Date());
sampleReport.setSampleMaterial(SampleMaterial.BLOOD);

TestReportDto testReport1 = TestReportDto.build();
testReport1.setTestType(PathogenTestType.CULTURE);
testReport1.setTestResult(PathogenTestResultType.POSITIVE);
sampleReport.addTestReport(testReport1);

ProcessingResult<ExternalMessageProcessingResult> result = runFlow(labMessage);

assertThat(result.getStatus(), is(DONE));
assertThat(getExternalMessageFacade().getByUuid(labMessage.getUuid()).getStatus(), is(ExternalMessageStatus.PROCESSED));
assertThat(getSurveillanceReportFacade().getByCaseUuids(Collections.singletonList(result.getData().getCase().getUuid())), hasSize(1));

verify(handleCreateSampleAndPathogenTests).handle(argThat(sample -> {
assertThat(sample.getAssociatedCase(), is(caseCaptor.getValue().toReference()));
assertThat(sample.getSampleDateTime(), is(labMessage.getSampleReports().get(0).getSampleDateTime()));
assertThat(sample.getSampleMaterial(), is(SampleMaterial.BLOOD));
assertThat(sample.getReportingUser(), is(user.toReference()));

return true;
}), argThat(pathogenTests -> {
assertThat(pathogenTests, hasSize(1));

assertThat(pathogenTests.get(0).getTestType(), is(testReport1.getTestType()));
assertThat(pathogenTests.get(0).getTestResult(), is(testReport1.getTestResult()));

return true;
}), argThat(entityCreated -> {
assertThat(entityCreated, is(true));

return true;
}), argThat(lastSample -> {
assertThat(lastSample, is(Boolean.TRUE));

return true;
}), any());

verify(handleCreateCase).handle(argThat(c -> {
assertThat(c.getPerson(), is(personCaptor.getValue().toReference()));
assertThat(c.getDisease(), is(Disease.PERTUSSIS));
assertThat(c.getCaseClassification(), is(CaseClassification.CONFIRMED));
assertThat(c.getInvestigationStatus(), is(InvestigationStatus.PENDING));
assertThat(c.getOutcome(), is(CaseOutcome.NO_OUTCOME));
assertThat(c.getReportingUser(), is(user.toReference()));
return true;
}), argThat(p -> p.equals(personCaptor.getValue())), any());
}

@Test
public void testCreateCaseWithPertusisOtherTestTypeForLuServers() throws ExecutionException, InterruptedException {
MockProducer.getProperties().setProperty(ConfigFacadeEjb.COUNTRY_LOCALE, "lu");
ArgumentCaptor<PersonDto> personCaptor = ArgumentCaptor.forClass(PersonDto.class);
doAnswer(invocation -> {
HandlerCallback<EntitySelection<PersonDto>> callback = invocation.getArgument(1);
PersonDto person = invocation.getArgument(0);

getPersonFacade().save(person);

callback.done(new EntitySelection<>(person, true));

return null;

}).when(handlePickOrCreatePerson).apply(personCaptor.capture(), any());

PickOrCreateEntryResult pickOrCreateEntryResult = new PickOrCreateEntryResult();
pickOrCreateEntryResult.setNewCase(true);
doAnswer(answerPickOrCreateEntry(pickOrCreateEntryResult)).when(handlePickOrCreateEntry).handle(any(), any(), any(), any());

ArgumentCaptor<CaseDataDto> caseCaptor = ArgumentCaptor.forClass(CaseDataDto.class);
doAnswer((invocation) -> {
CaseDataDto caze = invocation.getArgument(0);
caze.setResponsibleRegion(rdcf.region);
caze.setResponsibleDistrict(rdcf.district);
caze.setFacilityType(FacilityType.HOSPITAL);
caze.setHealthFacility(rdcf.facility);
getCaseFacade().save(caze);
getCallbackParam(invocation).done(caze);
return null;
}).when(handleCreateCase).handle(caseCaptor.capture(), any(), any());

doAnswer((invocation) -> {
SampleDto sample = invocation.getArgument(0);
sample.setSamplingReason(SamplingReason.PROFESSIONAL_REASON);

List<PathogenTestDto> pathogenTests = invocation.getArgument(1);
pathogenTests.get(0).setTestResultText("Dummy test result text");

getCallbackParam(invocation).done(new SampleAndPathogenTests(sample, pathogenTests));
return null;
}).when(handleCreateSampleAndPathogenTests).handle(any(), any(), any(), eq(true), any());

SampleReportDto sampleReport = SampleReportDto.build();
ExternalMessageDto labMessage = createLabMessage(Disease.PERTUSSIS, "test-report-id", ExternalMessageStatus.UNPROCESSED);
labMessage.addSampleReport(sampleReport);
sampleReport.setSampleDateTime(new Date());
sampleReport.setSampleMaterial(SampleMaterial.BLOOD);

TestReportDto testReport1 = TestReportDto.build();
testReport1.setTestType(PathogenTestType.RAPID_TEST);
testReport1.setTestResult(PathogenTestResultType.POSITIVE);
sampleReport.addTestReport(testReport1);

ProcessingResult<ExternalMessageProcessingResult> result = runFlow(labMessage);

assertThat(result.getStatus(), is(DONE));
assertThat(getExternalMessageFacade().getByUuid(labMessage.getUuid()).getStatus(), is(ExternalMessageStatus.PROCESSED));
assertThat(getSurveillanceReportFacade().getByCaseUuids(Collections.singletonList(result.getData().getCase().getUuid())), hasSize(1));

verify(handleCreateSampleAndPathogenTests).handle(argThat(sample -> {
assertThat(sample.getAssociatedCase(), is(caseCaptor.getValue().toReference()));
assertThat(sample.getSampleDateTime(), is(labMessage.getSampleReports().get(0).getSampleDateTime()));
assertThat(sample.getSampleMaterial(), is(SampleMaterial.BLOOD));
assertThat(sample.getReportingUser(), is(user.toReference()));

return true;
}), argThat(pathogenTests -> {
assertThat(pathogenTests, hasSize(1));

assertThat(pathogenTests.get(0).getTestType(), is(testReport1.getTestType()));
assertThat(pathogenTests.get(0).getTestResult(), is(testReport1.getTestResult()));

return true;
}), argThat(entityCreated -> {
assertThat(entityCreated, is(true));

return true;
}), argThat(lastSample -> {
assertThat(lastSample, is(Boolean.TRUE));

return true;
}), any());

verify(handleCreateCase).handle(argThat(c -> {
assertThat(c.getPerson(), is(personCaptor.getValue().toReference()));
assertThat(c.getDisease(), is(Disease.PERTUSSIS));
assertThat(c.getCaseClassification(), is(CaseClassification.NOT_CLASSIFIED));
assertThat(c.getInvestigationStatus(), is(InvestigationStatus.PENDING));
assertThat(c.getOutcome(), is(CaseOutcome.NO_OUTCOME));
assertThat(c.getReportingUser(), is(user.toReference()));
return true;
}), argThat(p -> p.equals(personCaptor.getValue())), any());
}

private ProcessingResult<ExternalMessageProcessingResult> runFlow(ExternalMessageDto labMessage) throws ExecutionException, InterruptedException {
ExternalMessageProcessingFacade processingFacade = getExternalMessageProcessingFacade();
AbstractLabMessageProcessingFlow flow = new AbstractLabMessageProcessingFlow(
Expand Down
Loading