Skip to content

Commit

Permalink
Create new mongoose model for NCPDP NewRx and POST to EHR from update…
Browse files Browse the repository at this point in the history
…Rx/:id/pickedUp
  • Loading branch information
jtquach1 committed Feb 6, 2024
1 parent d67d0ca commit 22d9740
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 45 deletions.
4 changes: 2 additions & 2 deletions backend/env.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
"type": "boolean",
"default": false
},
"EHR_URL": {
"EHR_RXFILL_URL": {
"type": "string",
"default": "http://localhost:8080/test-ehr/"
"default": "http://localhost:8080/test-ehr/script/rxfill"
}
}
8 changes: 8 additions & 0 deletions backend/src/database/schemas/newRx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Schema, model } from 'mongoose';
const schema = new Schema({
prescriberOrderNumber: String,
serializedJSON: String
});

schema.index({ prescriberOrderNumber: 1 }, { unique: true });
export const NewRx = model('NewRx', schema);
156 changes: 127 additions & 29 deletions backend/src/ncpdpScriptBuilder/buildScript.v2017071.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
/* NCPDP SCRIPT v2017071 Support */
import { XMLBuilder } from 'fast-xml-parser';
import { v4 as uuidv4 } from 'uuid';

const MOCK_VALUE = 'MOCK_VALUE';
const PICKED_UP = 'Picked up';

const XML_BUILDER_OPTIONS = {
ignoreAttributes: false,
attributeNamePrefix: '@@',
format: true,
oneListGroup: 'true'
};

export function buildRxStatus(newOrder) {
var time = new Date();
var rxStatus = {
const time = new Date();
const rxStatus = {
Message: [
{
Header: [
Expand Down Expand Up @@ -46,43 +57,130 @@ export function buildRxStatus(newOrder) {
}
]
};
const options = {
ignoreAttributes: false,
attributeNamePrefix: '@@',
format: true,
oneListGroup: 'true'
};
const builder = new XMLBuilder(options);
var RxStatus = builder.build(rxStatus);

return RxStatus;
const builder = new XMLBuilder(XML_BUILDER_OPTIONS);
return builder.build(rxStatus);
}

export const buildRxFill = caseNumber => {
export const buildRxFill = newRx => {
const { Message } = JSON.parse(newRx.serializedJSON);
const { Header, Body } = Message;
const time = new Date();
const message = {
Message: {
Header: {
// To: 'MOCK_VALUE',
// From: 'MOCK_VALUE',
// MessageID: 'MOCK_VALUE',
RelatesToMessageID: caseNumber, // use Zach's stuff above
SentTime: time,
// RxReferenceNumber: 'MOCK_VALUE',
PrescriberOrderNumber: 'GENERATE_FROM_HAPI_FHIR_EHR_MEDICATION_REQUEST_ID'
},
Body: {
RxFill: {
FillStatus: {
Dispensed: {
Note: 'PROFILE MEDICATION APPROPRIATE FOR ADMINISTRATION',
ReasonCode: 'DH'
Header: [
{
To: {
'#text': Header.From._,
'@@Qualifier': Header.From.$.Qualifier
}
},
{
From: {
'#text': Header.To._,
'@@Qualifier': Header.To.$.Qualifier
}
},
{ MessageID: uuidv4() }, // new randomly generated value, something different from the NewRx
{ RelatesToMessageID: Header.MessageID },
{ SentTime: time },
{ PrescriberOrderNumber: Header.PrescriberOrderNumber }
],
Body: [
{
RxFill: {
FillStatus: {
Dispensed: {
Note: PICKED_UP
}
},
Patient: {
HumanPatient: {
Name: {
LastName: Body.NewRx.Patient.HumanPatient.Name.LastName,
FirstName: Body.NewRx.Patient.HumanPatient.Name.FirstName
},
Gender: Body.NewRx.Patient.HumanPatient.Gender,
DateOfBirth: { Date: Body.NewRx.Patient.HumanPatient.DateOfBirth.Date },
Address: {
AddressLine1: Body.NewRx.Patient.HumanPatient.Address.AddressLine1,
City: Body.NewRx.Patient.HumanPatient.Address.City,
StateProvince: Body.NewRx.Patient.HumanPatient.Address.StateProvince,
PostalCode: Body.NewRx.Patient.HumanPatient.Address.PostalCode,
Country: Body.NewRx.Patient.HumanPatient.Address.Country
}
}
},
Pharmacy: {
Identification: {
NCPDPID: MOCK_VALUE,
NPI: MOCK_VALUE
},
BusinessName: MOCK_VALUE,
Address: {
AddressLine1: MOCK_VALUE,
City: MOCK_VALUE,
StateProvince: MOCK_VALUE,
PostalCode: MOCK_VALUE,
Country: MOCK_VALUE
},
CommunicationNumbers: {
PrimaryTelephone: {
Number: MOCK_VALUE
}
}
},
Prescriber: {
NonVeterinarian: {
Identification: Body.NewRx.Prescriber.NonVeterinarian.Identification.NPI
},
Name: {
LastName: Body.NewRx.Prescriber.NonVeterinarian.Name.LastName,
FirstName: Body.NewRx.Prescriber.NonVeterinarian.Name.FirstName
},
Address: {
AddressLine1: Body.NewRx.Prescriber.NonVeterinarian.Address.AddressLine1,
City: Body.NewRx.Prescriber.NonVeterinarian.Address.City,
StateProvince: Body.NewRx.Prescriber.NonVeterinarian.Address.StateProvince,
PostalCode: Body.NewRx.Prescriber.NonVeterinarian.Address.PostalCode,
Country: Body.NewRx.Prescriber.NonVeterinarian.Address.Country
},
CommunicationNumbers: {
PrimaryTelephone: {
Number:
Body.NewRx.Prescriber.NonVeterinarian.CommunicationNumbers.PrimaryTelephone
.Number
},
ElectronicMail:
Body.NewRx.Prescriber.NonVeterinarian.CommunicationNumbers.ElectronicMail
}
},
MedicationPrescribed: {
DrugDescription: Body.NewRx.MedicationPrescribed.DrugDescription,
DrugCoded: {
ProductCode: {
Code: Body.NewRx.MedicationPrescribed.DrugCoded.ProductCode.Code,
Qualifier: Body.NewRx.MedicationPrescribed.DrugCoded.ProductCode.Qualifier
}
},
Quantity: {
Value: Body.NewRx.MedicationPrescribed.Quantity.Value,
CodeListQuantifier: Body.NewRx.MedicationPrescribed.Quantity.CodeListQuantifier,
QuantityUnitOfMeasure: {
Code: Body.NewRx.MedicationPrescribed.Quantity.QuantityUnitOfMeasure.Code
},
WrittenDate: { Date: Body.NewRx.MedicationPrescribed.WrittenDate.Date },
Substitutions: Body.NewRx.MedicationPrescribed.Substitutions,
NumberOfRefills: Body.NewRx.MedicationPrescribed.NumberOfRefills,
Sig: { SigText: Body.NewRx.MedicationPrescribed.Sig.SigText },
PrescriberCheckedREMS: Body.NewRx.MedicationPrescribed.PrescriberCheckedREMS
}
}
}
}
}
]
}
};
const builder = new XMLBuilder({ oneListGroup: 'true' });
const builder = new XMLBuilder(XML_BUILDER_OPTIONS);
return builder.build(message);
};
51 changes: 37 additions & 14 deletions backend/src/routes/doctorOrders.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import axios from 'axios';
import bodyParser from 'body-parser';
import bpx from 'body-parser-xml';
import env from 'var';
import { buildRxStatus } from '../ncpdpScriptBuilder/buildScript.v2017071.js';
import { buildRxStatus, buildRxFill } from '../ncpdpScriptBuilder/buildScript.v2017071.js';
import { NewRx } from '../database/schemas/newRx.js';

bpx(bodyParser);
router.use(
Expand Down Expand Up @@ -38,12 +39,24 @@ router.get('/api/getRx', async (req, res) => {
*/
router.post('/api/addRx', async (req, res) => {
// Parsing incoming NCPDP SCRIPT XML to doctorOrder JSON
const newOrder = parseNCPDPScript(req.body);
const newRxMessageConvertedToJSON = req.body;
const newOrder = parseNCPDPScript(newRxMessageConvertedToJSON);

try {
await newOrder.save(); //updating the object or adding to it
const newRx = new NewRx({
prescriberOrderNumber: newRxMessageConvertedToJSON.Message.Header.PrescriberOrderNumber,
serializedJSON: JSON.stringify(newRxMessageConvertedToJSON)
});
await newRx.save();
} catch (error) {
console.log('ERROR! duplicate found, prescription already exists');
console.log('Could not store the NewRx', error);
return error;
}

try {
await newOrder.save();
} catch (error) {
console.log('ERROR! duplicate found, prescription already exists', error);
return error;
}

Expand All @@ -68,7 +81,7 @@ router.patch('/api/updateRx/:id', async (req, res) => {
const order = await doctorOrder.findById(req.params.id).exec();
console.log('found by id!');

console.log('order', order);
console.log('Current order', order);

// Reaching out to REMS Admin finding by pt name and drug name
// '/etasu/met/patient/:patientFirstName/:patientLastName/:patientDOB/drug/:drugName',
Expand Down Expand Up @@ -103,19 +116,16 @@ router.patch('/api/updateRx/:id', async (req, res) => {
}
);

// Reach out to test-ehr to update dispense status as XML
const RxFillStatus = await axios.post(`${env.EHR_URL}`);

console.log(newOrder, 'New order');
res.send(newOrder);
console.log('Updated order', newOrder);
} catch (error) {
console.log(error, 'Error');
return error;
}
});

/**
* Route: 'doctorOrders//api/updateRx/:id/pickedUp'
* Route: 'doctorOrders/api/updateRx/:id/pickedUp'
* Description : 'Updates prescription dispense status based on mongo id to be picked up '
*/
router.patch('/api/updateRx/:id/pickedUp', async (req, res) => {
Expand All @@ -128,13 +138,24 @@ router.patch('/api/updateRx/:id/pickedUp', async (req, res) => {
}
);
res.send(newOrder);

// Reach out to EHR to update dispense status as XML
const newRx = await NewRx.findOne({
prescriberOrderNumber: newOrder.prescriberOrderNumber
});
const rxFill = buildRxFill(newRx);
console.log('RxFill', rxFill);
const status = await axios.post(env.EHR_RXFILL_URL, rxFill, {
headers: {
Accept: 'application/xml', // Expect that the Status that the EHR returns back is in XML
'Content-Type': 'application/xml' // Tell the EHR that the RxFill is in XML
}
});
console.log('Sent RxFill status to EHR', status);
} catch (error) {
console.log(error);
console.log('ERROR! Could not find id');
return error;
}

// console.log(newOrder);
});

/**
Expand Down Expand Up @@ -175,6 +196,8 @@ router.get('/api/getRx/:patientFirstName/:patientLastName/:patientDOB', async (r
router.delete('/api/deleteAll', async (req, res) => {
await doctorOrder.deleteMany({});
console.log('All doctorOrders deleted in PIMS!');
await NewRx.deleteMany({});
console.log("All NewRx's deleted in PIMS!");
res.send([]);
});

Expand Down Expand Up @@ -215,7 +238,7 @@ function parseNCPDPScript(newRx) {
drugNdcCode: newRx.Message.Body.NewRx.MedicationPrescribed.DrugCoded.ProductCode.Code,
rxDate: newRx.Message.Body.NewRx.MedicationPrescribed.WrittenDate.Date,
drugPrice: 200, // Add later?
quanitities: newRx.Message.Body.NewRx.MedicationPrescribed.Quantity.Value,
quantity: newRx.Message.Body.NewRx.MedicationPrescribed.Quantity.Value,
total: 1800,
pickupDate: 'Tue Dec 13 2022', // Add later?
dispenseStatus: 'Pending',
Expand Down

0 comments on commit 22d9740

Please sign in to comment.