From 242d3e9836137c85c14efe756fbb65522868b4d3 Mon Sep 17 00:00:00 2001 From: au2 Date: Fri, 29 Aug 2014 15:44:32 -0400 Subject: [PATCH] Vitera_CCDA_SMART_Sample medications now match --- .../ccda/lib/templating_functions.js | 14 +- lib/generator/ccda/templates/medications.js | 130 ++++++++++-------- lib/parser/ccda/sections/medications.js | 3 +- test/generator-ccda/test-generator-ccda.js | 2 +- 4 files changed, 88 insertions(+), 61 deletions(-) diff --git a/lib/generator/ccda/lib/templating_functions.js b/lib/generator/ccda/lib/templating_functions.js index 8ae8aabe..32674d5e 100644 --- a/lib/generator/ccda/lib/templating_functions.js +++ b/lib/generator/ccda/lib/templating_functions.js @@ -185,6 +185,9 @@ var name = function (xmlDoc, name, use) { xmlDoc = xmlDoc.node('given', name[0]["middle"][0]).parent(); if (name[0]["last"]) xmlDoc = xmlDoc.node('family', name[0]["last"]).parent(); + if (name[0].suffix) { + xmlDoc = xmlDoc.node('suffix', name[0].suffix).parent(); + } xmlDoc = xmlDoc.parent(); return xmlDoc; } else { @@ -200,6 +203,9 @@ var name = function (xmlDoc, name, use) { xmlDoc = xmlDoc.node('given', name["middle"][0]).parent(); if (name["last"]) xmlDoc = xmlDoc.node('family', name["last"]).parent(); + if (name.suffix) { + xmlDoc = xmlDoc.node('suffix', name.suffix).parent(); + } xmlDoc = xmlDoc.parent(); return xmlDoc; } @@ -416,9 +422,11 @@ var manufacturedProduct = function (xmlDoc, product, ref, sec) { xmlDoc = xmlDoc.node('lotNumberText', product["lot_number"]).parent(); } xmlDoc = xmlDoc.parent() // end manufacturedMaterial - xmlDoc = xmlDoc.node('manufacturerOrganization') - .node('name', product["manufacturer"]).parent() - .parent(); + if (product.manufacturer) { + xmlDoc = xmlDoc.node('manufacturerOrganization') + .node('name', product.manufacturer).parent() + .parent(); + } } else { xmlDoc = xmlDoc.node('id') .attr({nullFlavor: "UNK"}).parent() diff --git a/lib/generator/ccda/templates/medications.js b/lib/generator/ccda/templates/medications.js index fb23e1d6..9519a1ef 100644 --- a/lib/generator/ccda/templates/medications.js +++ b/lib/generator/ccda/templates/medications.js @@ -1,6 +1,33 @@ var libxmljs = require("libxmljs"); var libCCDAGen = require("../lib/templating_functions.js"); +var updateIndication = function(xmlDoc, indication) { + if (indication) { + xmlDoc = xmlDoc.node('entryRelationship') // Indication + .attr({typeCode: "RSON"}) + .node('observation').attr({classCode: "OBS"}) + .attr({moodCode: "EVN"}) + .node('templateId') + .attr({root: "2.16.840.1.113883.10.20.22.4.19"}).parent(); + xmlDoc = libCCDAGen.id(xmlDoc, indication.identifiers); + xmlDoc = libCCDAGen.code(xmlDoc, indication.code).parent(); + xmlDoc = xmlDoc.node('statusCode').attr({code: "completed"}).parent(); + xmlDoc = libCCDAGen.effectiveTime(xmlDoc, libCCDAGen.getTimes(indication.date_time)); + xmlDoc = libCCDAGen.value(xmlDoc, indication.value, "CD"); + } +} + +var administrationAttrs = function(entry) { + var attrs = {classCode: "SBADM"}; + var status = entry.status; + if (status === 'Prescribed') { + attrs.moodCode = 'INT' + } else if (status === 'Completed') { + attrs.moodCode = 'EVN'; + } + return attrs; +} + module.exports = function (data, codeSystems, isCCD, CCDxml) { var doc = new libxmljs.Document(); @@ -11,27 +38,30 @@ module.exports = function (data, codeSystems, isCCD, CCDxml) { for (var i = 0; i < data.length; i++) { var time = libCCDAGen.getTimes(data[i]["date_time"]); xmlDoc = xmlDoc.node('entry').attr({typeCode: "DRIV"}) - .node('substanceAdministration').attr({classCode: "SBADM"}).attr({moodCode: "EVN"}) + .node('substanceAdministration').attr(administrationAttrs(data[i])) .node('templateId').attr({root: "2.16.840.1.113883.10.20.22.4.16"}).parent(); // medication activity - xmlDoc = libCCDAGen.id(xmlDoc, data[0]["identifiers"]); - xmlDoc = xmlDoc.node('text', data[i]["product"] ? data[i]["product"]["unencoded_name"] : undefined) + xmlDoc = libCCDAGen.id(xmlDoc, data[i]["identifiers"]); + xmlDoc = xmlDoc.node('text', data[i].sig) .node('reference').attr({value: "#MedSec_1"}).parent() .parent() .node('statusCode').attr({code: 'completed'}).parent(); xmlDoc = libCCDAGen.effectiveTime(xmlDoc, time); - xmlDoc = xmlDoc.node('effectiveTime') - .attr({"xsi:type": "PIVL_TS"}) - .attr({institutionSpecified: "true"}) - .attr({operator: "A"}); - var period; - if (period = data[i]["administration"] ? data[i]["administration"]["interval"] ? data[i]["administration"]["interval"]["period"] : undefined : undefined) { - xmlDoc = xmlDoc.node('period').attr({value: period["value"]}) - .attr({unit: period["unit"]}).parent() - } - xmlDoc = xmlDoc.parent() + + if (data[i].administration && data[i].administration.interval) { + xmlDoc = xmlDoc.node('effectiveTime') + .attr({"xsi:type": "PIVL_TS"}) + .attr({institutionSpecified: "true"}) + .attr({operator: "A"}); + var period; + if (period = data[i]["administration"] ? data[i]["administration"]["interval"] ? data[i]["administration"]["interval"]["period"] : undefined : undefined) { + xmlDoc = xmlDoc.node('period').attr({value: period["value"]}) + .attr({unit: period["unit"]}).parent() + } + xmlDoc = xmlDoc.parent() + } xmlDoc = libCCDAGen.medication_administration(xmlDoc, data[i]["administration"]); xmlDoc = libCCDAGen.consumable(xmlDoc, data[i].product, data[i].product.unencoded_name); - xmlDoc = libCCDAGen.performerRevised(xmlDoc, data[i]["performer"], {}); + xmlDoc = libCCDAGen.performerRevised(xmlDoc, data[i].performer, {}); xmlDoc = xmlDoc.node('participant').attr({typeCode: "CSM"}) .node('participantRole').attr({classCode: "MANU"}) // drug vehicle @@ -45,27 +75,11 @@ module.exports = function (data, codeSystems, isCCD, CCDxml) { xmlDoc = xmlDoc.node('name', data[i]["drug_vehicle"] ? data[i]["drug_vehicle"]["name"] : "").parent() .parent() .parent() - .parent() - .node('entryRelationship') // Indication - .attr({typeCode: "RSON"}) - .node('observation').attr({classCode: "OBS"}) - .attr({moodCode: "EVN"}) - .node('templateId') - .attr({root: "2.16.840.1.113883.10.20.22.4.19"}).parent(); - xmlDoc = libCCDAGen.id(xmlDoc, data[i]["indication"] ? data[i]["indication"]["identifiers"] : undefined); - xmlDoc = xmlDoc.node('code') - .attr({code: "404684003"}) - .attr({displayName: "Finding"}) - .attr({codeSystem: codeSystems["SNOMED CT"][0]}) - .attr({codeSystemName: "SNOMED CT"}).parent() - .node('statusCode') - .attr({code: "completed"}).parent(); - xmlDoc = libCCDAGen.effectiveTime(xmlDoc, libCCDAGen.getTimes(data[i]["indication"] ? data[i]["indication"]["date_time"] : time)); - xmlDoc = libCCDAGen.value(xmlDoc, data[i]["indication"] ? data[i]["indication"]["value"] : undefined, "CD"); - xmlDoc = xmlDoc.parent() - .parent() + .parent(); + + updateIndication(xmlDoc, data[i].indication); - .node('entryRelationship').attr({typeCode: "REFR"}) // Supply + xmlDoc = xmlDoc.node('entryRelationship').attr({typeCode: "REFR"}) // Supply .node('supply').attr({classCode: "SPLY"}).attr({moodCode: "INT"}) .node('templateId').attr({root: "2.16.840.1.113883.10.20.22.4.17"}).parent() .node('id').attr({nullFlavor: "NI"}).parent() @@ -73,9 +87,16 @@ module.exports = function (data, codeSystems, isCCD, CCDxml) { if (data[i].supply && data[i].supply.date_time) { xmlDoc = libCCDAGen.effectiveTime(xmlDoc, libCCDAGen.getTimes(data[i].supply.date_time), undefined, "IVL_TS"); } - xmlDoc = xmlDoc.node('repeatNumber').attr({value: "1"}).parent() - .node('quantity').attr({value: "75"}).parent() - .node('product'); + if (data[i].supply) { + if (data[i].supply.repeatNumber) { + xmlDoc = xmlDoc.node('repeatNumber').attr({value: data[i].supply.repeatNumber}).parent(); + } + if (data[i].supply.quantity) { + xmlDoc = xmlDoc.node('quantity').attr({value: data[i].supply.quantity}).parent(); + } + } + + xmlDoc = xmlDoc.node('product'); xmlDoc = libCCDAGen.manufacturedProduct(xmlDoc, data[i]["product"], '#MedSec_1', 'MSO'); xmlDoc = xmlDoc.parent(); xmlDoc = libCCDAGen.performerRevised(xmlDoc, undefined, { @@ -88,18 +109,23 @@ module.exports = function (data, codeSystems, isCCD, CCDxml) { "templateId_in": undefined }); xmlDoc = xmlDoc.node('author') - .node('time').attr({nullFlavor: "UNK"}).parent() - .node('assignedAuthor'); + + if (data[i].supply && data[i].supply.author && data[i].supply.author.date_time) { + xmlDoc = libCCDAGen.effectiveTime(xmlDoc, libCCDAGen.getTimes(data[i].supply.author.date_time), 'time'); + } else { + xmlDoc = xmlDoc.node('time').attr({nullFlavor: "UNK"}).parent() + } + + xmlDoc = xmlDoc.node('assignedAuthor'); xmlDoc = libCCDAGen.id(xmlDoc, data[i].supply && data[i].supply.author ? data[i].supply.author.identifiers : undefined); xmlDoc = xmlDoc.node('addr').attr({nullFlavor: "UNK"}).parent() .node('telecom').attr({nullFlavor: "UNK"}).parent() - .node('assignedPerson') - .node('name') - .node('prefix', "Dr.").parent() - .node('given', "Henry").parent() - .node('family', 'Seven').parent() - .parent() - .parent() + .node('assignedPerson'); + + if (data[i].supply.author && data[i].supply.author.name) { + xmlDoc = libCCDAGen.name(xmlDoc, data[i].supply.author.name); + } + xmlDoc = xmlDoc.parent() .parent() .parent() xmlDoc = libCCDAGen.entryRelationship(xmlDoc, data[i]["instructions"], 'act', 'SUBJ'); // Instructions @@ -118,15 +144,9 @@ module.exports = function (data, codeSystems, isCCD, CCDxml) { .node('product'); xmlDoc = libCCDAGen.manufacturedProduct(xmlDoc, data[i]["product"], '#MedSec_1', "MD"); xmlDoc = xmlDoc.parent(); - xmlDoc = libCCDAGen.performerRevised(xmlDoc, undefined, { - "id": "2.16.840.1.113883.19.5.9999.456", - "extension": "2981823", - "addr": "generic", - "tel": undefined, - "repOrg": "generic", - "assignedP": "generic", - "templateId_in": undefined - }); + if (data[i].dispense && data[i].dispense.performer) { + xmlDoc = libCCDAGen.performerRevised(xmlDoc, data[i].dispense.performer); + } xmlDoc = xmlDoc.parent() .parent() xmlDoc = libCCDAGen.precondition(xmlDoc, data[i]["precondition"]); diff --git a/lib/parser/ccda/sections/medications.js b/lib/parser/ccda/sections/medications.js index 71b7d4bf..a59c9496 100644 --- a/lib/parser/ccda/sections/medications.js +++ b/lib/parser/ccda/sections/medications.js @@ -31,14 +31,13 @@ var exportMedicationsSection = function (version) { */ var MedicationInterval = component.define("MedicationInterval") .fields([ - ["xsiType", "0..1", "./@xsi:type"], ["phase", "0..1", "./h:phase", shared.EffectiveTime], ["period", "0..1", "./h:period", shared.PhysicalQuantity], ["alignment", "0..1", "./@alignment"], ["frequency", "0..1", "./@institutionSpecified", Processor.asBoolean], ["event", "0..1", "./h:event/@code", shared.SimpleCode("2.16.840.1.113883.5.139")], ["event_offset", "0..1", "./h:offset", shared.EventOffset] - ]).cleanupStep(cleanup.removeField('xsiType')) + ]); var MedicationAdministration = component.define("MedicationAdministration") .fields([ diff --git a/test/generator-ccda/test-generator-ccda.js b/test/generator-ccda/test-generator-ccda.js index 03c928fd..ba2ba12b 100644 --- a/test/generator-ccda/test-generator-ccda.js +++ b/test/generator-ccda/test-generator-ccda.js @@ -66,6 +66,6 @@ describe('parse generate parse generate', function () { delete result.errors; delete result2.errors; - assert.deepEqual(result2.data.results, result.data.results); + assert.deepEqual(result2.data.medications, result.data.medications); }); });