diff --git a/.dockerignore b/.dockerignore index 650a1be3..782f0ace 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,4 @@ !src !*.gradle !gradle.properties +!lombok.config diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsPatientMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsPatientMapper.java index d89ccb26..8b3e2436 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsPatientMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsPatientMapper.java @@ -32,6 +32,7 @@ public ObdsPatientMapper(FhirProperties fhirProperties) { public Bundle mapOnkoResourcesToPatient(List meldungExportList) { if (meldungExportList.isEmpty()) { + LOG.warn("Cannot map empty list of MeldungExport to {}", ResourceType.Patient); return null; } @@ -39,7 +40,10 @@ public Bundle mapOnkoResourcesToPatient(List meldungExportList) { var meldungExport = meldungExportList.get(0); LOG.debug( - "Mapping Meldung {} to {}", getReportingIdFromAdt(meldungExport), ResourceType.Patient); + "Mapping Meldung {} (one of total {} in export list) to {}", + getReportingIdFromAdt(meldungExport), + meldungExportList.size(), + ResourceType.Patient); var patient = new Patient(); @@ -82,15 +86,12 @@ public Bundle mapOnkoResourcesToPatient(List meldungExportList) { meldungExport.getXml_daten().getMenge_Patient().getPatient().getPatienten_Stammdaten(); // gender - var genderMap = - new HashMap() { - { - put("W", Enumerations.AdministrativeGender.FEMALE); - put("M", Enumerations.AdministrativeGender.MALE); - put("D", Enumerations.AdministrativeGender.OTHER); // TODO set genderExtension - put("U", Enumerations.AdministrativeGender.UNKNOWN); - } - }; + // TODO set genderExtension if AdministrativeGender.OTHER + var genderMap = new HashMap(); + genderMap.put("W", Enumerations.AdministrativeGender.FEMALE); + genderMap.put("M", Enumerations.AdministrativeGender.MALE); + genderMap.put("D", Enumerations.AdministrativeGender.OTHER); + genderMap.put("U", Enumerations.AdministrativeGender.UNKNOWN); patient.setGender(genderMap.getOrDefault(patData.getPatienten_Geschlecht(), null)); @@ -99,33 +100,66 @@ public Bundle mapOnkoResourcesToPatient(List meldungExportList) { new DateType(getBirthDateYearMonthString(patData.getPatienten_Geburtsdatum()))); } - var reportingReason = - meldungExport - .getXml_daten() - .getMenge_Patient() - .getPatient() - .getMenge_Meldung() - .getMeldung() - .getMeldeanlass(); + // check if any one of the meldungen reported the death + var deathReports = + meldungExportList.stream() + .filter(m -> getReportingReasonFromAdt(m) == Meldeanlass.TOD) + .toList(); // deceased - if (reportingReason == Meldeanlass.TOD) { - var mengeVerlauf = - meldungExport - .getXml_daten() - .getMenge_Patient() - .getPatient() - .getMenge_Meldung() - .getMeldung() - .getMenge_Verlauf(); - - if (mengeVerlauf != null && mengeVerlauf.getVerlauf() != null) { - - var death = mengeVerlauf.getVerlauf().getTod(); - - if (death.getSterbedatum() != null) { - patient.setDeceased(convertObdsDateToDateTimeType(death.getSterbedatum())); - } + if (!deathReports.isEmpty()) { + // start by setting deceased to true. If a more detailed death date is + // available in the data, override it further down this code path. + patient.setDeceased(new BooleanType(true)); + + // get the first entry with the largest version number where the death date is set + var reportWithSterbeDatum = + deathReports.stream() + .sorted(Comparator.comparingInt(MeldungExport::getVersionsnummer).reversed()) + .filter( + m -> { + var mengeVerlauf = + m.getXml_daten() + .getMenge_Patient() + .getPatient() + .getMenge_Meldung() + .getMeldung() + .getMenge_Verlauf(); + + if (mengeVerlauf == null) { + return false; + } + + if (mengeVerlauf.getVerlauf() == null) { + return false; + } + + if (mengeVerlauf.getVerlauf().getTod() == null) { + return false; + } + + return StringUtils.hasLength( + mengeVerlauf.getVerlauf().getTod().getSterbedatum()); + }) + .findFirst(); + + if (reportWithSterbeDatum.isPresent()) { + var deathDate = + reportWithSterbeDatum + .get() + .getXml_daten() + .getMenge_Patient() + .getPatient() + .getMenge_Meldung() + .getMeldung() + .getMenge_Verlauf() + .getVerlauf() + .getTod() + .getSterbedatum(); + + patient.setDeceased(convertObdsDateToDateTimeType(deathDate)); + } else { + LOG.warn("Sterbedatum not set on any of the Tod Meldungen."); } } diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapper.java index bf023d1b..9a108e79 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapper.java @@ -99,9 +99,6 @@ public static List prioritiseLatestMeldungExports( return index == -1 ? Integer.MAX_VALUE : index; }); - // TODO: do this in-place sort instead: - // meldungExportList.sort(meldungComparator); - return meldungExportList.stream().sorted(meldungComparator).collect(Collectors.toList()); } diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessor.java b/src/main/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessor.java index e83ea7b8..5d43dee1 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessor.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessor.java @@ -166,19 +166,8 @@ public ValueMapper getOnkoToObservationBundleMapper() } public ValueMapper getOnkoToPatientBundleMapper() { - return meldungExporte -> { - List meldungExportList = - prioritiseLatestMeldungExports( - meldungExporte, - Arrays.asList( - Meldeanlass.TOD, - Meldeanlass.BEHANDLUNGSENDE, - Meldeanlass.STATUSAENDERUNG, - Meldeanlass.DIAGNOSE), - null); - - return onkoPatientMapper.mapOnkoResourcesToPatient(meldungExportList); - }; + return meldungExporte -> + onkoPatientMapper.mapOnkoResourcesToPatient(meldungExporte.getElements()); } public ValueMapper, Bundle> getOnkoToConditionBundleMapper() { diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapperTests.java b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapperTests.java index 6e73d552..8b018282 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapperTests.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsToFhirMapperTests.java @@ -59,13 +59,15 @@ void extractDateTimeFromADTDate_withGivenObdsDate_shouldConvertToExpectedFhirDat @Test void prioritiseLatestMeldungExports_withSamePrioriyOrderUsedForMappingThePatientResource_shouldHandleMultipleDeathReports() { + var expectedFirstDeathMeldung = createMeldungExport("3", 5, Meldeanlass.TOD); + var meldungExports = new MeldungExportList(); meldungExports.addElement(createMeldungExport("0", 1, Meldeanlass.DIAGNOSE)); meldungExports.addElement(createMeldungExport("1", 1, Meldeanlass.BEHANDLUNGSBEGINN)); meldungExports.addElement(createMeldungExport("2", 1, Meldeanlass.BEHANDLUNGSENDE)); meldungExports.addElement(createMeldungExport("3", 1, Meldeanlass.TOD)); meldungExports.addElement(createMeldungExport("4", 3, Meldeanlass.BEHANDLUNGSBEGINN)); - meldungExports.addElement(createMeldungExport("3", 5, Meldeanlass.TOD)); + meldungExports.addElement(expectedFirstDeathMeldung); meldungExports.addElement(createMeldungExport("6", 7, Meldeanlass.BEHANDLUNGSENDE)); meldungExports.addElement(createMeldungExport("0", 2, Meldeanlass.DIAGNOSE)); meldungExports.addElement(createMeldungExport("3", 3, Meldeanlass.TOD)); @@ -80,6 +82,6 @@ void extractDateTimeFromADTDate_withGivenObdsDate_shouldConvertToExpectedFhirDat Meldeanlass.DIAGNOSE), null); - assertThat(prioritised).isNotEmpty(); + assertThat(prioritised).first().isEqualTo(expectedFirstDeathMeldung); } } diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsPatientMapperTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsPatientMapperTest.java index b8419b8b..223bdf96 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsPatientMapperTest.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsPatientMapperTest.java @@ -7,6 +7,7 @@ import java.util.stream.Stream; import org.approvaltests.Approvals; import org.hl7.fhir.r4.model.Patient; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -14,6 +15,7 @@ import org.junit.jupiter.params.provider.ValueSource; import org.miracum.streams.ume.obdstofhir.mapper.*; import org.miracum.streams.ume.obdstofhir.model.ADT_GEKID; +import org.miracum.streams.ume.obdstofhir.model.Meldeanlass; import org.miracum.streams.ume.obdstofhir.model.MeldungExport; import org.miracum.streams.ume.obdstofhir.model.MeldungExportList; import org.miracum.streams.ume.obdstofhir.model.Tupel; @@ -28,7 +30,7 @@ public ObdsPatientMapperTest(ObdsPatientMapper onkoPatientMapper) { this.onkoPatientMapper = onkoPatientMapper; } - private static MeldungExportList createMeldungExportListFromPLZ(String plz) { + private static MeldungExport createMeldungExportFromPLZ(String plz) { // TODO: we might want to introduce more concise builder patterns var meldung = new ADT_GEKID.Menge_Patient.Patient.Menge_Meldung.Meldung(); meldung.setMeldung_ID("id-" + plz); @@ -62,6 +64,17 @@ private static MeldungExportList createMeldungExportListFromPLZ(String plz) { var meldungExport = new MeldungExport(); meldungExport.setXml_daten(obdsData); + return meldungExport; + } + + private static MeldungExportList createMeldungExportListFromPLZ(String plz) { + var meldungExport = createMeldungExportFromPLZ(plz); + + return createMeldungExportListFromMeldungExport(meldungExport); + } + + private static MeldungExportList createMeldungExportListFromMeldungExport( + MeldungExport meldungExport) { var meldungExportList = new MeldungExportList(); meldungExportList.addElement(meldungExport); @@ -126,4 +139,86 @@ void mapOnkoResourcesToPatient_withMeldungExportWithInvalidPLZ_shouldCreateNotFi assertThat(patient.getAddress()).isEmpty(); } + + @Test + void + mapOnkoResourcesToPatient_withMeldungExportListWithMultipleDeathReports_shouldSetDeathDateFromMostRecentReport() + throws IOException { + var meldungExportList = new MeldungExportList(); + for (int i = 1; i < 6; i++) { + var tod = + new ADT_GEKID.Menge_Patient.Patient.Menge_Meldung.Meldung.Menge_Verlauf.Verlauf.Tod(); + tod.setSterbedatum(String.format("%02d.%02d.2%03d", i, i, i)); + var verlauf = + new ADT_GEKID.Menge_Patient.Patient.Menge_Meldung.Meldung.Menge_Verlauf.Verlauf(); + verlauf.setTod(tod); + var mengeVerlauf = new ADT_GEKID.Menge_Patient.Patient.Menge_Meldung.Meldung.Menge_Verlauf(); + mengeVerlauf.setVerlauf(verlauf); + var meldungExport = createMeldungExportFromPLZ("" + i); + meldungExport.setVersionsnummer(i); + meldungExport + .getXml_daten() + .getMenge_Patient() + .getPatient() + .getMenge_Meldung() + .getMeldung() + // set death only for even "i"s for more realistic testing. + .setMeldeanlass(i % 2 == 0 ? Meldeanlass.TOD : Meldeanlass.DIAGNOSE); + meldungExport + .getXml_daten() + .getMenge_Patient() + .getPatient() + .getMenge_Meldung() + .getMeldung() + .setMenge_Verlauf(mengeVerlauf); + + meldungExportList.addElement(meldungExport); + } + + var resultBundle = onkoPatientMapper.mapOnkoResourcesToPatient(meldungExportList.getElements()); + + assertThat(resultBundle.getEntry()).hasSize(1); + + var patient = (Patient) resultBundle.getEntry().get(0).getResource(); + + assertThat(patient.getDeceasedDateTimeType().asStringValue()).isEqualTo("2004-04-04"); + } + + @Test + void mapOnkoResourcesToPatient_withMeldungExportListWithoutDeathDate_shouldSetDeathBooleanToTrue() + throws IOException { + var tod = new ADT_GEKID.Menge_Patient.Patient.Menge_Meldung.Meldung.Menge_Verlauf.Verlauf.Tod(); + var verlauf = new ADT_GEKID.Menge_Patient.Patient.Menge_Meldung.Meldung.Menge_Verlauf.Verlauf(); + verlauf.setTod(tod); + var mengeVerlauf = new ADT_GEKID.Menge_Patient.Patient.Menge_Meldung.Meldung.Menge_Verlauf(); + mengeVerlauf.setVerlauf(verlauf); + var meldungExport = createMeldungExportFromPLZ("" + 0); + meldungExport.setVersionsnummer(0); + meldungExport + .getXml_daten() + .getMenge_Patient() + .getPatient() + .getMenge_Meldung() + .getMeldung() + // set death only for even "i"s for more realistic testing. + .setMeldeanlass(Meldeanlass.TOD); + meldungExport + .getXml_daten() + .getMenge_Patient() + .getPatient() + .getMenge_Meldung() + .getMeldung() + .setMenge_Verlauf(mengeVerlauf); + + var meldungExportList = new MeldungExportList(); + meldungExportList.addElement(meldungExport); + + var resultBundle = onkoPatientMapper.mapOnkoResourcesToPatient(meldungExportList.getElements()); + + assertThat(resultBundle.getEntry()).hasSize(1); + + var patient = (Patient) resultBundle.getEntry().get(0).getResource(); + + assertThat(patient.getDeceasedBooleanType().getValue()).isTrue(); + } }