From 6a51d8d951a098e6a7669159f2e7853798c21052 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Mon, 20 Apr 2026 15:01:56 +0200 Subject: [PATCH 1/8] first run --- input/fsh/DkCoreMedication.fsh | 44 +++++++ input/fsh/DkCoreMedicationRequest.fsh | 119 ++++++++++++++++++ input/fsh/DkCoreMedicationStatement.fsh | 97 ++++++++++++++ input/fsh/aliases.fsh | 12 ++ ...tureDefinition-dk-core-medication-intro.md | 18 +++ ...inition-dk-core-medicationrequest-intro.md | 46 +++++++ ...ition-dk-core-medicationstatement-intro.md | 37 ++++++ 7 files changed, 373 insertions(+) create mode 100644 input/fsh/DkCoreMedication.fsh create mode 100644 input/fsh/DkCoreMedicationRequest.fsh create mode 100644 input/fsh/DkCoreMedicationStatement.fsh create mode 100644 input/pagecontent/StructureDefinition-dk-core-medication-intro.md create mode 100644 input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md create mode 100644 input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md diff --git a/input/fsh/DkCoreMedication.fsh b/input/fsh/DkCoreMedication.fsh new file mode 100644 index 000000000..3ec2fcf90 --- /dev/null +++ b/input/fsh/DkCoreMedication.fsh @@ -0,0 +1,44 @@ +Profile: DkCoreMedication +Parent: Medication +Id: dk-core-medication +Title: "Danish Core Medication Profile" +Description: "HL7 Denmark core profile for a medicinal product, aligned with the Danish Shared Medication Record (Fælles Medicinkort, FMK). Used where richer structured data about a drug is needed than fits in an inline CodeableConcept on MedicationRequest / MedicationStatement." +* ^status = #active +* code.coding ^slicing.discriminator.type = #value + * ^slicing.discriminator.path = "system" + * ^slicing.rules = #open + * ^slicing.ordered = false + * ^slicing.description = "Slice code.coding by system to accommodate the terminologies FMK uses for a drug" +* code.coding contains + ATC 0..1 and + ActiveSubstance 0..1 +* code.coding[ATC] + * ^short = "WHO ATC code. In FMK: DrugMedication.AtcCode / AtcText." + * system 1.. + * system = $atc (exactly) + * code 1.. +* code.coding[ActiveSubstance] + * ^short = "[DA] Aktivt stof. In FMK: DrugMedication.ActiveSubstance." + * system 1.. + * system = $FmkActiveSubstance (exactly) + * code 1.. +* form ^short = "[DA] Lægemiddelform. In FMK: DrugMedication.Form (may be free text)." +* ingredient.strength ^short = "[DA] Styrke. In FMK: DrugMedication.Strength (may be free text until structured data is available)." +* manufacturer only Reference(DkCoreOrganization) + + +Instance: SimvastatinActavis40mg +InstanceOf: DkCoreMedication +Title: "Simvastatin \"Actavis\" 40 mg filmovertrukne tabletter" +Description: "Example DkCoreMedication for a named Simvastatin product, as it might be drawn from FMK's DrugMedication." +Usage: #example +* code.coding[ATC] = $atc#C10AA01 "Simvastatin" +* code.coding[ActiveSubstance].system = $FmkActiveSubstance +* code.coding[ActiveSubstance].code = #simvastatin +* code.coding[ActiveSubstance].display = "Simvastatin" +* code.text = "Simvastatin \"Actavis\" filmovertrukne tabletter 40 mg" +* status = #active +* form.text = "filmovertrukne tabletter" +* ingredient.itemCodeableConcept.coding = $FmkActiveSubstance#simvastatin "Simvastatin" +* ingredient.strength.numerator = 40 'mg' "mg" +* ingredient.strength.denominator = 1 '{tablet}' "tablet" diff --git a/input/fsh/DkCoreMedicationRequest.fsh b/input/fsh/DkCoreMedicationRequest.fsh new file mode 100644 index 000000000..2a9e68444 --- /dev/null +++ b/input/fsh/DkCoreMedicationRequest.fsh @@ -0,0 +1,119 @@ +Profile: DkCoreMedicationRequest +Parent: MedicationRequest +Id: dk-core-medicationrequest +Title: "Danish Core MedicationRequest Profile" +Description: "HL7 Denmark core profile for medication orders (ordinationer), aligned with the Danish Shared Medication Record (Fælles Medicinkort, FMK) and the HL7 Europe Base MedicationRequest profile." +* ^status = #active +* ^extension[+].url = $imposeProfile +* ^extension[=].valueCanonical = $eu-medicationRequest +* extension contains + $mr-effectiveDosePeriod named effectiveDosePeriod 0..1 and + $mr-renderedDosageInstruction named renderedDosageInstruction 0..1 +* extension[effectiveDosePeriod] ^short = "R5 back-port: period over which the medication is to be taken. In FMK: Treatment.StartDate / Treatment.EndDate." +* extension[renderedDosageInstruction] ^short = "R5 back-port: full human-rendered dosage instruction. In FMK: Dosage.Text." +* identifier ^slicing.discriminator.type = #value + * ^slicing.discriminator.path = "system" + * ^slicing.rules = #open + * ^slicing.ordered = false + * ^slicing.description = "Slice identifier by system to distinguish FMK OrdinationIdentifier and DrugMedicationIdentifier" +* identifier contains + FmkOrdinationId 0..1 and + FmkDrugMedicationId 0..1 +* identifier[FmkOrdinationId] ^short = "[DA] FMK OrdinationIdentifier - identificerer en ordination på det fælles medicinkort" + * system 1.. + * system = $FmkOrdinationId (exactly) + * value 1.. +* identifier[FmkDrugMedicationId] ^short = "[DA] FMK DrugMedicationIdentifier - identificerer en lægemiddelordination (specifik version af ordinationen)" + * system 1.. + * system = $FmkDrugMedicationId (exactly) + * value 1.. +* status ^short = "Status for ordinationen. Active = aktiv på medicinkortet; stopped = seponeret / HasNegativeConsent = true i FMK." +* intent ^short = "FMK ordinationer modelleres typisk som intent = order." +* medication[x] only CodeableConcept or Reference(DkCoreMedication) +* medicationCodeableConcept.coding ^slicing.discriminator.type = #value + * ^slicing.discriminator.path = "system" + * ^slicing.rules = #open + * ^slicing.ordered = false + * ^slicing.description = "Slice medication.coding by system to accommodate the terminologies FMK uses for a drug" +* medicationCodeableConcept.coding contains + ATC 0..1 and + ActiveSubstance 0..1 +* medicationCodeableConcept.coding[ATC] + * ^short = "WHO ATC code for the ordinated drug. In FMK: DrugMedication.AtcCode / AtcText." + * system 1.. + * system = $atc (exactly) + * code 1.. +* medicationCodeableConcept.coding[ActiveSubstance] + * ^short = "[DA] Aktivt stof for ordinationen. In FMK: DrugMedication.ActiveSubstance." + * system 1.. + * system = $FmkActiveSubstance (exactly) + * code 1.. +* subject only Reference(DkCorePatient) +* subject 1.. +* requester only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCoreOrganization or DkCorePatient or DkCoreRelatedPerson or Device) +* recorder only Reference(DkCorePractitioner or DkCorePractitionerRole) +* performer only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCoreOrganization or DkCorePatient or DkCoreRelatedPerson or Device or CareTeam) +* reasonReference only Reference(DkCoreCondition or DkCoreObservation) +* reasonCode ^short = "Indikation / årsag for ordinationen. In FMK: Treatment.Cause." +* dosageInstruction ^short = "Dosering. In FMK: Dosage.Text (free text, prefer the renderedDosageInstruction extension for full FMK text) and/or Treatment.Administration (route)." +* dispenseRequest.performer only Reference(DkCoreOrganization) + + +Instance: JohnMedicationRequestSimvastatin +InstanceOf: DkCoreMedicationRequest +Title: "John's Simvastatin ordination" +Description: "Example of a DkCoreMedicationRequest derived from an FMK ordination for Simvastatin 40 mg." +Usage: #example +* identifier[FmkOrdinationId].system = $FmkOrdinationId +* identifier[FmkOrdinationId].value = "123456789" +* identifier[FmkDrugMedicationId].system = $FmkDrugMedicationId +* identifier[FmkDrugMedicationId].value = "DM-987654321" +* status = #active +* intent = #order +* medicationCodeableConcept.coding[ATC] = $atc#C10AA01 "Simvastatin" +* medicationCodeableConcept.coding[ActiveSubstance].system = $FmkActiveSubstance +* medicationCodeableConcept.coding[ActiveSubstance].code = #simvastatin +* medicationCodeableConcept.coding[ActiveSubstance].display = "Simvastatin" +* medicationCodeableConcept.text = "Simvastatin \"Actavis\" filmovertrukne tabletter 40 mg" +* subject = Reference(Patient/john) +* authoredOn = "2024-03-15" +* requester = Reference(Practitioner/AbrahamLaege) +* reasonCode.text = "Hyperkolesterolæmi" +* dosageInstruction + * text = "1 tablet dagligt til aftensmad" + * route = http://snomed.info/sct#26643006 "Oral use" +* extension[effectiveDosePeriod].valuePeriod.start = "2024-03-15" +* extension[renderedDosageInstruction].valueMarkdown = "1 tablet (40 mg) dagligt til aftensmad, til kontrol" + + +Instance: JohnMedicationRequestWithMedicationRef +InstanceOf: DkCoreMedicationRequest +Title: "John's Simvastatin ordination (with Medication reference)" +Description: "Example using Reference(DkCoreMedication) rather than inline CodeableConcept, demonstrating the EU-compatible path." +Usage: #example +* identifier[FmkOrdinationId].system = $FmkOrdinationId +* identifier[FmkOrdinationId].value = "123456790" +* status = #active +* intent = #order +* medicationReference = Reference(Medication/SimvastatinActavis40mg) +* subject = Reference(Patient/john) +* authoredOn = "2024-03-15" +* requester = Reference(Practitioner/AbrahamLaege) +* dosageInstruction.text = "1 tablet dagligt til aftensmad" + + +Instance: JohnMedicationRequestStopped +InstanceOf: DkCoreMedicationRequest +Title: "John's seponerede Metformin ordination" +Description: "Example of a DkCoreMedicationRequest that has been stopped (seponeret) in FMK (HasNegativeConsent = true)." +Usage: #example +* identifier[FmkOrdinationId].system = $FmkOrdinationId +* identifier[FmkOrdinationId].value = "987654321" +* status = #stopped +* intent = #order +* medicationCodeableConcept.coding[ATC] = $atc#A10BA02 "Metformin" +* medicationCodeableConcept.text = "Metformin 500 mg" +* subject = Reference(Patient/john) +* authoredOn = "2023-11-01" +* requester = Reference(Practitioner/AbrahamLaege) +* dosageInstruction.text = "2 tabletter morgen og aften" diff --git a/input/fsh/DkCoreMedicationStatement.fsh b/input/fsh/DkCoreMedicationStatement.fsh new file mode 100644 index 000000000..8d2d9cdd4 --- /dev/null +++ b/input/fsh/DkCoreMedicationStatement.fsh @@ -0,0 +1,97 @@ +Profile: DkCoreMedicationStatement +Parent: MedicationStatement +Id: dk-core-medicationstatement +Title: "Danish Core MedicationStatement Profile" +Description: "HL7 Denmark core profile for a statement about medication being taken by a patient, aligned with the Danish Shared Medication Record (Fælles Medicinkort, FMK) and the HL7 Europe Base MedicationStatement profile. Intended to represent the current, authoritative medication card snapshot (aktuelt medicinbillede)." +* ^status = #active +* ^extension[+].url = $imposeProfile +* ^extension[=].valueCanonical = $eu-medicationStatement +* extension contains + $ms-adherence named adherence 0..1 +* extension[adherence] ^short = "R5 back-port: whether the medication is being taken / refused / stopped. In FMK: HasNegativeConsent = true should be surfaced here with an appropriate adherence code in addition to (or instead of) status = stopped." +* identifier ^slicing.discriminator.type = #value + * ^slicing.discriminator.path = "system" + * ^slicing.rules = #open + * ^slicing.ordered = false + * ^slicing.description = "Slice identifier by system to distinguish FMK OrdinationIdentifier and DrugMedicationIdentifier" +* identifier contains + FmkOrdinationId 0..1 and + FmkDrugMedicationId 0..1 +* identifier[FmkOrdinationId] ^short = "[DA] FMK OrdinationIdentifier" + * system 1.. + * system = $FmkOrdinationId (exactly) + * value 1.. +* identifier[FmkDrugMedicationId] ^short = "[DA] FMK DrugMedicationIdentifier" + * system 1.. + * system = $FmkDrugMedicationId (exactly) + * value 1.. +* status ^short = "Status of the medication card entry. active = aktiv på medicinkortet; stopped = seponeret (HasNegativeConsent = true i FMK); completed = afsluttet behandling." +* medication[x] only CodeableConcept or Reference(DkCoreMedication) +* medicationCodeableConcept.coding ^slicing.discriminator.type = #value + * ^slicing.discriminator.path = "system" + * ^slicing.rules = #open + * ^slicing.ordered = false + * ^slicing.description = "Slice medication.coding by system to accommodate the terminologies FMK uses for a drug" +* medicationCodeableConcept.coding contains + ATC 0..1 and + ActiveSubstance 0..1 +* medicationCodeableConcept.coding[ATC] + * ^short = "WHO ATC code. In FMK: DrugMedication.AtcCode / AtcText." + * system 1.. + * system = $atc (exactly) + * code 1.. +* medicationCodeableConcept.coding[ActiveSubstance] + * ^short = "[DA] Aktivt stof. In FMK: DrugMedication.ActiveSubstance or MedicationCardEntry.ActiveSubstance." + * system 1.. + * system = $FmkActiveSubstance (exactly) + * code 1.. +* subject only Reference(DkCorePatient) +* subject 1.. +* informationSource only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCoreOrganization or DkCorePatient or DkCoreRelatedPerson) +* reasonReference only Reference(DkCoreCondition or DkCoreObservation) +* reasonCode ^short = "Indikation / årsag. In FMK: Treatment.Cause." +* effective[x] only dateTime or Period +* effective[x] ^short = "When the medication is/was being taken. Prefer effectivePeriod when both start and end (or open-ended start) are known - maps to FMK Treatment.StartDate / Treatment.EndDate. Use effectiveDateTime only for point-in-time statements." +* dateAsserted ^short = "Tidspunkt hvor udsagnet om medicineringen blev indført. Typisk hentningstidspunktet for medicinkortet." +* dosage ^short = "Dosering. In FMK: Dosage.Text; Treatment.Administration (route) kan lægges i dosage.route eller dosage.patientInstruction." + + +Instance: JohnMedicationStatementSimvastatin +InstanceOf: DkCoreMedicationStatement +Title: "John's aktive Simvastatin på medicinkortet" +Description: "Example DkCoreMedicationStatement derived from the current FMK medication card for Simvastatin." +Usage: #example +* identifier[FmkOrdinationId].system = $FmkOrdinationId +* identifier[FmkOrdinationId].value = "123456789" +* status = #active +* medicationCodeableConcept.coding[ATC] = $atc#C10AA01 "Simvastatin" +* medicationCodeableConcept.coding[ActiveSubstance].system = $FmkActiveSubstance +* medicationCodeableConcept.coding[ActiveSubstance].code = #simvastatin +* medicationCodeableConcept.coding[ActiveSubstance].display = "Simvastatin" +* medicationCodeableConcept.text = "Simvastatin \"Actavis\" filmovertrukne tabletter 40 mg" +* subject = Reference(Patient/john) +* effectivePeriod.start = "2024-03-15" +* dateAsserted = "2026-04-20" +* reasonCode.text = "Hyperkolesterolæmi" +* dosage.text = "1 tablet dagligt til aftensmad" +* dosage.route = http://snomed.info/sct#26643006 "Oral use" + + +Instance: JohnMedicationStatementStopped +InstanceOf: DkCoreMedicationStatement +Title: "John's seponerede Metformin" +Description: "Example DkCoreMedicationStatement for a medication that has been stopped (seponeret). Note: uses the adherence extension in addition to status = stopped to carry the richer R5 semantics." +Usage: #example +* identifier[FmkOrdinationId].system = $FmkOrdinationId +* identifier[FmkOrdinationId].value = "987654321" +* status = #stopped +* extension[adherence].extension[code].valueCodeableConcept.coding.system = "http://terminology.hl7.org/CodeSystem/medicationstatement-adherence" +* extension[adherence].extension[code].valueCodeableConcept.coding.code = #no-longer-taking +* extension[adherence].extension[code].valueCodeableConcept.coding.display = "No longer Taking" +* medicationCodeableConcept.coding[ATC] = $atc#A10BA02 "Metformin" +* medicationCodeableConcept.text = "Metformin 500 mg" +* subject = Reference(Patient/john) +* effectivePeriod.start = "2022-05-01" +* effectivePeriod.end = "2023-11-01" +* dateAsserted = "2026-04-20" +* dosage.text = "2 tabletter morgen og aften" diff --git a/input/fsh/aliases.fsh b/input/fsh/aliases.fsh index 0ff32aaa1..fdabd287a 100644 --- a/input/fsh/aliases.fsh +++ b/input/fsh/aliases.fsh @@ -31,6 +31,18 @@ Alias: $v3-Confidentiality = http://terminology.hl7.org/CodeSystem/v3-Confidenti Alias: $v3-RoleCode = http://terminology.hl7.org/CodeSystem/v3-RoleCode Alias: $v3-ActPriority = http://terminology.hl7.org/CodeSystem/v3-ActPriority Alias: $v3-ActCode3.0.0 = http://terminology.hl7.org/ValueSet/v3-ActCode|3.0.0 +Alias: $atc = http://www.whocc.no/atc +Alias: $FmkOrdinationId = https://www.sundhed.dk/medicinkort/ordination +Alias: $FmkDrugMedicationId = https://www.sundhed.dk/medicinkort/drug-medication +Alias: $FmkActiveSubstance = https://www.sundhed.dk/medicinkort/active-substance +Alias: $mr-effectiveDosePeriod = http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationRequest.effectiveDosePeriod +Alias: $mr-renderedDosageInstruction = http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationRequest.renderedDosageInstruction +Alias: $ms-adherence = http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationStatement.adherence +Alias: $ihe-prescribedQuantity = https://profiles.ihe.net/PHARM/MPD/StructureDefinition/ihe-ext-medicationrequest-prescribedQuantity +Alias: $imposeProfile = http://hl7.org/fhir/StructureDefinition/structuredefinition-imposeProfile +Alias: $eu-medicationRequest = http://hl7.eu/fhir/base/StructureDefinition/medicationRequest-eu-core +Alias: $eu-medicationStatement = http://hl7.eu/fhir/base/StructureDefinition/medicationStatement-eu-core +Alias: $eu-medication = http://hl7.eu/fhir/base/StructureDefinition/medication-eu-core Alias: $DanishXdsOid = urn:oid:1.2.208.184.100.9 Alias: $MedComFormatOID = urn:oid:1.2.208.184.100.10 Alias: $IANALanguageOID = urn:oid:2.16.840.1.113883.6.121 diff --git a/input/pagecontent/StructureDefinition-dk-core-medication-intro.md b/input/pagecontent/StructureDefinition-dk-core-medication-intro.md new file mode 100644 index 000000000..d2506f09c --- /dev/null +++ b/input/pagecontent/StructureDefinition-dk-core-medication-intro.md @@ -0,0 +1,18 @@ +### Scope and usage + +The Danish Core Medication profile describes a medicinal product, in particular as it appears in the Danish Shared Medication Record (Fælles Medicinkort, FMK). It is used when a MedicationRequest or MedicationStatement needs to reference a reusable, structured drug representation — for example, an FMK `DrugMedication` with form, strength and active substance information. + +Most Danish systems today will be able to inline the drug as a `CodeableConcept` on [DkCoreMedicationRequest](StructureDefinition-dk-core-medicationrequest.html) / [DkCoreMedicationStatement](StructureDefinition-dk-core-medicationstatement.html). This profile is offered for the cases where structured data about the product itself (ingredients, strength, form, manufacturer) is valuable, or where the same product is referenced from multiple requests/statements. + +#### Mapping from FMK + +| FMK field | FHIR target | +| --- | --- | +| `DrugMedication.AtcCode` / `AtcText` | `code.coding[ATC]` (`http://www.whocc.no/atc`) | +| `DrugMedication.ActiveSubstance` | `code.coding[ActiveSubstance]` + `ingredient.itemCodeableConcept` | +| `DrugMedication` (name with form and strength) | `code.text` | +| `DrugMedication.Form` | `form` (free text allowed) | +| `DrugMedication.Strength` | `ingredient.strength` | + +#### Relationship to HL7 Europe Base +This profile is deliberately compatible with [Medication (EU core)](https://build.fhir.org/ig/hl7-eu/base/StructureDefinition-medication-eu-core.html) — it uses the same general shape (ATC as a sliced coding, ingredient-based strength) so that Danish content can be promoted to EU-wide exchanges without restructuring. diff --git a/input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md b/input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md new file mode 100644 index 000000000..c0142343e --- /dev/null +++ b/input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md @@ -0,0 +1,46 @@ +### Scope and usage + +The Danish Core MedicationRequest profile is intended to represent a single medication order (ordination), in particular as sourced from the Danish Shared Medication Record (Fælles Medicinkort, FMK). Source documentation for FMK: [wiki.fmk-teknik.dk](https://wiki.fmk-teknik.dk/start). + +In dk-core, the MedicationRequest has been constrained so that `subject` refers to a [DkCorePatient](StructureDefinition-dk-core-patient.html), and `requester` / `recorder` / `performer` refer to the Danish core profiles for Practitioner, PractitionerRole, Organization, Patient or RelatedPerson. + +The profile claims conformance to [MedicationRequest (EU core)](https://build.fhir.org/ig/hl7-eu/base/StructureDefinition-medicationRequest-eu-core.html) via an `imposeProfile` extension — any instance valid against DkCoreMedicationRequest must also be valid against the EU Core profile. + +#### Mapping from FMK +An FMK ordination carries two identifiers that are both useful for tracing a MedicationRequest back to its source: + +* **OrdinationIdentifier** — stable identifier for the ordination itself, across versions. Mapped to `identifier` slice `FmkOrdinationId` with system `https://www.sundhed.dk/medicinkort/ordination`. +* **DrugMedicationIdentifier** — identifier for a specific version of the lægemiddelordination. Mapped to `identifier` slice `FmkDrugMedicationId` with system `https://www.sundhed.dk/medicinkort/drug-medication`. + +The medicinal product can be represented in two ways: + +* As an inline `medicationCodeableConcept` (preferred for simple, self-contained FMK mappings), sliced on `coding.system` for: + * **ATC** (`http://www.whocc.no/atc`) from `DrugMedication.AtcCode` / `AtcText`. + * **Active substance** (`https://www.sundhed.dk/medicinkort/active-substance`) from `DrugMedication.ActiveSubstance`. + * A free-text product name in `medicationCodeableConcept.text`. +* As a `medicationReference` to a [DkCoreMedication](StructureDefinition-dk-core-medication.html) — useful when form, strength, ingredients or manufacturer need structured representation. + +FMK treatment and dosage fields map as follows: + +| FMK field | FHIR target | +| --- | --- | +| `Treatment.Cause` | `reasonCode.text` (or `reasonReference` when a coded condition is known) | +| `Treatment.StartDate` | `authoredOn` and `extension[effectiveDosePeriod].valuePeriod.start` | +| `Treatment.EndDate` | `extension[effectiveDosePeriod].valuePeriod.end` | +| `Treatment.Administration` | `dosageInstruction.route` (free-text allowed) | +| `Dosage.Text` | `dosageInstruction.text` and/or `extension[renderedDosageInstruction].valueMarkdown` | +| `HasNegativeConsent = true` | `status = #stopped` | +| `CreatedBy` | `requester` (display / reference) | +| `IsDoseDispensing = true` with a total quantity | `dispenseRequest.quantity` (and, when IHE Pharmacy MPD becomes an R4 dependency, the `prescribedQuantity` extension) | + +Systems that proxy FMK should populate both identifier slices when possible so the resource can be cross-referenced back to the underlying ordination and lægemiddelordination. + +#### Extensions in use +The profile brings forward three extensions from the HL7 Europe Base profile, all of which are already forward-compatible with FHIR R5: + +* **`effectiveDosePeriod`** (R5 back-port) — records the period over which the medication is to be taken. Natural home for FMK's `Treatment.StartDate` / `Treatment.EndDate`. +* **`renderedDosageInstruction`** (R5 back-port) — carries the full human-rendered dosage instruction in Markdown. Natural home for FMK's `Dosage.Text`. +* **IHE Pharmacy `prescribedQuantity`** — not currently wired in as a slice because the IHE MPD package is R5-based and not yet an R4 dependency of this IG. Implementers may add it as an ad-hoc extension on `dispenseRequest` when needed for FMK dose-dispensing flows. + +#### Status and intent +FMK ordinations are typically modelled with `intent = order`. Active ordinations use `status = active`; ordinations that have been stopped (seponeret) in FMK (`HasNegativeConsent = true`) use `status = stopped`. Historical/completed treatments use `status = completed`. diff --git a/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md b/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md new file mode 100644 index 000000000..48beca92b --- /dev/null +++ b/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md @@ -0,0 +1,37 @@ +### Scope and usage + +The Danish Core MedicationStatement profile is intended to represent a statement about a medication that a patient is taking (or has taken), as sourced from the Danish Shared Medication Record (Fælles Medicinkort, FMK). Source documentation for FMK: [wiki.fmk-teknik.dk](https://wiki.fmk-teknik.dk/start). + +A MedicationStatement is the natural FHIR representation of the FMK "medicinkort"/"aktuelt medicinbillede" — the authoritative list of medicines the patient is currently taking. Where a [DkCoreMedicationRequest](StructureDefinition-dk-core-medicationrequest.html) is the order that a prescriber issues, a DkCoreMedicationStatement is the snapshot of what is actually on the patient's medication card at a point in time. + +In dk-core, the MedicationStatement has been constrained so that `subject` refers to a [DkCorePatient](StructureDefinition-dk-core-patient.html) and `informationSource` refers to the Danish core profiles for Practitioner, PractitionerRole, Organization, Patient or RelatedPerson. + +The profile claims conformance to [MedicationStatement (EU core)](https://build.fhir.org/ig/hl7-eu/base/StructureDefinition-medicationStatement-eu-core.html) via an `imposeProfile` extension — any instance valid against DkCoreMedicationStatement must also be valid against the EU Core profile. + +#### Mapping from FMK + +| FMK field | FHIR target | +| --- | --- | +| `DrugMedication.OrdinationIdentifier` | `identifier[FmkOrdinationId]` (`https://www.sundhed.dk/medicinkort/ordination`) | +| `DrugMedication.DrugMedicationIdentifier` | `identifier[FmkDrugMedicationId]` (`https://www.sundhed.dk/medicinkort/drug-medication`) | +| `DrugMedication.AtcCode` / `AtcText` | `medicationCodeableConcept.coding[ATC]` (`http://www.whocc.no/atc`) or via `medicationReference` to a [DkCoreMedication](StructureDefinition-dk-core-medication.html) | +| `DrugMedication.ActiveSubstance` | `medicationCodeableConcept.coding[ActiveSubstance]` | +| `DrugMedication` (name/form/strength) | `medicationCodeableConcept.text` or the referenced DkCoreMedication | +| `Treatment.Cause` | `reasonCode.text` | +| `Treatment.StartDate` / `Treatment.EndDate` | `effectivePeriod.start` / `effectivePeriod.end` | +| `Dosage.Text` | `dosage.text` | +| `Treatment.Administration` | `dosage.route` (free-text allowed) | +| Snapshot timestamp (the time the card was retrieved) | `dateAsserted` | +| `HasNegativeConsent = true` | `status = #stopped` plus `extension[adherence]` with an appropriate `no-longer-taking` / `not-taking` code | +| `MedicationCardStatus.EnumStr` | `status` (active / completed / stopped / entered-in-error / unknown) | + +Consumers of this profile should be aware that a MedicationStatement derived from an FMK medication card is, by design, a *view* on the current state of one or more ordinations rather than an authoritative clinical assertion. When populating `dateAsserted`, use the timestamp of the FMK retrieval, not the ordination date. + +#### Extensions in use +The profile brings forward the R5 `adherence` extension from the HL7 Europe Base profile. FMK's `HasNegativeConsent` flag and card-level status should be surfaced as adherence codes where possible; the coarse `status = stopped` value remains but loses nuance compared to adherence codes such as `no-longer-taking`, `not-taking`, `on-hold`. + +#### Effective[x] +`effective[x]` is restricted to either `effectiveDateTime` (point-in-time) or `effectivePeriod` (typical for FMK). Prefer `effectivePeriod` when an end date is known, or when the start date is known and the medication is ongoing. + +#### Relationship to DkCoreMedicationRequest +When both resources are available (for example when proxying both `OrdinationDetails` and a medication card entry), the two resources MAY share identifiers so that a consumer can correlate a MedicationStatement with the MedicationRequest that it is derived from. From eb90980d5d0d05af432825e18a9fbe2cb4774194 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Thu, 23 Apr 2026 11:15:27 +0200 Subject: [PATCH 2/8] Adding immunization --- _build.bat | 120 +++++------ _build.sh | 204 +++++++++++------- input/fsh/DkCoreImmunization.fsh | 74 +++++++ input/fsh/DkCoreMedicationRequest.fsh | 2 +- input/fsh/DkCoreMedicationStatement.fsh | 8 +- input/fsh/aliases.fsh | 2 + input/fsh/codeSystems.fsh | 2 +- ...reDefinition-dk-core-immunization-intro.md | 34 +++ ...ition-dk-core-medicationstatement-intro.md | 4 +- sushi-config.yaml | 2 +- 10 files changed, 303 insertions(+), 149 deletions(-) create mode 100644 input/fsh/DkCoreImmunization.fsh create mode 100644 input/pagecontent/StructureDefinition-dk-core-immunization-intro.md diff --git a/_build.bat b/_build.bat index 99d0e1f97..a78d0130c 100644 --- a/_build.bat +++ b/_build.bat @@ -25,38 +25,54 @@ IF EXIST "%input_cache_path%%publisher_jar%" ( ) ELSE ( SET "jar_location=not_found" SET "default_choice=1" + SET "default_reason=publisher not found" ECHO publisher.jar not found in input-cache or parent folder ) ) :: Handle command-line argument to bypass the menu -IF NOT "%~1"=="" ( - IF /I "%~1"=="update" SET "userChoice=1" - IF /I "%~1"=="build" SET "userChoice=2" - IF /I "%~1"=="nosushi" SET "userChoice=3" - IF /I "%~1"=="notx" SET "userChoice=4" - IF /I "%~1"=="jekyll" SET "userChoice=5" - IF /I "%~1"=="clean" SET "userChoice=6" - IF /I "%~1"=="exit" SET "userChoice=0" - GOTO executeChoice -) +:: Known first arguments select a menu option; anything else is passed through to the publisher +SET "extraArgs=" +IF "%~1"=="" GOTO showMenu +IF /I "%~1"=="update" SET "userChoice=1" & GOTO parseExtra +IF /I "%~1"=="build" SET "userChoice=2" & GOTO parseExtra +IF /I "%~1"=="nosushi" SET "userChoice=3" & GOTO parseExtra +IF /I "%~1"=="notx" SET "userChoice=4" & GOTO parseExtra +IF /I "%~1"=="jekyll" SET "userChoice=5" & GOTO parseExtra +IF /I "%~1"=="clean" SET "userChoice=6" & GOTO parseExtra +IF /I "%~1"=="exit" SET "userChoice=0" & GOTO parseExtra +:: Unknown first arg - default to build, pass all args through +SET "userChoice=2" +GOTO collectArgs +:parseExtra +SHIFT +:collectArgs +IF "%~1"=="" GOTO executeChoice +SET "extraArgs=!extraArgs! %1" +SHIFT +GOTO collectArgs +:showMenu echo --------------------------------------------------------------- ECHO Checking internet connection... PING tx.fhir.org -4 -n 1 -w 4000 >nul 2>&1 && SET "online_status=true" || SET "online_status=false" IF "%online_status%"=="true" ( - ECHO We're online and tx.fhir.org is available. + ECHO We are online and tx.fhir.org is available. FOR /F "tokens=2 delims=:" %%a IN ('curl -s https://api.github.com/repos/HL7/fhir-ig-publisher/releases/latest ^| findstr "tag_name"') DO SET "latest_version=%%a" SET "latest_version=!latest_version:"=!" SET "latest_version=!latest_version: =!" SET "latest_version=!latest_version:~0,-1!" ) ELSE ( - ECHO We're offline or tx.fhir.org is not available, can only run the publisher without TX... + ECHO. + ECHO *** WARNING: Working offline - this is not the normal mode. + ECHO Some features including terminology rendering will not work. + ECHO. SET "txoption=-tx n/a" SET "latest_version=unknown" SET "default_choice=4" + SET "default_reason=working offline" ) echo --------------------------------------------------------------- @@ -74,14 +90,16 @@ IF NOT "%jar_location%"=="not_found" ( ECHO Publisher version: !publisher_version!; Latest is !latest_version! IF NOT "%online_status%"=="true" ( - ECHO We're offline. + ECHO We are offline. ) ELSE ( IF NOT "!publisher_version!"=="!latest_version!" ( ECHO An update is recommended. SET "default_choice=1" + SET "default_reason=newer version available" ) ELSE ( ECHO Publisher is up to date. SET "default_choice=2" + SET "default_reason=publisher is up to date" ) ) @@ -96,12 +114,9 @@ echo 4. Build IG - force no TX server echo 5. Jekyll build echo 6. Clean up temp directories echo 0. Exit -:: echo [Press Enter for default (%default_choice%) or type an option number:] echo. -:: Using CHOICE to handle input with timeout -:: ECHO [Enter=Continue, 1-7=Option, 0=Exit] -choice /C 12345670 /N /CS /D %default_choice% /T 5 /M "Choose an option number or wait 5 seconds for default (%default_choice%):" +choice /C 12345670 /N /CS /D %default_choice% /T 5 /M "Choose an option number or wait 5 seconds for default (%default_choice% - %default_reason%):" SET "userChoice=%ERRORLEVEL%" @@ -115,15 +130,12 @@ IF "%userChoice%"=="4" GOTO publish_notx IF "%userChoice%"=="5" GOTO debugjekyll IF "%userChoice%"=="6" GOTO clean IF "%userChoice%"=="0" EXIT /B - -:end - - +GOTO endscript :debugjekyll echo Running Jekyll build... jekyll build -s temp/pages -d output -GOTO end +GOTO endscript :clean @@ -152,10 +164,7 @@ GOTO end echo Removed: .\template ) -GOTO end - - - +GOTO endscript :downloadpublisher @@ -198,7 +207,7 @@ IF DEFINED FORCE ( GOTO download ) -IF "%skipPrompts%"=="y" ( +IF "%skipPrompts%"=="true" ( SET create=Y ) ELSE ( SET /p create="Download? (Y/N) " @@ -211,7 +220,7 @@ IF /I "%create%"=="Y" ( GOTO done :upgrade -IF "%skipPrompts%"=="y" ( +IF "%skipPrompts%"=="true" ( SET overwrite=Y ) ELSE ( SET /p overwrite="Overwrite %jarlocation%? (Y/N) " @@ -265,7 +274,7 @@ GOTO done ECHO. ECHO Updating scripts -IF "%skipPrompts%"=="y" ( +IF "%skipPrompts%"=="true" ( SET updateScripts=Y ) ELSE ( SET /p updateScripts="Update scripts? (Y/N) " @@ -273,7 +282,7 @@ IF "%skipPrompts%"=="y" ( IF /I "%updateScripts%"=="Y" ( GOTO scripts ) -GOTO end +GOTO endscript :scripts @@ -299,12 +308,12 @@ ECHO Updating _build.bat call POWERSHELL -command if ('System.Net.WebClient' -as [type]) {(new-object System.Net.WebClient).DownloadFile(\"%build_bat_url%\",\"_build.new.bat\") } else { Invoke-WebRequest -Uri "%build_bat_url%" -Outfile "_build.new.bat" } if %ERRORLEVEL% == 0 goto upd_script_2 echo "Errors encountered during download: %errorlevel%" -goto end +goto endscript :upd_script_2 start copy /y "_build.new.bat" "_build.bat" ^&^& del "_build.new.bat" ^&^& exit -GOTO end +GOTO endscript :publish_once @@ -312,14 +321,15 @@ GOTO end SET JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 :: Debugging statements before running publisher -ECHO 1jar_location is: %jar_location% +ECHO jar_location is: %jar_location% IF NOT "%jar_location%"=="not_found" ( - java %JAVA_OPTS% -jar "%jar_location%" -ig . %txoption% %* + ECHO IG Publisher FOUND, Publishing... + java %JAVA_OPTS% -jar "%jar_location%" -ig . %txoption% %extraArgs% ) ELSE ( - ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run _updatePublisher. Aborting... + ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run the script and update the publisher. Aborting... ) -GOTO end +GOTO endscript @@ -328,14 +338,14 @@ GOTO end SET JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 :: Debugging statements before running publisher -ECHO 3jar_location is: %jar_location% +ECHO jar_location is: %jar_location% IF NOT "%jar_location%"=="not_found" ( - java %JAVA_OPTS% -jar "%jar_location%" -ig . %txoption% -no-sushi %* + java %JAVA_OPTS% -jar "%jar_location%" -ig . %txoption% -no-sushi %extraArgs% ) ELSE ( - ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run _updatePublisher. Aborting... + ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run the script and update the publisher. Aborting... ) -GOTO end +GOTO endscript :publish_notx @@ -344,43 +354,33 @@ SET txoption=-tx n/a SET JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 :: Debugging statements before running publisher -ECHO 2jar_location is: %jar_location% +ECHO jar_location is: %jar_location% IF NOT "%jar_location%"=="not_found" ( - java %JAVA_OPTS% -jar "%jar_location%" -ig . %txoption% %* + java %JAVA_OPTS% -jar "%jar_location%" -ig . %txoption% %extraArgs% ) ELSE ( - ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run _updatePublisher. Aborting... + ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run the script and update the publisher. Aborting... ) -GOTO end - - +GOTO endscript :publish_continuous SET JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 -:: Debugging statements before running publisher -ECHO Checking %input_cache_path% for publisher.jar -IF EXIST "%input_cache_path%\%publisher_jar%" ( - java %JAVA_OPTS% -jar "%input_cache_path%\%publisher_jar%" -ig . %txoption% -watch %* +ECHO jar_location is: %jar_location% +IF NOT "%jar_location%"=="not_found" ( + java %JAVA_OPTS% -jar "%jar_location%" -ig . %txoption% -watch %extraArgs% ) ELSE ( - ECHO Checking %upper_path% for publisher.jar - IF EXIST "..\%publisher_jar%" ( - java %JAVA_OPTS% -jar "..\%publisher_jar%" -ig . %txoption% -watch %* - ) ELSE ( - ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run _updatePublisher. Aborting... - ) + ECHO IG Publisher NOT FOUND in input-cache or parent folder. Please run the script and update the publisher. Aborting... ) -GOTO end +GOTO endscript -:end +:endscript :: Pausing at the end - - IF NOT "%skipPrompts%"=="true" ( PAUSE ) diff --git a/_build.sh b/_build.sh index f11edff67..69ac585cf 100755 --- a/_build.sh +++ b/_build.sh @@ -26,20 +26,44 @@ function check_jar_location() { } function check_internet_connection() { - if ping -c 1 tx.fhir.org &>/dev/null; then + local target="tx.fhir.org" + local reachable=false + + if command -v ping > /dev/null 2>&1; then + if ping -c 1 -W 5 "$target" > /dev/null 2>&1 \ + || ping -c 1 -w 5 "$target" > /dev/null 2>&1; then + reachable=true + fi + elif command -v curl > /dev/null 2>&1; then + if curl --silent --max-time 5 --output /dev/null "https://$target"; then + reachable=true + fi + else + echo "WARNING: Neither ping nor curl available — assuming offline." + fi + + if [ "$reachable" = "true" ]; then online=true - echo "We're online and tx.fhir.org is available." + echo "We're online and $target is available." latest_version=$(curl -s https://api.github.com/repos/HL7/fhir-ig-publisher/releases/latest | grep tag_name | cut -d'"' -f4) else online=false - echo "We're offline or tx.fhir.org is unavailable." + echo "" + echo "⚠️ WARNING: Working offline — this is not the normal mode." + echo " Some features (e.g. terminology rendering) will not work." + echo "" fi } + function update_publisher() { echo "Publisher jar location: ${input_cache_path}${publisher_jar}" - read -p "Download or update publisher.jar? (Y/N): " confirm + if [ "$skipPrompts" = "true" ]; then + confirm="Y" + else + read -p "Download or update publisher.jar? (Y/N): " confirm + fi if [[ "$confirm" =~ ^[Yy]$ ]]; then echo "Downloading latest publisher.jar (~200 MB)..." mkdir -p "$input_cache_path" @@ -53,7 +77,11 @@ function update_publisher() { function update_scripts_prompt() { - read -p "Update scripts (_build.bat and _build.sh)? (Y/N): " update_confirm + if [ "$skipPrompts" = "true" ]; then + update_confirm="Y" + else + read -p "Update scripts (_build.bat and _build.sh)? (Y/N): " update_confirm + fi if [[ "$update_confirm" =~ ^[Yy]$ ]]; then echo "Updating scripts..." curl -L "$build_bat_url" -o "_build.new.bat" && mv "_build.new.bat" "_build.bat" @@ -66,33 +94,35 @@ function update_scripts_prompt() { } -function build_ig() { +function run_publisher() { + local extra_flags=("$@") if [ "$jar_location" != "not_found" ]; then - args=() - if [ "$online" = "false" ]; then - args+=("-tx" "n/a") - fi - java -Dfile.encoding=UTF-8 -jar "$jar_location" -ig . "${args[@]}" "$@" + echo "jar_location is: $jar_location" + export JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8" + java $JAVA_OPTS -jar "$jar_location" -ig . "${extra_flags[@]}" else - echo "publisher.jar not found. Please run update." + echo "IG Publisher NOT FOUND in input-cache or parent folder. Please run update. Aborting..." fi } +function build_ig() { + local args=() + if [ "$online" = "false" ]; then + args+=("-tx" "n/a") + fi + run_publisher "${args[@]}" "$@" +} function build_nosushi() { - if [ "$jar_location" != "not_found" ]; then - java -Dfile.encoding=UTF-8 -jar "$jar_location" -ig . -no-sushi "$@" - else - echo "publisher.jar not found. Please run update." - fi + run_publisher -no-sushi "$@" } function build_notx() { - if [ "$jar_location" != "not_found" ]; then - java -Dfile.encoding=UTF-8 -jar "$jar_location" -ig . -tx n/a "$@" - else - echo "publisher.jar not found. Please run update." - fi + run_publisher -tx n/a "$@" +} + +function build_continuous() { + run_publisher -watch "$@" } function jekyll_build() { @@ -113,64 +143,78 @@ function cleanup() { } check_jar_location -check_internet_connection -# Handle command-line argument or menu -case "$1" in - update) update_publisher ;; - build) build_ig ;; - nosushi) build_nosushi ;; - notx) build_notx ;; - jekyll) jekyll_build ;; - clean) cleanup ;; - exit) exit 0 ;; - *) - # Compute default choice - default_choice=2 # Build by default - - if [ "$jar_location" = "not_found" ]; then - default_choice=1 # Download if jar is missing - elif [ "$online" = "false" ]; then - default_choice=4 # Offline build - elif [ -n "$latest_version" ]; then - current_version=$(java -jar "$jar_location" -v 2>/dev/null | tr -d '\r') - if [ "$current_version" != "$latest_version" ]; then - default_choice=1 # Offer update if newer version exists - fi - fi - - echo "---------------------------------------------" - echo "Publisher: ${current_version:-unknown}; Latest: ${latest_version:-unknown}" - echo "Publisher location: $jar_location" - echo "Online: $online" - echo "---------------------------------------------" - echo - echo "Please select an option:" - echo "1) Download or update publisher" - echo "2) Build IG" - echo "3) Build IG without Sushi" - echo "4) Build IG without TX server" - echo "5) Jekyll build" - echo "6) Cleanup temp directories" - echo "0) Exit" - echo - - # Read with timeout, but default if nothing entered - echo -n "Choose an option [default: $default_choice]: " - read -t 5 choice || choice="$default_choice" - choice="${choice:-$default_choice}" - echo "You selected: $choice" - - case "$choice" in - 1) update_publisher ;; - 2) build_ig ;; - 3) build_nosushi ;; - 4) build_notx ;; - 5) jekyll_build ;; - 6) cleanup ;; - 0) exit 0 ;; - *) echo "Invalid option." ;; - esac - ;; +# Handle command-line arguments +# Known first arguments select a menu option; anything else is passed through to the publisher +extraArgs=() +if [ $# -gt 0 ]; then + case "$1" in + update) shift; extraArgs=("$@"); update_publisher; exit 0 ;; + build) shift; extraArgs=("$@"); check_internet_connection; build_ig "${extraArgs[@]}"; exit 0 ;; + nosushi) shift; extraArgs=("$@"); check_internet_connection; build_nosushi "${extraArgs[@]}"; exit 0 ;; + notx) shift; extraArgs=("$@"); build_notx "${extraArgs[@]}"; exit 0 ;; + jekyll) jekyll_build; exit 0 ;; + clean) cleanup; exit 0 ;; + exit) exit 0 ;; + *) + # Unknown first arg - default to build, pass all args through + extraArgs=("$@") + run_publisher "${extraArgs[@]}" + exit 0 + ;; + esac +fi + +# Interactive menu +check_internet_connection +# Compute default choice and reason +default_choice=2 +default_reason="publisher is up to date" + +if [ "$jar_location" = "not_found" ]; then + default_choice=1 + default_reason="publisher not found" +elif [ "$online" = "false" ]; then + default_choice=4 + default_reason="working offline" +elif [ -n "$latest_version" ]; then + current_version=$(java -jar "$jar_location" -v 2>/dev/null | tr -d '\r') + if [ "$current_version" != "$latest_version" ]; then + default_choice=1 + default_reason="newer version available" + fi +fi + +echo "---------------------------------------------" +echo "Publisher: ${current_version:-unknown}; Latest: ${latest_version:-unknown}" +echo "Publisher location: $jar_location" +echo "Online: $online" +echo "---------------------------------------------" +echo +echo "Please select an option:" +echo "1) Download or update publisher" +echo "2) Build IG" +echo "3) Build IG without Sushi" +echo "4) Build IG without TX server" +echo "5) Jekyll build" +echo "6) Cleanup temp directories" +echo "0) Exit" +echo + +# Read with timeout, but default if nothing entered +echo -n "Choose an option [default: $default_choice - $default_reason]: " +read -t 5 choice || choice="$default_choice" +choice="${choice:-$default_choice}" +echo "You selected: $choice" + +case "$choice" in + 1) update_publisher ;; + 2) build_ig ;; + 3) build_nosushi ;; + 4) build_notx ;; + 5) jekyll_build ;; + 6) cleanup ;; + 0) exit 0 ;; + *) echo "Invalid option." ;; esac diff --git a/input/fsh/DkCoreImmunization.fsh b/input/fsh/DkCoreImmunization.fsh new file mode 100644 index 000000000..b9ace25d3 --- /dev/null +++ b/input/fsh/DkCoreImmunization.fsh @@ -0,0 +1,74 @@ +Profile: DkCoreImmunization +Parent: Immunization +Id: dk-core-immunization +Title: "Danish Core Immunization Profile" +Description: "HL7 Denmark core profile for an administered or refused vaccination, aligned with Det Danske Vaccinationsregister (DDV) as exposed via sundhed.dk. A DDV vaccination carries a numeric VaccinationIdentifier, a free-text Vaccine name, an optional coverage duration, an effectuator, an effectuation date/time, and flags for active status, negative consent and self-created entries. See https://www.nspop.dk/pages/releaseview.action?pageId=31798109 for the DDV service description." +* ^status = #active +* identifier ^slicing.discriminator.type = #value + * ^slicing.discriminator.path = "system" + * ^slicing.rules = #open + * ^slicing.ordered = false + * ^slicing.description = "Slice identifier by system to carry the DDV VaccinationIdentifier" +* identifier contains + DdvVaccinationId 0..1 +* identifier[DdvVaccinationId] ^short = "[DA] DDV VaccinationIdentifier - identificerer en vaccination i Det Danske Vaccinationsregister" + * system 1.. + * system = $DdvVaccinationId (exactly) + * value 1.. +* status ^short = "Status for vaccinationen. completed = effektueret (ActiveStatus = true i DDV); not-done = aflyst/afvist, herunder HasNegativeConsent = true. entered-in-error bruges for fejlregistreringer." +* statusReason ^short = "Begrundelse når status = not-done, fx negativ samtykke eller aflyst vaccination." +* vaccineCode ^short = "Vaccinen. DDV leverer typisk navnet som fritekst (Vaccine-feltet). ATC J07* eller SNOMED CT codings kan tilføjes hvor det er kendt." +* vaccineCode.coding ^slicing.discriminator.type = #value + * ^slicing.discriminator.path = "system" + * ^slicing.rules = #open + * ^slicing.ordered = false + * ^slicing.description = "Slice vaccineCode.coding by system to accommodate ATC or SNOMED CT coding alongside the DDV free-text name" +* vaccineCode.coding contains + ATC 0..1 and + SCTVaccineCode 0..1 +* vaccineCode.coding[ATC] ^short = "WHO ATC code for vaccinen (J07-gruppen)." + * system 1.. + * system = $atc (exactly) + * code 1.. +* vaccineCode.coding[SCTVaccineCode] ^short = "SNOMED CT code for vaccinen." + * system 1.. + * system = "http://snomed.info/sct" + * code 1.. +* patient only Reference(DkCorePatient) +* patient 1.. +* occurrence[x] ^short = "Tidspunktet hvor vaccinationen blev givet. Mappes fra DDV EffectuatedDateTime." +* recorded ^short = "Tidspunkt hvor vaccinationen blev registreret i DDV. Når dette ikke er særskilt tilgængeligt, anvendes EffectuatedDateTime." +* performer.actor only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCoreOrganization) +* performer.actor ^short = "Den der har effektueret vaccinationen. DDV EffectuatedBy leveres ofte som fritekst (fx 'Danske Lægers Vaccinations Service') og kan placeres i actor.display når en egentlig reference ikke er tilgængelig." +* note ^short = "Fri tekst. Anvendes blandt andet til DDV CoverageDuration, SelfCreated, NegativeConsent og historikoplysninger der ikke har et dedikeret Immunization-element." + + +Instance: JohnImmunizationInfluvac +InstanceOf: DkCoreImmunization +Title: "John's Influvac vaccination" +Description: "Example DkCoreImmunization derived from a DDV vaccination record for influenza (Influvac)." +Usage: #example +* identifier[DdvVaccinationId].system = $DdvVaccinationId +* identifier[DdvVaccinationId].value = "32206056656" +* status = #completed +* vaccineCode.text = "Influvac mod Influenza" +* vaccineCode.coding[ATC] = $atc#J07BB02 "Influenza, inactivated, split virus or surface antigen" +* patient = Reference(Patient/john) +* occurrenceDateTime = "2025-09-30T09:11:14+02:00" +* recorded = "2025-09-30T09:11:14+02:00" +* performer.actor.display = "Danske Lægers Vaccinations Service" +* note[+].text = "Coverage duration: 1 year" + + +Instance: JohnImmunizationNegativeConsent +InstanceOf: DkCoreImmunization +Title: "John's afviste vaccination" +Description: "Example DkCoreImmunization for a DDV entry where HasNegativeConsent = true, mapping to status = not-done." +Usage: #example +* identifier[DdvVaccinationId].system = $DdvVaccinationId +* identifier[DdvVaccinationId].value = "1" +* status = #not-done +* vaccineCode.text = "Example Vaccine" +* patient = Reference(Patient/john) +* occurrenceDateTime = "2025-09-30" +* note[+].text = "Negative consent recorded" diff --git a/input/fsh/DkCoreMedicationRequest.fsh b/input/fsh/DkCoreMedicationRequest.fsh index 2a9e68444..99ae481c6 100644 --- a/input/fsh/DkCoreMedicationRequest.fsh +++ b/input/fsh/DkCoreMedicationRequest.fsh @@ -81,7 +81,7 @@ Usage: #example * reasonCode.text = "Hyperkolesterolæmi" * dosageInstruction * text = "1 tablet dagligt til aftensmad" - * route = http://snomed.info/sct#26643006 "Oral use" + * route = http://snomed.info/sct#26643006 "Oral route" * extension[effectiveDosePeriod].valuePeriod.start = "2024-03-15" * extension[renderedDosageInstruction].valueMarkdown = "1 tablet (40 mg) dagligt til aftensmad, til kontrol" diff --git a/input/fsh/DkCoreMedicationStatement.fsh b/input/fsh/DkCoreMedicationStatement.fsh index 8d2d9cdd4..f82b60e69 100644 --- a/input/fsh/DkCoreMedicationStatement.fsh +++ b/input/fsh/DkCoreMedicationStatement.fsh @@ -74,7 +74,7 @@ Usage: #example * dateAsserted = "2026-04-20" * reasonCode.text = "Hyperkolesterolæmi" * dosage.text = "1 tablet dagligt til aftensmad" -* dosage.route = http://snomed.info/sct#26643006 "Oral use" +* dosage.route = http://snomed.info/sct#26643006 "Oral route" Instance: JohnMedicationStatementStopped @@ -85,9 +85,9 @@ Usage: #example * identifier[FmkOrdinationId].system = $FmkOrdinationId * identifier[FmkOrdinationId].value = "987654321" * status = #stopped -* extension[adherence].extension[code].valueCodeableConcept.coding.system = "http://terminology.hl7.org/CodeSystem/medicationstatement-adherence" -* extension[adherence].extension[code].valueCodeableConcept.coding.code = #no-longer-taking -* extension[adherence].extension[code].valueCodeableConcept.coding.display = "No longer Taking" +* extension[adherence].extension[code].valueCodeableConcept.coding.system = "http://hl7.org/fhir/CodeSystem/medication-statement-adherence" +* extension[adherence].extension[code].valueCodeableConcept.coding.code = #stopped +* extension[adherence].extension[code].valueCodeableConcept.coding.display = "Stopped" * medicationCodeableConcept.coding[ATC] = $atc#A10BA02 "Metformin" * medicationCodeableConcept.text = "Metformin 500 mg" * subject = Reference(Patient/john) diff --git a/input/fsh/aliases.fsh b/input/fsh/aliases.fsh index fdabd287a..91110dc19 100644 --- a/input/fsh/aliases.fsh +++ b/input/fsh/aliases.fsh @@ -43,6 +43,8 @@ Alias: $imposeProfile = http://hl7.org/fhir/StructureDefinition/structuredefinit Alias: $eu-medicationRequest = http://hl7.eu/fhir/base/StructureDefinition/medicationRequest-eu-core Alias: $eu-medicationStatement = http://hl7.eu/fhir/base/StructureDefinition/medicationStatement-eu-core Alias: $eu-medication = http://hl7.eu/fhir/base/StructureDefinition/medication-eu-core +Alias: $DdvVaccinationId = https://www.sundhed.dk/vaccination/id +Alias: $DdvPatientId = https://www.sundhed.dk/patient Alias: $DanishXdsOid = urn:oid:1.2.208.184.100.9 Alias: $MedComFormatOID = urn:oid:1.2.208.184.100.10 Alias: $IANALanguageOID = urn:oid:2.16.840.1.113883.6.121 diff --git a/input/fsh/codeSystems.fsh b/input/fsh/codeSystems.fsh index 1917594fc..b84be17d4 100644 --- a/input/fsh/codeSystems.fsh +++ b/input/fsh/codeSystems.fsh @@ -546,7 +546,7 @@ Id: consent-state-codes-dk-supplement Description: "Indicates the state of the consent" * ^experimental = false * ^content = #supplement -* ^supplements = "http://hl7.org/fhir/consent-state-codes" +* ^supplements = "http://hl7.org/fhir/consent-state-codes|4.0.1" * #draft * ^designation.language = #da * ^designation.use = $sct-int#900000000000013009 diff --git a/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md b/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md new file mode 100644 index 000000000..37200025f --- /dev/null +++ b/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md @@ -0,0 +1,34 @@ +### Scope and usage + +The Danish Core Immunization profile is intended to represent an administered or refused vaccination, as sourced from Det Danske Vaccinationsregister (DDV) via the sundhed.dk vaccination API. Source documentation for the DDV service: [nspop.dk - DDV](https://www.nspop.dk/pages/releaseview.action?pageId=31798109). + +A DDV vaccination record carries a numeric `VaccinationIdentifier`, a free-text `Vaccine` name, an effectuator, an effectuation date/time, and a set of flags (`ActiveStatus`, `NegativeConsent`, `SelfCreated`, `IsEditable`) plus an optional `CoverageDuration`. In dk-core the `patient` element has been constrained to [DkCorePatient](StructureDefinition-dk-core-patient.html) and `performer.actor` to the Danish core profiles for Practitioner, PractitionerRole or Organization. When the DDV effectuator is available only as free text (e.g. "Danske Lægers Vaccinations Service"), it should be carried as `performer.actor.display`. + +#### Mapping from DDV + +| DDV field | FHIR target | +| --- | --- | +| `VaccinationIdentifier` | `identifier[DdvVaccinationId]` (`https://www.sundhed.dk/vaccination/id`) | +| `Vaccine` | `vaccineCode.text` (ATC or SNOMED CT coding MAY also be supplied via `vaccineCode.coding[ATC]` / `vaccineCode.coding[SCTVaccineCode]`) | +| `EffectuatedDateTime` | `occurrenceDateTime` and, when no distinct registration timestamp is available, `recorded` | +| `EffectuatedBy` | `performer.actor` (or `performer.actor.display` when only a free-text name is known) | +| `ActiveStatus = true` | `status = #completed` | +| `ActiveStatus = false` | `status = #not-done` | +| `NegativeConsent = true` | `status = #not-done` (takes precedence over `ActiveStatus`) | +| `CoverageDuration` | `note` (free text, e.g. "Coverage duration: 1 year") | +| `SelfCreated = true` | `note` (free text, e.g. "Recorded as self-created") | +| `NegativeConsent = true` | `note` (free text, e.g. "Negative consent recorded") | +| DDV vaccination history entries | `note` (free text, listing prior entry dates/ids) | + +#### Status semantics + +DDV does not expose the full set of FHIR `Immunization.status` values. The mapping collapses DDV's boolean flags as follows: + +- `NegativeConsent = true` → `status = #not-done` (regardless of `ActiveStatus`). +- `ActiveStatus = true` → `status = #completed`. +- `ActiveStatus = false` → `status = #not-done`. +- Unknown / missing → omit `status` (the resource will fail the base cardinality check; ensure one of the flags is known before producing the resource). + +#### Vaccine coding + +DDV typically returns the vaccine product name as free text in the `Vaccine` field. Implementations MAY supplement this with an ATC coding from the J07 group, or with a SNOMED CT coding where known. The free-text form is preserved in `vaccineCode.text` so no information is lost. diff --git a/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md b/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md index 48beca92b..fcb8176d7 100644 --- a/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md +++ b/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md @@ -22,13 +22,13 @@ The profile claims conformance to [MedicationStatement (EU core)](https://build. | `Dosage.Text` | `dosage.text` | | `Treatment.Administration` | `dosage.route` (free-text allowed) | | Snapshot timestamp (the time the card was retrieved) | `dateAsserted` | -| `HasNegativeConsent = true` | `status = #stopped` plus `extension[adherence]` with an appropriate `no-longer-taking` / `not-taking` code | +| `HasNegativeConsent = true` | `status = #stopped` plus `extension[adherence]` with an appropriate `stopped` / `not-taking` code | | `MedicationCardStatus.EnumStr` | `status` (active / completed / stopped / entered-in-error / unknown) | Consumers of this profile should be aware that a MedicationStatement derived from an FMK medication card is, by design, a *view* on the current state of one or more ordinations rather than an authoritative clinical assertion. When populating `dateAsserted`, use the timestamp of the FMK retrieval, not the ordination date. #### Extensions in use -The profile brings forward the R5 `adherence` extension from the HL7 Europe Base profile. FMK's `HasNegativeConsent` flag and card-level status should be surfaced as adherence codes where possible; the coarse `status = stopped` value remains but loses nuance compared to adherence codes such as `no-longer-taking`, `not-taking`, `on-hold`. +The profile brings forward the R5 `adherence` extension from the HL7 Europe Base profile. FMK's `HasNegativeConsent` flag and card-level status should be surfaced as adherence codes where possible; the coarse `status = stopped` value remains but loses nuance compared to adherence codes such as `stopped`, `not-taking`, `on-hold`. #### Effective[x] `effective[x]` is restricted to either `effectiveDateTime` (point-in-time) or `effectivePeriod` (typical for FMK). Prefer `effectivePeriod` when an end date is known, or when the start date is known and the medication is ongoing. diff --git a/sushi-config.yaml b/sushi-config.yaml index fcee485e1..69c7525b8 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -42,7 +42,7 @@ parameters: path-expansion-params: Parameters-expParam.json dependencies: - hl7.fhir.extensions.r5: 4.0.1 + hl7.fhir.uv.xver-r5.r4: 0.1.0 hl7.fhir.uv.extensions.r4: version: 5.3.0-ballot-tc1 uri: http://hl7.org/fhir/extensions/ImplementationGuide/hl7.fhir.uv.extensions From 2fce4c388fa9d8a153eef614efab9706055a8a02 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Thu, 23 Apr 2026 11:48:23 +0200 Subject: [PATCH 3/8] Adding mappings for several resources --- input/fsh/DkCoreCondition.fsh | 21 +++++++++++++++++ input/fsh/DkCoreImmunization.fsh | 15 ++++++++++++ input/fsh/DkCoreMedication.fsh | 14 ++++++++++++ input/fsh/DkCoreMedicationRequest.fsh | 23 +++++++++++++++++++ input/fsh/DkCoreMedicationStatement.fsh | 21 +++++++++++++++++ input/fsh/DkCoreMinimalDocumentReference.fsh | 24 ++++++++++++++++++++ input/fsh/DkCoreOrganization.fsh | 18 +++++++++++++++ input/fsh/DkCorePatient.fsh | 21 +++++++++++++++++ input/fsh/DkCorePractitioner.fsh | 12 ++++++++++ input/fsh/DkCorePractitionerRole.fsh | 14 ++++++++++++ 10 files changed, 183 insertions(+) diff --git a/input/fsh/DkCoreCondition.fsh b/input/fsh/DkCoreCondition.fsh index ddbcf9e66..0ecc53c65 100644 --- a/input/fsh/DkCoreCondition.fsh +++ b/input/fsh/DkCoreCondition.fsh @@ -42,6 +42,27 @@ Description: "HL7 Denmark core profile for professionally asserted conditions, a * recorder only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCorePatient or DkCoreRelatedPerson) * asserter only Reference(DkCorePractitioner or DkCorePractitionerRole) +Mapping: DkCoreConditionToDanishClassifications +Source: DkCoreCondition +Target: "https://medinfo.dk/sks/brows.php" +Title: "Danish Condition Classifications (SKS-D, ICPC-2, FSIII, FFB)" +Id: dk-core-condition-classifications +* -> "Condition / Tilstand" "**Danish condition-classification systems used across sectors. A single DkCoreCondition MAY carry multiple codings when the same condition is represented in more than one classification.**" +* code.coding[SCTConditionCode] -> "SNOMED CT" "International SNOMED CT condition code under `http://snomed.info/sct`; bound to the FHIR R4 condition-code value set." +* code.coding[SKS-D] -> "SKS (Sundhedsvæsenets Klassifikations System), D-hierarkiet" "Secondary-sector diagnosis code from the SKS D-hierarchy under `urn:oid:1.2.208.176.2.4.12`." +* code.coding[ICPC2code] -> "ICPC-2" "International Classification of Primary Care, 2nd edition under `urn:oid:1.2.208.176.2.31`. Primary-care / general practice." +* code.coding[FSIIIConditionCode] -> "FSIII tilstande" "Municipal-care condition code (Fælles Sprog III) under `urn:oid:1.2.208.176.2.21`." +* code.coding[FFBConditionCode] -> "FFB undertemaer" "Municipal rehabilitation sub-theme code (Fælles Faglige Begreber) under `urn:oid:1.2.208.176.2.22`." +* clinicalStatus -> "Klinisk status" "active / recurrence / relapse / inactive / remission / resolved." +* verificationStatus -> "Verifikationsstatus" "unconfirmed / provisional / differential / confirmed / refuted / entered-in-error." +* subject -> "Patient" "DkCorePatient reference." +* recorder -> "Registrerer" "Who recorded the condition (Practitioner / PractitionerRole / Patient / RelatedPerson)." +* asserter -> "Asserter" "Clinician asserting the condition (Practitioner / PractitionerRole)." +* extension[conditionLastAssertedDate] -> "Sidst bekræftet" "Last date the condition was confirmed valid in its current state (typically last follow-up)." +* extension[notFollowedAnymore] -> "Ikke længere fulgt" "Date the condition lost focus in a specific clinical context." +* extension[dueTo] -> "Forårsaget af" "Link to another condition / observation that caused this condition." + + Instance: ConditionPressureUlcer InstanceOf: DkCoreCondition Title: "John tryksår" diff --git a/input/fsh/DkCoreImmunization.fsh b/input/fsh/DkCoreImmunization.fsh index b9ace25d3..202b52460 100644 --- a/input/fsh/DkCoreImmunization.fsh +++ b/input/fsh/DkCoreImmunization.fsh @@ -43,6 +43,21 @@ Description: "HL7 Denmark core profile for an administered or refused vaccinatio * note ^short = "Fri tekst. Anvendes blandt andet til DDV CoverageDuration, SelfCreated, NegativeConsent og historikoplysninger der ikke har et dedikeret Immunization-element." +Mapping: DkCoreImmunizationToDdv +Source: DkCoreImmunization +Target: "https://www.nspop.dk/pages/releaseview.action?pageId=31798109" +Title: "Det Danske Vaccinationsregister (DDV)" +Id: dk-core-immunization-ddv +* -> "VaccinationRecord" "**DDV vaccination record, as exposed via sundhed.dk's `/app/vaccination/api/v1/effectuatedvaccinations/` endpoint.**" +* identifier[DdvVaccinationId] -> "VaccinationIdentifier" "Numeric DDV identifier of the vaccination. Serialised as `identifier.value` under system `https://www.sundhed.dk/vaccination/id`." +* status -> "ActiveStatus / NegativeConsent" "Derived: `NegativeConsent = true` → `not-done`; else `ActiveStatus = true` → `completed`; `ActiveStatus = false` → `not-done`." +* vaccineCode -> "Vaccine" "DDV `Vaccine` is a free-text product name, carried in `vaccineCode.text`. Optional ATC J07 / SNOMED CT codings MAY be added." +* occurrence[x] -> "EffectuatedDateTime" "Time the vaccination was administered." +* recorded -> "EffectuatedDateTime" "Used in lieu of a separate registration timestamp when none is available." +* performer.actor -> "EffectuatedBy" "Who effectuated the vaccination. DDV often delivers this as free text; use `actor.display` when no structured reference is available." +* note -> "CoverageDuration / SelfCreated / NegativeConsent / history" "Free-text notes for DDV fields without a dedicated Immunization element (e.g. coverage duration, self-created flag, negative-consent marker, prior history entries)." + + Instance: JohnImmunizationInfluvac InstanceOf: DkCoreImmunization Title: "John's Influvac vaccination" diff --git a/input/fsh/DkCoreMedication.fsh b/input/fsh/DkCoreMedication.fsh index 3ec2fcf90..834b32aed 100644 --- a/input/fsh/DkCoreMedication.fsh +++ b/input/fsh/DkCoreMedication.fsh @@ -27,6 +27,20 @@ Description: "HL7 Denmark core profile for a medicinal product, aligned with the * manufacturer only Reference(DkCoreOrganization) +Mapping: DkCoreMedicationToFmk +Source: DkCoreMedication +Target: "https://wiki.fmk-teknik.dk/start" +Title: "Fælles Medicinkort (FMK)" +Id: dk-core-medication-fmk +* -> "DrugMedication" "**Named medicinal product in FMK.**" +* code.coding[ATC] -> "DrugMedication.AtcCode / AtcText" "WHO ATC code." +* code.coding[ActiveSubstance] -> "DrugMedication.ActiveSubstance" "Active-substance coding." +* code.text -> "DrugMedication (name/form/strength)" "Free-text rendering of the drug name, form and strength." +* form -> "DrugMedication.Form" "Lægemiddelform. May be free text." +* ingredient.strength -> "DrugMedication.Strength" "Styrke; may be free text until structured data is available." +* manufacturer -> "DrugMedication (manufacturer)" "Organisation reference for the drug manufacturer." + + Instance: SimvastatinActavis40mg InstanceOf: DkCoreMedication Title: "Simvastatin \"Actavis\" 40 mg filmovertrukne tabletter" diff --git a/input/fsh/DkCoreMedicationRequest.fsh b/input/fsh/DkCoreMedicationRequest.fsh index 99ae481c6..a77121e99 100644 --- a/input/fsh/DkCoreMedicationRequest.fsh +++ b/input/fsh/DkCoreMedicationRequest.fsh @@ -59,6 +59,29 @@ Description: "HL7 Denmark core profile for medication orders (ordinationer), ali * dispenseRequest.performer only Reference(DkCoreOrganization) +Mapping: DkCoreMedicationRequestToFmk +Source: DkCoreMedicationRequest +Target: "https://wiki.fmk-teknik.dk/start" +Title: "Fælles Medicinkort (FMK)" +Id: dk-core-medicationrequest-fmk +* -> "Ordination" "**FMK drug order (ordination).**" +* identifier[FmkOrdinationId] -> "DrugMedication.OrdinationIdentifier" "Identifier of an FMK ordination." +* identifier[FmkDrugMedicationId] -> "DrugMedication.DrugMedicationIdentifier" "Identifier of a specific version of the drug medication." +* status -> "MedicationCardStatus.EnumStr / HasNegativeConsent" "`active` / `stopped` / `completed`. `HasNegativeConsent = true` maps to `stopped`." +* intent -> "Ordination type" "FMK ordinations are typically modelled as `intent = order`." +* medicationCodeableConcept.coding[ATC] -> "DrugMedication.AtcCode / AtcText" "WHO ATC code." +* medicationCodeableConcept.coding[ActiveSubstance] -> "DrugMedication.ActiveSubstance" "Active-substance coding." +* medicationCodeableConcept.text -> "DrugMedication (name/form/strength)" "Free-text rendering of the drug name, form and strength." +* subject -> "Patient" "FMK patient reference." +* authoredOn -> "Ordination date" "When the ordination was authored." +* requester -> "Ordinerende behandler" "Prescriber." +* reasonCode -> "Treatment.Cause" "Indikation / årsag." +* dosageInstruction.text -> "Dosage.Text" "Human-rendered dosage." +* dosageInstruction.route -> "Treatment.Administration" "Administration route." +* extension[effectiveDosePeriod] -> "Treatment.StartDate / Treatment.EndDate" "R5 back-port: period over which the medication is to be taken." +* extension[renderedDosageInstruction] -> "Dosage.Text" "R5 back-port: full human-rendered dosage string." + + Instance: JohnMedicationRequestSimvastatin InstanceOf: DkCoreMedicationRequest Title: "John's Simvastatin ordination" diff --git a/input/fsh/DkCoreMedicationStatement.fsh b/input/fsh/DkCoreMedicationStatement.fsh index f82b60e69..29010ef43 100644 --- a/input/fsh/DkCoreMedicationStatement.fsh +++ b/input/fsh/DkCoreMedicationStatement.fsh @@ -56,6 +56,27 @@ Description: "HL7 Denmark core profile for a statement about medication being ta * dosage ^short = "Dosering. In FMK: Dosage.Text; Treatment.Administration (route) kan lægges i dosage.route eller dosage.patientInstruction." +Mapping: DkCoreMedicationStatementToFmk +Source: DkCoreMedicationStatement +Target: "https://wiki.fmk-teknik.dk/start" +Title: "Fælles Medicinkort (FMK)" +Id: dk-core-medicationstatement-fmk +* -> "MedicationCard entry" "**Snapshot of a drug on the FMK medication card (aktuelt medicinbillede).**" +* identifier[FmkOrdinationId] -> "DrugMedication.OrdinationIdentifier" "Identifier of an FMK ordination." +* identifier[FmkDrugMedicationId] -> "DrugMedication.DrugMedicationIdentifier" "Identifier of a specific version of the drug medication." +* status -> "MedicationCardStatus.EnumStr / HasNegativeConsent" "`active` / `completed` / `stopped` / `entered-in-error` / `unknown`. `HasNegativeConsent = true` maps to `stopped` and SHOULD be supplemented via the adherence extension." +* medicationCodeableConcept.coding[ATC] -> "DrugMedication.AtcCode / AtcText" "WHO ATC code for the drug." +* medicationCodeableConcept.coding[ActiveSubstance] -> "DrugMedication.ActiveSubstance" "Active-substance coding." +* medicationCodeableConcept.text -> "DrugMedication (name/form/strength)" "Free-text rendering of the drug name, form and strength." +* subject -> "Patient" "FMK patient reference." +* effective[x] -> "Treatment.StartDate / Treatment.EndDate" "Prefer `effectivePeriod` when start and/or end are known; use `effectiveDateTime` for point-in-time statements." +* dateAsserted -> "Snapshot timestamp" "Timestamp of the FMK medication-card retrieval (NOT the ordination date)." +* reasonCode -> "Treatment.Cause" "Indikation / årsag." +* dosage.text -> "Dosage.Text" "Human-rendered dosage." +* dosage.route -> "Treatment.Administration" "Administration route (may be free text)." +* extension[adherence] -> "HasNegativeConsent" "R5 adherence code (e.g. `stopped`, `not-taking`, `on-hold`) for richer semantics than `status = stopped` alone." + + Instance: JohnMedicationStatementSimvastatin InstanceOf: DkCoreMedicationStatement Title: "John's aktive Simvastatin på medicinkortet" diff --git a/input/fsh/DkCoreMinimalDocumentReference.fsh b/input/fsh/DkCoreMinimalDocumentReference.fsh index f37d049aa..0d5d24a85 100644 --- a/input/fsh/DkCoreMinimalDocumentReference.fsh +++ b/input/fsh/DkCoreMinimalDocumentReference.fsh @@ -15,6 +15,30 @@ Description: "HL7 Denmark core profile for a Minimal DocumentReference inherited * subject only Reference(DkCorePatient) * context.sourcePatientInfo only Reference(DkCorePatient) +Mapping: DkCoreMinimalDocumentReferenceToXds +Source: DkCoreMinimalDocumentReference +Target: "https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html" +Title: "IHE MHD / MedCom XDS DocumentEntry" +Id: dk-core-minimaldocref-xds +* -> "DocumentEntry" "**IHE MHD DocumentReference mapped to an XDS DocumentEntry. Format and category codings follow the Danish XDS OID (`urn:oid:1.2.208.184.100.9`) and the MedCom format OID (`urn:oid:1.2.208.184.100.10`).**" +* masterIdentifier -> "DocumentEntry.uniqueId" "[DocumentEntry.uniqueId](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.26)" +* identifier -> "DocumentEntry.entryUUID" "[DocumentEntry.entryUUID](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.7)" +* status -> "DocumentEntry.availabilityStatus" "[DocumentEntry.availabilityStatus](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.2)" +* type -> "DocumentEntry.typeCode" "[DocumentEntry.typeCode](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.28) - LOINC document type." +* category -> "DocumentEntry.classCode" "[DocumentEntry.classCode](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.3) - bound to the Danish XDS category OID." +* subject -> "DocumentEntry.patientId" "[DocumentEntry.patientId](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.16) - CPR-keyed." +* author -> "DocumentEntry.author" "[DocumentEntry.author](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.1)" +* authenticator -> "DocumentEntry.legalAuthenticator" "[DocumentEntry.legalAuthenticator](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.14)" +* securityLabel -> "DocumentEntry.confidentialityCode" "[DocumentEntry.confidentialityCode](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.4)" +* content.attachment -> "DocumentEntry.repositoryUniqueId / size / hash / mimeType / language" "Physical document metadata and pointer." +* content.format -> "DocumentEntry.formatCode" "[DocumentEntry.formatCode](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.8) - MedCom format OID (e.g. APD, PLR)." +* context.event -> "DocumentEntry.eventCodeList" "[DocumentEntry.eventCodeList](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.6) - SKS event codes." +* context.facilityType -> "DocumentEntry.healthcareFacilityTypeCode" "[DocumentEntry.healthcareFacilityTypeCode](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.10) - SOR organization-type binding." +* context.practiceSetting -> "DocumentEntry.practiceSettingCode" "[DocumentEntry.practiceSettingCode](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.17) - SOR practice-setting binding." +* context.sourcePatientInfo -> "DocumentEntry.sourcePatientInfo" "[DocumentEntry.sourcePatientInfo](https://profiles.ihe.net/ITI/TF/Volume3/ch-4.2.html#4.2.3.2.23)" +* extension[versionid] -> "DocumentEntry.version" "R5 back-port: document version string." + + // DkCoreDocumentReference instance Instance: 94e65db8-2f0c-4a2c-a7c9-06a160d59a12 InstanceOf: DkCoreMinimalDocumentReference diff --git a/input/fsh/DkCoreOrganization.fsh b/input/fsh/DkCoreOrganization.fsh index 95a444d22..dbd489b8b 100644 --- a/input/fsh/DkCoreOrganization.fsh +++ b/input/fsh/DkCoreOrganization.fsh @@ -42,6 +42,24 @@ Description: "HL7 Denmark core profile for a danish health organization" * ^short = "[DA] Producent Id" * type from $sor-organization-type (preferred) +Mapping: DkCoreOrganizationToDanishRegistries +Source: DkCoreOrganization +Target: "https://www.nspop.dk/display/public/web/SOR" +Title: "Danish Organization Registries (SOR, CVR, GLN, Ydernummer, FK-ORG, MedCom)" +Id: dk-core-organization-registries +* -> "Organization" "**Danish organizational identity registries. SOR is the primary source of truth for healthcare organizations; other slices carry the organization's cross-references to parallel registries.**" +* identifier[SOR-ID] -> "SOR (Sundhedsvæsenets Organisationsregister)" "SOR-id under `urn:oid:1.2.208.176.1.1`. Authoritative healthcare-organization registry." +* identifier[CVR-ID] -> "CVR (Det Centrale Virksomhedsregister)" "CVR-nummer under `http://cvr.dk`. The national business register." +* identifier[EAN-ID] -> "GLN (GS1)" "GLN / EAN location number under `https://www.gs1.org/gln`." +* identifier[Ydernummer] -> "Ydernummerregisteret" "Ydernummer under `urn:oid:1.2.208.176.1.4`. Regional register used for primary-care practice settlements." +* identifier[KOMBIT-ORG-ID] -> "FK-ORG (KOMBIT Organisationsregister)" "FK-ORG organizational-unit id under `https://kombit.dk/sts/organisation`. Municipal organization register." +* identifier[Kommunekode] -> "Kommunekoder" "Municipality code under `http://hl7.dk/fhir/core/CodeSystem/dk-core-municipality-codes`." +* identifier[Regionskode] -> "ISO 3166-2 (Danske regioner)" "Region code under `urn:iso:std:iso:3166:-2`." +* identifier[ProducentID] -> "MedCom ProducentID" "MedCom producer identifier under `http://medcomfhir.dk/ig/terminology/CodeSystem/MedComProducentID`." +* type -> "SOR enhedstype" "Organization type, preferred from the SOR organization-type value set." +* partOf -> "SOR parent unit" "Parent SOR unit in the organizational hierarchy." + + Instance: CenterForDiabetes InstanceOf: DkCoreOrganization Title: "Center for Diabetes" diff --git a/input/fsh/DkCorePatient.fsh b/input/fsh/DkCorePatient.fsh index 6afcce6cc..115b5c385 100644 --- a/input/fsh/DkCorePatient.fsh +++ b/input/fsh/DkCorePatient.fsh @@ -46,6 +46,27 @@ Description: "HL7 Denmark core profile for a patient" * link.other only Reference(DkCorePatient or DkCoreRelatedPerson) * contact.relationship from extended-patient-contactrelationship (extensible) +Mapping: DkCorePatientToCprAndDawa +Source: DkCorePatient +Target: "https://cpr.dk" +Title: "CPR-registeret (and DAWA for addresses)" +Id: dk-core-patient-cpr +* -> "Person" "**Danish person-identity registries. `identifier[cpr]` / `name[official]` / `gender` / `birthDate` / the official address extension derive from the CPR register; address is curated against DAWA.**" +* identifier[cpr] -> "CPR-nummer" "CPR-nummer under `urn:oid:1.2.208.176.1.2` - the national civil registration number." +* identifier[x-ecpr] -> "X-eCPR" "Externally assigned eCPR from the national eCPR service for persons without a permanent CPR (e.g. foreign patients, newborns pre-registration)." +* identifier[d-ecpr] -> "D-eCPR" "Decentralised eCPR assigned locally." +* name[official] -> "CPR officielt navn" "Official name as recorded in CPR (`use = official`, `family` mandatory)." +* gender -> "CPR køn" "Gender as recorded in CPR (derived from the 10th digit of CPR-nummer unless corrected)." +* birthDate -> "CPR fødselsdag" "Birth date as recorded in CPR." +* address -> "DAWA (Danmarks Adressers Web API)" "Danish addresses curated per https://dawa.aws.dk/." +* address.extension[municipalityCode] -> "Kommunekode" "Municipality code for the address." +* address.extension[regionalSubDivisionCodes] -> "ISO 3166-2 regionskode" "Region code for the address." +* address.extension[address-official] -> "CPR bopælsadresse" "Marks the address as the CPR-registered official address (see https://www.retsinformation.dk/eli/lta/2023/1010)." +* maritalStatus -> "CPR civilstand" "Civil status from the CPR register." +* generalPractitioner -> "SOR almen praksis" "The patient's general practitioner, typically referenced via a SOR unit id." +* managingOrganization -> "Patientens administrerende organisation" "DkCoreOrganization responsible for managing the patient record." + + Instance: 283 InstanceOf: DkCorePatient Title: "Example of valid patient with full address" diff --git a/input/fsh/DkCorePractitioner.fsh b/input/fsh/DkCorePractitioner.fsh index d8b1fa6f3..c73883079 100644 --- a/input/fsh/DkCorePractitioner.fsh +++ b/input/fsh/DkCorePractitioner.fsh @@ -14,6 +14,18 @@ Description: "HL7 Denmark core profile for health professionals and other actors * qualification[officialHealthAuthorization].code from DkCoreProfessionGroupValueSet (extensible) * ^short = "[DA] Kode for kvalifikation, som specificeret af autorisationsregisteret" +Mapping: DkCorePractitionerToAutregweb +Source: DkCorePractitioner +Target: "https://autregweb.sst.dk" +Title: "Autorisationsregisteret (Styrelsen for Patientsikkerhed)" +Id: dk-core-practitioner-autreg +* -> "Authorised health professional" "**Danish Authorization Register (Autorisationsregisteret), maintained by Styrelsen for Patientsikkerhed.**" +* qualification[officialHealthAuthorization] -> "Autorisation" "A formally registered qualification in the national authorization register." +* qualification[officialHealthAuthorization].identifier -> "Autorisations-id" "Authorization identifier under `https://autregweb.sst.dk`." +* qualification[officialHealthAuthorization].code -> "Faggruppekode" "Profession-group code from the `DkCoreProfessionGroupCodes` classification (e.g. `7170` = Læge, `5166` = Sygeplejerske)." +* qualification[officialHealthAuthorization].period -> "Gyldighedsperiode" "Validity period of the authorization (start = authorization granted, end = expiry or revocation)." + + Instance: AbrahamLaege InstanceOf: DkCorePractitioner Title: "AbrahamLæge" diff --git a/input/fsh/DkCorePractitionerRole.fsh b/input/fsh/DkCorePractitionerRole.fsh index d9f2dcb71..e4cea7280 100644 --- a/input/fsh/DkCorePractitionerRole.fsh +++ b/input/fsh/DkCorePractitionerRole.fsh @@ -8,6 +8,20 @@ Description: "HL7 Denmark core profile for health professional roles" * location only Reference(DkCoreLocation) +Mapping: DkCorePractitionerRoleToSor +Source: DkCorePractitionerRole +Target: "https://www.nspop.dk/display/public/web/SOR" +Title: "SOR (Sundhedsvæsenets Organisationsregister)" +Id: dk-core-practitionerrole-sor +* -> "SOR practitioner-at-unit" "**A health professional performing a role at a SOR-registered organizational unit.** Complements the DkCoreOrganization mapping (SOR unit) and the DkCorePractitioner mapping (Autorisationsregisteret)." +* practitioner -> "Autoriseret sundhedsperson" "Reference to the DkCorePractitioner performing the role." +* organization -> "SOR enhed" "Reference to the DkCoreOrganization (SOR-unit) where the role is performed." +* location -> "Fysisk lokation" "Physical site of service delivery." +* code -> "Rollekode" "Role the practitioner performs at the SOR unit." +* specialty -> "Speciale" "SNOMED CT speciality (e.g. `408443003` = almen lægepraksis)." +* availableTime -> "Åbningstider" "Practitioner availability at the SOR unit." + + Instance: AbrahamPractitionerRole InstanceOf: DkCorePractitionerRole Title: "Licensed physician in primary care" From ee5eeb481eda0c7b4aaacdfb928a282f3a58f8e9 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Thu, 23 Apr 2026 19:05:11 +0200 Subject: [PATCH 4/8] adjusted according to specs --- input/fsh/DkCoreImmunization.fsh | 74 +++++++++++------- input/fsh/DkCoreMedication.fsh | 33 ++++---- input/fsh/DkCoreMedicationRequest.fsh | 76 +++++++++---------- input/fsh/DkCoreMedicationStatement.fsh | 70 ++++++++--------- input/fsh/aliases.fsh | 18 ++++- input/ignoreWarnings.txt | 14 ++++ ...reDefinition-dk-core-immunization-intro.md | 46 +++++++---- ...tureDefinition-dk-core-medication-intro.md | 17 +++-- ...inition-dk-core-medicationrequest-intro.md | 48 +++++++----- ...ition-dk-core-medicationstatement-intro.md | 38 +++++----- sushi-config.yaml | 2 + 11 files changed, 258 insertions(+), 178 deletions(-) diff --git a/input/fsh/DkCoreImmunization.fsh b/input/fsh/DkCoreImmunization.fsh index 202b52460..dd4cf44d3 100644 --- a/input/fsh/DkCoreImmunization.fsh +++ b/input/fsh/DkCoreImmunization.fsh @@ -2,31 +2,37 @@ Profile: DkCoreImmunization Parent: Immunization Id: dk-core-immunization Title: "Danish Core Immunization Profile" -Description: "HL7 Denmark core profile for an administered or refused vaccination, aligned with Det Danske Vaccinationsregister (DDV) as exposed via sundhed.dk. A DDV vaccination carries a numeric VaccinationIdentifier, a free-text Vaccine name, an optional coverage duration, an effectuator, an effectuation date/time, and flags for active status, negative consent and self-created entries. See https://www.nspop.dk/pages/releaseview.action?pageId=31798109 for the DDV service description." +Description: "HL7 Denmark core profile for an administered or refused vaccination, aligned with Det Danske Vaccinationsregister (DDV) interface 1.4.0 + E1. Authoritative DDV XML schemas are published at https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1 with target namespace `http://vaccinationsregister.dk/schemas/2013/12/01`. A DDV `Vaccination` carries a numeric `VaccinationIdentifier` (+ `VaccinationVersionIdentifier`), a structured `Vaccine` element (VaccineIdentifier + VaccineName + Disease[] + ATC + SSIDrug[]), an optional `Effectuated` structure (date, effectuator name, authorisation and organisation), `CoverageDuration`, `BatchNumber`, `ActiveStatus`, `NegativeConsentIndicator`, `VaccinationCredibility` (credibility enum whose values include `Oprettet af borger` / citizen-created), and flags such as `IsPrevious` and `ConfirmedByPrescriptionServer`." * ^status = #active * identifier ^slicing.discriminator.type = #value * ^slicing.discriminator.path = "system" * ^slicing.rules = #open * ^slicing.ordered = false - * ^slicing.description = "Slice identifier by system to carry the DDV VaccinationIdentifier" + * ^slicing.description = "Slice identifier by system to carry DDV VaccinationIdentifier (+ optional VaccinationVersionIdentifier)" * identifier contains - DdvVaccinationId 0..1 -* identifier[DdvVaccinationId] ^short = "[DA] DDV VaccinationIdentifier - identificerer en vaccination i Det Danske Vaccinationsregister" + DdvVaccinationId 0..1 and + DdvVaccinationVersion 0..1 +* identifier[DdvVaccinationId] ^short = "[DA] DDV VaccinationIdentifier - unik identifikation af en vaccination (positiv long)." * system 1.. * system = $DdvVaccinationId (exactly) * value 1.. -* status ^short = "Status for vaccinationen. completed = effektueret (ActiveStatus = true i DDV); not-done = aflyst/afvist, herunder HasNegativeConsent = true. entered-in-error bruges for fejlregistreringer." -* statusReason ^short = "Begrundelse når status = not-done, fx negativ samtykke eller aflyst vaccination." -* vaccineCode ^short = "Vaccinen. DDV leverer typisk navnet som fritekst (Vaccine-feltet). ATC J07* eller SNOMED CT codings kan tilføjes hvor det er kendt." +* identifier[DdvVaccinationVersion] ^short = "[DA] DDV VaccinationVersionIdentifier - pairs with DdvVaccinationId to identify a specific revision." + * system 1.. + * system = $DdvVaccinationVersion (exactly) + * value 1.. +* status ^short = "Status for vaccinationen. `completed` = effektueret (DDV Vaccination.ActiveStatus = true); `not-done` = aflyst/afvist, herunder DDV Vaccination.NegativeConsentIndicator = true eller ActiveStatus = false. `entered-in-error` bruges for fejlregistreringer." +* statusReason ^short = "Begrundelse når status = not-done, fx negativt samtykke (NegativeConsentIndicator = true) eller aflyst vaccination." +* vaccineCode ^short = "Vaccinen. DDV leverer strukturen DDV Vaccination.Vaccine som VaccineName (≤100 tegn fritekst), ATC (Code + Text), Disease[] (sygdom m. ATC), SSIDrug[] (SSI-lægemiddel) og DisplayMinimumVaccinationPlan[]. VaccineName mappes til vaccineCode.text; ATC til vaccineCode.coding[ATC]." * vaccineCode.coding ^slicing.discriminator.type = #value * ^slicing.discriminator.path = "system" * ^slicing.rules = #open * ^slicing.ordered = false - * ^slicing.description = "Slice vaccineCode.coding by system to accommodate ATC or SNOMED CT coding alongside the DDV free-text name" + * ^slicing.description = "Slice vaccineCode.coding by system to accommodate ATC or SNOMED CT coding alongside the DDV VaccineName free text" * vaccineCode.coding contains ATC 0..1 and - SCTVaccineCode 0..1 -* vaccineCode.coding[ATC] ^short = "WHO ATC code for vaccinen (J07-gruppen)." + SCTVaccineCode 0..1 and + DdvVaccine 0..1 +* vaccineCode.coding[ATC] ^short = "WHO ATC code for vaccinen (J07-gruppen). In DDV: Vaccination.Vaccine.ATC.Code / ATC.Text." * system 1.. * system = $atc (exactly) * code 1.. @@ -34,34 +40,47 @@ Description: "HL7 Denmark core profile for an administered or refused vaccinatio * system 1.. * system = "http://snomed.info/sct" * code 1.. +* vaccineCode.coding[DdvVaccine] ^short = "[DA] DDV VaccineIdentifier - SSI-numerisk identifikation af vaccinen (findes på Vaccination.Vaccine.VaccineIdentifier)." + * system 1.. + * system = $DdvVaccineId (exactly) + * code 1.. * patient only Reference(DkCorePatient) * patient 1.. -* occurrence[x] ^short = "Tidspunktet hvor vaccinationen blev givet. Mappes fra DDV EffectuatedDateTime." -* recorded ^short = "Tidspunkt hvor vaccinationen blev registreret i DDV. Når dette ikke er særskilt tilgængeligt, anvendes EffectuatedDateTime." +* occurrence[x] ^short = "Tidspunktet hvor vaccinationen blev givet. Mappes fra DDV Vaccination.EffectuatedDateTime (eller Vaccination.Effectuated.EffectuatedDateTime når effektueringen er leveret som struktureret element)." +* recorded ^short = "Tidspunkt hvor vaccinationen blev registreret i DDV. Mappes fra DDV Vaccination.Created.CreatedDateTime når det findes; falder tilbage til EffectuatedDateTime." * performer.actor only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCoreOrganization) -* performer.actor ^short = "Den der har effektueret vaccinationen. DDV EffectuatedBy leveres ofte som fritekst (fx 'Danske Lægers Vaccinations Service') og kan placeres i actor.display når en egentlig reference ikke er tilgængelig." -* note ^short = "Fri tekst. Anvendes blandt andet til DDV CoverageDuration, SelfCreated, NegativeConsent og historikoplysninger der ikke har et dedikeret Immunization-element." +* performer.actor ^short = "Den der har effektueret vaccinationen. DDV Vaccination.Effectuated.EffectuatedByName er en fritekst (≤200 tegn) og placeres i actor.display når en egentlig reference ikke er tilgængelig. Strukturerede felter: Effectuated.AuthorisationIdentifier (yder-/autorisationsnummer), Effectuated.EffectuatedByOrganisationName / Number / Type, Effectuated.EffectuatedInCountryCode." +* lotNumber ^short = "Batchnummer. In DDV: Vaccination.BatchNumber." +* protocolApplied.targetDisease ^short = "Sygdom(me) vaccinationen beskytter imod. In DDV: Vaccination.Vaccine.Disease[] (DiseaseIdentifier + DiseaseName + DiseaseNameDK + ATC)." +* note ^short = "Fri tekst. Anvendes blandt andet til DDV CoverageDuration, VaccinationCredibility (fx \"Oprettet af borger\" svarer til borger-registreret / selfcreated), ConfirmedByPrescriptionServer, IsPrevious, og historikoplysninger der ikke har et dedikeret Immunization-element." Mapping: DkCoreImmunizationToDdv Source: DkCoreImmunization -Target: "https://www.nspop.dk/pages/releaseview.action?pageId=31798109" +Target: "https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1" Title: "Det Danske Vaccinationsregister (DDV)" Id: dk-core-immunization-ddv -* -> "VaccinationRecord" "**DDV vaccination record, as exposed via sundhed.dk's `/app/vaccination/api/v1/effectuatedvaccinations/` endpoint.**" -* identifier[DdvVaccinationId] -> "VaccinationIdentifier" "Numeric DDV identifier of the vaccination. Serialised as `identifier.value` under system `https://www.sundhed.dk/vaccination/id`." -* status -> "ActiveStatus / NegativeConsent" "Derived: `NegativeConsent = true` → `not-done`; else `ActiveStatus = true` → `completed`; `ActiveStatus = false` → `not-done`." -* vaccineCode -> "Vaccine" "DDV `Vaccine` is a free-text product name, carried in `vaccineCode.text`. Optional ATC J07 / SNOMED CT codings MAY be added." -* occurrence[x] -> "EffectuatedDateTime" "Time the vaccination was administered." -* recorded -> "EffectuatedDateTime" "Used in lieu of a separate registration timestamp when none is available." -* performer.actor -> "EffectuatedBy" "Who effectuated the vaccination. DDV often delivers this as free text; use `actor.display` when no structured reference is available." -* note -> "CoverageDuration / SelfCreated / NegativeConsent / history" "Free-text notes for DDV fields without a dedicated Immunization element (e.g. coverage duration, self-created flag, negative-consent marker, prior history entries)." +* -> "Vaccination" "**DDV Vaccination (namespace `http://vaccinationsregister.dk/schemas/2013/12/01`).**" +* identifier[DdvVaccinationId] -> "Vaccination.VaccinationIdentifier" "Numeric DDV identifier of the vaccination (positive long)." +* identifier[DdvVaccinationVersion] -> "Vaccination.VaccinationVersionIdentifier" "Revision number - populate alongside the identifier when pointing to a specific version." +* status -> "Vaccination.ActiveStatus / Vaccination.NegativeConsentIndicator" "`completed` when `ActiveStatus = true` and `NegativeConsentIndicator` is false/absent; `not-done` when `NegativeConsentIndicator = true` or `ActiveStatus = false`." +* vaccineCode -> "Vaccination.Vaccine" "Structured DDV `Vaccine` (VaccineName + ATC + Disease[] + SSIDrug[] + …)." +* vaccineCode.coding[ATC] -> "Vaccination.Vaccine.ATC.Code / ATC.Text" "WHO ATC code - typically J07*." +* vaccineCode.coding[DdvVaccine] -> "Vaccination.Vaccine.VaccineIdentifier" "SSI numeric vaccine identifier." +* vaccineCode.text -> "Vaccination.Vaccine.VaccineName" "Free-text product name (≤100 chars)." +* patient -> "Patient" "Vaccinated patient (CPR reference in DDV)." +* occurrence[x] -> "Vaccination.EffectuatedDateTime / Vaccination.Effectuated.EffectuatedDateTime" "Time the vaccination was administered." +* recorded -> "Vaccination.Created.CreatedDateTime" "Time the vaccination record was created in DDV." +* performer.actor -> "Vaccination.Effectuated.EffectuatedByName / AuthorisationIdentifier / EffectuatedByOrganisationName / Number" "Who effectuated the vaccination. DDV often provides this as free text (EffectuatedByName); map to `actor.display` when no structured reference is available, or resolve `AuthorisationIdentifier` / organisation details to a DkCorePractitioner / DkCoreOrganization reference where possible." +* lotNumber -> "Vaccination.BatchNumber" "Lot / batch number." +* protocolApplied.targetDisease -> "Vaccination.Vaccine.Disease[]" "Target disease(s) with optional DiseaseIdentifier + DiseaseName(DK) + ATC." +* note -> "Vaccination.CoverageDuration / VaccinationCredibility / IsPrevious / ConfirmedByPrescriptionServer" "Free-text notes for DDV fields without a dedicated Immunization element. `VaccinationCredibility` enum: `Slettet`, `Oprettet af læge / medhjælp`, `Oprettet på baggrund af data fra Sygesikringsregisteret`, `Udleveret på apotek og godkendt af læge`, `Oprettet af læge eller oprettet af borger og godkendt af læge`, `Udleveret på apotek`, `Oprettet af borger`." Instance: JohnImmunizationInfluvac InstanceOf: DkCoreImmunization Title: "John's Influvac vaccination" -Description: "Example DkCoreImmunization derived from a DDV vaccination record for influenza (Influvac)." +Description: "Example DkCoreImmunization derived from a DDV Vaccination record for influenza (Influvac)." Usage: #example * identifier[DdvVaccinationId].system = $DdvVaccinationId * identifier[DdvVaccinationId].value = "32206056656" @@ -72,13 +91,14 @@ Usage: #example * occurrenceDateTime = "2025-09-30T09:11:14+02:00" * recorded = "2025-09-30T09:11:14+02:00" * performer.actor.display = "Danske Lægers Vaccinations Service" -* note[+].text = "Coverage duration: 1 year" +* note[+].text = "CoverageDuration: 1 year" +* note[+].text = "VaccinationCredibility: Oprettet af læge / medhjælp" Instance: JohnImmunizationNegativeConsent InstanceOf: DkCoreImmunization Title: "John's afviste vaccination" -Description: "Example DkCoreImmunization for a DDV entry where HasNegativeConsent = true, mapping to status = not-done." +Description: "Example DkCoreImmunization for a DDV Vaccination where NegativeConsentIndicator = true, mapping to status = not-done." Usage: #example * identifier[DdvVaccinationId].system = $DdvVaccinationId * identifier[DdvVaccinationId].value = "1" @@ -86,4 +106,4 @@ Usage: #example * vaccineCode.text = "Example Vaccine" * patient = Reference(Patient/john) * occurrenceDateTime = "2025-09-30" -* note[+].text = "Negative consent recorded" +* note[+].text = "NegativeConsentIndicator = true" diff --git a/input/fsh/DkCoreMedication.fsh b/input/fsh/DkCoreMedication.fsh index 834b32aed..d4a496764 100644 --- a/input/fsh/DkCoreMedication.fsh +++ b/input/fsh/DkCoreMedication.fsh @@ -11,34 +11,41 @@ Description: "HL7 Denmark core profile for a medicinal product, aligned with the * ^slicing.description = "Slice code.coding by system to accommodate the terminologies FMK uses for a drug" * code.coding contains ATC 0..1 and - ActiveSubstance 0..1 + ActiveSubstance 0..1 and + Varenummer 0..1 * code.coding[ATC] - * ^short = "WHO ATC code. In FMK: DrugMedication.AtcCode / AtcText." + * ^short = "WHO ATC code. In FMK: DrugMedication.Drug.ATC (Code + Text)." * system 1.. * system = $atc (exactly) * code 1.. * code.coding[ActiveSubstance] - * ^short = "[DA] Aktivt stof. In FMK: DrugMedication.ActiveSubstance." + * ^short = "[DA] Aktivt stof. In FMK: DrugMedication.Drug.Substances.ActiveSubstance." * system 1.. * system = $FmkActiveSubstance (exactly) * code 1.. -* form ^short = "[DA] Lægemiddelform. In FMK: DrugMedication.Form (may be free text)." -* ingredient.strength ^short = "[DA] Styrke. In FMK: DrugMedication.Strength (may be free text until structured data is available)." +* code.coding[Varenummer] + * ^short = "[DA] Varenummer fra Medicinpriser (LMS01 felt 1, 11-cifret). In FMK: DrugMedication.Drug.Identifier (source = Medicinpriser / Local / Magistrel / Stærke vitaminer m.v. / Tilknyttede behandlinger)." + * system 1.. + * system = $FmkDrugId (exactly) + * code 1.. +* form ^short = "[DA] Lægemiddelform. In FMK: DrugMedication.Drug.Form (Code + Text)." +* ingredient.strength ^short = "[DA] Styrke. In FMK: DrugMedication.Drug.Strength (Value + UnitCode + UnitText, or free text)." * manufacturer only Reference(DkCoreOrganization) Mapping: DkCoreMedicationToFmk Source: DkCoreMedication -Target: "https://wiki.fmk-teknik.dk/start" +Target: "https://wiki.fmk-teknik.dk/fmk:extensions:e5" Title: "Fælles Medicinkort (FMK)" Id: dk-core-medication-fmk -* -> "DrugMedication" "**Named medicinal product in FMK.**" -* code.coding[ATC] -> "DrugMedication.AtcCode / AtcText" "WHO ATC code." -* code.coding[ActiveSubstance] -> "DrugMedication.ActiveSubstance" "Active-substance coding." -* code.text -> "DrugMedication (name/form/strength)" "Free-text rendering of the drug name, form and strength." -* form -> "DrugMedication.Form" "Lægemiddelform. May be free text." -* ingredient.strength -> "DrugMedication.Strength" "Styrke; may be free text until structured data is available." -* manufacturer -> "DrugMedication (manufacturer)" "Organisation reference for the drug manufacturer." +* -> "DrugMedication.Drug" "**Named medicinal product within an FMK DrugMedication (lægemiddelordination).**" +* code.coding[ATC] -> "DrugMedication.Drug.ATC.Code / ATC.Text" "WHO ATC code." +* code.coding[ActiveSubstance] -> "DrugMedication.Drug.Substances.ActiveSubstance" "Active-substance coding (source: Medicinpriser / Local / Magistrel)." +* code.coding[Varenummer] -> "DrugMedication.Drug.Identifier" "Danish drug product number (varenummer, 11-digit, Medicinpriser)." +* code.text -> "DrugMedication.Drug.Name (+ Form/Strength)" "Free-text rendering of the drug name, form and strength." +* form -> "DrugMedication.Drug.Form" "Lægemiddelform (Code + Text)." +* ingredient.strength -> "DrugMedication.Drug.Strength" "Styrke (Value + UnitCode + UnitText, or free text)." +* manufacturer -> "DrugMedication.Drug (manufacturer)" "Organisation reference for the drug manufacturer." Instance: SimvastatinActavis40mg diff --git a/input/fsh/DkCoreMedicationRequest.fsh b/input/fsh/DkCoreMedicationRequest.fsh index a77121e99..f70ec5a1a 100644 --- a/input/fsh/DkCoreMedicationRequest.fsh +++ b/input/fsh/DkCoreMedicationRequest.fsh @@ -9,25 +9,25 @@ Description: "HL7 Denmark core profile for medication orders (ordinationer), ali * extension contains $mr-effectiveDosePeriod named effectiveDosePeriod 0..1 and $mr-renderedDosageInstruction named renderedDosageInstruction 0..1 -* extension[effectiveDosePeriod] ^short = "R5 back-port: period over which the medication is to be taken. In FMK: Treatment.StartDate / Treatment.EndDate." +* extension[effectiveDosePeriod] ^short = "R5 back-port: period over which the medication is to be taken. In FMK: DrugMedication.BeginEndDate.TreatmentStartDate / TreatmentEndDate." * extension[renderedDosageInstruction] ^short = "R5 back-port: full human-rendered dosage instruction. In FMK: Dosage.Text." * identifier ^slicing.discriminator.type = #value * ^slicing.discriminator.path = "system" * ^slicing.rules = #open * ^slicing.ordered = false - * ^slicing.description = "Slice identifier by system to distinguish FMK OrdinationIdentifier and DrugMedicationIdentifier" + * ^slicing.description = "Slice identifier by system to carry the FMK DrugMedicationIdentifier." * identifier contains - FmkOrdinationId 0..1 and - FmkDrugMedicationId 0..1 -* identifier[FmkOrdinationId] ^short = "[DA] FMK OrdinationIdentifier - identificerer en ordination på det fælles medicinkort" + FmkDrugMedicationId 0..1 and + FmkDrugMedicationVersion 0..1 +* identifier[FmkDrugMedicationId] ^short = "[DA] FMK DrugMedicationIdentifier - unik identifikation af lægemiddelordinationen (positiv long)." * system 1.. - * system = $FmkOrdinationId (exactly) + * system = $FmkDrugMedicationId (exactly) * value 1.. -* identifier[FmkDrugMedicationId] ^short = "[DA] FMK DrugMedicationIdentifier - identificerer en lægemiddelordination (specifik version af ordinationen)" +* identifier[FmkDrugMedicationVersion] ^short = "[DA] FMK DrugMedication.Version - pairs with FmkDrugMedicationId to identify a specific revision of the lægemiddelordination." * system 1.. - * system = $FmkDrugMedicationId (exactly) + * system = $FmkDrugMedicationVersion (exactly) * value 1.. -* status ^short = "Status for ordinationen. Active = aktiv på medicinkortet; stopped = seponeret / HasNegativeConsent = true i FMK." +* status ^short = "Status for ordinationen. `active` = aktiv på medicinkortet; `stopped` = seponeret (DrugMedication.Withdrawn er sat); `on-hold` = pauseret (DrugMedication.Paused er sat); `completed` = afsluttet behandling." * intent ^short = "FMK ordinationer modelleres typisk som intent = order." * medication[x] only CodeableConcept or Reference(DkCoreMedication) * medicationCodeableConcept.coding ^slicing.discriminator.type = #value @@ -39,12 +39,12 @@ Description: "HL7 Denmark core profile for medication orders (ordinationer), ali ATC 0..1 and ActiveSubstance 0..1 * medicationCodeableConcept.coding[ATC] - * ^short = "WHO ATC code for the ordinated drug. In FMK: DrugMedication.AtcCode / AtcText." + * ^short = "WHO ATC code for the ordinated drug. In FMK: DrugMedication.Drug.ATC (Code + Text)." * system 1.. * system = $atc (exactly) * code 1.. * medicationCodeableConcept.coding[ActiveSubstance] - * ^short = "[DA] Aktivt stof for ordinationen. In FMK: DrugMedication.ActiveSubstance." + * ^short = "[DA] Aktivt stof for ordinationen. In FMK: DrugMedication.Drug.Substances.ActiveSubstance." * system 1.. * system = $FmkActiveSubstance (exactly) * code 1.. @@ -54,43 +54,41 @@ Description: "HL7 Denmark core profile for medication orders (ordinationer), ali * recorder only Reference(DkCorePractitioner or DkCorePractitionerRole) * performer only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCoreOrganization or DkCorePatient or DkCoreRelatedPerson or Device or CareTeam) * reasonReference only Reference(DkCoreCondition or DkCoreObservation) -* reasonCode ^short = "Indikation / årsag for ordinationen. In FMK: Treatment.Cause." -* dosageInstruction ^short = "Dosering. In FMK: Dosage.Text (free text, prefer the renderedDosageInstruction extension for full FMK text) and/or Treatment.Administration (route)." +* reasonCode ^short = "Indikation / årsag for ordinationen. In FMK: DrugMedication.Indication (Code + Text, or FreeText)." +* dosageInstruction ^short = "Dosering. In FMK: DrugMedication.Dosage (prefer the renderedDosageInstruction extension for the full FMK dosage text) and DrugMedication.RouteOfAdministration (Code + Text) for the route." * dispenseRequest.performer only Reference(DkCoreOrganization) Mapping: DkCoreMedicationRequestToFmk Source: DkCoreMedicationRequest -Target: "https://wiki.fmk-teknik.dk/start" +Target: "https://wiki.fmk-teknik.dk/fmk:extensions:e5" Title: "Fælles Medicinkort (FMK)" Id: dk-core-medicationrequest-fmk -* -> "Ordination" "**FMK drug order (ordination).**" -* identifier[FmkOrdinationId] -> "DrugMedication.OrdinationIdentifier" "Identifier of an FMK ordination." -* identifier[FmkDrugMedicationId] -> "DrugMedication.DrugMedicationIdentifier" "Identifier of a specific version of the drug medication." -* status -> "MedicationCardStatus.EnumStr / HasNegativeConsent" "`active` / `stopped` / `completed`. `HasNegativeConsent = true` maps to `stopped`." -* intent -> "Ordination type" "FMK ordinations are typically modelled as `intent = order`." -* medicationCodeableConcept.coding[ATC] -> "DrugMedication.AtcCode / AtcText" "WHO ATC code." -* medicationCodeableConcept.coding[ActiveSubstance] -> "DrugMedication.ActiveSubstance" "Active-substance coding." -* medicationCodeableConcept.text -> "DrugMedication (name/form/strength)" "Free-text rendering of the drug name, form and strength." -* subject -> "Patient" "FMK patient reference." -* authoredOn -> "Ordination date" "When the ordination was authored." -* requester -> "Ordinerende behandler" "Prescriber." -* reasonCode -> "Treatment.Cause" "Indikation / årsag." -* dosageInstruction.text -> "Dosage.Text" "Human-rendered dosage." -* dosageInstruction.route -> "Treatment.Administration" "Administration route." -* extension[effectiveDosePeriod] -> "Treatment.StartDate / Treatment.EndDate" "R5 back-port: period over which the medication is to be taken." -* extension[renderedDosageInstruction] -> "Dosage.Text" "R5 back-port: full human-rendered dosage string." +* -> "DrugMedication" "**FMK lægemiddelordination (DrugMedication on the medicine card).**" +* identifier[FmkDrugMedicationId] -> "DrugMedication.Identifier" "DrugMedicationIdentifier - unique id of the lægemiddelordination." +* identifier[FmkDrugMedicationVersion] -> "DrugMedication.Version" "Revision number, carried alongside the identifier when a specific version of the ordination is being referenced." +* status -> "DrugMedication.Withdrawn / DrugMedication.Paused" "`active` = neither Withdrawn nor Paused; `stopped` = Withdrawn element present (seponeret); `on-hold` = Paused element present; `completed` = behandlingsperiode afsluttet." +* intent -> "Ordination" "FMK ordinations are typically modelled as `intent = order`." +* medicationCodeableConcept.coding[ATC] -> "DrugMedication.Drug.ATC.Code / ATC.Text" "WHO ATC code." +* medicationCodeableConcept.coding[ActiveSubstance] -> "DrugMedication.Drug.Substances.ActiveSubstance" "Active-substance coding (source: Medicinpriser / Local / Magistrel)." +* medicationCodeableConcept.text -> "DrugMedication.Drug.Name (+ Form/Strength)" "Free-text rendering of the drug name, form and strength." +* subject -> "DrugMedication (context patient)" "FMK patient reference (the MedicineCard.Patient that owns the DrugMedication)." +* authoredOn -> "DrugMedication.Created / DrugMedication.BeginEndDate.CreatedDateTime" "When the ordination was authored." +* requester -> "DrugMedication.Created.By / DrugMedication.ReportedBy" "Ordinerende behandler (prescriber). `ReportedBy` is the E5 addition." +* reasonCode -> "DrugMedication.Indication" "Indikation / årsag (Code + Text, or FreeText)." +* dosageInstruction.text -> "DrugMedication.Dosage" "Human-rendered dosage." +* dosageInstruction.route -> "DrugMedication.RouteOfAdministration" "Administration route (Code + Text)." +* extension[effectiveDosePeriod] -> "DrugMedication.BeginEndDate.TreatmentStartDate / TreatmentEndDate" "R5 back-port: treatment period. FMK also supports `TreatmentStartedPreviously` and `TreatmentEndingUndetermined` as alternatives to concrete dates." +* extension[renderedDosageInstruction] -> "DrugMedication.Dosage" "R5 back-port: full human-rendered dosage string." Instance: JohnMedicationRequestSimvastatin InstanceOf: DkCoreMedicationRequest Title: "John's Simvastatin ordination" -Description: "Example of a DkCoreMedicationRequest derived from an FMK ordination for Simvastatin 40 mg." +Description: "Example of a DkCoreMedicationRequest derived from an FMK lægemiddelordination for Simvastatin 40 mg." Usage: #example -* identifier[FmkOrdinationId].system = $FmkOrdinationId -* identifier[FmkOrdinationId].value = "123456789" * identifier[FmkDrugMedicationId].system = $FmkDrugMedicationId -* identifier[FmkDrugMedicationId].value = "DM-987654321" +* identifier[FmkDrugMedicationId].value = "987654321" * status = #active * intent = #order * medicationCodeableConcept.coding[ATC] = $atc#C10AA01 "Simvastatin" @@ -114,8 +112,8 @@ InstanceOf: DkCoreMedicationRequest Title: "John's Simvastatin ordination (with Medication reference)" Description: "Example using Reference(DkCoreMedication) rather than inline CodeableConcept, demonstrating the EU-compatible path." Usage: #example -* identifier[FmkOrdinationId].system = $FmkOrdinationId -* identifier[FmkOrdinationId].value = "123456790" +* identifier[FmkDrugMedicationId].system = $FmkDrugMedicationId +* identifier[FmkDrugMedicationId].value = "987654322" * status = #active * intent = #order * medicationReference = Reference(Medication/SimvastatinActavis40mg) @@ -128,10 +126,10 @@ Usage: #example Instance: JohnMedicationRequestStopped InstanceOf: DkCoreMedicationRequest Title: "John's seponerede Metformin ordination" -Description: "Example of a DkCoreMedicationRequest that has been stopped (seponeret) in FMK (HasNegativeConsent = true)." +Description: "Example of a DkCoreMedicationRequest that has been stopped (seponeret) in FMK (the DrugMedication.Withdrawn element is set)." Usage: #example -* identifier[FmkOrdinationId].system = $FmkOrdinationId -* identifier[FmkOrdinationId].value = "987654321" +* identifier[FmkDrugMedicationId].system = $FmkDrugMedicationId +* identifier[FmkDrugMedicationId].value = "987654323" * status = #stopped * intent = #order * medicationCodeableConcept.coding[ATC] = $atc#A10BA02 "Metformin" diff --git a/input/fsh/DkCoreMedicationStatement.fsh b/input/fsh/DkCoreMedicationStatement.fsh index 29010ef43..7b0ee3802 100644 --- a/input/fsh/DkCoreMedicationStatement.fsh +++ b/input/fsh/DkCoreMedicationStatement.fsh @@ -8,24 +8,24 @@ Description: "HL7 Denmark core profile for a statement about medication being ta * ^extension[=].valueCanonical = $eu-medicationStatement * extension contains $ms-adherence named adherence 0..1 -* extension[adherence] ^short = "R5 back-port: whether the medication is being taken / refused / stopped. In FMK: HasNegativeConsent = true should be surfaced here with an appropriate adherence code in addition to (or instead of) status = stopped." +* extension[adherence] ^short = "R5 back-port: whether the medication is being taken / refused / stopped. In FMK, presence of DrugMedication.Withdrawn (seponering) or DrugMedication.Paused should be surfaced here with an appropriate adherence code in addition to (or instead of) status." * identifier ^slicing.discriminator.type = #value * ^slicing.discriminator.path = "system" * ^slicing.rules = #open * ^slicing.ordered = false - * ^slicing.description = "Slice identifier by system to distinguish FMK OrdinationIdentifier and DrugMedicationIdentifier" + * ^slicing.description = "Slice identifier by system to carry the FMK DrugMedicationIdentifier." * identifier contains - FmkOrdinationId 0..1 and - FmkDrugMedicationId 0..1 -* identifier[FmkOrdinationId] ^short = "[DA] FMK OrdinationIdentifier" + FmkDrugMedicationId 0..1 and + FmkDrugMedicationVersion 0..1 +* identifier[FmkDrugMedicationId] ^short = "[DA] FMK DrugMedicationIdentifier (positiv long)." * system 1.. - * system = $FmkOrdinationId (exactly) + * system = $FmkDrugMedicationId (exactly) * value 1.. -* identifier[FmkDrugMedicationId] ^short = "[DA] FMK DrugMedicationIdentifier" +* identifier[FmkDrugMedicationVersion] ^short = "[DA] FMK DrugMedication.Version - pairs with FmkDrugMedicationId to identify a specific revision of the lægemiddelordination on the medicinkort." * system 1.. - * system = $FmkDrugMedicationId (exactly) + * system = $FmkDrugMedicationVersion (exactly) * value 1.. -* status ^short = "Status of the medication card entry. active = aktiv på medicinkortet; stopped = seponeret (HasNegativeConsent = true i FMK); completed = afsluttet behandling." +* status ^short = "Status of the medication card entry. `active` = aktiv på medicinkortet; `on-hold` = Paused; `stopped` = seponeret (DrugMedication.Withdrawn er sat); `completed` = afsluttet behandling." * medication[x] only CodeableConcept or Reference(DkCoreMedication) * medicationCodeableConcept.coding ^slicing.discriminator.type = #value * ^slicing.discriminator.path = "system" @@ -36,12 +36,12 @@ Description: "HL7 Denmark core profile for a statement about medication being ta ATC 0..1 and ActiveSubstance 0..1 * medicationCodeableConcept.coding[ATC] - * ^short = "WHO ATC code. In FMK: DrugMedication.AtcCode / AtcText." + * ^short = "WHO ATC code. In FMK: DrugMedication.Drug.ATC (Code + Text)." * system 1.. * system = $atc (exactly) * code 1.. * medicationCodeableConcept.coding[ActiveSubstance] - * ^short = "[DA] Aktivt stof. In FMK: DrugMedication.ActiveSubstance or MedicationCardEntry.ActiveSubstance." + * ^short = "[DA] Aktivt stof. In FMK: DrugMedication.Drug.Substances.ActiveSubstance." * system 1.. * system = $FmkActiveSubstance (exactly) * code 1.. @@ -49,41 +49,41 @@ Description: "HL7 Denmark core profile for a statement about medication being ta * subject 1.. * informationSource only Reference(DkCorePractitioner or DkCorePractitionerRole or DkCoreOrganization or DkCorePatient or DkCoreRelatedPerson) * reasonReference only Reference(DkCoreCondition or DkCoreObservation) -* reasonCode ^short = "Indikation / årsag. In FMK: Treatment.Cause." +* reasonCode ^short = "Indikation / årsag. In FMK: DrugMedication.Indication (Code + Text, or FreeText)." * effective[x] only dateTime or Period -* effective[x] ^short = "When the medication is/was being taken. Prefer effectivePeriod when both start and end (or open-ended start) are known - maps to FMK Treatment.StartDate / Treatment.EndDate. Use effectiveDateTime only for point-in-time statements." +* effective[x] ^short = "When the medication is/was being taken. Prefer effectivePeriod when both start and end (or open-ended start) are known - maps to FMK DrugMedication.BeginEndDate.TreatmentStartDate / TreatmentEndDate. Use effectiveDateTime only for point-in-time statements." * dateAsserted ^short = "Tidspunkt hvor udsagnet om medicineringen blev indført. Typisk hentningstidspunktet for medicinkortet." -* dosage ^short = "Dosering. In FMK: Dosage.Text; Treatment.Administration (route) kan lægges i dosage.route eller dosage.patientInstruction." +* dosage ^short = "Dosering. In FMK: DrugMedication.Dosage; DrugMedication.RouteOfAdministration (Code + Text) maps to dosage.route." Mapping: DkCoreMedicationStatementToFmk Source: DkCoreMedicationStatement -Target: "https://wiki.fmk-teknik.dk/start" +Target: "https://wiki.fmk-teknik.dk/fmk:extensions:e5" Title: "Fælles Medicinkort (FMK)" Id: dk-core-medicationstatement-fmk -* -> "MedicationCard entry" "**Snapshot of a drug on the FMK medication card (aktuelt medicinbillede).**" -* identifier[FmkOrdinationId] -> "DrugMedication.OrdinationIdentifier" "Identifier of an FMK ordination." -* identifier[FmkDrugMedicationId] -> "DrugMedication.DrugMedicationIdentifier" "Identifier of a specific version of the drug medication." -* status -> "MedicationCardStatus.EnumStr / HasNegativeConsent" "`active` / `completed` / `stopped` / `entered-in-error` / `unknown`. `HasNegativeConsent = true` maps to `stopped` and SHOULD be supplemented via the adherence extension." -* medicationCodeableConcept.coding[ATC] -> "DrugMedication.AtcCode / AtcText" "WHO ATC code for the drug." -* medicationCodeableConcept.coding[ActiveSubstance] -> "DrugMedication.ActiveSubstance" "Active-substance coding." -* medicationCodeableConcept.text -> "DrugMedication (name/form/strength)" "Free-text rendering of the drug name, form and strength." -* subject -> "Patient" "FMK patient reference." -* effective[x] -> "Treatment.StartDate / Treatment.EndDate" "Prefer `effectivePeriod` when start and/or end are known; use `effectiveDateTime` for point-in-time statements." -* dateAsserted -> "Snapshot timestamp" "Timestamp of the FMK medication-card retrieval (NOT the ordination date)." -* reasonCode -> "Treatment.Cause" "Indikation / årsag." -* dosage.text -> "Dosage.Text" "Human-rendered dosage." -* dosage.route -> "Treatment.Administration" "Administration route (may be free text)." -* extension[adherence] -> "HasNegativeConsent" "R5 adherence code (e.g. `stopped`, `not-taking`, `on-hold`) for richer semantics than `status = stopped` alone." +* -> "MedicineCard.DrugMedication" "**Snapshot of a lægemiddelordination on the FMK medicinkort (aktuelt medicinbillede).**" +* identifier[FmkDrugMedicationId] -> "DrugMedication.Identifier" "DrugMedicationIdentifier - unique id of the lægemiddelordination." +* identifier[FmkDrugMedicationVersion] -> "DrugMedication.Version" "Revision number, carried alongside the identifier when a specific version of the ordination is being referenced." +* status -> "DrugMedication.Withdrawn / DrugMedication.Paused" "`active` = neither Withdrawn nor Paused; `on-hold` = Paused element present; `stopped` = Withdrawn element present (seponeret) - SHOULD be supplemented via the adherence extension; `completed` = behandlingsperiode afsluttet; `entered-in-error` / `unknown` as per FHIR." +* medicationCodeableConcept.coding[ATC] -> "DrugMedication.Drug.ATC.Code / ATC.Text" "WHO ATC code for the drug." +* medicationCodeableConcept.coding[ActiveSubstance] -> "DrugMedication.Drug.Substances.ActiveSubstance" "Active-substance coding (source: Medicinpriser / Local / Magistrel)." +* medicationCodeableConcept.text -> "DrugMedication.Drug.Name (+ Form/Strength)" "Free-text rendering of the drug name, form and strength." +* subject -> "MedicineCard.Patient" "FMK patient reference." +* effective[x] -> "DrugMedication.BeginEndDate.TreatmentStartDate / TreatmentEndDate" "Prefer `effectivePeriod` when start and/or end are known; use `effectiveDateTime` for point-in-time statements. FMK also supports `TreatmentStartedPreviously` and `TreatmentEndingUndetermined`." +* dateAsserted -> "MedicineCard retrieval timestamp" "Timestamp of the FMK medicinkort retrieval (NOT the ordination date). In FMK, see GetMedicineCardResponse." +* reasonCode -> "DrugMedication.Indication" "Indikation / årsag (Code + Text, or FreeText)." +* dosage.text -> "DrugMedication.Dosage" "Human-rendered dosage." +* dosage.route -> "DrugMedication.RouteOfAdministration" "Administration route (Code + Text)." +* extension[adherence] -> "DrugMedication.Withdrawn / Paused" "R5 adherence code (e.g. `stopped`, `not-taking`, `on-hold`) for richer semantics than `status` alone." Instance: JohnMedicationStatementSimvastatin InstanceOf: DkCoreMedicationStatement Title: "John's aktive Simvastatin på medicinkortet" -Description: "Example DkCoreMedicationStatement derived from the current FMK medication card for Simvastatin." +Description: "Example DkCoreMedicationStatement derived from the current FMK medicinkort for Simvastatin." Usage: #example -* identifier[FmkOrdinationId].system = $FmkOrdinationId -* identifier[FmkOrdinationId].value = "123456789" +* identifier[FmkDrugMedicationId].system = $FmkDrugMedicationId +* identifier[FmkDrugMedicationId].value = "987654321" * status = #active * medicationCodeableConcept.coding[ATC] = $atc#C10AA01 "Simvastatin" * medicationCodeableConcept.coding[ActiveSubstance].system = $FmkActiveSubstance @@ -101,10 +101,10 @@ Usage: #example Instance: JohnMedicationStatementStopped InstanceOf: DkCoreMedicationStatement Title: "John's seponerede Metformin" -Description: "Example DkCoreMedicationStatement for a medication that has been stopped (seponeret). Note: uses the adherence extension in addition to status = stopped to carry the richer R5 semantics." +Description: "Example DkCoreMedicationStatement for a medication that has been stopped (seponeret i FMK, dvs. DrugMedication.Withdrawn er sat). Note: uses the adherence extension in addition to status = stopped to carry the richer R5 semantics." Usage: #example -* identifier[FmkOrdinationId].system = $FmkOrdinationId -* identifier[FmkOrdinationId].value = "987654321" +* identifier[FmkDrugMedicationId].system = $FmkDrugMedicationId +* identifier[FmkDrugMedicationId].value = "987654323" * status = #stopped * extension[adherence].extension[code].valueCodeableConcept.coding.system = "http://hl7.org/fhir/CodeSystem/medication-statement-adherence" * extension[adherence].extension[code].valueCodeableConcept.coding.code = #stopped diff --git a/input/fsh/aliases.fsh b/input/fsh/aliases.fsh index 91110dc19..caba27ca0 100644 --- a/input/fsh/aliases.fsh +++ b/input/fsh/aliases.fsh @@ -32,9 +32,14 @@ Alias: $v3-RoleCode = http://terminology.hl7.org/CodeSystem/v3-RoleCode Alias: $v3-ActPriority = http://terminology.hl7.org/CodeSystem/v3-ActPriority Alias: $v3-ActCode3.0.0 = http://terminology.hl7.org/ValueSet/v3-ActCode|3.0.0 Alias: $atc = http://www.whocc.no/atc -Alias: $FmkOrdinationId = https://www.sundhed.dk/medicinkort/ordination -Alias: $FmkDrugMedicationId = https://www.sundhed.dk/medicinkort/drug-medication -Alias: $FmkActiveSubstance = https://www.sundhed.dk/medicinkort/active-substance +// FMK schema namespace (see https://wiki.fmk-teknik.dk/fmk:extensions:e5). FMK's canonical +// identifier for an ordination is the DrugMedicationIdentifier (a long, paired with Version +// when a specific revision is meant); there is no separate "ordination" identifier. +Alias: $FmkDrugMedicationId = http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationIdentifier +Alias: $FmkDrugMedicationVersion = http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationVersion +// Varenummer from Medicinpriser (LMS01 field 1); 11-digit product identifier. +Alias: $FmkDrugId = http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugIdentifier +Alias: $FmkActiveSubstance = http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/ActiveSubstance Alias: $mr-effectiveDosePeriod = http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationRequest.effectiveDosePeriod Alias: $mr-renderedDosageInstruction = http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationRequest.renderedDosageInstruction Alias: $ms-adherence = http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationStatement.adherence @@ -43,7 +48,12 @@ Alias: $imposeProfile = http://hl7.org/fhir/StructureDefinition/structuredefinit Alias: $eu-medicationRequest = http://hl7.eu/fhir/base/StructureDefinition/medicationRequest-eu-core Alias: $eu-medicationStatement = http://hl7.eu/fhir/base/StructureDefinition/medicationStatement-eu-core Alias: $eu-medication = http://hl7.eu/fhir/base/StructureDefinition/medication-eu-core -Alias: $DdvVaccinationId = https://www.sundhed.dk/vaccination/id +// DDV (Det Danske Vaccinationsregister) XML schema namespace, base interface 1.4.0 + E1. +// Source of truth: https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1 +Alias: $DdvVaccinationId = http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationIdentifier +Alias: $DdvVaccinationVersion = http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationVersionIdentifier +Alias: $DdvVaccineId = http://vaccinationsregister.dk/schemas/2013/12/01/VaccineIdentifier +Alias: $DdvCredibility = http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationCredibility Alias: $DdvPatientId = https://www.sundhed.dk/patient Alias: $DanishXdsOid = urn:oid:1.2.208.184.100.9 Alias: $MedComFormatOID = urn:oid:1.2.208.184.100.10 diff --git a/input/ignoreWarnings.txt b/input/ignoreWarnings.txt index d942bf5bf..29bf4158e 100644 --- a/input/ignoreWarnings.txt +++ b/input/ignoreWarnings.txt @@ -29,6 +29,20 @@ %A definition for CodeSystem 'urn:oid:1.2.208.176.2.4' could not be found, so the code cannot be validated %A definition for CodeSystem 'http://medcomfhir.dk/ig/terminology/CodeSystem/medcom-observation-codes' could not be found, so the code cannot be validated +# FMK (Fælles Medicinkort) schema-namespace URIs used as identifier systems and coded CodeSystems. +# Source of truth: https://wiki.fmk-teknik.dk/fmk:extensions:e5 (DKMA XML schemas). +# Not registered as FHIR NamingSystems/CodeSystems; suppress the unknown-URL noise. +%A definition for CodeSystem 'http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/ActiveSubstance' could not be found, so the code cannot be validated +%A definition for CodeSystem 'http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugIdentifier' could not be found, so the code cannot be validated +%No definition could be found for URL value 'http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationIdentifier' +%No definition could be found for URL value 'http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationVersion' + +# DDV (Det Danske Vaccinationsregister) schema-namespace URIs used as identifier systems and coding systems. +# Source of truth: https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1 (namespace http://vaccinationsregister.dk/schemas/2013/12/01). +%No definition could be found for URL value 'http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationIdentifier' +%No definition could be found for URL value 'http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationVersionIdentifier' +%A definition for CodeSystem 'http://vaccinationsregister.dk/schemas/2013/12/01/VaccineIdentifier' could not be found, so the code cannot be validated + # Missing Danish translations for LOINC codes %There are no valid display names found for the code http://loinc.org% diff --git a/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md b/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md index 37200025f..111972daa 100644 --- a/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md +++ b/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md @@ -1,34 +1,50 @@ ### Scope and usage -The Danish Core Immunization profile is intended to represent an administered or refused vaccination, as sourced from Det Danske Vaccinationsregister (DDV) via the sundhed.dk vaccination API. Source documentation for the DDV service: [nspop.dk - DDV](https://www.nspop.dk/pages/releaseview.action?pageId=31798109). +The Danish Core Immunization profile is intended to represent an administered or refused vaccination, as sourced from Det Danske Vaccinationsregister (DDV). Authoritative DDV XML schemas are published at [wiki.fmk-teknik.dk/fmk:ddv:extensions:e1](https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1) with target namespace `http://vaccinationsregister.dk/schemas/2013/12/01` (interface 1.4.0 + extension E1). Service delivery is described at [nspop.dk](https://www.nspop.dk/pages/releaseview.action?pageId=31798109). -A DDV vaccination record carries a numeric `VaccinationIdentifier`, a free-text `Vaccine` name, an effectuator, an effectuation date/time, and a set of flags (`ActiveStatus`, `NegativeConsent`, `SelfCreated`, `IsEditable`) plus an optional `CoverageDuration`. In dk-core the `patient` element has been constrained to [DkCorePatient](StructureDefinition-dk-core-patient.html) and `performer.actor` to the Danish core profiles for Practitioner, PractitionerRole or Organization. When the DDV effectuator is available only as free text (e.g. "Danske Lægers Vaccinations Service"), it should be carried as `performer.actor.display`. +A DDV `Vaccination` carries a numeric `VaccinationIdentifier` (paired with `VaccinationVersionIdentifier` for revision tracking), a structured `Vaccine` element (`VaccineIdentifier` + `VaccineName` + `Disease[]` + `ATC` + optional `SSIDrug[]` and keyword metadata), an optional `Effectuated` structure (date, effectuator name, authorisation and organisation), `CoverageDuration`, `BatchNumber`, `ActiveStatus`, `NegativeConsentIndicator`, `VaccinationCredibility` (a credibility enum), and flags such as `IsPrevious` and `ConfirmedByPrescriptionServer`. + +In dk-core the `patient` element has been constrained to [DkCorePatient](StructureDefinition-dk-core-patient.html) and `performer.actor` to the Danish core profiles for Practitioner, PractitionerRole or Organization. When the DDV effectuator is available only as free text (e.g. "Danske Lægers Vaccinations Service"), it should be carried as `performer.actor.display`. #### Mapping from DDV | DDV field | FHIR target | | --- | --- | -| `VaccinationIdentifier` | `identifier[DdvVaccinationId]` (`https://www.sundhed.dk/vaccination/id`) | -| `Vaccine` | `vaccineCode.text` (ATC or SNOMED CT coding MAY also be supplied via `vaccineCode.coding[ATC]` / `vaccineCode.coding[SCTVaccineCode]`) | -| `EffectuatedDateTime` | `occurrenceDateTime` and, when no distinct registration timestamp is available, `recorded` | -| `EffectuatedBy` | `performer.actor` (or `performer.actor.display` when only a free-text name is known) | -| `ActiveStatus = true` | `status = #completed` | -| `ActiveStatus = false` | `status = #not-done` | -| `NegativeConsent = true` | `status = #not-done` (takes precedence over `ActiveStatus`) | -| `CoverageDuration` | `note` (free text, e.g. "Coverage duration: 1 year") | -| `SelfCreated = true` | `note` (free text, e.g. "Recorded as self-created") | -| `NegativeConsent = true` | `note` (free text, e.g. "Negative consent recorded") | -| DDV vaccination history entries | `note` (free text, listing prior entry dates/ids) | +| `Vaccination.VaccinationIdentifier` | `identifier[DdvVaccinationId]` (`http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationIdentifier`) | +| `Vaccination.VaccinationVersionIdentifier` | `identifier[DdvVaccinationVersion]` (`http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationVersionIdentifier`) — populate when pointing to a specific revision | +| `Vaccination.Vaccine.VaccineIdentifier` | `vaccineCode.coding[DdvVaccine]` (`http://vaccinationsregister.dk/schemas/2013/12/01/VaccineIdentifier`) | +| `Vaccination.Vaccine.VaccineName` | `vaccineCode.text` | +| `Vaccination.Vaccine.ATC.Code` / `ATC.Text` | `vaccineCode.coding[ATC]` (`http://www.whocc.no/atc`) — typically J07* | +| `Vaccination.Vaccine.Disease[]` | `protocolApplied.targetDisease` (with `DiseaseIdentifier` / `DiseaseName` / `DiseaseNameDK` / `ATC` as children) | +| `Vaccination.EffectuatedDateTime` / `Vaccination.Effectuated.EffectuatedDateTime` | `occurrenceDateTime` | +| `Vaccination.Created.CreatedDateTime` | `recorded` (fall back to `EffectuatedDateTime` when the record has no distinct `Created` element) | +| `Vaccination.Effectuated.EffectuatedByName` (≤200 char free text) | `performer.actor.display` | +| `Vaccination.Effectuated.AuthorisationIdentifier` | `performer.actor` → `Reference(DkCorePractitioner)` when resolvable | +| `Vaccination.Effectuated.EffectuatedByOrganisationName` / `Number` / `Type` | `performer.actor` → `Reference(DkCoreOrganization)` when resolvable; free-text fallback via `actor.display` | +| `Vaccination.BatchNumber` | `lotNumber` | +| `Vaccination.CoverageDuration` | `note` (free text, e.g. "CoverageDuration: 1 year") | +| `Vaccination.VaccinationCredibility` | `note` (e.g. "VaccinationCredibility: Oprettet af borger"). See status section. | +| `Vaccination.ActiveStatus = true` | `status = #completed` | +| `Vaccination.ActiveStatus = false` | `status = #not-done` | +| `Vaccination.NegativeConsentIndicator = true` | `status = #not-done` (takes precedence over `ActiveStatus`) | +| `Vaccination.IsPrevious = true` | `note` (history entry marker) | +| `Vaccination.ConfirmedByPrescriptionServer` | `note` (pharmacy-confirmed marker) | #### Status semantics DDV does not expose the full set of FHIR `Immunization.status` values. The mapping collapses DDV's boolean flags as follows: -- `NegativeConsent = true` → `status = #not-done` (regardless of `ActiveStatus`). +- `NegativeConsentIndicator = true` → `status = #not-done` (regardless of `ActiveStatus`). - `ActiveStatus = true` → `status = #completed`. - `ActiveStatus = false` → `status = #not-done`. - Unknown / missing → omit `status` (the resource will fail the base cardinality check; ensure one of the flags is known before producing the resource). +`entered-in-error` may be used for DDV records whose `VaccinationCredibility` is `Slettet` ("deleted"). + #### Vaccine coding -DDV typically returns the vaccine product name as free text in the `Vaccine` field. Implementations MAY supplement this with an ATC coding from the J07 group, or with a SNOMED CT coding where known. The free-text form is preserved in `vaccineCode.text` so no information is lost. +DDV delivers the vaccine as a structured `Vaccine` element with a free-text `VaccineName`, an SSI `VaccineIdentifier`, an ATC code (typically J07*), a list of target diseases (each with its own ATC coding), and optional SSI-defined drugs (`SSIDrug`). The profile accommodates this via three coding slices on `vaccineCode` (`ATC`, `SCTVaccineCode`, `DdvVaccine`) with the free-text name in `vaccineCode.text`. A SNOMED CT coding MAY be added where known. + +#### Identifier namespace note + +Earlier drafts of this profile used `https://www.sundhed.dk/vaccination/...` URLs deduced from the sundhed.dk JSON proxy. Those URLs are not registered anywhere and have been replaced with URIs rooted at the authoritative DDV XML schema namespace (`http://vaccinationsregister.dk/schemas/2013/12/01`). Consumers proxying DDV via sundhed.dk should normalise their identifier systems to these authoritative URIs when producing dk-core resources. diff --git a/input/pagecontent/StructureDefinition-dk-core-medication-intro.md b/input/pagecontent/StructureDefinition-dk-core-medication-intro.md index d2506f09c..92d424dd9 100644 --- a/input/pagecontent/StructureDefinition-dk-core-medication-intro.md +++ b/input/pagecontent/StructureDefinition-dk-core-medication-intro.md @@ -1,18 +1,23 @@ ### Scope and usage -The Danish Core Medication profile describes a medicinal product, in particular as it appears in the Danish Shared Medication Record (Fælles Medicinkort, FMK). It is used when a MedicationRequest or MedicationStatement needs to reference a reusable, structured drug representation — for example, an FMK `DrugMedication` with form, strength and active substance information. +The Danish Core Medication profile describes a medicinal product, in particular as it appears in the Danish Shared Medication Record (Fælles Medicinkort, FMK). It is used when a MedicationRequest or MedicationStatement needs to reference a reusable, structured drug representation — for example, an FMK `DrugMedication.Drug` with form, strength and active-substance information. Most Danish systems today will be able to inline the drug as a `CodeableConcept` on [DkCoreMedicationRequest](StructureDefinition-dk-core-medicationrequest.html) / [DkCoreMedicationStatement](StructureDefinition-dk-core-medicationstatement.html). This profile is offered for the cases where structured data about the product itself (ingredients, strength, form, manufacturer) is valuable, or where the same product is referenced from multiple requests/statements. #### Mapping from FMK +In FMK, a `DrugMedication` (lægemiddelordination) contains exactly one `Drug` element, and the drug's attributes (ATC, form, strength, substances, varenummer) are children of `Drug`: + | FMK field | FHIR target | | --- | --- | -| `DrugMedication.AtcCode` / `AtcText` | `code.coding[ATC]` (`http://www.whocc.no/atc`) | -| `DrugMedication.ActiveSubstance` | `code.coding[ActiveSubstance]` + `ingredient.itemCodeableConcept` | -| `DrugMedication` (name with form and strength) | `code.text` | -| `DrugMedication.Form` | `form` (free text allowed) | -| `DrugMedication.Strength` | `ingredient.strength` | +| `DrugMedication.Drug.ATC.Code` / `ATC.Text` | `code.coding[ATC]` (`http://www.whocc.no/atc`) | +| `DrugMedication.Drug.Substances.ActiveSubstance` | `code.coding[ActiveSubstance]` + `ingredient.itemCodeableConcept` | +| `DrugMedication.Drug.Identifier` (varenummer, LMS01 field 1, 11-digit) | `code.coding[Varenummer]` | +| `DrugMedication.Drug.Name` (with Form and Strength) | `code.text` | +| `DrugMedication.Drug.Form` (Code + Text) | `form` | +| `DrugMedication.Drug.Strength` (Value + UnitCode + UnitText, or Text) | `ingredient.strength` | + +The authoritative FMK schemas are published at [wiki.fmk-teknik.dk](https://wiki.fmk-teknik.dk/fmk:extensions:e5) (XML namespace `http://www.dkma.dk/medicinecard/xml.schema/2015/06/01`). #### Relationship to HL7 Europe Base This profile is deliberately compatible with [Medication (EU core)](https://build.fhir.org/ig/hl7-eu/base/StructureDefinition-medication-eu-core.html) — it uses the same general shape (ATC as a sliced coding, ingredient-based strength) so that Danish content can be promoted to EU-wide exchanges without restructuring. diff --git a/input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md b/input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md index c0142343e..9e0084708 100644 --- a/input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md +++ b/input/pagecontent/StructureDefinition-dk-core-medicationrequest-intro.md @@ -1,46 +1,54 @@ ### Scope and usage -The Danish Core MedicationRequest profile is intended to represent a single medication order (ordination), in particular as sourced from the Danish Shared Medication Record (Fælles Medicinkort, FMK). Source documentation for FMK: [wiki.fmk-teknik.dk](https://wiki.fmk-teknik.dk/start). +The Danish Core MedicationRequest profile is intended to represent a single medication order (lægemiddelordination), in particular as sourced from the Danish Shared Medication Record (Fælles Medicinkort, FMK). Source documentation for FMK: [wiki.fmk-teknik.dk](https://wiki.fmk-teknik.dk/fmk:extensions:e5) (XML schemas in namespace `http://www.dkma.dk/medicinecard/xml.schema/2015/06/01`). In dk-core, the MedicationRequest has been constrained so that `subject` refers to a [DkCorePatient](StructureDefinition-dk-core-patient.html), and `requester` / `recorder` / `performer` refer to the Danish core profiles for Practitioner, PractitionerRole, Organization, Patient or RelatedPerson. The profile claims conformance to [MedicationRequest (EU core)](https://build.fhir.org/ig/hl7-eu/base/StructureDefinition-medicationRequest-eu-core.html) via an `imposeProfile` extension — any instance valid against DkCoreMedicationRequest must also be valid against the EU Core profile. #### Mapping from FMK -An FMK ordination carries two identifiers that are both useful for tracing a MedicationRequest back to its source: -* **OrdinationIdentifier** — stable identifier for the ordination itself, across versions. Mapped to `identifier` slice `FmkOrdinationId` with system `https://www.sundhed.dk/medicinkort/ordination`. -* **DrugMedicationIdentifier** — identifier for a specific version of the lægemiddelordination. Mapped to `identifier` slice `FmkDrugMedicationId` with system `https://www.sundhed.dk/medicinkort/drug-medication`. +An FMK `DrugMedication` (lægemiddelordination) on the medicinkort is uniquely identified by a `DrugMedicationIdentifier` (a positive long). A specific revision is identified by the pair `(Identifier, Version)`; there is no separate "ordination" identifier on top of that. + +* **DrugMedicationIdentifier** — mapped to `identifier` slice `FmkDrugMedicationId` with system `http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationIdentifier`. +* **DrugMedication.Version** — mapped to `identifier` slice `FmkDrugMedicationVersion` with system `http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationVersion`. Populate alongside the DrugMedicationIdentifier when pointing to a specific revision. The medicinal product can be represented in two ways: * As an inline `medicationCodeableConcept` (preferred for simple, self-contained FMK mappings), sliced on `coding.system` for: - * **ATC** (`http://www.whocc.no/atc`) from `DrugMedication.AtcCode` / `AtcText`. - * **Active substance** (`https://www.sundhed.dk/medicinkort/active-substance`) from `DrugMedication.ActiveSubstance`. + * **ATC** (`http://www.whocc.no/atc`) from `DrugMedication.Drug.ATC.Code` / `ATC.Text`. + * **Active substance** (`http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/ActiveSubstance`) from `DrugMedication.Drug.Substances.ActiveSubstance`. The FMK `source` attribute may be `Medicinpriser`, `Local` or `Magistrel`. * A free-text product name in `medicationCodeableConcept.text`. * As a `medicationReference` to a [DkCoreMedication](StructureDefinition-dk-core-medication.html) — useful when form, strength, ingredients or manufacturer need structured representation. -FMK treatment and dosage fields map as follows: +FMK indication, treatment-period and dosage fields map as follows: | FMK field | FHIR target | | --- | --- | -| `Treatment.Cause` | `reasonCode.text` (or `reasonReference` when a coded condition is known) | -| `Treatment.StartDate` | `authoredOn` and `extension[effectiveDosePeriod].valuePeriod.start` | -| `Treatment.EndDate` | `extension[effectiveDosePeriod].valuePeriod.end` | -| `Treatment.Administration` | `dosageInstruction.route` (free-text allowed) | -| `Dosage.Text` | `dosageInstruction.text` and/or `extension[renderedDosageInstruction].valueMarkdown` | -| `HasNegativeConsent = true` | `status = #stopped` | -| `CreatedBy` | `requester` (display / reference) | -| `IsDoseDispensing = true` with a total quantity | `dispenseRequest.quantity` (and, when IHE Pharmacy MPD becomes an R4 dependency, the `prescribedQuantity` extension) | - -Systems that proxy FMK should populate both identifier slices when possible so the resource can be cross-referenced back to the underlying ordination and lægemiddelordination. +| `DrugMedication.Indication` (Code + Text, or FreeText) | `reasonCode` (coded or free text), or `reasonReference` when a coded condition is known | +| `DrugMedication.BeginEndDate.TreatmentStartDate` | `authoredOn` and `extension[effectiveDosePeriod].valuePeriod.start` | +| `DrugMedication.BeginEndDate.TreatmentEndDate` | `extension[effectiveDosePeriod].valuePeriod.end` | +| `DrugMedication.BeginEndDate.TreatmentStartedPreviously` / `TreatmentEndingUndetermined` | Represented by the absence of an explicit start/end in `effectiveDosePeriod.valuePeriod` | +| `DrugMedication.RouteOfAdministration` (Code + Text) | `dosageInstruction.route` | +| `DrugMedication.Dosage` | `dosageInstruction.text` and/or `extension[renderedDosageInstruction].valueMarkdown` | +| `DrugMedication.Withdrawn` element present (seponeret) | `status = #stopped` | +| `DrugMedication.Paused` element present | `status = #on-hold` | +| `DrugMedication.Created.By` / `DrugMedication.ReportedBy` (E5) | `requester` (display / reference) | +| `DrugMedication.Dosage` with a total quantity for dose dispensing | `dispenseRequest.quantity` (and, when IHE Pharmacy MPD becomes an R4 dependency, the `prescribedQuantity` extension) | #### Extensions in use The profile brings forward three extensions from the HL7 Europe Base profile, all of which are already forward-compatible with FHIR R5: -* **`effectiveDosePeriod`** (R5 back-port) — records the period over which the medication is to be taken. Natural home for FMK's `Treatment.StartDate` / `Treatment.EndDate`. -* **`renderedDosageInstruction`** (R5 back-port) — carries the full human-rendered dosage instruction in Markdown. Natural home for FMK's `Dosage.Text`. +* **`effectiveDosePeriod`** (R5 back-port) — records the period over which the medication is to be taken. Natural home for FMK's `DrugMedication.BeginEndDate.TreatmentStartDate` / `TreatmentEndDate`. +* **`renderedDosageInstruction`** (R5 back-port) — carries the full human-rendered dosage instruction in Markdown. Natural home for FMK's `DrugMedication.Dosage`. * **IHE Pharmacy `prescribedQuantity`** — not currently wired in as a slice because the IHE MPD package is R5-based and not yet an R4 dependency of this IG. Implementers may add it as an ad-hoc extension on `dispenseRequest` when needed for FMK dose-dispensing flows. #### Status and intent -FMK ordinations are typically modelled with `intent = order`. Active ordinations use `status = active`; ordinations that have been stopped (seponeret) in FMK (`HasNegativeConsent = true`) use `status = stopped`. Historical/completed treatments use `status = completed`. +FMK ordinations are typically modelled with `intent = order`. Active ordinations use `status = active`; ordinations with a `DrugMedication.Paused` element use `status = on-hold`; ordinations that have been stopped (`DrugMedication.Withdrawn` element set) use `status = stopped`. Historical/completed treatments use `status = completed`. + +#### E5-specific considerations +FMK extension E5 introduces a handful of capabilities worth noting for implementers: + +* **`DrugMedication.ReportedBy`** — identifies who reported the medication (distinct from who authored it). Use this where the prescriber differs from the original source, for example when a pharmacy or another clinician reports a medication seen outside of FMK. In FHIR the prescriber maps to `requester`; `ReportedBy` can be surfaced in `requester.display` or via the `reported[x]` field of MedicationRequest. +* **Prescriptions without a CPR** (`CreatePrescriptionWithoutCPR_2015_06_01_E2`) and **for use in practice** (`CreatePrescriptionForUseInPractice_2015_06_01_E2`) — these E5 operations create ordinations that are not tied to a specific person. For the first, `subject` may reference a placeholder Patient resource with an `X-eCPR` / `MedicineCardKey` PersonIdentifier source; for the second, `subject` references an organisational Patient representing the practice itself. In both cases consumers should be prepared for `subject.reference` to not resolve to a standard CPR-based patient. +* **Explicit dose dispensing** (`GetExplicitDoseDispensingCard_2015_06_01_E3`) — the separate DoseDispensingCard view carries per-period dispensed doses. When representing a single MedicationRequest sourced from an ordination attached to a DoseDispensingPeriod, `dispenseRequest.quantity` is appropriate for the period's total dispensed quantity; full period-by-period history is outside the scope of this profile. diff --git a/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md b/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md index fcb8176d7..e21406c8f 100644 --- a/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md +++ b/input/pagecontent/StructureDefinition-dk-core-medicationstatement-intro.md @@ -1,8 +1,8 @@ ### Scope and usage -The Danish Core MedicationStatement profile is intended to represent a statement about a medication that a patient is taking (or has taken), as sourced from the Danish Shared Medication Record (Fælles Medicinkort, FMK). Source documentation for FMK: [wiki.fmk-teknik.dk](https://wiki.fmk-teknik.dk/start). +The Danish Core MedicationStatement profile is intended to represent a statement about a medication that a patient is taking (or has taken), as sourced from the Danish Shared Medication Record (Fælles Medicinkort, FMK). Source documentation for FMK: [wiki.fmk-teknik.dk](https://wiki.fmk-teknik.dk/fmk:extensions:e5) (XML schemas in namespace `http://www.dkma.dk/medicinecard/xml.schema/2015/06/01`). -A MedicationStatement is the natural FHIR representation of the FMK "medicinkort"/"aktuelt medicinbillede" — the authoritative list of medicines the patient is currently taking. Where a [DkCoreMedicationRequest](StructureDefinition-dk-core-medicationrequest.html) is the order that a prescriber issues, a DkCoreMedicationStatement is the snapshot of what is actually on the patient's medication card at a point in time. +A MedicationStatement is the natural FHIR representation of the FMK "medicinkort"/"aktuelt medicinbillede" — the authoritative list of medicines the patient is currently taking, materialised from the `DrugMedication` entries on the `MedicineCard`. Where a [DkCoreMedicationRequest](StructureDefinition-dk-core-medicationrequest.html) is the order that a prescriber issues, a DkCoreMedicationStatement is the snapshot of what is actually on the patient's medicinkort at a point in time. In dk-core, the MedicationStatement has been constrained so that `subject` refers to a [DkCorePatient](StructureDefinition-dk-core-patient.html) and `informationSource` refers to the Danish core profiles for Practitioner, PractitionerRole, Organization, Patient or RelatedPerson. @@ -12,26 +12,26 @@ The profile claims conformance to [MedicationStatement (EU core)](https://build. | FMK field | FHIR target | | --- | --- | -| `DrugMedication.OrdinationIdentifier` | `identifier[FmkOrdinationId]` (`https://www.sundhed.dk/medicinkort/ordination`) | -| `DrugMedication.DrugMedicationIdentifier` | `identifier[FmkDrugMedicationId]` (`https://www.sundhed.dk/medicinkort/drug-medication`) | -| `DrugMedication.AtcCode` / `AtcText` | `medicationCodeableConcept.coding[ATC]` (`http://www.whocc.no/atc`) or via `medicationReference` to a [DkCoreMedication](StructureDefinition-dk-core-medication.html) | -| `DrugMedication.ActiveSubstance` | `medicationCodeableConcept.coding[ActiveSubstance]` | -| `DrugMedication` (name/form/strength) | `medicationCodeableConcept.text` or the referenced DkCoreMedication | -| `Treatment.Cause` | `reasonCode.text` | -| `Treatment.StartDate` / `Treatment.EndDate` | `effectivePeriod.start` / `effectivePeriod.end` | -| `Dosage.Text` | `dosage.text` | -| `Treatment.Administration` | `dosage.route` (free-text allowed) | -| Snapshot timestamp (the time the card was retrieved) | `dateAsserted` | -| `HasNegativeConsent = true` | `status = #stopped` plus `extension[adherence]` with an appropriate `stopped` / `not-taking` code | -| `MedicationCardStatus.EnumStr` | `status` (active / completed / stopped / entered-in-error / unknown) | - -Consumers of this profile should be aware that a MedicationStatement derived from an FMK medication card is, by design, a *view* on the current state of one or more ordinations rather than an authoritative clinical assertion. When populating `dateAsserted`, use the timestamp of the FMK retrieval, not the ordination date. +| `DrugMedication.Identifier` | `identifier[FmkDrugMedicationId]` (`http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationIdentifier`) | +| `DrugMedication.Version` | `identifier[FmkDrugMedicationVersion]` (`http://www.dkma.dk/medicinecard/xml.schema/2015/06/01/DrugMedicationVersion`) — populate alongside the Identifier when pointing to a specific revision | +| `DrugMedication.Drug.ATC.Code` / `ATC.Text` | `medicationCodeableConcept.coding[ATC]` (`http://www.whocc.no/atc`) or via `medicationReference` to a [DkCoreMedication](StructureDefinition-dk-core-medication.html) | +| `DrugMedication.Drug.Substances.ActiveSubstance` | `medicationCodeableConcept.coding[ActiveSubstance]` (source: `Medicinpriser` / `Local` / `Magistrel`) | +| `DrugMedication.Drug.Name` (with Form/Strength) | `medicationCodeableConcept.text` or the referenced DkCoreMedication | +| `DrugMedication.Indication` (Code + Text, or FreeText) | `reasonCode` | +| `DrugMedication.BeginEndDate.TreatmentStartDate` / `TreatmentEndDate` | `effectivePeriod.start` / `effectivePeriod.end` | +| `DrugMedication.Dosage` | `dosage.text` | +| `DrugMedication.RouteOfAdministration` (Code + Text) | `dosage.route` | +| MedicineCard retrieval timestamp | `dateAsserted` | +| `DrugMedication.Withdrawn` element present (seponeret) | `status = #stopped` plus `extension[adherence]` with an appropriate `stopped` / `not-taking` code | +| `DrugMedication.Paused` element present | `status = #on-hold` plus `extension[adherence]` with `on-hold` | + +Consumers of this profile should be aware that a MedicationStatement derived from the FMK medicinkort is, by design, a *view* on the current state of one or more `DrugMedication` entries rather than an authoritative clinical assertion. When populating `dateAsserted`, use the timestamp of the FMK retrieval, not the ordination date. #### Extensions in use -The profile brings forward the R5 `adherence` extension from the HL7 Europe Base profile. FMK's `HasNegativeConsent` flag and card-level status should be surfaced as adherence codes where possible; the coarse `status = stopped` value remains but loses nuance compared to adherence codes such as `stopped`, `not-taking`, `on-hold`. +The profile brings forward the R5 `adherence` extension from the HL7 Europe Base profile. FMK's `Withdrawn` / `Paused` elements and card-level status should be surfaced as adherence codes where possible; the coarse `status` value remains but loses nuance compared to adherence codes such as `stopped`, `not-taking`, `on-hold`. #### Effective[x] -`effective[x]` is restricted to either `effectiveDateTime` (point-in-time) or `effectivePeriod` (typical for FMK). Prefer `effectivePeriod` when an end date is known, or when the start date is known and the medication is ongoing. +`effective[x]` is restricted to either `effectiveDateTime` (point-in-time) or `effectivePeriod` (typical for FMK). Prefer `effectivePeriod` when an end date is known, or when the start date is known and the medication is ongoing. FMK alternatives `TreatmentStartedPreviously` and `TreatmentEndingUndetermined` are represented by the absence of an explicit start/end in the period. #### Relationship to DkCoreMedicationRequest -When both resources are available (for example when proxying both `OrdinationDetails` and a medication card entry), the two resources MAY share identifiers so that a consumer can correlate a MedicationStatement with the MedicationRequest that it is derived from. +When both resources are available (for example when proxying both an ordination detail view and a medicinkort entry), the two resources MAY share the `FmkDrugMedicationId` identifier so that a consumer can correlate a MedicationStatement with the MedicationRequest that it is derived from. diff --git a/sushi-config.yaml b/sushi-config.yaml index 69c7525b8..666f17358 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -49,6 +49,8 @@ dependencies: hl7.fhir.uv.phd: 1.1.0 hl7.fhir.uv.ipa: 1.1.0 ihe.iti.mhd: 4.2.3 + # HL7 Europe base profiles - referenced by the DkCoreMedication* profiles via imposeProfile. + hl7.fhir.eu.base: 2.0.0-ballot From 090da38e46f6f1f8c65e42ec552f0129c6ed4dc1 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Sat, 9 May 2026 11:22:32 +0200 Subject: [PATCH 5/8] removed unused mappings --- sushi-config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sushi-config.yaml b/sushi-config.yaml index 666f17358..7503bd94f 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -40,6 +40,13 @@ parameters: - urn:oid:1.2.208.176.2.21 - urn:oid:1.2.208.176.2.4.12 path-expansion-params: Parameters-expParam.json + suppress-mappings: + - http://hl7.org/fhir/fivews + - http://hl7.org/fhir/workflow + - http://hl7.org/v3 +# - http://hl7.org/v3/cda +# - http://ihe.net/xds + - http://hl7.org/v2 dependencies: hl7.fhir.uv.xver-r5.r4: 0.1.0 From 80da8d3d679167b9d95711a03974bf4efd941c58 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Sat, 9 May 2026 20:56:17 +0200 Subject: [PATCH 6/8] Update sushi-config.yaml --- sushi-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sushi-config.yaml b/sushi-config.yaml index 7503bd94f..e382bdbb3 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -44,7 +44,7 @@ parameters: - http://hl7.org/fhir/fivews - http://hl7.org/fhir/workflow - http://hl7.org/v3 -# - http://hl7.org/v3/cda + - http://hl7.org/v3/cda # - http://ihe.net/xds - http://hl7.org/v2 From 0311029aac56017ca548d3f0b1da1b209f7a14e5 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Sat, 9 May 2026 21:01:48 +0200 Subject: [PATCH 7/8] Add NCPDP SCRIPT10_6 URL to sushi-config.yaml --- sushi-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/sushi-config.yaml b/sushi-config.yaml index e382bdbb3..3aa1bc74d 100644 --- a/sushi-config.yaml +++ b/sushi-config.yaml @@ -47,6 +47,7 @@ parameters: - http://hl7.org/v3/cda # - http://ihe.net/xds - http://hl7.org/v2 + - http://ncpdp.org/SCRIPT10_6 dependencies: hl7.fhir.uv.xver-r5.r4: 0.1.0 From 750dfd3d16dd26549e463b80b4ebb65e44c5c3d5 Mon Sep 17 00:00:00 2001 From: Jens Kristian Villadsen Date: Sun, 31 May 2026 20:00:27 +0200 Subject: [PATCH 8/8] updated mapping --- input/fsh/DkCoreImmunization.fsh | 36 ++++++------ input/fsh/aliases.fsh | 1 - ...reDefinition-dk-core-immunization-intro.md | 58 ++++++++++++++----- 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/input/fsh/DkCoreImmunization.fsh b/input/fsh/DkCoreImmunization.fsh index dd4cf44d3..c81e780b8 100644 --- a/input/fsh/DkCoreImmunization.fsh +++ b/input/fsh/DkCoreImmunization.fsh @@ -2,26 +2,23 @@ Profile: DkCoreImmunization Parent: Immunization Id: dk-core-immunization Title: "Danish Core Immunization Profile" -Description: "HL7 Denmark core profile for an administered or refused vaccination, aligned with Det Danske Vaccinationsregister (DDV) interface 1.4.0 + E1. Authoritative DDV XML schemas are published at https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1 with target namespace `http://vaccinationsregister.dk/schemas/2013/12/01`. A DDV `Vaccination` carries a numeric `VaccinationIdentifier` (+ `VaccinationVersionIdentifier`), a structured `Vaccine` element (VaccineIdentifier + VaccineName + Disease[] + ATC + SSIDrug[]), an optional `Effectuated` structure (date, effectuator name, authorisation and organisation), `CoverageDuration`, `BatchNumber`, `ActiveStatus`, `NegativeConsentIndicator`, `VaccinationCredibility` (credibility enum whose values include `Oprettet af borger` / citizen-created), and flags such as `IsPrevious` and `ConfirmedByPrescriptionServer`." +Description: "HL7 Denmark core profile for an administered vaccination, aligned with Det Danske Vaccinationsregister (DDV) interface 1.4.0 + E1. A registered DDV `Vaccination` is **always** an administered/effectuated vaccination, so `status` is essentially always `completed`; `ActiveStatus` is only used to mark a deletion (a `Vaccination` may exist in several versions with `Status=A` (Active) and later be deleted, whereby the latest version gets `Status=D` (Deleted)) which maps to `entered-in-error`. Refusals/omissions are **not** recorded as DDV Vaccinations, so FHIR `status = not-done` / `statusReason` cannot be derived from DDV. Authoritative DDV XML schemas are published at https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1 with target namespace `http://vaccinationsregister.dk/schemas/2013/12/01`. A DDV `Vaccination` carries a numeric `VaccinationIdentifier` (with `VaccinationVersionIdentifier` as a revision/optimistic-locking token, mapped to `meta.versionId`), a structured `Vaccine` element (VaccineIdentifier + VaccineName + Disease[] + ATC + SSIDrug[]), an optional `Effectuated` structure (date, effectuator name, authorisation and organisation), an optional `EffectuatedPlannedItem` (course/series context), `CoverageDuration`, `BatchNumber`, `ActiveStatus`, `NegativeConsentIndicator` (citizen private-marking, not a refusal), `VaccinationCredibility` (credibility enum whose values include `Oprettet af borger` / citizen-created), and flags such as `IsPrevious` and `ConfirmedByPrescriptionServer`." * ^status = #active * identifier ^slicing.discriminator.type = #value * ^slicing.discriminator.path = "system" * ^slicing.rules = #open * ^slicing.ordered = false - * ^slicing.description = "Slice identifier by system to carry DDV VaccinationIdentifier (+ optional VaccinationVersionIdentifier)" + * ^slicing.description = "Slice identifier by system to carry the DDV VaccinationIdentifier" * identifier contains - DdvVaccinationId 0..1 and - DdvVaccinationVersion 0..1 + DdvVaccinationId 0..1 * identifier[DdvVaccinationId] ^short = "[DA] DDV VaccinationIdentifier - unik identifikation af en vaccination (positiv long)." * system 1.. * system = $DdvVaccinationId (exactly) * value 1.. -* identifier[DdvVaccinationVersion] ^short = "[DA] DDV VaccinationVersionIdentifier - pairs with DdvVaccinationId to identify a specific revision." - * system 1.. - * system = $DdvVaccinationVersion (exactly) - * value 1.. -* status ^short = "Status for vaccinationen. `completed` = effektueret (DDV Vaccination.ActiveStatus = true); `not-done` = aflyst/afvist, herunder DDV Vaccination.NegativeConsentIndicator = true eller ActiveStatus = false. `entered-in-error` bruges for fejlregistreringer." -* statusReason ^short = "Begrundelse når status = not-done, fx negativt samtykke (NegativeConsentIndicator = true) eller aflyst vaccination." +* meta.versionId ^short = "[DA] DDV VaccinationVersionIdentifier - revisionsnummer for vaccinationen. Bruges internt i DDV til optimistic locking ved updates og svarer til FHIRs versionsmekanisme (meta.versionId / _history)." +* meta.security ^short = "[DA] Privatmarkering. Når DDV Vaccination.NegativeConsentIndicator = true har borgeren ønsket at privatmarkere vaccinationen. Den er stadig effektueret på lige fod med øvrige registreringer (status = completed), men må ikke synliggøres med mindre den sundhedsansvarlige anvender værdispring eller har samtykke. Markeres som dk-core gør på Patient: meta.security = http://terminology.hl7.org/CodeSystem/v3-Confidentiality#R (Restricted)." +* status ^short = "Status for vaccinationen. En registreret DDV Vaccination er altid effektueret, så `completed` er den normale værdi (DDV Vaccination.ActiveStatus = true / Status=A). `entered-in-error` bruges når en vaccination er slettet i DDV (ActiveStatus = false / seneste version Status=D). DDV registrerer ikke afviste/undladte vaccinationer, så `not-done`/`statusReason` kan IKKE udledes af DDV. NegativeConsentIndicator er ikke en afvisning, men en privatmarkering - se meta.security." +* statusReason ^short = "Kan IKKE udledes af DDV Vaccination-registreringer. Afviste/undladte vaccinationer registreres ikke som DDV Vaccinations, og historiske PlannedVaccinations kan ikke hentes via snitfladen." * vaccineCode ^short = "Vaccinen. DDV leverer strukturen DDV Vaccination.Vaccine som VaccineName (≤100 tegn fritekst), ATC (Code + Text), Disease[] (sygdom m. ATC), SSIDrug[] (SSI-lægemiddel) og DisplayMinimumVaccinationPlan[]. VaccineName mappes til vaccineCode.text; ATC til vaccineCode.coding[ATC]." * vaccineCode.coding ^slicing.discriminator.type = #value * ^slicing.discriminator.path = "system" @@ -52,7 +49,8 @@ Description: "HL7 Denmark core profile for an administered or refused vaccinatio * performer.actor ^short = "Den der har effektueret vaccinationen. DDV Vaccination.Effectuated.EffectuatedByName er en fritekst (≤200 tegn) og placeres i actor.display når en egentlig reference ikke er tilgængelig. Strukturerede felter: Effectuated.AuthorisationIdentifier (yder-/autorisationsnummer), Effectuated.EffectuatedByOrganisationName / Number / Type, Effectuated.EffectuatedInCountryCode." * lotNumber ^short = "Batchnummer. In DDV: Vaccination.BatchNumber." * protocolApplied.targetDisease ^short = "Sygdom(me) vaccinationen beskytter imod. In DDV: Vaccination.Vaccine.Disease[] (DiseaseIdentifier + DiseaseName + DiseaseNameDK + ATC)." -* note ^short = "Fri tekst. Anvendes blandt andet til DDV CoverageDuration, VaccinationCredibility (fx \"Oprettet af borger\" svarer til borger-registreret / selfcreated), ConfirmedByPrescriptionServer, IsPrevious, og historikoplysninger der ikke har et dedikeret Immunization-element." +* protocolApplied ^short = "Vaccinationsforløb/-serie. Hvis effektueringen er sket som del af et vaccinationsforløb, findes oplysninger om forløbet typisk i DDV Vaccination.EffectuatedPlannedItem." +* note ^short = "Fri tekst. Anvendes blandt andet til DDV CoverageDuration og felter uden et dedikeret Immunization-element. `VaccinationCredibility` angiver troværdighed/oprindelse (fx \"Oprettet af borger\" = borger-registreret). `IsPrevious = true` angiver at selve effektueringen er sket på et andet tidspunkt, sted og/eller af en anden person end den der registrerer - fx vaccinationer modtaget i udlandet eller før registrering i DDV blev lovpligtig; sådanne tidligere vaccinationer kan oprettes af både sundhedsfaglige og borgeren selv (afspejles i VaccinationCredibility). `ConfirmedByPrescriptionServer` har kun historisk interesse og siger noget om datakvaliteten - tilsvarende kan aflæses i VaccinationCredibility." Mapping: DkCoreImmunizationToDdv @@ -62,8 +60,9 @@ Title: "Det Danske Vaccinationsregister (DDV)" Id: dk-core-immunization-ddv * -> "Vaccination" "**DDV Vaccination (namespace `http://vaccinationsregister.dk/schemas/2013/12/01`).**" * identifier[DdvVaccinationId] -> "Vaccination.VaccinationIdentifier" "Numeric DDV identifier of the vaccination (positive long)." -* identifier[DdvVaccinationVersion] -> "Vaccination.VaccinationVersionIdentifier" "Revision number - populate alongside the identifier when pointing to a specific version." -* status -> "Vaccination.ActiveStatus / Vaccination.NegativeConsentIndicator" "`completed` when `ActiveStatus = true` and `NegativeConsentIndicator` is false/absent; `not-done` when `NegativeConsentIndicator = true` or `ActiveStatus = false`." +* meta.versionId -> "Vaccination.VaccinationVersionIdentifier" "Revision number, used internally in DDV for optimistic locking on updates. Maps to FHIR's resource versioning mechanism (`meta.versionId` / `_history`)." +* status -> "Vaccination.ActiveStatus" "A registered DDV Vaccination is always effectuated, so `completed` is the normal value (ActiveStatus = true / Status=A). `entered-in-error` when the vaccination has been deleted (ActiveStatus = false / latest version Status=D). DDV does not record refusals/omissions, so `not-done`/`statusReason` cannot be derived." +* meta.security -> "Vaccination.NegativeConsentIndicator" "`NegativeConsentIndicator = true` is a citizen private-marking (not a refusal); the vaccination is still effectuated. Carried as `meta.security = http://terminology.hl7.org/CodeSystem/v3-Confidentiality#R`, mirroring DkCorePatient. Only visible via værdispring/consent." * vaccineCode -> "Vaccination.Vaccine" "Structured DDV `Vaccine` (VaccineName + ATC + Disease[] + SSIDrug[] + …)." * vaccineCode.coding[ATC] -> "Vaccination.Vaccine.ATC.Code / ATC.Text" "WHO ATC code - typically J07*." * vaccineCode.coding[DdvVaccine] -> "Vaccination.Vaccine.VaccineIdentifier" "SSI numeric vaccine identifier." @@ -74,7 +73,8 @@ Id: dk-core-immunization-ddv * performer.actor -> "Vaccination.Effectuated.EffectuatedByName / AuthorisationIdentifier / EffectuatedByOrganisationName / Number" "Who effectuated the vaccination. DDV often provides this as free text (EffectuatedByName); map to `actor.display` when no structured reference is available, or resolve `AuthorisationIdentifier` / organisation details to a DkCorePractitioner / DkCoreOrganization reference where possible." * lotNumber -> "Vaccination.BatchNumber" "Lot / batch number." * protocolApplied.targetDisease -> "Vaccination.Vaccine.Disease[]" "Target disease(s) with optional DiseaseIdentifier + DiseaseName(DK) + ATC." -* note -> "Vaccination.CoverageDuration / VaccinationCredibility / IsPrevious / ConfirmedByPrescriptionServer" "Free-text notes for DDV fields without a dedicated Immunization element. `VaccinationCredibility` enum: `Slettet`, `Oprettet af læge / medhjælp`, `Oprettet på baggrund af data fra Sygesikringsregisteret`, `Udleveret på apotek og godkendt af læge`, `Oprettet af læge eller oprettet af borger og godkendt af læge`, `Udleveret på apotek`, `Oprettet af borger`." +* protocolApplied -> "Vaccination.EffectuatedPlannedItem" "When the effectuation is part of a vaccination course/series, course information is usually found in the DDV `EffectuatedPlannedItem` element." +* note -> "Vaccination.CoverageDuration / VaccinationCredibility / IsPrevious / ConfirmedByPrescriptionServer" "Free-text notes for DDV fields without a dedicated Immunization element. `IsPrevious = true` = the effectuation happened at another time/place/person than the registrar (e.g. abroad or before DDV registration was mandatory; may be created by professionals or the citizen). `ConfirmedByPrescriptionServer` has historical interest only (data quality), mirrored by `VaccinationCredibility`. `VaccinationCredibility` enum: `Slettet`, `Oprettet af læge / medhjælp`, `Oprettet på baggrund af data fra Sygesikringsregisteret`, `Udleveret på apotek og godkendt af læge`, `Oprettet af læge eller oprettet af borger og godkendt af læge`, `Udleveret på apotek`, `Oprettet af borger`." Instance: JohnImmunizationInfluvac @@ -97,13 +97,13 @@ Usage: #example Instance: JohnImmunizationNegativeConsent InstanceOf: DkCoreImmunization -Title: "John's afviste vaccination" -Description: "Example DkCoreImmunization for a DDV Vaccination where NegativeConsentIndicator = true, mapping to status = not-done." +Title: "John's privatmarkerede vaccination" +Description: "Example DkCoreImmunization for a DDV Vaccination where NegativeConsentIndicator = true. The vaccination is still effectuated (status = completed); the citizen has private-marked it, so it carries a Restricted confidentiality security label and is only visible via værdispring or consent." Usage: #example +* meta.security = $v3-Confidentiality#R "Restricted" * identifier[DdvVaccinationId].system = $DdvVaccinationId * identifier[DdvVaccinationId].value = "1" -* status = #not-done +* status = #completed * vaccineCode.text = "Example Vaccine" * patient = Reference(Patient/john) * occurrenceDateTime = "2025-09-30" -* note[+].text = "NegativeConsentIndicator = true" diff --git a/input/fsh/aliases.fsh b/input/fsh/aliases.fsh index ca6de65f7..4aa5613e8 100644 --- a/input/fsh/aliases.fsh +++ b/input/fsh/aliases.fsh @@ -50,7 +50,6 @@ Alias: $eu-medication = http://hl7.eu/fhir/base/StructureDefinition/medication-e // DDV (Det Danske Vaccinationsregister) XML schema namespace, base interface 1.4.0 + E1. // Source of truth: https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1 Alias: $DdvVaccinationId = http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationIdentifier -Alias: $DdvVaccinationVersion = http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationVersionIdentifier Alias: $DdvVaccineId = http://vaccinationsregister.dk/schemas/2013/12/01/VaccineIdentifier Alias: $DdvCredibility = http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationCredibility Alias: $DdvPatientId = https://www.sundhed.dk/patient diff --git a/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md b/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md index 111972daa..d545f990f 100644 --- a/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md +++ b/input/pagecontent/StructureDefinition-dk-core-immunization-intro.md @@ -1,8 +1,17 @@ ### Scope and usage -The Danish Core Immunization profile is intended to represent an administered or refused vaccination, as sourced from Det Danske Vaccinationsregister (DDV). Authoritative DDV XML schemas are published at [wiki.fmk-teknik.dk/fmk:ddv:extensions:e1](https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1) with target namespace `http://vaccinationsregister.dk/schemas/2013/12/01` (interface 1.4.0 + extension E1). Service delivery is described at [nspop.dk](https://www.nspop.dk/pages/releaseview.action?pageId=31798109). +The Danish Core Immunization profile is intended to represent an **administered** vaccination, as sourced from Det Danske Vaccinationsregister (DDV). Authoritative DDV XML schemas are published at [wiki.fmk-teknik.dk/fmk:ddv:extensions:e1](https://wiki.fmk-teknik.dk/fmk:ddv:extensions:e1) with target namespace `http://vaccinationsregister.dk/schemas/2013/12/01` (interface 1.4.0 + extension E1). Service delivery is described at [nspop.dk](https://www.nspop.dk/pages/releaseview.action?pageId=31798109). -A DDV `Vaccination` carries a numeric `VaccinationIdentifier` (paired with `VaccinationVersionIdentifier` for revision tracking), a structured `Vaccine` element (`VaccineIdentifier` + `VaccineName` + `Disease[]` + `ATC` + optional `SSIDrug[]` and keyword metadata), an optional `Effectuated` structure (date, effectuator name, authorisation and organisation), `CoverageDuration`, `BatchNumber`, `ActiveStatus`, `NegativeConsentIndicator`, `VaccinationCredibility` (a credibility enum), and flags such as `IsPrevious` and `ConfirmedByPrescriptionServer`. +#### Two DDV concepts: Vaccinations vs PlannedVaccinations + +DDV exposes two overarching data types, fetched via separate services: + +- **Vaccinations** (`getVaccinationCard`) — administered/effectuated vaccinations. This is what the Danish Core Immunization profile represents. Only `Vaccinations` expose **historical** data via the interface; history is controlled internally in DDV's database with `ValidFrom`/`ValidTo` dates, and `VersionID` is used internally for optimistic locking on updates. +- **PlannedVaccinations** (`getPlannedVaccinations`) — recommended/planned vaccinations. Historical entries for `PlannedVaccinations` **cannot** be fetched via the interface. + +A consequence is that a citizen who has **declined or omitted** a planned/recommended vaccination leaves no trace in DDV `Vaccinations` (a refusal is never recorded there), and because `PlannedVaccinations` history is not retrievable, the refusal cannot be inferred either. Therefore the FHIR fields **`status = not-done` / `statusReason` cannot be derived from DDV** — see the status section below. + +A DDV `Vaccination` carries a numeric `VaccinationIdentifier` (with `VaccinationVersionIdentifier` as a revision/optimistic-locking token, carried in `meta.versionId`), a structured `Vaccine` element (`VaccineIdentifier` + `VaccineName` + `Disease[]` + `ATC` + optional `SSIDrug[]` and keyword metadata), an optional `Effectuated` structure (date, effectuator name, authorisation and organisation), an optional `EffectuatedPlannedItem` (course/series context), `CoverageDuration`, `BatchNumber`, `ActiveStatus`, `NegativeConsentIndicator` (citizen private-marking — **not** a refusal), `VaccinationCredibility` (a credibility enum), and flags such as `IsPrevious` and `ConfirmedByPrescriptionServer`. In dk-core the `patient` element has been constrained to [DkCorePatient](StructureDefinition-dk-core-patient.html) and `performer.actor` to the Danish core profiles for Practitioner, PractitionerRole or Organization. When the DDV effectuator is available only as free text (e.g. "Danske Lægers Vaccinations Service"), it should be carried as `performer.actor.display`. @@ -11,7 +20,7 @@ In dk-core the `patient` element has been constrained to [DkCorePatient](Structu | DDV field | FHIR target | | --- | --- | | `Vaccination.VaccinationIdentifier` | `identifier[DdvVaccinationId]` (`http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationIdentifier`) | -| `Vaccination.VaccinationVersionIdentifier` | `identifier[DdvVaccinationVersion]` (`http://vaccinationsregister.dk/schemas/2013/12/01/VaccinationVersionIdentifier`) — populate when pointing to a specific revision | +| `Vaccination.VaccinationVersionIdentifier` | `meta.versionId` — revision/optimistic-locking token; aligns with FHIR's `_history` versioning | | `Vaccination.Vaccine.VaccineIdentifier` | `vaccineCode.coding[DdvVaccine]` (`http://vaccinationsregister.dk/schemas/2013/12/01/VaccineIdentifier`) | | `Vaccination.Vaccine.VaccineName` | `vaccineCode.text` | | `Vaccination.Vaccine.ATC.Code` / `ATC.Text` | `vaccineCode.coding[ATC]` (`http://www.whocc.no/atc`) — typically J07* | @@ -22,24 +31,43 @@ In dk-core the `patient` element has been constrained to [DkCorePatient](Structu | `Vaccination.Effectuated.AuthorisationIdentifier` | `performer.actor` → `Reference(DkCorePractitioner)` when resolvable | | `Vaccination.Effectuated.EffectuatedByOrganisationName` / `Number` / `Type` | `performer.actor` → `Reference(DkCoreOrganization)` when resolvable; free-text fallback via `actor.display` | | `Vaccination.BatchNumber` | `lotNumber` | +| `Vaccination.EffectuatedPlannedItem` | `protocolApplied` (vaccination course/series context, when the effectuation is part of a planned course) | | `Vaccination.CoverageDuration` | `note` (free text, e.g. "CoverageDuration: 1 year") | -| `Vaccination.VaccinationCredibility` | `note` (e.g. "VaccinationCredibility: Oprettet af borger"). See status section. | -| `Vaccination.ActiveStatus = true` | `status = #completed` | -| `Vaccination.ActiveStatus = false` | `status = #not-done` | -| `Vaccination.NegativeConsentIndicator = true` | `status = #not-done` (takes precedence over `ActiveStatus`) | -| `Vaccination.IsPrevious = true` | `note` (history entry marker) | -| `Vaccination.ConfirmedByPrescriptionServer` | `note` (pharmacy-confirmed marker) | +| `Vaccination.VaccinationCredibility` | `note` (e.g. "VaccinationCredibility: Oprettet af borger"). Credibility/origin of the record. | +| `Vaccination.ActiveStatus = true` (Status=A) | `status = #completed` (a registered DDV Vaccination is always effectuated) | +| `Vaccination.ActiveStatus = false` (Status=D, deleted) | `status = #entered-in-error` | +| `Vaccination.NegativeConsentIndicator = true` | `meta.security = `[`v3-Confidentiality#R`](http://terminology.hl7.org/CodeSystem/v3-Confidentiality)` (Restricted)` — citizen private-marking, **not** a status change. See section below. | +| `Vaccination.IsPrevious = true` | `note` (effectuation done at another time/place/person, e.g. abroad or pre-mandate) | +| `Vaccination.ConfirmedByPrescriptionServer` | `note` (historical data-quality marker; mirrored by `VaccinationCredibility`) | #### Status semantics -DDV does not expose the full set of FHIR `Immunization.status` values. The mapping collapses DDV's boolean flags as follows: +A registered DDV `Vaccination` is **always** an administered/effectuated vaccination. `ActiveStatus` is **not** a clinical status — it is only used to indicate deletion: a `Vaccination` may exist in several versions with `Status=A` (Active), and when it is deleted the latest version gets `Status=D` (Deleted). The mapping is therefore: + +- `ActiveStatus = true` (Status=A) → `status = #completed`. This is the normal value. +- `ActiveStatus = false` (Status=D, deleted) → `status = #entered-in-error`. Records whose `VaccinationCredibility` is `Slettet` ("deleted") likewise map here. + +`status = #not-done` and `statusReason` are **not derivable from DDV** and are not used by this profile. A citizen who declines or omits a planned/recommended vaccination leaves no `Vaccination` record (refusals are never written to `Vaccinations`), and `PlannedVaccinations` history is not retrievable via the interface, so the refusal cannot be inferred. Consumers must not infer a refusal from the absence of a record. + +#### Private-marking (NegativeConsentIndicator) + +`NegativeConsentIndicator = true` is **not** a refusal and does **not** change `status` — the vaccination is still effectuated on equal footing with every other registration. The flag indicates that the citizen has chosen to **private-mark** the specific vaccination: it must not be made visible unless the responsible health professional invokes *værdispring* (break-glass) or holds the citizen's consent. + +This is modelled the same way dk-core marks confidential data on [DkCorePatient](StructureDefinition-dk-core-patient.html): a security label + +``` +meta.security = http://terminology.hl7.org/CodeSystem/v3-Confidentiality#R // "Restricted" +``` + +Systems consuming dk-core Immunization resources must treat a `#R` (Restricted) security label as a private-mark and suppress the resource from normal display, releasing it only under *værdispring* or consent. + +#### IsPrevious, ConfirmedByPrescriptionServer and credibility -- `NegativeConsentIndicator = true` → `status = #not-done` (regardless of `ActiveStatus`). -- `ActiveStatus = true` → `status = #completed`. -- `ActiveStatus = false` → `status = #not-done`. -- Unknown / missing → omit `status` (the resource will fail the base cardinality check; ensure one of the flags is known before producing the resource). +- **`IsPrevious = true`** indicates that the actual effectuation happened at a different time, place and/or by a different person than the one performing the registration — e.g. vaccinations received abroad or before registration in DDV became legally required. Such previous vaccinations may be created by health professionals as well as by the citizen themselves; this is reflected in `VaccinationCredibility`. +- **`ConfirmedByPrescriptionServer`** has only historical interest and primarily reflects the data quality of the registration. Comparable information can be read from `VaccinationCredibility`. +- **`EffectuatedPlannedItem`** carries course/series context when the effectuation was part of a planned vaccination course; map to `protocolApplied`. -`entered-in-error` may be used for DDV records whose `VaccinationCredibility` is `Slettet` ("deleted"). +Many of the non-mandatory data elements inherited from the generic profile do exist in DDV, but remain optional here and will only be populated in certain cases. #### Vaccine coding