CH ALIS (R4)
0.3.0 - CI build Switzerland flag

CH ALIS (R4), published by ALIS-Connect. This guide is not an authorized publication; it is the continuous build for version 0.3.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/ahdis/ch-alis/ and changes regularly. See the Directory of published versions

StructureMap: Alis43ToBundle

Official URL: http://fhir.ch/ig/ch-alis/StructureMap/Alis43ToBundle Version: 0.3.0
Draft as of 2024-10-29 Computable Name: Alis43ToBundle

Copyright/Legal: not-open-source

Convert ALIS43 XML to a Bundle according to the CH ALIS implmementation guide, 2020-12-03 by Oliver Egger, copyright ahdis ag, Apache License, FHIR: http://hl7.org/fhir/r4/. ISSUE7: what are the URL's oid's we have to define.

/// url = "http://fhir.ch/ig/ch-alis/StructureMap/Alis43ToBundle"
/// name = "Alis43ToBundle"
/// title = "null"
/// status = "draft"

// Convert ALIS43 XML to a Bundle according to the CH ALIS implmementation guide,
// 2020-12-03 by Oliver Egger, copyright ahdis ag, Apache License,
// FHIR: http://hl7.org/fhir/r4/.
// ISSUE7: what are the URL's oid's we have to define.

conceptmap "serviceMap" {
  prefix s = "http://fhir.ch/ig/ch-alis"
  prefix t = "http://hl7.org/fhir"

  s:TARMED == t:"urn:oid:2.16.756.5.30.1.129.1.4"
  s:ICD10 == t:"urn:oid:2.16.756.5.30.1.126.3.2"
}

conceptmap "gender" {
  prefix s = "http://fhir.ch/ig/ch-alis"
  prefix t = "http://hl7.org/fhir/ValueSet/administrative-gender"

  s:M == t:male
  s:F == t:female
}

conceptmap "laterality" {
  prefix s = "http://fhir.ch/ig/ch-alis"
  prefix t = "http://snomed.info/sct"

  s:l == t:"7771000"
  s:r == t:"24028007"
  s:b == t:"51440002"
}

uses "http://fhir.ch/ig/ch-alis/StructureDefinition/Header" alias Header as source
uses "http://fhir.ch/ig/ch-alis/StructureDefinition/Visit" alias Visit as source
uses "http://fhir.ch/ig/ch-alis/StructureDefinition/Service" alias Service as source
uses "http://fhir.ch/ig/ch-alis/StructureDefinition/PersonV40" alias PersonV40 as source
uses "http://fhir.ch/ig/ch-alis/StructureDefinition/ParameterV40" alias ParameterV40 as source
uses "http://fhir.ch/ig/ch-alis/StructureDefinition/DiagGroup" alias DiagGroup as source
uses "http://fhir.ch/ig/ch-alis/StructureDefinition/LeistungsschnittstelleProcedure" alias Proc as source
uses "http://fhir.ch/ig/ch-alis/StructureDefinition/Diagnosis" alias Diagnosis as source
uses "http://hl7.org/fhir/StructureDefinition/Bundle" alias Bundle as target
uses "http://hl7.org/fhir/StructureDefinition/ChargeItem" alias ChargeItem as target
uses "http://hl7.org/fhir/StructureDefinition/Extension" alias Extension as target
uses "http://hl7.org/fhir/StructureDefinition/MessageHeader" alias MessageHeader as target
uses "http://hl7.org/fhir/StructureDefinition/BackboneElement" alias BackboneElement as target
uses "http://hl7.org/fhir/StructureDefinition/HumanName" alias HumanName as target
uses "http://hl7.org/fhir/StructureDefinition/Condition" alias Condition as target
uses "http://hl7.org/fhir/StructureDefinition/Encounter" alias Encounter as target
uses "http://hl7.org/fhir/StructureDefinition/Procedure" alias Procedure as target

group Alis43ToBundle(source header : Header, target bundle : Bundle) {
  header ->  bundle.meta as meta,  meta.profile as profile,  profile.value = 'http://fhir.ch/ig/ch-alis/StructureDefinition/ch-alis-message',  bundle.entry as e,  e.resource = create('MessageHeader') as messageHeader,  messageHeader.id = uuid() as uuid,  e.fullUrl = append('urn:uuid:', uuid),  bundle.entry as e2,  e2.resource = create('Bundle') as transactionBundle,  transactionBundle.id = uuid() as uuid2,  e2.fullUrl = append('urn:uuid:', uuid2),  messageHeader.focus = create('Reference') as reference,  reference.type = 'Bundle',  reference.reference = append('urn:uuid:', uuid2) then {
    header then Alis43ToMessageHeader(header, messageHeader) "messageHeader";
    header then Alis43ToBundleTransaction(header, transactionBundle) "bundleTransaction";
  } "bundle";
  header -> bundle.type = 'message' "type";
  header.FileCreationDate as fileCreationDate then {
    fileCreationDate.data as date -> bundle.timestamp = date "date";
  };
}

group Alis43ToMessageHeader(source header : Header, target messageHeader : MessageHeader) {
  // ISSUE1: should be link to a MessageDefinition or a code?
  header ->  messageHeader.event = create('uri') as value,  value.value = 'http://fhir.ch/ig/ch-alis-43' "eventUri";
  // ISSUE2: MessageControlID cannot be id of entry, needs to be either fullUrl oder uuid, need to map this to an identifier
  header -> messageHeader.source as source then {
    header.SoftwareReleaseNumber as version -> source.version = (%version.data) "version";
    // ISSUE3: " : "urn:SendingApplication:SendingFacility:SendingServiceCode" -> add urn: in example/docu
    header -> source.endpoint = ('urn:' + %header.SendingApplication.data + ':' + %header.SendingFacility.data + ':' + %header.SendingServiceCode.data) "endpoint";
  } "source";
  header -> messageHeader.destination as destination then {
    // ISSUE4: " : "urn:ReceivingApplication, ReceivingFacility, ReceivingServiceCode" -> add urn: in example/docu
    header -> destination.endpoint = ('urn:' + %header.ReceivingApplication.data + ':' + %header.ReceivingFacility.data + ':' + %header.ReceivingServiceCode.data) "endpoint";
  } "destination";
}

group Alis43ToBundleTransaction(source header : Header, target transactionBundle : Bundle) {
  header -> transactionBundle.type = 'transaction' "transaction";
  header.Visit as visit then {
    visit.Service as service ->  transactionBundle.entry as e,  e.resource = create('ChargeItem') as chargeItem then ServiceToChargeItem(service, visit, chargeItem, e) "ServiceToChargeItem";
  };
}

group ServiceToChargeItem(source service : Service, source visit : Visit, target chargeItem : ChargeItem, target entry) {
  service.ItemNumber as itemNumber ->  chargeItem.id = (%itemNumber.data.lower()) as uuid,  entry.fullUrl = append('urn:uuid:', uuid) "R311LaufnummerItemNumber";
  service ->  chargeItem.contained = create('Patient') as patient,  patient.id = 'pat' as containedid,  chargeItem.subject = create('Reference') as ref,  ref.reference = ('#' + %containedid) then ServiceToPatient(service, visit, patient) "patient";
  visit ->  chargeItem.contained = create('Encounter') as encounter,  encounter.id = 'enc' as containedid,  chargeItem.context = create('Reference') as ref,  ref.reference = ('#' + %containedid) then {
    visit then VisitToEncounter(visit, encounter) "VisitToEncounter";
    service.Diagnosis as diag ->  chargeItem.contained = create('Condition') as condition,  condition.id = uuid() as containedid,  encounter.diagnosis as diag,  diag.condition = create('Reference') as ref,  ref.reference = ('#' + %containedid) then DiagnosisToCondition(diag, condition) "DiagnosisToCondition";
  } "encounter";
  visit.DiagGroup as diaggroup ->  chargeItem.contained = create('Condition') as cond,  cond.id = 'cond' as containedid then DiagGroupToCondition(diaggroup, cond) "DiagGroupToCondition";
  service where (service.Transaction.exists() = false) ->  entry.request as request,  request.method = 'POST',  request.url = 'ChargeItem' "POSTDEFAULT";
  service.Transaction where (service.Transaction = 'insert') ->  entry.request as request,  request.method = 'POST',  request.url = 'ChargeItem' "POST";
  service.Transaction where (service.Transaction = 'update') ->  entry.request as request,  request.method = 'PUT',  request.url = 'ChargeItem' "UPDATE";
  service.Transaction where (service.Transaction = 'delete') ->  entry.request as request,  request.method = 'DELETE',  request.url = 'ChargeItem' "DELETE";
  service.SessionID as sessionID ->  chargeItem.extension as extension,  extension.url = 'http://fhir.ch/ig/ch-alis/StructureDefinition/ch-alis-ext-sessionid',  extension.value = create('string') as value,  value.value = (%sessionID.data) "R32SitzungSessionID";
  service.OrderID as orderID ->  chargeItem.extension as extension,  extension.url = 'http://fhir.ch/ig/ch-alis/StructureDefinition/ch-alis-ext-orderid',  extension.value = create('string') as value,  value.value = (%orderID.data) "R33AuftragsnummerOrderID";
  service.OrderDate as orderDate ->  chargeItem.extension as extension,  extension.url = 'http://fhir.ch/ig/ch-alis/StructureDefinition/ch-alis-ext-orderdate',  extension.value = create('dateTime') as value,  value.value = (%orderDate.data) "R33AuftragsnummerOrderID";
  service.Form as form ->  chargeItem.extension as extension,  extension.url = 'http://fhir.ch/ig/ch-alis/StructureDefinition/ch-alis-ext-form',  extension.value = create('string') as value,  value.value = (%form.data) "R37FormularbezeichnungForm";
  service.ParameterV40 as parameterV40 ->  chargeItem.extension as extension,  extension.url = 'http://fhir.ch/ig/ch-alis/StructureDefinition/ch-alis-ext-parameterv40' then ParameterV40ToExtension(parameterV40, extension) "R4ParamterV40ParameterV40";
  service -> chargeItem.status = 'billable' "billable";
  service.RefItemNumber as refItemNumber then {
    refItemNumber.data as data ->  chargeItem.partOf = create('Reference') as ref,  ref.reference = ('urn:uuid:' + %data.lower()),  ref.type = 'ChargeItem' "R312ReferenzzuHauptleistungRefItemNumber";
  };
  service.ServiceItem as serviceItem then {
    serviceItem.data as data ->  chargeItem.code = create('CodeableConcept') as cc,  cc.coding = create('Coding') as coding,  coding.code = data then {
      service.ServiceType as serviceType then {
        serviceType.data as data -> coding.system = translate(data, '#serviceMap', 'code') "R35KatalogServiceType";
      } "servicType";
    } "R36TarifpositionServiceItem";
  } "R36Tarifposition";
  service.ServiceDate as serviceData ->  chargeItem.occurrence = create('dateTime') as occurrence,  occurrence.value = (%serviceData.data) "R31LeistungsdatumServiceDate";
  service.PersonV40 as personV40 -> chargeItem.performer = create('BackboneElement') as performer then PersonV40ToPerformer(personV40, performer) "R315PersonV40PersonV40";
  service.ProviderID as providerID ->  chargeItem.performingOrganization = create('Reference') as reference,  reference.display = (%providerID.data) "R39ErbringendeOrganizationProviderID";
  service.ReferrerID as referrerID ->  chargeItem.costCenter = create('Reference') as reference,  reference.display = (%referrerID.data) "R34AuftraggebendeKostenstelleReferrerID";
  service.Quantity as quantity ->  chargeItem.quantity = create('Quantity') as q,  q.value as value,  value.value = (%quantity.data) "R313AnzahlQuantity";
  service.EnteredBy as enteredBy ->  chargeItem.enterer = create('Reference') as reference,  reference.display = (%enteredBy.data) "R310ErfasserEnteredBy";
  service.EnteredDateTime as enteredDateTime ->  chargeItem.enteredDate = create('dateTime') as enteredDate,  enteredDate.value = (%enteredDateTime.data) "R38ErfassungsdatumEnteredDateTime";
  service.PatientContactID as patientContactID then {
    patientContactID.data as data ->  chargeItem.identifier = create('Identifier') as identifier,  identifier.value = data "PatientContactID";
  } "patientContactID";
  service.Costweight as costweight then {
    costweight.data as data -> chargeItem.factorOverride = data "Costweight";
  } "costweight";
  service.Procedure as proc ->  chargeItem.contained = create('Procedure') as procedure,  procedure.id = uuid() as containedid,  chargeItem.service = create('Reference') as service,  service.reference = ('#' + %containedid) then ServiceProcedureToFhirProcedure(proc, procedure) "ServiceProcedureToFhirProcedure";
}

group ServiceProcedureToFhirProcedure(source proc : Proc, target procedure : Procedure) {
  proc.Identifier as identifier ->  procedure.identifier = create('Identifier') as identifier,  identifier.value = (%identifier.data) "R314ProzedurIDIdentifier";
  proc.Code as chopcode where (%proc.Category.data = 'CHOP_2023') ->  procedure.code = create('CodeableConcept') as cc,  cc.coding = create('Coding') as coding,  coding.code = (%chopcode.data),  coding.system = 'https://www.bfs.admin.ch/bfs/statistiche/catalog/chop2023',  coding.display = (%proc.Display.data) "R316ProzedurcodeCode";
  proc.PerformedDateTime as performedDateTime -> procedure.performed = (%performedDateTime.data) "R317DatumZeitPerformedDateTime";
  proc.Laterality as laterality then {
    laterality.data as v ->  procedure.bodySite = create('CodeableConcept') as cc,  cc.coding = create('Coding') as coding,  coding.code = translate(v, '#laterality', 'code'),  coding.system = 'http://snomed.info/sct',  coding.display = (%proc.LateralityDisplay.data) "R318SeiteLaterality";
  } "laterality";
  proc.Performer as performer then {
    // TODO Perfomer.function
    performer.Identifier as identifier then {
      identifier.data as data ->  procedure.performer as performer,  performer.actor as actor,  actor.identifier as identifier,  identifier.value = data "identifier";
    };
  } "performer";
  proc ->  procedure.subject = create('Reference') as ref,  ref.reference = '#pat' "containedpatient";
  proc -> procedure.status = 'completed' "status";
}

group PersonV40ToPerformer(source personV40 : PersonV40, target performer) {
  personV40.PersonTyp as personTyp ->  performer.function as cc,  cc.coding as coding,  coding.system as system,  system.value = 'http://fhir.ch/ig/ch-alis/CodeSystem/ch-alis-persontyp',  coding.code as code,  code.value = personTyp "R3152PersonIDPersonID";
  personV40.PersonID as personId ->  performer.actor = create('Reference') as reference,  reference.display = (%personId.data) "R3152PersonIDPersonID";
}

group ParameterV40ToExtension(source parameterV40 : ParameterV40, target extension : Extension) {
  parameterV40.ParamTyp as paramTyp -> extension.extension as extInner then InnerExtensionParamTyp(paramTyp, extInner);
  parameterV40.ParamValue as paramValue then {
    paramValue.data as data -> extension.extension as extInner then InnerExtensionParamValue(data, extInner);
  };
}

group InnerExtensionParamTyp(source src, target ext : Extension) {
  src -> ext.url = 'ParamTyp' "url";
  src ->  ext.value = create('CodeableConcept') as cc,  cc.text as text,  text.value = src "string";
}

group InnerExtensionParamValue(source src, target ext : Extension) {
  src -> ext.url = 'ParamValue' "url";
  src ->  ext.value = create('string') as string,  string.value = src "string";
}

group ServiceToPatientName(source visit : Visit, target name : HumanName) {
  visit.PatientName as patientName then {
    patientName.data as data -> name.family = data "R23PatientNamePatientName";
  } "patientName";
  visit.PatientGivenName as patientGivenName then {
    patientGivenName.data as data -> name.given = data "R24PatientVornamePatientGivenName";
  } "patientGivenName";
}

group ServiceToPatient(source service : Service, source visit : Visit, target patient : Patient) {
  visit.PatientID as patientID then {
    patientID.data as patId ->  patient.identifier as identifier,  identifier.value as value,  value.value = patId,  identifier.system as idsystem,  idsystem.value = 'http://www.example.ch/patienteniddomain',  identifier.type as type,  type.coding as coding,  coding.system as system,  system.value = 'http://terminology.hl7.org/CodeSystem/v2-0203',  coding.code as code,  code.value = 'MR' "R22PatientPIDPatientID";
  } "patientID";
  // <!-- 2.2 Patient.PID (PatientID) -->
  // <identifier>
  // <type>
  // <coding>
  // <system value="http://terminology.hl7.org/CodeSystem/v2-0203" />
  // <code value="MR" />
  // <display value="Medical record number"/>
  // </coding>
  // </type>
  // ISSUE8: what do with system value
  // <system value="http://www.example.ch/patienteniddomain"/>
  // <value value="Patienten-ID"/>
  // </identifier>//
  visit where (visit.PatientName or visit.PatientGivenName) -> patient.name as name then ServiceToPatientName(visit, name) "ServiceToPatient";
  visit.PatientGender as gender then {
    gender.data as v -> patient.gender = translate(v, '#gender', 'code') "gender";
  } "R26PatientGeschlechtPatientGender";
  visit.PatientBirthDate as birthDate then {
    birthDate.data as v -> patient.birthDate = v "birthDate";
  } "R25PatientGebDatumPatientBirthDate";
}

group DiagnosisToCondition(source diagnosis : Diagnosis, target cond : Condition) {
  diagnosis ->  cond.subject = create('Reference') as ref,  ref.reference = '#pat' "containedpatient";
  // * Identifier 0..1 http://fhir.ch/ig/ch-alis/StructureDefinition/Text "TODO"
  diagnosis.Identifier as identifier then {
    identifier.data as data ->  cond.identifier as identifier,  identifier.value = data "identifier";
  };
  diagnosis.Code as code ->  cond.code = create('CodeableConcept') as cc,  cc.coding = create('Coding') as coding,  coding.code = (%code.data),  coding.display = (%diagnosis.Display.data) then {
    diagnosis.Category as category then {
      category.data as data where (startsWith('ICD')) -> coding.system = 'http://hl7.org/fhir/sid/icd-10';
    } "serviceType";
  } "R316ProzedurcodeCode";
  // TODO system is not yet correct
  diagnosis.OnsetDateTime as onsetDateTime -> cond.onset = (%onsetDateTime.data) "onsetDateTime";
  diagnosis.Laterality as laterality then {
    laterality.data as v ->  cond.bodySite = create('CodeableConcept') as cc,  cc.coding = create('Coding') as coding,  coding.code = translate(v, '#laterality', 'code'),  coding.system = 'http://snomed.info/sct',  coding.display = (%diagnosis.LateralityDisplay.data) "R318SeiteLaterality";
  } "laterality";
}

group DiagGroupToCondition(source diagGroup : DiagGroup, target cond : Condition) {
  diagGroup ->  cond.subject = create('Reference') as ref,  ref.reference = '#pat' "containedpatient";
  diagGroup.DiagCode as data ->  cond.code = create('CodeableConcept') as cc,  cc.coding = create('Coding') as coding,  coding.code = data then {
    diagGroup.DiagCatType as diagCatType then {
      diagCatType.data as data -> coding.system = translate(data, '#serviceMap', 'code') "R293KatalogtypDiagCatType";
    } "serviceType";
  } "R291DiagnosecodeDiagCode";
}

group TerminationToExtension(source visit : Visit, target ext : Extension) {
  visit.TerminationVisit as visit then {
    visit.data as data ->  ext.extension as ext1,  ext1.url = 'TerminationVisit',  ext1.value = create('date') as date,  date.value = data "R27FallAbschlussTerminationVisit";
  };
  visit.TerminationReason as visit then {
    visit.data as data ->  ext.extension as ext1,  ext1.url = 'TerminationReason',  ext1.value = create('string') as string,  string.value = data "R28FallAbschlussgrundTerminationReason";
  } "TerminationVisit";
}

group VisitToEncounter(source visit : Visit, target encounter : Encounter) {
  visit where (visit.TerminationVisit or visit.TerminationReason) ->  encounter.extension as ext,  ext.url = 'http://fhir.ch/ig/ch-alis/StructureDefinition/ch-alis-ext-termination' then TerminationToExtension(visit, ext) "TerminationToExtension";
  visit.VisitNumber as visitNumber then {
    // ISSUE8: what to do with falldomain? <system value="http://www.example.ch/fallnummerdomain"/>
    visitNumber.data as data ->  encounter.identifier = create('Identifier') as identifier,  identifier.value as value,  value.value = data,  identifier.system as idsystem,  idsystem.value = 'http://www.example.ch/fallnummerdomain',  identifier.type as type,  type.coding as coding,  coding.system as system,  system.value = 'http://terminology.hl7.org/CodeSystem/v2-0203',  coding.code as code,  code.value = 'VN' "R21FallVisitNumber";
  } "encounterID";
  visit -> encounter.status = 'finished' "Finished";
  visit ->  encounter.class as coding,  coding.system as system,  system.value = 'http://terminology.hl7.org/CodeSystem/v3-ActCode',  coding.code as code,  code.value = 'IMP',  coding.display as display,  display.value = 'inpatient encounter' "R21FallVisitNumber";
  visit ->  encounter.subject = create('Reference') as ref,  ref.reference = '#pat' "subject";
  visit.DiagGroup as diaggroup ->  encounter.diagnosis as diag,  diag.condition = create('Reference') as ref,  ref.reference = '#cond' then {
    diaggroup.DiagType as diagType ->  diag.use as use,  use.text = (%diagType.data) "R292DiagnosetypDiagType";
  } "R29DiagnoseGruppeDiagGroup";
}