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

StructureMap: SenologieToObdsMeldung

Official URL: https://www.senologie.org/fhir/StructureMap/SenologieToObdsMeldung Version: 0.9.0
Draft as of 2026-05-04 Computable Name: SenologieToObdsMeldung

title: Senologie FHIR Bundle to oBDS Meldung (Master Orchestrator) status: draft

map "https://www.senologie.org/fhir/StructureMap/SenologieToObdsMeldung" = "SenologieToObdsMeldung"

// title: Senologie FHIR Bundle to oBDS Meldung (Master Orchestrator)
// 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/Procedure" alias Procedure as source
uses "http://hl7.org/fhir/StructureDefinition/CarePlan" alias CarePlan as source
uses "http://hl7.org/fhir/StructureDefinition/Patient" alias Patient as source
uses "http://hl7.org/fhir/StructureDefinition/Observation" alias Observation as source
uses "https://www.senologie.org/fhir/StructureDefinition/obds-meldung" alias OBDSMeldung as target

imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsTumorzuordnung"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsDiagnose"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsOP"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsSYST"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsST"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsTumorkonferenz"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsVerlauf"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsTod"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsTNM"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsHistologie"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsModulMamma"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsFernmetastasen"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsResidualstatus"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsNebenwirkung"
imports "https://www.senologie.org/fhir/StructureMap/SenologieToObdsLeistungszustand"

// ============================================================================
// Master Orchestrator: Bundle -> oBDS Meldung
// Empfaengt ein FHIR Bundle mit allen Ressourcen eines Patienten und
// dispatcht an die jeweiligen Teil-Maps basierend auf Ressourcentyp und Profil.
// Jede Ressource erzeugt eine separate oBDS-Meldung:
// - Condition (Erstdiagnose)         -> Diagnosemeldung
// - Condition (Rezidiv)              -> Verlaufsmeldung
// - Procedure (Operation)            -> OP-Meldung
// - Procedure (Systemtherapie)       -> SYST-Meldung
// - Procedure (Strahlentherapie)     -> ST-Meldung
// - CarePlan (Tumorboard)            -> Tumorkonferenzmeldung
// - Patient (verstorben)             -> Todesmeldung
// ============================================================================
group SenologieToObdsMeldung(source src : Bundle, target tgt : OBDSMeldung) {
  // --- Meldungs-Metadaten ---
  src -> tgt then SetMeldungMetadata(src, tgt) "CallSetMeldungMetadata";
  // --- Diagnose: Condition mit Senologie-Diagnose-Profil, NICHT Rezidiv ---
  // clinicalStatus != recurrence und Profil senologie-diagnose
  src.entry as entry where resource.is(Condition) and resource.meta.profile.exists($this.contains('senologie-diagnose')) and resource.clinicalStatus.coding.exists(code = 'recurrence').not() then {
    entry.resource as condition then {
      // Tumorzuordnung
      condition -> tgt.tumorzuordnung as tz then MapTumorzuordnung(condition, tz) "DiagnoseTZ";
      // Diagnose-Basisfelder
      condition -> tgt.diagnose as dx then MapDiagnose(condition, dx) "DiagnoseDX";
    } "DiagnoseConditionContext";
    // Bundle-Lookups fuer Diagnose (Histologie, TNM, ECOG, ModulMamma, Klassifikationen)
    src.entry as histEntry where resource.is(Observation) and resource.code.coding.exists(code = '59847-4') then {
      histEntry.resource as histObs ->  tgt.diagnose as dx,  dx.histologie as histo then MapHistologie(histObs, histo) "DiagCallHisto";
    } "DiagEntryHisto";
    src.entry as tnmEntry where resource.is(Observation) and resource.code.coding.exists(code = '21908-9') then {
      tnmEntry.resource as tnmObs ->  tgt.diagnose as dx,  dx.cTNM as ctnm then MapTNM(tnmObs, ctnm) "DiagCallCTNM";
    } "DiagEntryCTNM";
    entry.resource as cond2 -> tgt.diagnose as dx then MapLeistungszustandFromBundle(src, dx) "DiagCallECOG";
    entry.resource as cond3 ->  tgt.diagnose as dx,  dx.modulMamma as mamma then MapModulMamma(src, mamma) "DiagCallModulMamma";
    src.entry as raEntry where resource.is(RiskAssessment) then {
      raEntry.resource as ra ->  tgt.diagnose as dx,  dx.weitereKlassifikationen as wk then MapWeitereKlassifikation(ra, wk) "DiagCallWK";
    } "DiagEntryWK";
  } "EntryDiagnose";
  // --- Verlauf: Condition mit clinicalStatus = recurrence (Rezidiv) ---
  src.entry as entry where resource.is(Condition) and resource.clinicalStatus.coding.exists(code = 'recurrence') then {
    entry.resource as condition then {
      // Tumorzuordnung
      condition -> tgt.tumorzuordnung as tz then MapTumorzuordnung(condition, tz) "VerlaufTZ";
      // Verlauf: delegiert an SenologieToObdsVerlauf.MapVerlauf
      condition -> tgt.verlauf as verl then MapVerlauf(condition, verl) "VerlaufMap";
    } "VerlaufConditionContext";
  } "EntryVerlauf";
  // --- OP: Procedure mit Senologie-Operation-Profil ---
  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 procedure then {
      procedure -> tgt.op as op then MapOP(procedure, op) "OPMap";
    } "OPProcedureContext";
    // Bundle-Lookups fuer OP (Histologie, pTNM, ModulMamma)
    src.entry as histEntry where resource.is(Observation) and resource.code.coding.exists(code = '59847-4') then {
      histEntry.resource as histObs ->  tgt.op as op,  op.histologie as histo then MapHistologie(histObs, histo) "OPCallHisto";
    } "OPEntryHisto";
    src.entry as tnmEntry where resource.is(Observation) and resource.code.coding.exists(code = '21902-2') then {
      tnmEntry.resource as tnmObs ->  tgt.op as op,  op.tnm as ptnm then MapTNM(tnmObs, ptnm) "OPCallPTNM";
    } "OPEntryPTNM";
    entry.resource as proc2 ->  tgt.op as op,  op.modulMamma as mamma then MapModulMamma(src, mamma) "OPCallModulMamma";
  } "EntryOP";
  // --- Systemische Therapie: Procedure mit Systemtherapie-Profil ---
  src.entry as entry where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-systemtherapie-procedure')) then {
    entry.resource as procedure then {
      // SYST: delegiert an SenologieToObdsSYST.MapSYST
      procedure -> tgt.syst as syst then MapSYST(procedure, syst) "SYSTMap";
    } "SYSTProcedureContext";
  } "EntrySYST";
  // --- Strahlentherapie: Procedure mit Strahlentherapie-Profil ---
  src.entry as entry where resource.is(Procedure) and resource.meta.profile.exists($this.contains('senologie-strahlentherapie')) then {
    entry.resource as procedure then {
      // ST: delegiert an SenologieToObdsST.MapST
      procedure -> tgt.st as st then MapST(procedure, st) "STMap";
    } "STProcedureContext";
  } "EntryST";
  // --- Tumorkonferenz: CarePlan mit Tumorboard-Empfehlung-Profil ---
  src.entry as entry where resource.is(CarePlan) and resource.meta.profile.exists($this.contains('senologie-tumorboard-empfehlung')) then {
    entry.resource as careplan then {
      // Tumorkonferenz: delegiert an SenologieToObdsTumorkonferenz.MapTumorkonferenz
      careplan -> tgt.tumorkonferenz as tk then MapTumorkonferenz(careplan, tk) "TumorkonferenzMap";
    } "TumorkonferenzCarePlanContext";
  } "EntryTumorkonferenz";
  // --- Tod: Patient mit deceasedDateTime ---
  src.entry as entry where resource.is(Patient) and resource.deceased.exists() then {
    entry.resource as patient then {
      // Tod: delegiert an SenologieToObdsTod.MapTod
      patient -> tgt.tod as tod then MapTod(patient, tod) "TodMap";
    } "TodPatientContext";
  } "EntryTod";
}

// ============================================================================
// SetMeldungMetadata: Meldungs-Metadaten erzeugen
// meldungID, melderID, meldebegruendung, eigeneLeistung
// ============================================================================
group SetMeldungMetadata(source src : Bundle, target tgt : OBDSMeldung) {
  // Meldung_ID: aus Bundle.identifier oder generierte UUID
  src.identifier as id then {
    id.value as v -> tgt.meldungID = v "SetMeldungIDFromIdentifier";
  } "MapMeldungID";
  // Fallback: generierte UUID als Meldung_ID
  src where identifier.exists().not() -> tgt.meldungID = uuid() "SetMeldungIDGenerated";
  // Melder_ID: aus Bundle.meta.source oder fest konfigurierter Wert
  src.meta as meta then {
    meta.source as s -> tgt.melderID = s "SetMelderIDFromSource";
  } "MapMelderID";
  // Meldebegruendung: I (eigene Leistung) als Standard
  // Wird ggf. durch die Teil-Maps ueberschrieben basierend auf Meldungstyp
  src -> tgt.meldebegruendung = 'I' "SetMeldebegruendung";
  // Eigene Leistung: J als Standard (Behandlungseinrichtung meldet eigene Daten)
  src -> tgt.eigeneLeistung = 'J' "SetEigeneLeistung";
}