Data Management with FHIR
0.1.0 - ci-build France flag

Data Management with FHIR - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

StructureMap: Alignement de l''usage Core du modèle physique du DPI vers les ressources FHIR

Official URL: https://interop.aphp.fr/ig/fhir/dm/StructureMap/CorePhysical2FHIR Version: 0.1.0
Draft as of 2025-10-23 Computable Name: CorePhysical2FHIR

Alignement de l''usage Core du modèle physique du DPI vers les ressources FHIR

map "https://interop.aphp.fr/ig/fhir/dm/StructureMap/CorePhysical2FHIR" = "CorePhysical2FHIR"

// Alignement de l''usage Core du modèle physique du DPI vers les ressources FHIR

uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreDataSet" alias DataSet as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CorePatient" alias PatientTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreSejour" alias SejourTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreBiology" alias BiologyTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreClinical" alias ClinicalTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreDiag" alias DiagTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreActe" alias ActeTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreAddress" alias AddressTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreMedicationAdm" alias MedicationAdmTable as source
uses "https://interop.aphp.fr/ig/fhir/dm/StructureDefinition/CoreMedicationPre" alias MedicationPreTable as source
uses "http://hl7.org/fhir/StructureDefinition/Bundle" alias FHIRBundle as target
uses "http://hl7.org/fhir/StructureDefinition/Patient" alias FHIRPatient as target
uses "http://hl7.org/fhir/StructureDefinition/Encounter" alias FHIREncounter as target
uses "http://hl7.org/fhir/StructureDefinition/Observation" alias FHIRObservation as target
uses "http://hl7.org/fhir/StructureDefinition/Meta" alias FHIRMeta as target
uses "http://hl7.org/fhir/StructureDefinition/Procedure" alias FHIRProcedure as target
uses "http://hl7.org/fhir/StructureDefinition/Condition" alias FHIRCondition as target

group dataSet(source srcDataSet : DataSet, target tgtBundle : FHIRBundle) <<types>> {
  srcDataSet -> tgtBundle.id = uuid() "setId";
  srcDataSet -> tgtBundle.type = 'transaction' "setType";
  srcDataSet.patient as srcPatient ->  tgtBundle.entry as tgtPatientEntry,  tgtPatientEntry.resource = create('Patient') as newPatient then {
    srcPatient then patient(srcPatient, newPatient) "setPatient";
    srcPatient then setEntryRequestAndFullUrl(newPatient, tgtPatientEntry) "setRequestAndFullUrl";
    srcDataSet.address as srcAddress where patientNi.reference = ('PatientCore/' + %srcPatient.patientNi.toString()) then patientAddress(srcAddress, newPatient) "addPatientAddress";
    srcDataSet.sejour as srcSejour where patientNi.reference = ('PatientCore/' + %srcPatient.patientNi.toString()) ->  tgtBundle.entry as tgtEncounterEntry,  tgtEncounterEntry.resource = create('Encounter') as newEncounter then {
      srcSejour then encounter(srcSejour, newPatient, newEncounter) "setEncounter";
      srcSejour then setEntryRequestAndFullUrl(newEncounter, tgtEncounterEntry) "setRequestAndFullUrl";
      srcDataSet.acte as srcActe where sejourNi.reference = ('SejourCore/' + %srcSejour.sejourNi.toString()) ->  tgtBundle.entry as tgtProcedureEntry,  tgtProcedureEntry.resource = create('Procedure') as newProcedure then {
        srcActe then procedure(srcActe, newPatient, newEncounter, newProcedure) "setProcedure";
        srcActe then setEntryRequestAndFullUrl(newProcedure, tgtProcedureEntry) "setRequestAndFullUrl";
      } "createProcedure";
      srcDataSet.diag as srcDiag where sejourNi.reference = ('SejourCore/' + %srcSejour.sejourNi.toString()) ->  tgtBundle.entry as tgtConditionEntry,  tgtConditionEntry.resource = create('Condition') as newCondition then {
        srcDiag then condition(srcDiag, newPatient, newEncounter, newCondition) "setCondition";
        srcDiag then setEntryRequestAndFullUrl(newCondition, tgtConditionEntry) "setRequestAndFullUrl";
      } "createProcedure";
      srcDataSet.biology as srcBiology where sejourNi.reference = ('SejourCore/' + %srcSejour.sejourNi.toString()) ->  tgtBundle.entry as tgtBiologyEntry,  tgtBiologyEntry.resource = create('Observation') as newObservation then {
        srcBiology then observationBiol(srcBiology, newPatient, newEncounter, newObservation) "setBiology";
        srcBiology then setEntryRequestAndFullUrl(newObservation, tgtBiologyEntry) "setRequestAndFullUrl";
      } "createObservation";
    } "createEncounter";
  } "createPatient";
}

group patient(source srcPatient : PatientTable, target tgtPatient : FHIRPatient) {
  srcPatient -> tgtPatient.id = uuid() "setId";
  srcPatient.patientNi as srcNi -> tgtPatient.meta as tgtMeta then setPatientMeta(srcNi, tgtMeta) "setMeta"; // copie la valeur du champ patientNi de la table Patient dans l'élément id de la ressource FHIR Patient
  srcPatient -> tgtPatient.name as tgtPatientName then setHumainName(srcPatient, tgtPatientName) "setHumainName";
  srcPatient -> tgtPatient.identifier as tgtPatientIdentifier then setHumainNir(srcPatient, tgtPatientIdentifier) "setHumainNir";
  srcPatient.gender as srcPatientGender -> tgtPatient.gender = translate(srcPatientGender, 'https://interop.aphp.fr/ig/fhir/dm/ConceptMap/DpiGender2Hl7Gender', 'code') "setGender"; // traduit la valeur du champ gender de la table Patient dans l'élément gender de la ressource FHIR Patient
  srcPatient.birthDate as srcPatientBirthDate -> tgtPatient.birthDate = srcPatientBirthDate "setBirthDate"; // copie la valeur du champ birthDate de la table Patient dans l'élément birthDate de la ressource FHIR Patient
}

group setPatientMeta(source srcNi, target tgtMeta : FHIRMeta) {
  srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/PatientTable' + '/' + %srcNi.toString()) "setSource";
}

group setHumainName(source srcPatient : PatientTable, target tgtPatientName) {
  srcPatient -> tgtPatientName.use = 'usual' "setUse";
  // srcPatient -> tgtPatientName.text = (%srcPatient.firstName + ' ' + %srcPatient.name) "setText";
  // srcPatient.name as srcPatientName -> tgtPatientName.family = srcPatientName "setName";
  // srcPatient.firstName as srcPatientFirstName -> tgtPatientName.given = srcPatientFirstName "setFirstName";
  // les trois lignes précédentes marchent dans matchbox mais génèrent une erreur au QA. La solution ci dessous marche dans matchbox et ne génère pas d'erreur au QA.
  srcPatient.name as srcPatientName -> tgtPatientName.family = srcPatientName then {
    srcPatient.firstName as srcPatientFirstName ->  tgtPatientName.given = srcPatientFirstName,  tgtPatientName.text = (%srcPatientFirstName + ' ' + %srcPatientName) "setFirstNameAndText";
  } "setName";
}

group setHumainNir(source srcPatient : PatientTable, target tgtPatientIdentifier) {
  srcPatient.nir as srcPatientNir ->  tgtPatientIdentifier.use = 'official',  tgtPatientIdentifier.type = cc('https://hl7.fr/ig/fhir/core/CodeSystem/fr-core-cs-v2-0203', 'INS-NIR'),  tgtPatientIdentifier.system = 'urn:oid:1.2.250.1.213.1.4.8',  tgtPatientIdentifier.value = srcPatientNir "setNir";
}

group patientAddress(source srcAddress : AddressTable, target tgtPatient : FHIRPatient) {
  srcAddress -> tgtPatient.address = create('Address') as newAddress then {
    srcAddress.zipCode as srczip -> newAddress.postalCode = srczip "setZip";
    srcAddress.city as srcCity -> newAddress.city = srcCity "setCity";
    srcAddress.country as srcCountry -> newAddress.country = srcCountry "setCountry";
    srcAddress.address as srcAddressText -> newAddress.text = srcAddressText "setText";
    srcAddress where current = true -> newAddress.use = 'home' "setUseHome";
    srcAddress where current = false -> newAddress.use = 'old' "setUseOld";
    srcAddress where latitude.exists() or longitude.exists() -> newAddress.extension = create('Extension') as firstLevelExtension then {
      srcAddress -> firstLevelExtension.url = ('http://hl7.org/fhir/StructureDefinition/geolocation') then {
        srcAddress.latitude as srcLat -> firstLevelExtension.extension = create('Extension') as latExtension then {
          srcLat ->  latExtension.url = ('latitude'),  latExtension.value = srcLat "setLat";
        } "setLatExt";
        srcAddress.longitude as srcLong -> firstLevelExtension.extension = create('Extension') as longExtension then {
          srcLong ->  longExtension.url = ('longitude'),  longExtension.value = srcLong "setLong";
        } "setLongExt";
      } "setflext";
    } "setCoordinatesExtension";
  } "setAddress";
}

group encounter(source srcSejour : SejourTable, source srcPatient : FHIRPatient, target tgtEncounter : FHIREncounter) {
  srcSejour -> tgtEncounter.id = uuid() "setId";
  srcSejour.sejourNi as srcNi -> tgtEncounter.meta as tgtMeta then setEncounterMeta(srcNi, tgtMeta) "setMeta"; // copie la valeur du champ patientNi de la table Patient dans l'élément id de la ressource FHIR Patient
  srcSejour -> tgtEncounter.status = 'finished' "setStatus";
  srcSejour.sejourType as srcSejourType -> tgtEncounter.class = translate(srcSejourType, 'https://interop.aphp.fr/ig/fhir/dm/ConceptMap/DpiEncounterType2SemanticLayerEncounterClass', 'Coding') "setEncounterClass";
  srcPatient.id as patientId -> tgtEncounter.subject = create('Reference') as newSubject then setSubjectReference(patientId, newSubject) "setSubjectReference";
  srcSejour.patientNi; // fk vers le patient à conserver pour la construction auto du périmètre final
  srcSejour -> tgtEncounter.period = create('Period') as newActualPeriod then {
    srcSejour.sejourStart as srcPeriodStart -> newActualPeriod.start = srcPeriodStart "setStart";
    srcSejour.sejourEnd as srcPeriodEnd -> newActualPeriod.end = srcPeriodEnd "setEnd";
  } "setPeriod";
}

group setEncounterMeta(source srcNi, target tgtMeta : FHIRMeta) {
  srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/SejourTable' + '/' + %srcNi.toString()) "setSource";
}

group setSubjectReference(source srcPatientId, target newSubject) {
  srcPatientId -> newSubject.reference = ('Patient/' + %srcPatientId.toString()) "setReference";
}

group procedure(source srcActe : ActeTable, source srcPatient : FHIRPatient, source srcEncounter : FHIREncounter, target tgtProcedure : FHIRProcedure) {
  srcActe -> tgtProcedure.id = uuid() "setId";
  srcActe.acteNi as srcNi -> tgtProcedure.meta as tgtMeta then setProcedureMeta(srcNi, tgtMeta) "setMeta";
  srcPatient.id as patientId -> tgtProcedure.subject = create('Reference') as newSubject then setSubjectReference(patientId, newSubject) "setSubjectReference";
  srcEncounter.id as encounterId -> tgtProcedure.encounter = create('Reference') as newEncounter then setEncounterReference(encounterId, newEncounter) "setEncounterReference";
  srcActe -> tgtProcedure.status = 'completed' "setStatus";
  srcActe where dateStart.exists() or dateEnd.exists -> tgtProcedure.performed = create('Period') as tgtProcedurePeriod then {
    srcActe.dateStart as srcActeStart -> tgtProcedurePeriod.start = srcActeStart "setActeStart";
    srcActe.dateEnd as srcActeEnd -> tgtProcedurePeriod.end = srcActeEnd "setActeEnd";
  } "setDate";
  srcActe.code as acteCode -> tgtProcedure.code = cc('https://smt.esante.gouv.fr/terminologie-ccam', acteCode) "setCode"; // C'est le code de la CCAM facturante
}

group setProcedureMeta(source srcNi, target tgtMeta : FHIRMeta) {
  srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/ActeTable' + '/' + %srcNi.toString()) "setSource";
}

group setEncounterReference(source srcEncounterId, target newEncounter) {
  srcEncounterId -> newEncounter.reference = ('Encounter/' + %srcEncounterId.toString()) "setReference";
}

group condition(source srcDiag : DiagTable, source srcPatient : FHIRPatient, source srcEncounter : FHIREncounter, target tgtCondition : FHIRCondition) {
  srcDiag -> tgtCondition.id = uuid() "setId";
  srcDiag.diagNi as srcNi -> tgtCondition.meta as tgtMeta then setConditionMeta(srcNi, tgtMeta) "setMeta";
  srcPatient.id as patientId -> tgtCondition.subject = create('Reference') as newSubject then setSubjectReference(patientId, newSubject) "setSubjectReference";
  srcEncounter.id as encounterId -> tgtCondition.encounter = create('Reference') as newEncounter then setEncounterReference(encounterId, newEncounter) "setEncounterReference";
  srcDiag -> tgtCondition.verificationStatus = 'confirmed' "setVerificationStatus";
  srcDiag -> tgtCondition.category = cc('http://terminology.hl7.org/CodeSystem/condition-category', 'encounter-diagnosis') "setCategory";
  srcDiag.code as diagCode -> tgtCondition.code = cc('http://hl7.org/fhir/sid/icd-10', diagCode) "setCode";
}

group setConditionMeta(source srcNi, target tgtMeta : FHIRMeta) {
  srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/DiagTable' + '/' + %srcNi.toString()) "setSource";
}

group observationBiol(source srcBiology : BiologyTable, source srcPatient : FHIRPatient, source srcEncounter : FHIREncounter, target tgtObservation : FHIRObservation) {
  srcBiology -> tgtObservation.id = uuid() "setId";
  srcBiology.biologyNi as srcNi -> tgtObservation.meta as tgtMeta then setBiologyMeta(srcNi, tgtMeta) "setMeta";
  srcPatient.id as patientId -> tgtObservation.subject = create('Reference') as newSubject then setSubjectReference(patientId, newSubject) "setSubjectReference";
  srcEncounter.id as encounterId -> tgtObservation.encounter = create('Reference') as newEncounter then setEncounterReference(encounterId, newEncounter) "setEncounterReference";
  srcBiology -> tgtObservation.status = 'final' "setStatus";
  srcBiology -> tgtObservation.category = cc('http://terminology.hl7.org/CodeSystem/observation-category', 'vital-signs') "setCategory";
  srcBiology.biologyDatePrel as biologyDatePrel -> tgtObservation.effective = biologyDatePrel "setDate";
  srcBiology.biologyCode as biologyCode -> tgtObservation.code = cc('http://loinc.org', biologyCode) "setCode";
  srcBiology.biologyValue -> tgtObservation.value = create('Quantity') as tgtObsQuantity then {
    srcBiology.biologyValue as biologyValue -> tgtObsQuantity.value = biologyValue "setValue";
    srcBiology.biologyUnit as biologyUnit ->  tgtObsQuantity.code = biologyUnit,  tgtObsQuantity.unit = biologyUnit,  tgtObsQuantity.system = 'http://unitsofmeasure.org' "setUnit";
  } "setQuantity";
}

group setBiologyMeta(source srcNi, target tgtMeta : FHIRMeta) {
  srcNi -> tgtMeta.source = ('https://aphp.fr/fhir/Endpoint/dpi/BiologyTable' + '/' + %srcNi.toString()) "setSource";
}

group setEntryRequestAndFullUrl(source newRes, target tgtEntry) {
  newRes.id as newResId then {
    newResId -> tgtEntry.fullUrl = ('https://aphp.fr/' + %newRes.type().name + '/' + %newResId) "setFullUrl";
    newResId ->  tgtEntry.request as tgtEntryRequest,  tgtEntryRequest.method = 'POST',  tgtEntryRequest.url = (%newRes.type().name + '/' + %newResId) "setRequest";
  } "setResourceType";
}