Skip to content

Commit

Permalink
fix: handle Primaertumor_ICD_Version being unset or not matching regex (
Browse files Browse the repository at this point in the history
#39)

* fix: handle Primaertumor_ICD_Version being unset or not matching regex

* fix: handle Meldung.Diagnose.Primaertumor_* unset and default to TumorZuordnung

* fix: use distinct ID when condition is generated from a tumorzuordnung

avoids overriding existing resources but may cause duplicate diagnosis being present

* test: added snapshot tests for previously failing data
  • Loading branch information
chgl authored May 7, 2024
1 parent bbaceb5 commit 87a6b63
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand All @@ -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 (?<versionYear>20\\d{2}) ((GM)|(WHO))|Sonstige)$");

@Value("${app.version}")
private String appVersion;

Expand Down Expand Up @@ -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) {
Expand All @@ -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));

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand Down Expand Up @@ -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<String, Integer>(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"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ protected MeldungExportList buildMeldungExportList(List<Tupel<String, Integer>>
Map<String, Object> 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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
} ]
}
Original file line number Diff line number Diff line change
@@ -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"
}
} ]
}
110 changes: 110 additions & 0 deletions src/test/resources/diagnosis_set.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<ADT_GEKID xmlns="http://www.gekid.de/namespace" Schema_Version="2.2.3">
<Absender Absender_ID="KR7X825X" Software_ID="ONKOSTAR" Installations_ID="2030">
<Absender_Bezeichnung>UKI</Absender_Bezeichnung>
<Absender_Ansprechpartner>Chef</Absender_Ansprechpartner>
<Absender_Anschrift>Irgendwo-Straße 1, 12345 Phantasieland</Absender_Anschrift>
</Absender>
<Menge_Patient>
<Patient>
<Patienten_Stammdaten Patient_ID="0001234567">
<KrankenversichertenNr>privatversichert</KrankenversichertenNr>
<KrankenkassenNr>1234567890</KrankenkassenNr>
<Patienten_Nachname>TestpatientEnzensperger</Patienten_Nachname>
<Patienten_Titel></Patienten_Titel>
<Patienten_Vornamen>Horst</Patienten_Vornamen>
<Patienten_Geburtsname></Patienten_Geburtsname>
<Patienten_Geschlecht>M</Patienten_Geschlecht>
<Patienten_Geburtsdatum>01.01.1950</Patienten_Geburtsdatum>
<Menge_Adresse>
<Adresse>
<Patienten_Strasse>Irgendwo-Straße 2</Patienten_Strasse>
<Patienten_Hausnummer>2</Patienten_Hausnummer>
<Patienten_Land>DE</Patienten_Land>
<Patienten_PLZ>12345</Patienten_PLZ>
<Patienten_Ort>Phantasieland</Patienten_Ort>
</Adresse>
</Menge_Adresse>
</Patienten_Stammdaten>
<Menge_Meldung>
<Meldung Meldung_ID="000000B2-KR7X825X" Melder_ID="KR7X825X">
<Meldedatum>30.01.2024</Meldedatum>
<Meldebegruendung>D</Meldebegruendung>
<Meldeanlass>histologie_zytologie</Meldeanlass>
<Tumorzuordnung Tumor_ID="1">
<Primaertumor_ICD_Code>C43.2</Primaertumor_ICD_Code>
<Primaertumor_ICD_Version>10 2019 GM</Primaertumor_ICD_Version>
<Diagnosedatum>21.08.2019</Diagnosedatum>
<Seitenlokalisation>L</Seitenlokalisation>
</Tumorzuordnung>
<Diagnose Tumor_ID="1">
<Primaertumor_ICD_Code>C43.5</Primaertumor_ICD_Code>
<Primaertumor_ICD_Version>10 2010 GM</Primaertumor_ICD_Version>
<Primaertumor_Diagnosetext>Bösartiges Melanom des Rumpfes</Primaertumor_Diagnosetext>
<Menge_Histologie>
<Histologie Histologie_ID="1234567">
<Tumor_Histologiedatum>21.08.2019</Tumor_Histologiedatum>
<Histologie_EinsendeNr>p 21557-19</Histologie_EinsendeNr>
<Morphologie_Code>8720/3</Morphologie_Code>
<Morphologie_ICD_O_Version>33</Morphologie_ICD_O_Version>
</Histologie>
</Menge_Histologie>
<Modul_Allgemein>
<DatumStudienrekrutierung>
<NU>N</NU>
</DatumStudienrekrutierung>
</Modul_Allgemein>
<Anmerkung> *** Pathobericht</Anmerkung>
</Diagnose>
<Menge_Zusatzitem>
<Zusatzitem>
<Art>Einsender_Vorname</Art>
<Wert>Sepp</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_Nachname</Art>
<Wert>Prof. Dr. Doof</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_Titel</Art>
<Wert>-</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_Strasse</Art>
<Wert>Irgendwo-Straße</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_Hausnummer</Art>
<Wert>1</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_Ort</Art>
<Wert>Phantasieland</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_PLZ</Art>
<Wert>12345</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_Einrichtung</Art>
<Wert>Prof. Dr. Doof, UKI, HG</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_BSNR</Art>
<Wert>-</Wert>
</Zusatzitem>
<Zusatzitem>
<Art>Einsender_LANR</Art>
<Wert>-</Wert>
</Zusatzitem>
</Menge_Zusatzitem>
</Meldung>
</Menge_Meldung>
</Patient>
</Menge_Patient>
<Menge_Melder>
<Melder Melder_ID="KR7X825X">
<Meldende_Stelle>KR7X825X</Meldende_Stelle>
</Melder>
</Menge_Melder>
</ADT_GEKID>
Loading

0 comments on commit 87a6b63

Please sign in to comment.