From 8cbb36dafada02b968a261950e1eed8af04c12a6 Mon Sep 17 00:00:00 2001 From: chgl Date: Fri, 22 Nov 2024 20:25:09 +0100 Subject: [PATCH] feat: first draft version of ObdsToFhirBundleMapper --- .../mapper/mii/ObdsToFhirBundleMapper.java | 72 ++++ .../mapper/mii/StrahlentherapieMapper.java | 2 + .../mii/ObdsToFhirBundleMapperTest.java | 66 ++++ ...pshot.Testpatient_1.xml.approved.fhir.json | 345 ++++++++++++++++++ 4 files changed, 485 insertions(+) create mode 100644 src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapper.java create mode 100644 src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.java create mode 100644 src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.map_withGivenObds_shouldCreateBundleMatchingSnapshot.Testpatient_1.xml.approved.fhir.json diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapper.java new file mode 100644 index 00000000..bc40f1c8 --- /dev/null +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapper.java @@ -0,0 +1,72 @@ +package org.miracum.streams.ume.obdstofhir.mapper.mii; + +import de.basisdatensatz.obds.v3.OBDS; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Bundle.BundleType; +import org.hl7.fhir.r4.model.Bundle.HTTPVerb; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.Resource; +import org.springframework.stereotype.Service; + +@Service +public class ObdsToFhirBundleMapper { + + private final PatientMapper patientMapper; + private final ConditionMapper conditionMapper; + private final StrahlentherapieMapper strahlentherapieMapper; + private final SystemischeTherapieProcedureMapper systemischeTherapieProcedureMapper; + + public ObdsToFhirBundleMapper( + PatientMapper patientMapper, + ConditionMapper conditionMapper, + SystemischeTherapieProcedureMapper systemischeTherapieProcedureMapper, + StrahlentherapieMapper strahlentherapieMapper) { + this.patientMapper = patientMapper; + this.conditionMapper = conditionMapper; + this.systemischeTherapieProcedureMapper = systemischeTherapieProcedureMapper; + this.strahlentherapieMapper = strahlentherapieMapper; + } + + public Bundle map(OBDS obds) { + var bundle = new Bundle(); + bundle.setType(BundleType.TRANSACTION); + + // TODO: set bundle id... to the patient id? sum of all ids? + // TODO: or one bundle per Patient instead? + for (var obdsPatient : obds.getMengePatient().getPatient()) { + var meldungen = obdsPatient.getMengeMeldung().getMeldung(); + + // Patient + var patient = patientMapper.map(obdsPatient, meldungen); + var patientReference = new Reference("Patient/" + patient.getId()); + addEntryToBundle(bundle, patient); + + for (var meldung : meldungen) { + // Diagnose + if (meldung.getDiagnose() != null) { + var condition = conditionMapper.map(meldung, patientReference); + addEntryToBundle(bundle, condition); + } + + if (meldung.getSYST() != null) { + var systProcedure = + systemischeTherapieProcedureMapper.map(meldung.getSYST(), patientReference); + addEntryToBundle(bundle, systProcedure); + } + + if (meldung.getST() != null) { + var stProcedure = strahlentherapieMapper.map(meldung.getST(), patientReference); + addEntryToBundle(bundle, stProcedure); + } + } + } + + return bundle; + } + + private static Bundle addEntryToBundle(Bundle bundle, Resource resource) { + var url = String.format("%s/%s", resource.getResourceType(), resource.getIdBase()); + bundle.addEntry().setResource(resource).getRequest().setMethod(HTTPVerb.PUT).setUrl(url); + return bundle; + } +} diff --git a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java index c296d6cc..4606ea9c 100644 --- a/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java +++ b/src/main/java/org/miracum/streams/ume/obdstofhir/mapper/mii/StrahlentherapieMapper.java @@ -17,7 +17,9 @@ import org.miracum.streams.ume.obdstofhir.mapper.ObdsToFhirMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +@Service public class StrahlentherapieMapper extends ObdsToFhirMapper { private static final Logger LOG = LoggerFactory.getLogger(StrahlentherapieMapper.class); diff --git a/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.java b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.java new file mode 100644 index 00000000..98c41ecd --- /dev/null +++ b/src/test/java/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.java @@ -0,0 +1,66 @@ +package org.miracum.streams.ume.obdstofhir.mapper.mii; + +import static org.assertj.core.api.Assertions.assertThat; + +import ca.uhn.fhir.context.FhirContext; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationModule; +import de.basisdatensatz.obds.v3.OBDS; +import java.io.IOException; +import org.approvaltests.Approvals; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.miracum.streams.ume.obdstofhir.FhirProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest( + classes = { + FhirProperties.class, + ObdsToFhirBundleMapper.class, + PatientMapper.class, + ConditionMapper.class, + SystemischeTherapieProcedureMapper.class, + StrahlentherapieMapper.class, + }) +@EnableConfigurationProperties +class ObdsToFhirBundleMapperTest { + private static ObdsToFhirBundleMapper sut; + + @BeforeAll + static void beforeAll(@Autowired ObdsToFhirBundleMapper bundleMapper) { + sut = bundleMapper; + } + + @ParameterizedTest + @CsvSource({ + "Testpatient_1.xml", + }) + void map_withGivenObds_shouldCreateBundleMatchingSnapshot(String sourceFile) throws IOException { + final var resource = this.getClass().getClassLoader().getResource("obds3/" + sourceFile); + assertThat(resource).isNotNull(); + + final var xmlMapper = + XmlMapper.builder() + .defaultUseWrapper(false) + .addModule(new JakartaXmlBindAnnotationModule()) + .addModule(new Jdk8Module()) + // added because the Testpatient_*.xml contain the `xsi:schemaLocation` attribute which + // isn't code-generated + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + final var obds = xmlMapper.readValue(resource.openStream(), OBDS.class); + + final var bundle = sut.map(obds); + + var fhirParser = FhirContext.forR4().newJsonParser().setPrettyPrint(true); + var fhirJson = fhirParser.encodeResourceToString(bundle); + Approvals.verify( + fhirJson, Approvals.NAMES.withParameters(sourceFile).forFile().withExtension(".fhir.json")); + } +} diff --git a/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.map_withGivenObds_shouldCreateBundleMatchingSnapshot.Testpatient_1.xml.approved.fhir.json b/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.map_withGivenObds_shouldCreateBundleMatchingSnapshot.Testpatient_1.xml.approved.fhir.json new file mode 100644 index 00000000..e7421429 --- /dev/null +++ b/src/test/java/snapshots/org/miracum/streams/ume/obdstofhir/mapper/mii/ObdsToFhirBundleMapperTest.map_withGivenObds_shouldCreateBundleMatchingSnapshot.Testpatient_1.xml.approved.fhir.json @@ -0,0 +1,345 @@ +{ + "resourceType": "Bundle", + "type": "transaction", + "entry": [ { + "resource": { + "resourceType": "Patient", + "id": "a02e16474896f1d528cac71f2c9b4c45ac3c9028e3a53fb414a1f7882991ee07", + "meta": { + "profile": [ "https://www.medizininformatik-initiative.de/fhir/core/modul-person/StructureDefinition/PatientPseudonymisiert" ] + }, + "identifier": [ { + "type": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "MR", + "display": "Medical record number" + }, { + "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationValue", + "code": "PSEUDED", + "display": "pseudonymized" + } ] + }, + "system": "https://bzkf.github.io/obds-to-fhir/identifiers/patient-id", + "value": "10" + } ], + "gender": "female", + "birthDate": "1950-05-01", + "deceasedDateTime": "2022-08-01", + "address": [ { + "type": "both", + "postalCode": "12345", + "country": "DE" + } ] + }, + "request": { + "method": "PUT", + "url": "Patient/a02e16474896f1d528cac71f2c9b4c45ac3c9028e3a53fb414a1f7882991ee07" + } + }, { + "resource": { + "resourceType": "Condition", + "meta": { + "profile": [ "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-pr-onko-diagnose-primaertumor" ] + }, + "extension": [ { + "url": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-ex-onko-histology-morphology-behavior-icdo3", + "valueCodeableConcept": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/icd-o-3", + "version": "33", + "code": "8010/3" + } ] + } + } ], + "verificationStatus": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/condition-ver-status", + "code": "confirmed" + }, { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-primaertumor-diagnosesicherung", + "code": "7" + } ] + }, + "code": { + "coding": [ { + "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm", + "version": "2020", + "code": "C50.9" + } ] + }, + "bodySite": [ { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/icd-o-3", + "version": "33", + "code": "C50.9" + } ] + }, { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-seitenlokalisation", + "code": "R" + } ] + } ], + "subject": { + "reference": "Patient/a02e16474896f1d528cac71f2c9b4c45ac3c9028e3a53fb414a1f7882991ee07" + }, + "recordedDate": "2020-03-01T01:00:00+01:00" + }, + "request": { + "method": "PUT", + "url": "Condition/null" + } + }, { + "resource": { + "resourceType": "Procedure", + "id": "bfc5c7a0c00d1c00e9ab41a4507f8cfbbc87e13953eba89e14c3fe3a54325559", + "meta": { + "profile": [ "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-pr-onko-strahlentherapie" ] + }, + "extension": [ { + "url": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-ex-onko-strahlentherapie-intention", + "valueCodeableConcept": { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-intention", + "code": "P" + } ] + } + }, { + "url": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-ex-onko-strahlentherapie-bestrahlung", + "extension": [ { + "url": "Applikationsart", + "valueCodeableConcept": { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-strahlentherapie-applikationsart", + "code": "P-ST" + } ] + } + }, { + "url": "Strahlenart", + "valueCodeableConcept": { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-strahlentherapie-strahlenart", + "code": "UH" + } ] + } + }, { + "url": "Zielgebiet", + "valueCodeableConcept": { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-strahlentherapie-zielgebiet", + "code": "3.4" + } ] + } + } ] + } ], + "identifier": [ { + "system": "https://bzkf.github.io/obds-to-fhir/identifiers/strahlentherapie-procedure-id", + "value": "101_ST-2" + } ], + "status": "completed", + "category": { + "coding": [ { + "system": "http://snomed.info/sct", + "code": "277132007", + "display": "Therapeutic procedure" + } ] + }, + "code": { + "coding": [ { + "system": "http://fhir.de/CodeSystem/bfarm/ops", + "_code": { + "extension": [ { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + } ] + } + } ] + }, + "subject": { + "reference": "Patient/a02e16474896f1d528cac71f2c9b4c45ac3c9028e3a53fb414a1f7882991ee07" + }, + "performedPeriod": { + "_start": { + "extension": [ { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + } ] + } + } + }, + "request": { + "method": "PUT", + "url": "Procedure/bfc5c7a0c00d1c00e9ab41a4507f8cfbbc87e13953eba89e14c3fe3a54325559" + } + }, { + "resource": { + "resourceType": "Procedure", + "id": "8e5a61d808bb30074e894fc702086b24763c410267b91c86f75de0b3b6507ccf", + "meta": { + "profile": [ "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-pr-onko-systemische-therapie" ] + }, + "extension": [ { + "url": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-ex-onko-systemische-therapie-intention", + "valueCodeableConcept": { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-intention", + "code": "P" + } ] + } + } ], + "identifier": [ { + "system": "https://bzkf.github.io/obds-to-fhir/identifiers/systemische-therapie-procedure-id", + "value": "101_IN-1" + } ], + "status": "completed", + "category": { + "coding": [ { + "system": "http://snomed.info/sct", + "_code": { + "extension": [ { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + } ] + } + } ] + }, + "code": { + "coding": [ { + "system": "http://fhir.de/CodeSystem/bfarm/ops", + "_code": { + "extension": [ { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + } ] + } + }, { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-therapie-typ", + "code": "IM" + } ] + }, + "subject": { + "reference": "Patient/a02e16474896f1d528cac71f2c9b4c45ac3c9028e3a53fb414a1f7882991ee07" + }, + "performedPeriod": { + "start": "2020-05", + "end": "2020-10-15" + }, + "outcome": { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-therapie-grund-ende", + "code": "V" + } ] + } + }, + "request": { + "method": "PUT", + "url": "Procedure/8e5a61d808bb30074e894fc702086b24763c410267b91c86f75de0b3b6507ccf" + } + }, { + "resource": { + "resourceType": "Condition", + "meta": { + "profile": [ "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-pr-onko-diagnose-primaertumor" ] + }, + "extension": [ { + "url": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-ex-onko-histology-morphology-behavior-icdo3", + "valueCodeableConcept": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/icd-o-3", + "version": "33", + "code": "8010/3" + } ] + } + } ], + "verificationStatus": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/condition-ver-status", + "code": "confirmed" + }, { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-primaertumor-diagnosesicherung", + "code": "7" + } ] + }, + "code": { + "coding": [ { + "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm", + "version": "2020", + "code": "C20" + } ] + }, + "bodySite": [ { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/icd-o-3", + "version": "33", + "code": "C20.9" + } ] + }, { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-seitenlokalisation", + "code": "T" + } ] + } ], + "subject": { + "reference": "Patient/a02e16474896f1d528cac71f2c9b4c45ac3c9028e3a53fb414a1f7882991ee07" + }, + "recordedDate": "2020-01-01T01:00:00+01:00" + }, + "request": { + "method": "PUT", + "url": "Condition/null" + } + }, { + "resource": { + "resourceType": "Condition", + "meta": { + "profile": [ "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-pr-onko-diagnose-primaertumor" ] + }, + "extension": [ { + "url": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-ex-onko-histology-morphology-behavior-icdo3", + "valueCodeableConcept": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/icd-o-3", + "version": "33", + "code": "8720/3" + } ] + } + } ], + "verificationStatus": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/condition-ver-status", + "code": "confirmed" + }, { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-primaertumor-diagnosesicherung", + "code": "7" + } ] + }, + "code": { + "coding": [ { + "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm", + "version": "2020", + "code": "C43.5" + } ] + }, + "bodySite": [ { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/icd-o-3", + "version": "33", + "code": "C44.5" + } ] + }, { + "coding": [ { + "system": "https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/CodeSystem/mii-cs-onko-seitenlokalisation", + "code": "T" + } ] + } ], + "subject": { + "reference": "Patient/a02e16474896f1d528cac71f2c9b4c45ac3c9028e3a53fb414a1f7882991ee07" + }, + "recordedDate": "2020-03-01T01:00:00+01:00" + }, + "request": { + "method": "PUT", + "url": "Condition/null" + } + } ] +} \ No newline at end of file