diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsConditionMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsConditionMapper.java index 0106f8c9..c2b01a3c 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsConditionMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/ObdsConditionMapper.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; import org.hl7.fhir.r4.model.*; import org.miracum.streams.ume.obdstofhir.FhirProperties; import org.miracum.streams.ume.obdstofhir.lookup.*; @@ -12,12 +13,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; @Configuration public class ObdsConditionMapper extends ObdsToFhirMapper { private static final Logger LOG = LoggerFactory.getLogger(ObdsConditionMapper.class); + private static final Pattern icdVersionPattern = + Pattern.compile("^(10 (?20\\d{2}) ((GM)|(WHO))|Sonstige)$"); + @Value("${app.version}") private String appVersion; @@ -64,8 +69,12 @@ public Bundle mapOnkoResourcesToCondition( ADT_GEKID.PrimaryConditionAbs primDia = meldung.getDiagnose(); - // diagnose Tag ist only specified in meldeanlass 'diagnose', otherwise use tag 'Tumorzuordung' - if (primDia == null) { + // Diagnose Element is only fully specified in meldeanlass 'diagnose', otherwise use element + // 'Tumorzuordung' + // It's possible that 'Meldung.Diagnose' is set but 'Meldung.Diagnose.Primaertumor_*' is not, + // in that case also use the TumorZuordnung to construct the Condition. + var useTumorZuordnung = primDia == null || primDia.getPrimaertumor_ICD_Code() == null; + if (useTumorZuordnung) { primDia = meldung.getTumorzuordnung(); if (primDia == null) { @@ -80,6 +89,9 @@ public Bundle mapOnkoResourcesToCondition( } var conIdentifier = pid + "condition" + primDia.getTumor_ID(); + if (useTumorZuordnung) { + conIdentifier += "-from-tumorzuordnung"; + } onkoCondition.setId(this.getHash(ResourceType.Condition, conIdentifier)); @@ -94,18 +106,26 @@ public Bundle mapOnkoResourcesToCondition( .getMeta() .setProfile(List.of(new CanonicalType(fhirProperties.getProfiles().getCondition()))); - var coding = new Coding(); - var icd10Version = primDia.getPrimaertumor_ICD_Version(); - // Aufbau: "10 2021 GM" - String[] icdVersionArray = icd10Version.split(" "); - - if (icdVersionArray.length == 3 && icdVersionArray[1].matches("^20\\d{2}$")) { - coding.setVersion(icdVersionArray[1]); - } // FIXME: else throw exception? + var coding = + new Coding() + .setCode(primDia.getPrimaertumor_ICD_Code()) + .setSystem(fhirProperties.getSystems().getIcd10gm()); - coding - .setCode(primDia.getPrimaertumor_ICD_Code()) - .setSystem(fhirProperties.getSystems().getIcd10gm()); + // Aufbau: "10 2021 GM" + var icd10Version = primDia.getPrimaertumor_ICD_Version(); + if (StringUtils.hasLength(icd10Version)) { + var matcher = icdVersionPattern.matcher(icd10Version); + if (matcher.matches()) { + coding.setVersion(matcher.group("versionYear")); + } else { + LOG.warn( + "Primaertumor_ICD_Version doesn't match expected format. Expected: '{}', actual: '{}'", + icdVersionPattern.pattern(), + icd10Version); + } + } else { + LOG.warn("Primaertumor_ICD_Version is unset or contains only whitespaces"); + } var conditionCode = new CodeableConcept().addCoding(coding); onkoCondition.setCode(conditionCode); diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.java index 8211a138..790392b6 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.java @@ -6,11 +6,13 @@ import java.io.IOException; import java.util.*; import java.util.stream.Stream; +import org.apache.commons.lang3.tuple.Pair; import org.approvaltests.Approvals; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.Observation; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; import org.miracum.streams.ume.obdstofhir.FhirProperties; import org.miracum.streams.ume.obdstofhir.mapper.*; @@ -194,4 +196,35 @@ void mapObservation_withGivenAdtXml( .withExtension(".fhir.json")); } } + + @ParameterizedTest + @CsvSource({"diagnosis_set.xml", "diagnosis_unset.xml"}) + void mapObservation_withGivenObdsXml_shouldMatchSnapshot(String resourceXmlName) + throws IOException { + + var meldungExportList = + buildMeldungExportList(List.of(new Tupel(resourceXmlName, 1))); + + var onkoProcessor = + new ObdsProcessor( + fhirProps, + onkoMedicationStatementMapper, + onkoObservationMapper, + onkoProcedureMapper, + onkoPatientMapper, + onkoConditionMapper); + + var observResultBundle = + onkoProcessor.getOnkoToObservationBundleMapper().apply(meldungExportList); + + var resultBundle = + onkoProcessor + .getOnkoToConditionBundleMapper() + .apply(Pair.of(meldungExportList, observResultBundle)); + + var fhirJson = fhirParser.encodeResourceToString(resultBundle); + Approvals.verify( + fhirJson, + Approvals.NAMES.withParameters(resourceXmlName).forFile().withExtension(".fhir.json")); + } } diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessorTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessorTest.java index ab9e4b20..cd94228e 100644 --- a/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessorTest.java +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/processor/ObdsProcessorTest.java @@ -64,7 +64,7 @@ protected MeldungExportList buildMeldungExportList(List> Map payloadOnkoRessource = new HashMap<>(); payloadOnkoRessource.put("ID", payloadId); payloadOnkoRessource.put("REFERENZ_NUMMER", patId); - payloadOnkoRessource.put("LKR_MELDUNG", Integer.parseInt(meldungsId.replace(melderId, ""))); + payloadOnkoRessource.put("LKR_MELDUNG", meldungsId.replace(melderId, "")); payloadOnkoRessource.put("VERSIONSNUMMER", xmlTupel.getSecond()); payloadOnkoRessource.put("XML_DATEN", xmlContent); diff --git a/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.mapObservation_withGivenObdsXml_shouldMatchSnapshot.diagnosis_set.xml.approved.fhir.json b/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.mapObservation_withGivenObdsXml_shouldMatchSnapshot.diagnosis_set.xml.approved.fhir.json new file mode 100644 index 00000000..85fbcd34 --- /dev/null +++ b/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.mapObservation_withGivenObdsXml_shouldMatchSnapshot.diagnosis_set.xml.approved.fhir.json @@ -0,0 +1,39 @@ +{ + "resourceType": "Bundle", + "type": "transaction", + "entry": [ { + "fullUrl": "Condition/04c8f27ca021b8fd87ffd3abbde1f4b907bb3d6921fd61c5d4b9a0a756b8d110", + "resource": { + "resourceType": "Condition", + "id": "04c8f27ca021b8fd87ffd3abbde1f4b907bb3d6921fd61c5d4b9a0a756b8d110", + "meta": { + "source": "KR7X825X.ONKOSTAR:obds-to-fhir:0.0.0-test", + "profile": [ "http://dktk.dkfz.de/fhir/StructureDefinition/onco-core-Condition-Primaerdiagnose" ] + }, + "code": { + "coding": [ { + "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm", + "version": "2010", + "code": "C43.5" + } ] + }, + "subject": { + "reference": "Patient/19cc75fbfb51266ac0149828ae2f8522106e3ba176ceac2b40acb3cb1c9365f9", + "identifier": { + "type": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "MR" + } ] + }, + "system": "https://fhir.diz.uk-erlangen.de/identifiers/patient-id", + "value": "0001234567" + } + } + }, + "request": { + "method": "PUT", + "url": "Condition/04c8f27ca021b8fd87ffd3abbde1f4b907bb3d6921fd61c5d4b9a0a756b8d110" + } + } ] +} \ No newline at end of file diff --git a/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.mapObservation_withGivenObdsXml_shouldMatchSnapshot.diagnosis_unset.xml.approved.fhir.json b/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.mapObservation_withGivenObdsXml_shouldMatchSnapshot.diagnosis_unset.xml.approved.fhir.json new file mode 100644 index 00000000..b27a159f --- /dev/null +++ b/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/processor/ObdsObservationProcessorTest.mapObservation_withGivenObdsXml_shouldMatchSnapshot.diagnosis_unset.xml.approved.fhir.json @@ -0,0 +1,51 @@ +{ + "resourceType": "Bundle", + "type": "transaction", + "entry": [ { + "fullUrl": "Condition/dd9844e53c6d877fb91a9059f1bc0a433e7e892cd272770caa84aad4e7b7189d", + "resource": { + "resourceType": "Condition", + "id": "dd9844e53c6d877fb91a9059f1bc0a433e7e892cd272770caa84aad4e7b7189d", + "meta": { + "source": "KR7X825X.ONKOSTAR:obds-to-fhir:0.0.0-test", + "profile": [ "http://dktk.dkfz.de/fhir/StructureDefinition/onco-core-Condition-Primaerdiagnose" ] + }, + "code": { + "coding": [ { + "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm", + "version": "2019", + "code": "C43.2" + } ] + }, + "bodySite": [ { + "coding": [ { + "system": "http://dktk.dkfz.de/fhir/onco/core/CodeSystem/SeitenlokalisationCS", + "code": "L", + "display": "links" + }, { + "system": "http://snomed.info/sct", + "code": "7771000", + "display": "Left" + } ] + } ], + "subject": { + "reference": "Patient/19cc75fbfb51266ac0149828ae2f8522106e3ba176ceac2b40acb3cb1c9365f9", + "identifier": { + "type": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "MR" + } ] + }, + "system": "https://fhir.diz.uk-erlangen.de/identifiers/patient-id", + "value": "0001234567" + } + }, + "onsetDateTime": "2019-08-21" + }, + "request": { + "method": "PUT", + "url": "Condition/dd9844e53c6d877fb91a9059f1bc0a433e7e892cd272770caa84aad4e7b7189d" + } + } ] +} \ No newline at end of file diff --git a/src/test/resources/diagnosis_set.xml b/src/test/resources/diagnosis_set.xml new file mode 100644 index 00000000..d342d558 --- /dev/null +++ b/src/test/resources/diagnosis_set.xml @@ -0,0 +1,110 @@ + + + + UKI + Chef + Irgendwo-Straße 1, 12345 Phantasieland + + + + + privatversichert + 1234567890 + TestpatientEnzensperger + + Horst + + M + 01.01.1950 + + + Irgendwo-Straße 2 + 2 + DE + 12345 + Phantasieland + + + + + + 30.01.2024 + D + histologie_zytologie + + C43.2 + 10 2019 GM + 21.08.2019 + L + + + C43.5 + 10 2010 GM + Bösartiges Melanom des Rumpfes + + + 21.08.2019 + p 21557-19 + 8720/3 + 33 + + + + + N + + + *** Pathobericht + + + + Einsender_Vorname + Sepp + + + Einsender_Nachname + Prof. Dr. Doof + + + Einsender_Titel + - + + + Einsender_Strasse + Irgendwo-Straße + + + Einsender_Hausnummer + 1 + + + Einsender_Ort + Phantasieland + + + Einsender_PLZ + 12345 + + + Einsender_Einrichtung + Prof. Dr. Doof, UKI, HG + + + Einsender_BSNR + - + + + Einsender_LANR + - + + + + + + + + + KR7X825X + + + diff --git a/src/test/resources/diagnosis_unset.xml b/src/test/resources/diagnosis_unset.xml new file mode 100644 index 00000000..5bc464a8 --- /dev/null +++ b/src/test/resources/diagnosis_unset.xml @@ -0,0 +1,107 @@ + + + + UKI + Chef + Irgendwo-Straße 1, 12345 Phantasieland + + + + + privatversichert + 1234567890 + TestpatientEnzensperger + + Horst + + M + 01.01.1950 + + + Irgendwo-Straße 2 + 2 + DE + 12345 + Phantasieland + + + + + + 30.01.2024 + D + histologie_zytologie + + C43.2 + 10 2019 GM + 21.08.2019 + L + + + + + 21.08.2019 + p 21557-19 + 8720/3 + 33 + + + + + N + + + *** Pathobericht + + + + Einsender_Vorname + Sepp + + + Einsender_Nachname + Prof. Dr. Doof + + + Einsender_Titel + - + + + Einsender_Strasse + Irgendwo-Straße + + + Einsender_Hausnummer + 1 + + + Einsender_Ort + Phantasieland + + + Einsender_PLZ + 12345 + + + Einsender_Einrichtung + Prof. Dr. Doof, UKI, HG + + + Einsender_BSNR + - + + + Einsender_LANR + - + + + + + + + + + KR7X825X + + +