Kerndatensatz Senologie
0.9.0 - ci-build
Kerndatensatz Senologie - Local Development build (v0.9.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
| Official URL: https://www.senologie.org/fhir/StructureMap/SenologieToOncoBoxBrustVerlauf | Version: 0.9.0 | |||
| Draft as of 2026-05-04 | Computable Name: SenologieToOncoBoxBrustVerlauf | |||
title: Senologie Bundle to OncoBox Brust Verlauf (inkl. OncoBox 2.0 FM-Felder J03-J05) status: draft
map "https://www.senologie.org/fhir/StructureMap/SenologieToOncoBoxBrustVerlauf" = "SenologieToOncoBoxBrustVerlauf" // title: Senologie Bundle to OncoBox Brust Verlauf (inkl. OncoBox 2.0 FM-Felder J03-J05) // status: draft uses "http://hl7.org/fhir/StructureDefinition/Bundle" alias Bundle as source uses "http://hl7.org/fhir/StructureDefinition/Condition" alias Condition as source uses "http://hl7.org/fhir/StructureDefinition/Observation" alias Observation as source uses "http://hl7.org/fhir/StructureDefinition/Procedure" alias Procedure as source // Import-only map: no target `uses` declaration — the calling map // (SenologieToOncoBoxBrustPrimaerfall) provides the correct BackboneElement // context (primaerfall for MapVerlaufFromBundle, primaerfall.verlauf for sub-groups). // Omitting the root-level target type avoids SM_TARGET_PATH false positives // where the validator would resolve property names against oncobox-brust-meldung root. // ============================================================================ // MapVerlaufFromBundle: Bundle -> OncoBox Primaerfall.verlauf (repeating) // Extrahiert Verlaufsereignisse aus dem Bundle und mappt auf den OncoBox- // Verlauf-Block. Drei Quellen fuer Verlaufseintraege: // 1. Senologie_FollowUp Observations (SCT 396432002) -> M01-M10 + Gesamtbeurteilung // Bildet die vollstaendige Verlaufsmeldung ab inkl. Nachsorge-Art, Vitalstatus, // Tumorstatus lokal/LK/FM und Zweittumor. Gesamtbeurteilung (D27) wird auf // verlauf.ereignis gemappt: P->6 (Progress), Y->1 (Lokalrezidiv Default). // 2. Condition mit clinicalStatus=recurrence -> Rezidiv / Fernmetastase // 3. Observation LOINC 21907-1 (Distant metastases.clinical) -> Fernmetastase // Fuer Fernmetastasen-Ereignisse (ereignis=3) werden zusaetzlich die // OncoBox 2.0 Felder J03-J05 befuellt: // J03: FM_OP_Datum -> aus Procedure (Operation) mit FM-reasonReference // J04: FM_Therapien -> Existenz-Check fuer OP/Syst/ST/Endo im Bundle // J05: FM_Residualstatus -> aus Procedure.outcome (Operation) // ============================================================================ group MapVerlaufFromBundle(source src : Bundle, target tgt : BackboneElement) { // --- Senologie_FollowUp Observations -> Verlauf M01-M10 + Gesamtbeurteilung --- // SCT 396432002 = "Status of regression of tumor" src.entry as fuEntry where resource.is(Observation) and resource.code.coding.exists(code = '396432002') then { fuEntry.resource as fuObs -> tgt.verlauf as verl then MapVerlaufFollowUp(fuObs, verl) "CallMapVerlaufFU"; } "EntryVerlaufFU"; // --- Fernmetastasen-Observations -> Verlauf mit ereignis=3 --- // LOINC 21907-1 = "Distant metastases.clinical Cancer" src.entry as fmEntry where resource.is(Observation) and resource.code.coding.exists(code = '21907-1') then { fmEntry.resource as fmObs -> tgt.verlauf as verl then MapVerlaufFernmetastase(fmObs, verl) "CallMapVerlaufFM"; // === OncoBox 2.0: J03 — FM_OP_Datum (moved from MapVerlaufFernmetastase) === src.entry as opEntry where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-operation') or $this.contains('senologie-brustop')) then { opEntry.resource as proc then { proc.extension as ext where url.contains('Intention') then { ext.value as val then { val.coding as c where code = 'P' then { proc.performed as perf where $this.is(dateTime) -> verl.fmOperation as fmOp, fmOp.opDatum = perf "SetFMOpDatum"; } "CheckIntentionPalliativ"; } "MapIntentionValue"; } "MapIntentionExt"; } "MapFMOpProc"; } "EntryFMOp"; // === OncoBox 2.0: J04 — FM_Therapien (moved from MapVerlaufFernmetastase) === fmEntry.resource as fmObsCtx -> verl.fmTherapie as fmTh then MapFMTherapien(src, fmTh) "CallMapFMTherapien"; // === OncoBox 2.0: J05 — FM_Residualstatus (moved from MapVerlaufFernmetastase) === src.entry as opEntry2 where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-operation') or $this.contains('senologie-brustop')) then { opEntry2.resource as proc then { proc.extension as ext where url.contains('Intention') then { ext.value as val then { val.coding as c where code = 'P' then { proc.outcome as oc then { oc.coding as rc where system.contains('residualstatus') -> verl.fmOperation as fmOp, fmOp.residualstatus = rc "SetFMResidualCode"; } "MapFMResidualCoding"; } "CheckIntentionPalliativR"; } "MapIntentionValueR"; } "MapIntentionExtR"; } "MapFMResidualProc"; } "EntryFMResidual"; } "EntryVerlaufFM"; // --- Vitalstatus aus Patient.deceased (Fallback fuer Verlauf ohne FollowUp) --- src.entry as patEntry where resource.is(Patient) then { patEntry.resource as patient then { patient where deceased.exists() -> tgt.verlauf as verl, verl.vitalstatus = 'verstorben' "SetVSVerstorben"; patient where deceased.exists().not() -> tgt.verlauf as verl, verl.vitalstatus = 'lebend' "SetVSLebend"; } "PatientCtx"; } "EntryPatVS"; // --- Conditions mit recurrence -> Verlauf (Lokalrezidiv, Regionaerrezidiv, etc.) --- src.entry as recEntry where resource.is(Condition) and resource.clinicalStatus.coding.exists(code = 'recurrence') then { recEntry.resource as recCond -> tgt.verlauf as verl then MapVerlaufRezidiv(recCond, verl) "CallMapVerlaufRez"; } "EntryVerlaufRez"; } // ============================================================================ // MapVerlaufFollowUp: Observation (Senologie_FollowUp) -> Verlauf M01-M10 // Bildet eine Senologie_FollowUp Observation (SCT 396432002) auf den // vollstaendigen OncoBox-Verlauf-Block ab: // M01: Meldedatum <- effectiveDateTime // M02: Melder <- performer.display // M03: Nachsorge-Art <- component[nachsorge-art] // M04: Vitalstatus <- component[vitalstatus] // M05: Tumorstatus lok. <- component[Tumor_Verlauf] (SCT 445200009) // M06: Tumorstatus LK <- component[Lymphknoten_Verlauf] (SCT 399656008) // M07: Tumorstatus FM <- component[Fernmetastasen_Verlauf] (SCT 399608002) // M08: Zweittumor <- component[zweittumor] // M09: Zweittumor ICD <- component[zweittumor-icd] // M10: Zweittumor Datum <- component[zweittumor-datum] // Ereignis <- Gesamtbeurteilung (valueCodeableConcept): // P->6 (Progress), Y->1 (Lokalrezidiv Default) // ============================================================================ group MapVerlaufFollowUp(source src : Observation, target tgt : BackboneElement) { // M01: Meldedatum src.effective as eff where $this.is(dateTime) -> tgt.meldedatum = eff "SetM01Datum"; // M02: Melder (Performer-Name als String) src.performer as perf then { perf.display as d -> tgt.melder = d "SetM02Melder"; } "MapM02Perf"; // M03: Art der Nachsorge (aus Component mit Code nachsorge-art) src.component as comp where code.coding.exists(code = 'nachsorge-art') then { comp.value as val then { val.coding as c then { c.code as cd where $this = 'aktiv' -> tgt.nachsorgeArt = 'aktiv' "SetM03Aktiv"; c.code as cd where $this = 'passiv' -> tgt.nachsorgeArt = 'passiv' "SetM03Passiv"; } "MapM03Coding"; } "MapM03Val"; } "MapM03"; // M04: Vitalstatus (SCT 438949009=lebend, 419099009=verstorben, 261665006=unbekannt) src.component as comp where code.coding.exists(code = 'vitalstatus') then { comp.value as val then { val.coding as c then { c.code as cd where $this = '438949009' -> tgt.vitalstatus = 'lebend' "SetM04Lebend"; c.code as cd where $this = '419099009' -> tgt.vitalstatus = 'verstorben' "SetM04Verstorben"; c.code as cd where $this = '261665006' -> tgt.vitalstatus = 'unbekannt' "SetM04Unbekannt"; } "MapM04Coding"; } "MapM04Val"; } "MapM04"; // M05: Lokaler Tumorstatus (SCT 445200009 = Status of residual neoplasm) src.component as comp where code.coding.exists(code = '445200009') then { comp.value as val then { val.coding as c where system.contains('verlauf-primaertumor') then { c.code as cd -> tgt.tumorstatusLokal = cd "SetM05"; } "MapM05Coding"; } "MapM05Val"; } "MapM05"; // M06: Lymphknoten-Tumorstatus (SCT 399656008) src.component as comp where code.coding.exists(code = '399656008') then { comp.value as val then { val.coding as c where system.contains('verlauf-lymphknoten') then { c.code as cd -> tgt.tumorstatusLK = cd "SetM06"; } "MapM06Coding"; } "MapM06Val"; } "MapM06"; // M07: Fernmetastasen-Tumorstatus (SCT 399608002) src.component as comp where code.coding.exists(code = '399608002') then { comp.value as val then { val.coding as c where system.contains('verlauf-fernmetastasen') then { c.code as cd -> tgt.tumorstatusFM = cd "SetM07"; } "MapM07Coding"; } "MapM07Val"; } "MapM07"; // M08: Zweittumor (SCT 373066001=ja, 373067005=nein, 261665006=unbekannt) src.component as comp where code.coding.exists(code = 'zweittumor') then { comp.value as val then { val.coding as c then { c.code as cd where $this = '373066001' -> tgt.zweittumor = 'ja' "SetM08Ja"; c.code as cd where $this = '373067005' -> tgt.zweittumor = 'nein' "SetM08Nein"; c.code as cd where $this = '261665006' -> tgt.zweittumor = 'unbekannt' "SetM08Unbekannt"; } "MapM08Coding"; } "MapM08Val"; } "MapM08"; // M09: Zweittumor ICD-10-GM src.component as comp where code.coding.exists(code = 'zweittumor-icd') then { comp.value as val then { val.coding as c where system = 'http://fhir.de/CodeSystem/bfarm/icd-10-gm' then { c.code as cd -> tgt.zweitttumorIcd = cd "SetM09"; } "MapM09Coding"; } "MapM09Val"; } "MapM09"; // M10: Zweittumor Diagnosedatum src.component as comp where code.coding.exists(code = 'zweittumor-datum') then { comp.value as val where $this.is(dateTime) -> tgt.zweitttumorDatum = val "SetM10"; } "MapM10"; // Gesamtbeurteilung -> Verlauf_Ereignis // ConceptMap: V/T/K/B/R -> kein Ereignis (stabil); P -> 6; Y -> 1 src.value as val then { val.coding as c where system.contains('verlauf-gesamtbeurteilung') then { // P = Progression -> 6 (Progress) c.code as cd where $this = 'P' -> tgt.ereignis = '6' "SetEreignisProgress"; // Y = Rezidiv -> 1 (Lokalrezidiv als Default) c.code as cd where $this = 'Y' -> tgt.ereignis = '1' "SetEreignisRezidiv"; } "MapGesamtCoding"; } "MapGesamt"; } // ============================================================================ // MapVerlaufFernmetastase: Observation (FM) -> Verlauf + OncoBox 2.0 J03-J05 // Bildet eine Fernmetastasen-Observation auf den OncoBox-Verlauf-Block ab. // Zusaetzlich werden FM-spezifische Therapie-Procedures aus dem Bundle // extrahiert fuer die OncoBox 2.0 Felder. // FM-spezifische Procedures werden identifiziert ueber: // - meta.profile enthält das jeweilige Senologie-Profil // - extension:Intention mit code 'P' (palliativ) als FM-Kontextindikator // ============================================================================ group MapVerlaufFernmetastase(source src : Observation, target tgt : BackboneElement) { // Verlauf_Datum: aus Observation.effectiveDateTime src.effective as eff where $this.is(dateTime) -> tgt.meldedatum = eff "SetVerlaufDatumFM"; // Verlauf_Ereignis: 3 = Fernmetastase src -> tgt.ereignis = '3' "SetEreignisFM"; } // ============================================================================ // MapFMTherapien: Bundle -> FM_Therapien (J04) // Prueft fuer jede Therapieart ob eine Procedure mit palliativer Intention // im Bundle vorhanden ist und setzt entsprechend 0/1. // ============================================================================ group MapFMTherapien(source src : Bundle, target tgt : BackboneElement) { // Operation bei FM src.entry as entry where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-operation') or $this.contains('senologie-brustop')) then { entry.resource as proc then { proc.extension as ext where url.contains('Intention') then { ext.value as val then { val.coding as c where code = 'P' -> tgt.operation = '1' "SetFMThOP"; } "CheckIntentionPalliativOP"; } "MapIntentionExtOP"; } "MapFMThOPProc"; } "EntryFMThOP"; // Systemtherapie bei FM src.entry as entry where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-systemtherapie')) then { entry.resource as proc then { proc.extension as ext where url.contains('Intention') then { ext.value as val then { val.coding as c where code = 'P' -> tgt.systemtherapie = '1' "SetFMThSyst"; } "CheckIntentionPalliativSyst"; } "MapIntentionExtSyst"; } "MapFMThSystProc"; } "EntryFMThSyst"; // Strahlentherapie bei FM src.entry as entry where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-strahlentherapie')) then { entry.resource as proc then { proc.extension as ext where url.contains('Intention') then { ext.value as val then { val.coding as c where code = 'P' -> tgt.strahlentherapie = '1' "SetFMThST"; } "CheckIntentionPalliativST"; } "MapIntentionExtST"; } "MapFMThSTProc"; } "EntryFMThST"; // Endokrine Therapie bei FM (Senologie Systemtherapie mit endocrine type) // Endokrine Therapie wird als Systemtherapie mit spezifischem Code erfasst src.entry as entry where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-systemtherapie')) then { entry.resource as proc then { proc.code as code then { code.coding as c where code = '169413002' then { proc.extension as ext where url.contains('Intention') then { ext.value as val then { val.coding as ic where code = 'P' -> tgt.endokrineTherapie = '1' "SetFMThEndo"; } "CheckIntentionPalliativEndo"; } "MapIntentionExtEndo"; } "CheckEndocrineCode"; } "MapEndocrineCodeCtx"; } "MapFMThEndoProc"; } "EntryFMThEndo"; } // ============================================================================ // MapVerlaufRezidiv: Condition (Rezidiv) -> Verlauf (Nicht-FM-Ereignis) // Mappt Rezidiv-Conditions auf den OncoBox-Verlauf-Block fuer Lokalrezidive, // Regionaerrezidive und andere Verlaufsereignisse. // FM-spezifische Felder J03-J05 werden hier NICHT befuellt. // ============================================================================ group MapVerlaufRezidiv(source src : Condition, target tgt : BackboneElement) { // Verlauf_Datum: aus Condition.recordedDate oder extension Feststellungsdatum src.extension as ext where url = 'https://www.medizininformatik-initiative.de/fhir/ext/modul-onko/StructureDefinition/mii-ex-onko-feststellungsdatum' then { ext.value as val where $this.is(dateTime) -> tgt.datum = val "SetVerlaufDatumExt"; } "MapVerlaufDatumExt"; // Fallback: recordedDate src.recordedDate as rd -> tgt.datum = rd "SetVerlaufDatumFallback"; // Verlauf_Ereignis: aus Condition.code oder stage // Mapping: Lokalrezidiv=1, Regionaerrezidiv=2, kontralateral=4, Zweitmalignom=5, Progress=6 // (Fernmetastase=3 wird ueber MapVerlaufFernmetastase abgedeckt) src.code as code then { code.coding as c where system = 'http://snomed.info/sct' then { // 255226008 = Local recurrence of tumor c.code as cd where $this = '255226008' -> tgt.ereignis = '1' "SetEreignisLokal"; // 315266007 = Regional recurrence c.code as cd where $this = '315266007' -> tgt.ereignis = '2' "SetEreignisRegional"; // 94222008 = Contralateral breast cancer (Secondary malignant neoplasm of contralateral breast) c.code as cd where $this = '94222008' -> tgt.ereignis = '4' "SetEreignisKontralateral"; } "MapEreignisSCT"; } "MapEreignis"; }