From c588b4c90e08eccf77cfbda7b0ad289fe808df75 Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Fri, 3 Feb 2023 12:13:21 -0500 Subject: [PATCH 1/3] Update NCPDP SCRIPT NewRx message to contain the required fields and add support for version 2017071. --- src/components/RequestBox/RequestBox.js | 138 +---------- src/util/buildScript.2017071.js | 302 +++++++++++++++++++++++ src/util/buildScript.2022071.js | 313 ++++++++++++++++++++++++ 3 files changed, 619 insertions(+), 134 deletions(-) create mode 100644 src/util/buildScript.2017071.js create mode 100644 src/util/buildScript.2022071.js diff --git a/src/components/RequestBox/RequestBox.js b/src/components/RequestBox/RequestBox.js index 55a50b88..6f9b139e 100644 --- a/src/components/RequestBox/RequestBox.js +++ b/src/components/RequestBox/RequestBox.js @@ -5,11 +5,11 @@ import PatientBox from "../SMARTBox/PatientBox"; import CheckBox from '../Inputs/CheckBox'; import { types, defaultValues, shortNameMap } from "../../util/data"; import { getAge } from "../../util/fhir"; +import buildNewRxRequest from '../../util/buildScript.2017071.js'; import _ from "lodash"; import "./request.css"; import { PrefetchTemplate } from "../../PrefetchTemplate"; import { retrieveLaunchContext } from "../../util/util"; -import { Message } from "semantic-ui-react"; export default class RequestBox extends Component { constructor(props) { @@ -36,9 +36,7 @@ export default class RequestBox extends Component { this.renderPrefetchedResources = this.renderPrefetchedResources.bind(this); this.renderError = this.renderError.bind(this); this.buildLaunchLink = this.buildLaunchLink.bind(this); - this.buildNewRxRequest = this.buildNewRxRequest.bind(this); this.updateDeidentifyCheckbox = this.updateDeidentifyCheckbox.bind(this); - this.xmlAddTextNode = this.xmlAddTextNode.bind(this); } // TODO - see how to submit response for alternative therapy @@ -346,7 +344,9 @@ export default class RequestBox extends Component { console.log("sendRx: " + this.props.pimsUrl); // build the NewRx Message - var newRx = this.buildNewRxRequest(); + var newRx = buildNewRxRequest(this.state.prefetchedResources.patient, + this.state.prefetchedResources.practitioner, + this.state.request); console.log(newRx); const serializer = new XMLSerializer(); @@ -375,136 +375,6 @@ export default class RequestBox extends Component { } - xmlAddTextNode(xmlDoc, parent, sectionName, value) { - var section = xmlDoc.createElement(sectionName); - var textNode = xmlDoc.createTextNode(value); - section.appendChild(textNode); - parent.appendChild(section); - } - - buildNewRxRequest() { - var doc = document.implementation.createDocument("", "", null); - var message = doc.createElement("Message"); - - // Header - var header = doc.createElement("Header"); - // generate the message id (just get the milliseconds since epoch and use that) - const d1 = new Date(); - const messageIdValue = d1.getTime(); - // console.log(messageIdValue); - this.xmlAddTextNode(doc, header, "MessageID", messageIdValue); - message.appendChild(header); - - // Body - var body = doc.createElement("Body"); - var newRx = doc.createElement("NewRx"); - - // Patient - const patientResource = this.state.prefetchedResources.patient; - var patient = doc.createElement("Patient"); - var humanPatient = doc.createElement("HumanPatient"); - - // Patient Name - var patientNames = doc.createElement("Names"); - var patientName = doc.createElement("Name"); - this.xmlAddTextNode(doc, patientName, "LastName", patientResource.name[0].family); - this.xmlAddTextNode(doc, patientName, "FirstName", patientResource.name[0].given[0]); - patientNames.appendChild(patientName); - humanPatient.appendChild(patientNames); - - // Patient Birth Date - var dateOfBirth = doc.createElement("DateOfBirth"); - this.xmlAddTextNode(doc, dateOfBirth, "Date", patientResource.birthDate); - humanPatient.appendChild(dateOfBirth); - patient.appendChild(humanPatient); - newRx.appendChild(patient); - - // Prescriber - const practitionerResource = this.state.prefetchedResources.practitioner; - // console.log(practitionerResource); - var prescriber = doc.createElement("Prescriber"); - var nonVeterinarian = doc.createElement("NonVeterinarian"); - - // Prescriber Identifier - for (let i = 0; i < practitionerResource.identifier.length; i++) { - let id = practitionerResource.identifier[i]; - if ((id.system) && (id.system.includes("us-npi"))) { - var identification = doc.createElement("Identification"); - this.xmlAddTextNode(doc, identification, "NPI", id.value); - nonVeterinarian.appendChild(identification); - } - } - - // Prescriber Name - var prescriberNames = doc.createElement("Names"); - var prescriberName = doc.createElement("Name"); - this.xmlAddTextNode(doc, prescriberName, "LastName", practitionerResource.name[0].family); - this.xmlAddTextNode(doc, prescriberName, "FirstName", practitionerResource.name[0].given[0]); - prescriberNames.appendChild(prescriberName); - nonVeterinarian.appendChild(prescriberNames); - - // Prescriber Address - const practitionerAddress = practitionerResource.address[0]; - var address = doc.createElement("Address"); - this.xmlAddTextNode(doc, address, "AddressLine1", practitionerAddress.line[0]); - this.xmlAddTextNode(doc, address, "City", practitionerAddress.city); - this.xmlAddTextNode(doc, address, "StateProvince", practitionerAddress.state); - this.xmlAddTextNode(doc, address, "PostalCode", practitionerAddress.postalCode); - this.xmlAddTextNode(doc, address, "Country", "US"); // assume US for now - nonVeterinarian.appendChild(address); - - // Prescriber Phone Number and Email - var communicationNumbers = doc.createElement("CommunicationNumbers"); - for (let i = 0; i < practitionerResource.telecom.length; i++) { - const telecom = practitionerResource.telecom[i]; - if (telecom.system == "phone") { - var primaryTelephone = doc.createElement("PrimaryTelephone"); - this.xmlAddTextNode(doc, primaryTelephone, "Number", telecom.value); - communicationNumbers.appendChild(primaryTelephone); - } else if (telecom.system == "email") { - this.xmlAddTextNode(doc, communicationNumbers, "ElectronicMail", telecom.value); - } - } - nonVeterinarian.appendChild(communicationNumbers) - - prescriber.appendChild(nonVeterinarian); - newRx.appendChild(prescriber); - - // Medication - const medicationRequestResource = this.state.request; - // console.log(medicationRequestResource); - var medicationPrescribed = doc.createElement("MedicationPrescribed"); - - - // Medication Drug Description - const coding = medicationRequestResource.medicationCodeableConcept.coding[0]; - this.xmlAddTextNode(doc, medicationPrescribed, "DrugDescription", coding.display); - - // Medication Product - var product = doc.createElement("Product"); - var drugCoded = doc.createElement("DrugCoded"); - var productCode = doc.createElement("ProductCode"); - this.xmlAddTextNode(doc, productCode, "Code", coding.code); - this.xmlAddTextNode(doc, productCode, "Qualifier", coding.system); - drugCoded.appendChild(productCode); - product.appendChild(drugCoded); - medicationPrescribed.appendChild(product); - - // Medication Quantity - var quantity = doc.createElement("Quantity"); - this.xmlAddTextNode(doc, quantity, "Value", medicationRequestResource.dispenseRequest.quantity.value); - medicationPrescribed.appendChild(quantity); - - newRx.appendChild(medicationPrescribed); - - body.appendChild(newRx); - message.appendChild(body); - - doc.appendChild(message); - - return doc; - } - isOrderNotSelected() { return Object.keys(this.state.request).length === 0; } diff --git a/src/util/buildScript.2017071.js b/src/util/buildScript.2017071.js new file mode 100644 index 00000000..284ac03b --- /dev/null +++ b/src/util/buildScript.2017071.js @@ -0,0 +1,302 @@ +/* 2017071 NCPDP SCRIPT Support */ + + function xmlAddTextNode(xmlDoc, parent, sectionName, value) { + var section = xmlDoc.createElement(sectionName); + var textNode = xmlDoc.createTextNode(value); + section.appendChild(textNode); + parent.appendChild(section); + } + + function buildNewRxName(doc, nameResource) { + var name = doc.createElement("Name"); + xmlAddTextNode(doc, name, "LastName", nameResource.family); + xmlAddTextNode(doc, name, "FirstName", nameResource.given[0]); + return name; + } + + function buildNewRxAddress(doc, addressResource) { + // console.log(addressResource); + var address = doc.createElement("Address"); + xmlAddTextNode(doc, address, "AddressLine1", addressResource.line[0]); + xmlAddTextNode(doc, address, "City", addressResource.city); + xmlAddTextNode(doc, address, "StateProvince", addressResource.state); + xmlAddTextNode(doc, address, "PostalCode", addressResource.postalCode); + xmlAddTextNode(doc, address, "Country", "US"); // assume US for now + return address; + } + + function buildNewRxPatient(doc, patientResource) { + // console.log(patientResource); + var patient = doc.createElement("Patient"); + var humanPatient = doc.createElement("HumanPatient"); + + // Patient Name + const patientNameResource = patientResource.name[0]; + humanPatient.appendChild(buildNewRxName(doc, patientNameResource)); + + // Patient Gender and Sex + var gender = "U"; // unknown + var patientResourceGender = patientResource.gender.toLowerCase(); + if (patientResourceGender === "male") { + gender = "M"; // male + } else if (patientResourceGender === "female") { + gender = "F"; // female + } else if (patientResourceGender === "other") { + gender = "N"; // non-binary + } + xmlAddTextNode(doc, humanPatient, "Gender", gender); + + // Patient Birth Date + var dateOfBirth = doc.createElement("DateOfBirth"); + xmlAddTextNode(doc, dateOfBirth, "Date", patientResource.birthDate); + humanPatient.appendChild(dateOfBirth); + + // Patient Address + const patientAddressResource = patientResource.address[0]; + humanPatient.appendChild(buildNewRxAddress(doc, patientAddressResource)); + + patient.appendChild(humanPatient); + return patient; + } + + function buildNewRxPrescriber(doc, practitionerResource) { + // console.log(practitionerResource); + var prescriber = doc.createElement("Prescriber"); + var nonVeterinarian = doc.createElement("NonVeterinarian"); + + // Prescriber Identifier + for (let i = 0; i < practitionerResource.identifier.length; i++) { + let id = practitionerResource.identifier[i]; + if ((id.system) && (id.system.includes("us-npi"))) { + var identification = doc.createElement("Identification"); + xmlAddTextNode(doc, identification, "NPI", id.value); + nonVeterinarian.appendChild(identification); + } + } + + // Prescriber Name + const practitionerNameResource = practitionerResource.name[0]; + nonVeterinarian.appendChild(buildNewRxName(doc, practitionerNameResource)); + + // Prescriber Address + const practitionerAddressResource = practitionerResource.address[0]; + nonVeterinarian.appendChild(buildNewRxAddress(doc, practitionerAddressResource)); + + // Prescriber Phone Number and Email + var communicationNumbers = doc.createElement("CommunicationNumbers"); + for (let i = 0; i < practitionerResource.telecom.length; i++) { + const telecom = practitionerResource.telecom[i]; + if (telecom.system === "phone") { + var primaryTelephone = doc.createElement("PrimaryTelephone"); + xmlAddTextNode(doc, primaryTelephone, "Number", telecom.value); + communicationNumbers.appendChild(primaryTelephone); + } else if (telecom.system === "email") { + xmlAddTextNode(doc, communicationNumbers, "ElectronicMail", telecom.value); + } + } + nonVeterinarian.appendChild(communicationNumbers) + + prescriber.appendChild(nonVeterinarian); + return prescriber; + } + + function quantityUnitOfMeasureFromDrugFormCode(dispenseRequest) { + console.log(dispenseRequest); + // Switch on Orderable Drug Form codes from: + // https://terminology.hl7.org/5.0.0/CodeSystem-v3-orderableDrugForm.html + // Return NCPDP QuantityUnitOfMeasure + console.log(dispenseRequest.quantity.system); + console.log(dispenseRequest.quantity.system.toLowerCase()); + if (dispenseRequest.quantity.system.toLowerCase().endsWith("v3-orderableDrugForm".toLowerCase())) { + // is a subset of the codes, not a complete list + switch (dispenseRequest.quantity.code.toUpperCase()) { + case "APPFUL": // Applicatorful + case "FOAMAPL": // Foam with Applicator + case "VAGFOAMAPL": // Vaginal Foam with Applicator + case "VAGCRMAPL": // Vaginal Cream with Applicator + case "OINTAPL": // Ointment with Applicator + case "VAGOINTAPL": // Vaginal Ointment with Applicator + case "GELAPL": // Gel with Applicator + case "VGELAPL": // Vaginal Gel with Applicator + return "C62412"; // Applicator + //case "": + // return "C54564" // Blister + case "CAPLET": // Caplet + return "C64696"; // Caplet + case 'CAP': // Capsule + return "C48480"; // Capsule + //case "": + // return "C64933" // Each + //case "": + // return "C53499" // Film + //case "": + // return "C48155" // Gram + case "GUM": // Chewing Gum + return "C69124"; // Gum + //case "": + // return "C48499" // Implant + //case "": + // return "C62276" // Insert + //case "": + // return "C48504" // Kit + //case "": + // return "C120263" // Lancet + case "ORTROCHE": // Lozenge/Oral Troche + return "C48506"; // Lozenge + //case "": + // return "C28254" // Milliliter + //case "": + // return "C48521" // Packet + case "PAD": // Pad + case "MEDPAD": // Medicated Pad + return "C65032"; // Pad + case "PATCH": // Patch + case "TPATCH": // Transdermal Patch + case "TPATH16": // 16 Hour Transdermal Patch + case "TPATH24": // 24 Hour Transdermal Patch + case "TPATH2WK": // Biweekly Transdermal Patch + case "TPATH72": // 72 Hour Transdermal Patch + case "TPATHWK": // Weekly Hour Transdermal Patch + return "C48524"; // Patch + //case "": + // return "C120216" // Pen Needle + //case "": + // return "C62609" // Ring + // case "": + // return "C53502" // Sponge + //case "": + // return "C53503" // Stick + //case "": + // return "C48538" // Strip + case "SUPP": // Suppository + case "RECSUPP": // Rectal Suppository + case "URETHSUPP": // Urethral Suppository + case "VAGSUPP": // Vaginal Suppository + return "C48539"; // Suppository + case "SWAB": // Swab + case "MEDSWAB": // Medicated Swab + return "C53504"; // Swab + case "TAB": // Tablet + case "ORTAB": // Oral Tablet + case "BUCTAB": // Buccal Tablet + case "SRBUCTAB": // Sustained Release Buccal Tablet + case "CHEWTAB": // Chewable Tablet + case "CPTAB": // Coated Particles Tablet + case "DISINTTAB": // Disintegrating Tablet + case "DRTAB": // Delayed Release Tablet + case "ECTAB": // Enteric Coated Tablet + case "ERECTTAB": // Extended Release Enteric Coated Tablet + case "ERTAB": // Extended Release Tablet + case "ERTAB12": // 12 Hour Extended Release Tablet + case "ERTAB24": // 24 Hour Extended Release Tablet + case "SLTAB": // Sublingual Tablet + case "VAGTAB": // Vaginal Tablet + return "C48542"; // Tablet + //case "": + // return "C48548" // Troche + case "WAFER": // Wafer + return "C48552"; // Wafer + default: + return "C38046"; // Unspecified + } + } + return "C38046"; // unspecified + } + + function buildNewRxMedication(doc, medicationRequestResource) { + // console.log(medicationRequestResource); + var medicationPrescribed = doc.createElement("MedicationPrescribed"); + + // Medication Product + var drugCoded = doc.createElement("DrugCoded"); + + // loop through the coding values and find the ndc code and the rxnorm code + const medicationCodingList = medicationRequestResource.medicationCodeableConcept.coding; + for (let i = 0; i < medicationCodingList.length; i++) { + const coding = medicationCodingList[i]; + const system = coding.system.toLowerCase(); + + if (system.endsWith("rxnorm")) { + // Medication Drug Description + xmlAddTextNode(doc, medicationPrescribed, "DrugDescription", coding.display); + + } else if (system.endsWith("ndc")) { + // Medication Drug Code + var productCode = doc.createElement("ProductCode"); + xmlAddTextNode(doc, productCode, "Code", coding.code); + xmlAddTextNode(doc, productCode, "Qualifier", "ND"); // National Drug Code (NDC) + drugCoded.appendChild(productCode); + } + } + + medicationPrescribed.appendChild(drugCoded); + + // Medication Quantity + const dispenseRequest = medicationRequestResource.dispenseRequest; + var quantity = doc.createElement("Quantity"); + xmlAddTextNode(doc, quantity, "Value", dispenseRequest.quantity.value); + xmlAddTextNode(doc, quantity, "CodeListQualifier", 38); // Original Quantity + var quantityUnitOfMeasure = doc.createElement("QuantityUnitOfMeasure"); + xmlAddTextNode(doc, quantityUnitOfMeasure, "Code", quantityUnitOfMeasureFromDrugFormCode(dispenseRequest)); + quantity.appendChild(quantityUnitOfMeasure); + medicationPrescribed.appendChild(quantity); + + // Medication Written Date + var writtenDate = doc.createElement("WrittenDate"); + xmlAddTextNode(doc, writtenDate, "Date", medicationRequestResource.authoredOn); + medicationPrescribed.appendChild(writtenDate); + + // Medication Substitutions (0 - None) + xmlAddTextNode(doc, medicationPrescribed, "Substitutions", 0); + + // Medication NumberOfRefills (0 - None) + xmlAddTextNode(doc, medicationPrescribed, "NumberOfRefills", dispenseRequest.numberOfRepeatsAllowed); + + // Medication Sig + var sig = doc.createElement("Sig"); + xmlAddTextNode(doc, sig, "SigText", medicationRequestResource.dosageInstruction[0].text); + medicationPrescribed.appendChild(sig); + + // Medication REMS + // A - Prescriber has checked REMS and the prescriber's actions have been completed. + // B - Prescriber has checked REMS and the prescriber's actions are not yet completed. + // N - Prescriber has not checked REMS. + xmlAddTextNode(doc, medicationPrescribed, "PrescriberCheckedREMS", "B"); + + return medicationPrescribed; + } + + export default function buildNewRxRequest(patientResource, practitionerResource, medicationRequestResource) { + // console.log(medicationRequestResource); + var doc = document.implementation.createDocument("", "", null); + var message = doc.createElement("Message"); + + // Header + var header = doc.createElement("Header"); + // generate the message id (just get the milliseconds since epoch and use that) + const d1 = new Date(); + const messageIdValue = d1.getTime(); + // console.log(messageIdValue); + xmlAddTextNode(doc, header, "MessageID", messageIdValue); + message.appendChild(header); + + // Body + var body = doc.createElement("Body"); + var newRx = doc.createElement("NewRx"); + + // Patient + newRx.appendChild(buildNewRxPatient(doc, patientResource)); + + // Prescriber + newRx.appendChild(buildNewRxPrescriber(doc, practitionerResource)); + + // Medication + newRx.appendChild(buildNewRxMedication(doc, medicationRequestResource)); + + body.appendChild(newRx); + message.appendChild(body); + + doc.appendChild(message); + + return doc; + } \ No newline at end of file diff --git a/src/util/buildScript.2022071.js b/src/util/buildScript.2022071.js new file mode 100644 index 00000000..8f652db4 --- /dev/null +++ b/src/util/buildScript.2022071.js @@ -0,0 +1,313 @@ +/* 2022071 NCPDP SCRIPT Support */ + + function xmlAddTextNode(xmlDoc, parent, sectionName, value) { + var section = xmlDoc.createElement(sectionName); + var textNode = xmlDoc.createTextNode(value); + section.appendChild(textNode); + parent.appendChild(section); + } + + function buildNewRxName(doc, nameResource) { + var names = doc.createElement("Names"); + var name = doc.createElement("Name"); + xmlAddTextNode(doc, name, "LastName", nameResource.family); + xmlAddTextNode(doc, name, "FirstName", nameResource.given[0]); + names.appendChild(name); + return names; + } + + function buildNewRxAddress(doc, addressResource) { + // console.log(addressResource); + var address = doc.createElement("Address"); + xmlAddTextNode(doc, address, "AddressLine1", addressResource.line[0]); + xmlAddTextNode(doc, address, "City", addressResource.city); + xmlAddTextNode(doc, address, "StateProvince", addressResource.state); + xmlAddTextNode(doc, address, "PostalCode", addressResource.postalCode); + xmlAddTextNode(doc, address, "Country", "US"); // assume US for now + return address; + } + + function buildNewRxPatient(doc, patientResource) { + // console.log(patientResource); + var patient = doc.createElement("Patient"); + var humanPatient = doc.createElement("HumanPatient"); + + // Patient Name + const patientNameResource = patientResource.name[0]; + humanPatient.appendChild(buildNewRxName(doc, patientNameResource)); + + // Patient Gender and Sex + var genderAndSex = doc.createElement("GenderAndSex"); + var gender = "U"; // unknown + var patientResourceGender = patientResource.gender.toLowerCase(); + if (patientResourceGender === "male") { + gender = "M"; // male + } else if (patientResourceGender === "female") { + gender = "F"; // female + } else if (patientResourceGender === "other") { + gender = "N"; // non-binary + } + xmlAddTextNode(doc, genderAndSex, "AdministrativeGender", gender); + humanPatient.appendChild(genderAndSex); + + // Patient Birth Date + var dateOfBirth = doc.createElement("DateOfBirth"); + xmlAddTextNode(doc, dateOfBirth, "Date", patientResource.birthDate); + humanPatient.appendChild(dateOfBirth); + + // Patient Address + const patientAddressResource = patientResource.address[0]; + humanPatient.appendChild(buildNewRxAddress(doc, patientAddressResource)); + + patient.appendChild(humanPatient); + return patient; + } + + function buildNewRxPrescriber(doc, practitionerResource) { + // console.log(practitionerResource); + var prescriber = doc.createElement("Prescriber"); + var nonVeterinarian = doc.createElement("NonVeterinarian"); + + // Prescriber Identifier + for (let i = 0; i < practitionerResource.identifier.length; i++) { + let id = practitionerResource.identifier[i]; + if ((id.system) && (id.system.includes("us-npi"))) { + var identification = doc.createElement("Identification"); + xmlAddTextNode(doc, identification, "NPI", id.value); + nonVeterinarian.appendChild(identification); + } + } + + // Prescriber Name + const practitionerNameResource = practitionerResource.name[0]; + nonVeterinarian.appendChild(buildNewRxName(doc, practitionerNameResource)); + + // Prescriber Address + const practitionerAddressResource = practitionerResource.address[0]; + nonVeterinarian.appendChild(buildNewRxAddress(doc, practitionerAddressResource)); + + // Prescriber Phone Number and Email + var communicationNumbers = doc.createElement("CommunicationNumbers"); + for (let i = 0; i < practitionerResource.telecom.length; i++) { + const telecom = practitionerResource.telecom[i]; + if (telecom.system === "phone") { + var primaryTelephone = doc.createElement("PrimaryTelephone"); + xmlAddTextNode(doc, primaryTelephone, "Number", telecom.value); + communicationNumbers.appendChild(primaryTelephone); + } else if (telecom.system === "email") { + xmlAddTextNode(doc, communicationNumbers, "ElectronicMail", telecom.value); + } + } + nonVeterinarian.appendChild(communicationNumbers) + + prescriber.appendChild(nonVeterinarian); + return prescriber; + } + + function quantityUnitOfMeasureFromDrugFormCode(dispenseRequest) { + console.log(dispenseRequest); + // Switch on Orderable Drug Form codes from: + // https://terminology.hl7.org/5.0.0/CodeSystem-v3-orderableDrugForm.html + // Return NCPDP QuantityUnitOfMeasure + console.log(dispenseRequest.quantity.system); + console.log(dispenseRequest.quantity.system.toLowerCase()); + if (dispenseRequest.quantity.system.toLowerCase().endsWith("v3-orderableDrugForm".toLowerCase())) { + // is a subset of the codes, not a complete list + switch (dispenseRequest.quantity.code.toUpperCase()) { + case "APPFUL": // Applicatorful + case "FOAMAPL": // Foam with Applicator + case "VAGFOAMAPL": // Vaginal Foam with Applicator + case "VAGCRMAPL": // Vaginal Cream with Applicator + case "OINTAPL": // Ointment with Applicator + case "VAGOINTAPL": // Vaginal Ointment with Applicator + case "GELAPL": // Gel with Applicator + case "VGELAPL": // Vaginal Gel with Applicator + return "C62412"; // Applicator + //case "": + // return "C54564" // Blister + case "CAPLET": // Caplet + return "C64696"; // Caplet + case 'CAP': // Capsule + return "C48480"; // Capsule + //case "": + // return "C64933" // Each + //case "": + // return "C53499" // Film + //case "": + // return "C48155" // Gram + case "GUM": // Chewing Gum + return "C69124"; // Gum + //case "": + // return "C48499" // Implant + //case "": + // return "C62276" // Insert + //case "": + // return "C48504" // Kit + //case "": + // return "C120263" // Lancet + case "ORTROCHE": // Lozenge/Oral Troche + return "C48506"; // Lozenge + //case "": + // return "C28254" // Milliliter + //case "": + // return "C48521" // Packet + case "PAD": // Pad + case "MEDPAD": // Medicated Pad + return "C65032"; // Pad + case "PATCH": // Patch + case "TPATCH": // Transdermal Patch + case "TPATH16": // 16 Hour Transdermal Patch + case "TPATH24": // 24 Hour Transdermal Patch + case "TPATH2WK": // Biweekly Transdermal Patch + case "TPATH72": // 72 Hour Transdermal Patch + case "TPATHWK": // Weekly Hour Transdermal Patch + return "C48524"; // Patch + //case "": + // return "C120216" // Pen Needle + //case "": + // return "C62609" // Ring + // case "": + // return "C53502" // Sponge + //case "": + // return "C53503" // Stick + //case "": + // return "C48538" // Strip + case "SUPP": // Suppository + case "RECSUPP": // Rectal Suppository + case "URETHSUPP": // Urethral Suppository + case "VAGSUPP": // Vaginal Suppository + return "C48539"; // Suppository + case "SWAB": // Swab + case "MEDSWAB": // Medicated Swab + return "C53504"; // Swab + case "TAB": // Tablet + case "ORTAB": // Oral Tablet + case "BUCTAB": // Buccal Tablet + case "SRBUCTAB": // Sustained Release Buccal Tablet + case "CHEWTAB": // Chewable Tablet + case "CPTAB": // Coated Particles Tablet + case "DISINTTAB": // Disintegrating Tablet + case "DRTAB": // Delayed Release Tablet + case "ECTAB": // Enteric Coated Tablet + case "ERECTTAB": // Extended Release Enteric Coated Tablet + case "ERTAB": // Extended Release Tablet + case "ERTAB12": // 12 Hour Extended Release Tablet + case "ERTAB24": // 24 Hour Extended Release Tablet + case "SLTAB": // Sublingual Tablet + case "VAGTAB": // Vaginal Tablet + return "C48542"; // Tablet + //case "": + // return "C48548" // Troche + case "WAFER": // Wafer + return "C48552"; // Wafer + default: + return "C38046"; // Unspecified + } + } + return "C38046"; // unspecified + } + + function buildNewRxMedication(doc, medicationRequestResource) { + // console.log(medicationRequestResource); + var medicationPrescribed = doc.createElement("MedicationPrescribed"); + + // Medication Product + var product = doc.createElement("Product"); + var drugCoded = doc.createElement("DrugCoded"); + + // loop through the coding values and find the ndc code and the rxnorm code + const medicationCodingList = medicationRequestResource.medicationCodeableConcept.coding; + for (let i = 0; i < medicationCodingList.length; i++) { + const coding = medicationCodingList[i]; + const system = coding.system.toLowerCase(); + + if (system.endsWith("rxnorm")) { + // Medication Drug Description + xmlAddTextNode(doc, medicationPrescribed, "DrugDescription", coding.display); + + // Medication Drug Code + var productCode = doc.createElement("ProductCode"); + xmlAddTextNode(doc, productCode, "Code", coding.code); + xmlAddTextNode(doc, productCode, "Qualifier", "SBD"); // RxNorm Semantic Branded Drug + drugCoded.appendChild(productCode); + + } else if (system.endsWith("ndc")) { + // Medication NDC + xmlAddTextNode(doc, drugCoded, "NDC", coding.code); // 10-digit number + } + } + + product.appendChild(drugCoded); + medicationPrescribed.appendChild(product); + + // Medication Quantity + const dispenseRequest = medicationRequestResource.dispenseRequest; + var quantity = doc.createElement("Quantity"); + xmlAddTextNode(doc, quantity, "Value", dispenseRequest.quantity.value); + xmlAddTextNode(doc, quantity, "CodeListQualifier", 38); // Original Quantity + var quantityUnitOfMeasure = doc.createElement("QuantityUnitOfMeasure"); + xmlAddTextNode(doc, quantityUnitOfMeasure, "Code", quantityUnitOfMeasureFromDrugFormCode(dispenseRequest)); + quantity.appendChild(quantityUnitOfMeasure); + medicationPrescribed.appendChild(quantity); + + // Medication Written Date + var writtenDate = doc.createElement("WrittenDate"); + xmlAddTextNode(doc, writtenDate, "Date", medicationRequestResource.authoredOn); + medicationPrescribed.appendChild(writtenDate); + + // Medication Substitutions (0 - None) + var substitutions = doc.createElement("Substitutions"); + xmlAddTextNode(doc, substitutions, "Substitutions", 0); + medicationPrescribed.appendChild(substitutions); + + // Medication NumberOfRefills (0 - None) + xmlAddTextNode(doc, medicationPrescribed, "NumberOfRefills", dispenseRequest.numberOfRepeatsAllowed); + + // Medication Sig + var sig = doc.createElement("Sig"); + xmlAddTextNode(doc, sig, "SigText", medicationRequestResource.dosageInstruction[0].text); + medicationPrescribed.appendChild(sig); + + // Medication REMS + // A - Prescriber has checked REMS and the prescriber's actions have been completed. + // B - Prescriber has checked REMS and the prescriber's actions are not yet completed. + // N - Prescriber has not checked REMS. + xmlAddTextNode(doc, medicationPrescribed, "PrescriberCheckedREMS", "B"); + + return medicationPrescribed; + } + + export default function buildNewRxRequest(patientResource, practitionerResource, medicationRequestResource) { + // console.log(medicationRequestResource); + var doc = document.implementation.createDocument("", "", null); + var message = doc.createElement("Message"); + + // Header + var header = doc.createElement("Header"); + // generate the message id (just get the milliseconds since epoch and use that) + const d1 = new Date(); + const messageIdValue = d1.getTime(); + // console.log(messageIdValue); + xmlAddTextNode(doc, header, "MessageID", messageIdValue); + message.appendChild(header); + + // Body + var body = doc.createElement("Body"); + var newRx = doc.createElement("NewRx"); + + // Patient + newRx.appendChild(buildNewRxPatient(doc, patientResource)); + + // Prescriber + newRx.appendChild(buildNewRxPrescriber(doc, practitionerResource)); + + // Medication + newRx.appendChild(buildNewRxMedication(doc, medicationRequestResource)); + + body.appendChild(newRx); + message.appendChild(body); + + doc.appendChild(message); + + return doc; + } \ No newline at end of file From 21f678dd3f7e60b49555ac6fc3448f90cbccc249 Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Fri, 3 Feb 2023 12:15:18 -0500 Subject: [PATCH 2/3] Remove extra logging. --- src/util/buildScript.2017071.js | 3 --- src/util/buildScript.2022071.js | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/util/buildScript.2017071.js b/src/util/buildScript.2017071.js index 284ac03b..62ca37df 100644 --- a/src/util/buildScript.2017071.js +++ b/src/util/buildScript.2017071.js @@ -101,12 +101,9 @@ } function quantityUnitOfMeasureFromDrugFormCode(dispenseRequest) { - console.log(dispenseRequest); // Switch on Orderable Drug Form codes from: // https://terminology.hl7.org/5.0.0/CodeSystem-v3-orderableDrugForm.html // Return NCPDP QuantityUnitOfMeasure - console.log(dispenseRequest.quantity.system); - console.log(dispenseRequest.quantity.system.toLowerCase()); if (dispenseRequest.quantity.system.toLowerCase().endsWith("v3-orderableDrugForm".toLowerCase())) { // is a subset of the codes, not a complete list switch (dispenseRequest.quantity.code.toUpperCase()) { diff --git a/src/util/buildScript.2022071.js b/src/util/buildScript.2022071.js index 8f652db4..3ec9c2b5 100644 --- a/src/util/buildScript.2022071.js +++ b/src/util/buildScript.2022071.js @@ -105,12 +105,9 @@ } function quantityUnitOfMeasureFromDrugFormCode(dispenseRequest) { - console.log(dispenseRequest); // Switch on Orderable Drug Form codes from: // https://terminology.hl7.org/5.0.0/CodeSystem-v3-orderableDrugForm.html // Return NCPDP QuantityUnitOfMeasure - console.log(dispenseRequest.quantity.system); - console.log(dispenseRequest.quantity.system.toLowerCase()); if (dispenseRequest.quantity.system.toLowerCase().endsWith("v3-orderableDrugForm".toLowerCase())) { // is a subset of the codes, not a complete list switch (dispenseRequest.quantity.code.toUpperCase()) { From 51296ad5561293ac30b4036aa592937a6b97a00a Mon Sep 17 00:00:00 2001 From: Patrick LaRocque Date: Thu, 9 Feb 2023 11:38:22 -0500 Subject: [PATCH 3/3] Update the PIMS endpoint. --- src/properties.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/properties.json b/src/properties.json index e9c34691..7295b544 100644 --- a/src/properties.json +++ b/src/properties.json @@ -14,5 +14,5 @@ "alt_drug": true, "launch_url": "http://localhost:3005/launch", "response_expiration_days": 30, - "pims_server": "http://localhost:3010" + "pims_server": "http://localhost:5051/doctorOrders/api/addRx" }