SMART PH4H
0.9.9 - release
This page is part of the PH4H (v0.9.9: Releases Draft) based on FHIR (HL7® FHIR® Standard) R4. This is the current published version in its permanent home (it will always be available at this URL). For a full list of available versions, see the Directory of published versions
| Official URL: http://smart.who.int/ph4h/StructureMap/MedicationOverviewLMToMedicationOverviewBundle | Version: 0.9.9 | |||
| Draft as of 2026-07-09 | Computable Name: MedicationOverviewLMToMedicationOverviewBundle | |||
map "http://smart.who.int/ph4h/StructureMap/MedicationOverviewLMToMedicationOverviewBundle" = "MedicationOverviewLMToMedicationOverviewBundle" uses "https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationOverviewLM" alias MedicationOverviewLM as source uses "https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/PatientLM" alias PatientLM as source uses "https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationTreatmentLineLM" alias MedicationTreatmentLineLM as source uses "https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/PractitionerLM" alias PractitionerLM as source uses "https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationOverview" alias MedicationOverviewBundle as target uses "https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationOverviewComposition" alias MedicationOverviewComposition as target uses "https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/MedicationTreatmentLine" alias MedicationTreatmentLine as target uses "http://hl7.org/fhir/StructureDefinition/Patient" alias Patient as target uses "http://hl7.org/fhir/StructureDefinition/Practitioner" alias Practitioner as target // --------------------------------------------------------------------------- // Top-level group: assemble MedicationOverview Bundle (document) // --------------------------------------------------------------------------- group MedicationOverviewLMToMedicationOverviewBundle(source src : MedicationOverviewLM, target tgt : MedicationOverviewBundle) { src -> tgt.type = 'document' "bundleType"; src -> tgt.timestamp = (now()) "bundleTimestamp"; // Generate fixed UUIDs once; reuse them across entries and Reference targets. src -> uuid() as bid, uuid() as cid, uuid() as pid then { // Bundle.identifier (UUID identifier per RFC 4122) src -> tgt.identifier as id, id.system = 'urn:ietf:rfc:4122', id.value = bid "bundleIdentifier"; // Composition entry. The Composition group ALSO emits the treatment-line bundle // entries (passing tgt in), so each section.entry reference can share the same // UUID as its bundle entry — making the lines reachable from the Composition. src -> tgt.entry as ce, ce.fullUrl = append('urn:uuid:', cid), ce.resource = create('MedicationOverviewComposition') as comp then { src then MedicationOverviewLMToComposition(src, comp, pid, tgt) "compositionContent"; } "compositionEntry"; // Patient entry src.patient as pref -> tgt.entry as pe, pe.fullUrl = append('urn:uuid:', pid), pe.resource = create('Patient') as pat then { pref then PatientLMToPatient(pref, pat) "patientContent"; } "patientEntry"; } "setEntries"; } // --------------------------------------------------------------------------- // MedicationOverviewLM -> MedicationOverviewComposition // Receives the Patient entry's UUID (pid) so subject can reference it. // --------------------------------------------------------------------------- group MedicationOverviewLMToComposition(source src : MedicationOverviewLM, target tgt : MedicationOverviewComposition, source pid, target bundle : MedicationOverviewBundle) { src -> tgt.status = 'final' "compStatus"; // Composition.type — LOINC 56445-0 "Medication summary Document" src -> create('Coding') as cc, cc.system = 'http://loinc.org', cc.code = '56445-0', cc.display = 'Medication summary Document', create('CodeableConcept') as ct, ct.coding = cc, tgt.type = ct "compType"; // Composition.subject -> Patient entry by uuid src -> create('Reference') as subj, subj.reference = append('urn:uuid:', pid), tgt.subject = subj "compSubject"; src -> tgt.date = (now()) "compDate"; src -> tgt.title = 'Medication Overview' "compTitle"; // Composition.author is 1..* (required). The Min source carries no author, so // emit a display-only placeholder Reference to satisfy the cardinality. // TODO: replace with the real authoring Organization/Device once the source // (or a config value) provides it. src -> create('Reference') as au, au.display = 'Medication Overview generator', tgt.author = au "compAuthor"; // Section: MedRecordTreatmentLine src -> tgt.section as sect then { src -> sect.title = 'Medication Treatment Lines' "sectTitle"; src -> create('Coding') as scc, scc.system = 'http://loinc.org', scc.code = '10160-0', scc.display = 'History of Medication use Narrative', create('CodeableConcept') as sc, sc.coding = scc, sect.code = sc "sectCode"; // One UUID per line, shared by the section.entry reference AND the bundle entry, // so each treatment line is reachable by forward traversal from the Composition // (mirrors the ICVP ICVPLMToIPS pattern). This is why the group receives the // Bundle: the line entries are created here, not in the top-level group. src.medicationTreatmentLine as lref -> uuid() as tid then { lref -> sect.entry as se, se.reference = append('urn:uuid:', tid) "sectEntry"; lref -> bundle.entry as te, te.fullUrl = append('urn:uuid:', tid), te.resource = create('MedicationTreatmentLine') as ms then { lref then MedicationTreatmentLineLMToMedicationStatement(lref, ms, pid) "lineContent"; } "lineEntry"; } "treatmentLines"; } "sectionTreatmentLines"; // Attester from verification BackboneElement src.verification as v -> tgt.attester as att then { v -> att.mode = 'professional' "attMode"; v.verificationTime as vt -> att.time = vt "attTime"; // practicioner is Reference(PractitionerLM) in the LM — copy the reference // as-is ((pr.name.text) was invalid: References have no name). v.practicioner as pr -> att.party = pr "attParty"; } "attester"; // Comment -> R4 Composition has NO `note` element (R5-only). Use the // cross-version extension, mirroring the r4 profile's approach for adherence. src.comment as cm -> create('Extension') as ext, ext.url = 'http://hl7.org/fhir/5.0/StructureDefinition/extension-Composition.note', create('Annotation') as nt then { cm.commentText as ctxt -> nt.text = ctxt "noteText"; cm.date as d -> nt.time = d "noteTime"; // author is a Reference in the LM; Annotation.author[x] resolves by type. cm.author as a -> nt.author = a "noteAuthor"; cm -> ext.value = nt, tgt.extension = ext "noteAssign"; } "noteFromComment"; } // --------------------------------------------------------------------------- // PatientLM -> FHIR Patient // --------------------------------------------------------------------------- group PatientLMToPatient(source src : PatientLM, target tgt : Patient) { src.identifier as id -> tgt.identifier = id "patIdentifier"; src.name as n -> tgt.name = n "patName"; // gender: navigate instead of a FHIRPath evaluate — validator can't scope // rule variables inside (…) expressions. src.gender as g then { g.coding as gc then { gc.code as gcode -> tgt.gender = gcode "patGenderCode"; } "patGenderCoding"; } "patGender"; // dateOfBirth is dateTime in LM; birthDate is date — silent truncation expected. src.dateOfBirth as d -> tgt.birthDate = d "patBirthDate"; } // --------------------------------------------------------------------------- // MedicationTreatmentLineLM -> MedicationTreatmentLine (profile on MedicationStatement, R4) // Receives the Patient entry's UUID (pid) so MS.subject can reference it. // --------------------------------------------------------------------------- group MedicationTreatmentLineLMToMedicationStatement(source src : MedicationTreatmentLineLM, target tgt : MedicationTreatmentLine, source pid) { src.identifier as id -> tgt.identifier = id; // subject -> Patient entry by uuid (MS.subject is 1..1) src -> create('Reference') as subj, subj.reference = append('urn:uuid:', pid), tgt.subject = subj "subject"; src.status as st -> tgt.status = st; // medication[x] choice -> R4 medication[x] (no CodeableReference in R4; // the engine resolves medicationReference/medicationCodeableConcept by value type) src.medication : Reference as mr -> tgt.medication = mr "medicationRef"; src.medication : CodeableConcept as mc -> tgt.medication = mc "medicationCC"; // effective[x] on R4 MedicationStatement — address the choice by base name. src.effectivePeriod as ep -> tgt.effective = ep; src.recordingMetadata as rm then { rm.recordedTime as rt -> tgt.dateAsserted = rt "dateAsserted"; rm.recorder as rc -> tgt.informationSource = rc "informationSource"; }; // reason -> R4 reasonCode (0..* CodeableConcept; no CodeableReference in R4) src.indication as ind -> tgt.reasonCode = ind "reasonIndication"; src.indicationText as it -> create('CodeableConcept') as cc, cc.text = it, tgt.reasonCode = cc "reasonIndicationText"; // intendedUse: no R4 MedicationStatement element and no extension slice in the // r4 MEOW profile — intentionally not mapped (stays LM-only). src.usageInstructions as ui -> tgt.dosage = ui "dosage"; src.preparationInstructions as pi -> create('Dosage') as dos, dos.text = pi, tgt.dosage = dos "prepInstructions"; // note = comment src.comment as cm -> create('Annotation') as nt then { cm.commentText as ct -> nt.text = ct "lineNoteText"; cm.date as d -> nt.time = d "lineNoteTime"; cm.author as a -> nt.author = a "lineNoteAuthor"; cm -> tgt.note = nt "lineNoteAssign"; } "lineNote"; // adherence -> R4 has no MS.adherence; the r4 profile slices the R5 // cross-version extension (1..1 in the profile, sub-extensions code/reason). src.treatmentStatus as ts -> create('Extension') as ext, ext.url = 'http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationStatement.adherence', create('Extension') as e1, e1.url = 'code', e1.value = ts, ext.extension = e1, tgt.extension = ext "extAdherence"; src.treatmentStatusReasonCode as tsr -> create('Extension') as ext, ext.url = 'http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationStatement.adherence', create('Extension') as e1, e1.url = 'reason', e1.value = tsr, ext.extension = e1, tgt.extension = ext "extAdherenceReason"; src.category as cat -> tgt.category = cat; src.derivedFrom as df then { df.request as rq -> tgt.derivedFrom = rq "derivedFromRequest"; df.statement as stm -> tgt.derivedFrom = stm "derivedFromStatement"; df.dispensation as dsp -> tgt.derivedFrom = dsp "derivedFromDispensation"; df.administration as adm -> tgt.derivedFrom = adm "derivedFromAdministration"; df.other as oth -> tgt.derivedFrom = oth "derivedFromOther"; }; // Extension: artifact-version src.version as v -> create('Extension') as ext, ext.url = 'http://hl7.org/fhir/StructureDefinition/artifact-version', ext.value = v, tgt.extension = ext "extVersion"; // Extension: VerificationInformation src.verificationInformation as vi -> create('Extension') as ext then { vi -> ext.url = 'https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/ihe-ext-medicationstatement-verificationinformation' "viUrl"; vi.verifier as vr -> create('Extension') as e1, e1.url = 'verifier', e1.value = vr, ext.extension = e1 "viVerifier"; vi.verificationTime as vt -> create('Extension') as e2, e2.url = 'verificationTime', e2.value = vt, ext.extension = e2 "viTime"; vi -> tgt.extension = ext "viAssign"; } "extVerification"; // Extension: Substitution src.substitution as sub -> create('Extension') as ext then { sub -> ext.url = 'https://profiles.ihe.net/PHARM/MEOW/StructureDefinition/ihe-ext-medicationstatement-substitution' "subUrl"; sub.substitutionType as t -> create('Extension') as e1, e1.url = 'substitutionType', e1.value = t, ext.extension = e1 "subType"; sub.substitutionTypeReason as r -> create('Extension') as e2, e2.url = 'substitutionTypeReason', e2.value = r, ext.extension = e2 "subReason"; sub.substitutionTypeReasonText as rt -> create('Extension') as e3, e3.url = 'substitutionTypeReasonText', e3.value = rt, ext.extension = e3 "subReasonText"; sub -> tgt.extension = ext "subAssign"; } "extSubstitution"; } // --------------------------------------------------------------------------- // PractitionerLM -> FHIR Practitioner // --------------------------------------------------------------------------- group PractitionerLMToPractitioner(source src : PractitionerLM, target tgt : Practitioner) { src.identifier as id -> tgt.identifier = id "practIdentifier"; src.name as n -> tgt.name = n "practName"; }