Skip to content
6 changes: 5 additions & 1 deletion backend/src/database/schemas/doctorOrderSchemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export const orderSchema = new mongoose.Schema({
total: Number,
pickupDate: String,
dispenseStatus: String,
authorizationNumber: String,
authorizationExpiration: String,
denialReasonCode: String,
remsNote: String,
metRequirements: [
{
name: String,
Expand All @@ -44,4 +48,4 @@ export const orderSchema = new mongoose.Schema({
// Compound index is used to prevent duplicates based off of the given parameters
orderSchema.index({ simpleDrugName: 1, patientName: 1 }, { unique: true }); // schema level

export const doctorOrder = mongoose.model('doctorOrder', orderSchema);
export const doctorOrder = mongoose.model('doctorOrder', orderSchema);
257 changes: 247 additions & 10 deletions backend/src/ncpdpScriptBuilder/buildScript.v2017071.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* NCPDP SCRIPT v2017071 Support */
/* NCPDP SCRIPT v2017071 Support - Enhanced for Full REMS Compliance */
import { XMLBuilder } from 'fast-xml-parser';
import { v4 as uuidv4 } from 'uuid';

Expand All @@ -12,6 +12,9 @@ const XML_BUILDER_OPTIONS = {
oneListGroup: 'true'
};

/**
* Build base NCPDP message structure
*/
function buildMessage(inputMessage, body) {
const { Message } = inputMessage;
const { Header, Body } = Message;
Expand All @@ -33,8 +36,10 @@ function buildMessage(inputMessage, body) {
}
},
{
Message:
'NewRx Request Received For: ' + Body.NewRx.MedicationPrescribed.DrugDescription
MessageID: Header.MessageID
},
{
Message: 'NewRx Request Received For: ' + Body.NewRx.MedicationPrescribed.DrugDescription
},
{ RelatesToMessageID: Header.MessageID },
{ SentTime: time.toISOString() },
Expand All @@ -49,12 +54,15 @@ function buildMessage(inputMessage, body) {
return message;
}

/**
* Build NCPDP Status message (success response)
*/
export function buildRxStatus(newRxMessageConvertedToJSON) {
const body = [
{
Status: [
{
Code: '000' // Placeholder: This is dependent on individual pharmacy
Code: '000'
}
]
}
Expand All @@ -64,13 +72,16 @@ export function buildRxStatus(newRxMessageConvertedToJSON) {
return builder.build(rxStatus);
}

/**
* Build NCPDP Error message
*/
export function buildRxError(newRxMessageConvertedToJSON, errorMessage) {
const body = [
{
Error: [
{
Code: 900, // Transaction was rejected
DescriptionCode: 1000, // Unable to identify based on information submitted
Code: 900,
DescriptionCode: 1000,
Description: errorMessage
}
]
Expand All @@ -81,13 +92,56 @@ export function buildRxError(newRxMessageConvertedToJSON, errorMessage) {
return builder.build(rxStatus);
}

/**
* Build NCPDP RxFill message
* Per NCPDP spec: Sent when medication is dispensed/picked up
* Must be sent to both EHR and REMS Admin for REMS drugs
*/
export const buildRxFill = newRx => {
const { Message } = JSON.parse(newRx.serializedJSON);
const { Header, Body } = Message;
console.log('Message', Message);
console.log('Building RxFill per NCPDP SCRIPT');
const time = new Date();

// Extract medication data from NewRx
const medicationPrescribed = Body.NewRx.MedicationPrescribed;
const drugCoded = medicationPrescribed.DrugCoded;

const medicationDispensed = {
DrugDescription: medicationPrescribed.DrugDescription,
DrugCoded: {
ProductCode: drugCoded.ProductCode ? {
Code: drugCoded.ProductCode.Code,
Qualifier: drugCoded.ProductCode.Qualifier
} : undefined,
Strength: drugCoded.Strength ? {
StrengthValue: drugCoded.Strength.StrengthValue,
StrengthForm: drugCoded.Strength.StrengthForm,
StrengthUnitOfMeasure: drugCoded.Strength.StrengthUnitOfMeasure
} : undefined
},
Quantity: {
Value: medicationPrescribed.Quantity.Value,
CodeListQualifier: medicationPrescribed.Quantity.CodeListQualifier || '87',
QuantityUnitOfMeasure: medicationPrescribed.Quantity.QuantityUnitOfMeasure
},
DaysSupply: medicationPrescribed.DaysSupply,
WrittenDate: medicationPrescribed.WrittenDate,
Substitutions: medicationPrescribed.Substitutions?.Substitutions ||
medicationPrescribed.Substitutions || '0',
NumberOfRefills: medicationPrescribed.Refills?.Quantity ||
medicationPrescribed.NumberOfRefills || 0,
Sig: medicationPrescribed.Sig
};

const message = {
Message: {
'@@DatatypesVersion': '20170715',
'@@TransportVersion': '20170715',
'@@TransactionDomain': 'SCRIPT',
'@@TransactionVersion': '20170715',
'@@StructuresVersion': '20170715',
'@@ECLVersion': '20170715',
Header: [
{
To: {
Expand All @@ -104,6 +158,7 @@ export const buildRxFill = newRx => {
{ MessageID: uuidv4() },
{ RelatesToMessageID: Header.MessageID },
{ SentTime: time.toISOString() },
{ RxReferenceNumber: Header.MessageID },
{ PrescriberOrderNumber: Header.PrescriberOrderNumber }
],
Body: [
Expand All @@ -117,16 +172,16 @@ export const buildRxFill = newRx => {
Patient: Body.NewRx.Patient,
Pharmacy: {
Identification: {
NCPDPID: MOCK_VALUE,
NCPDPID: Header.To._ || MOCK_VALUE,
NPI: MOCK_VALUE
},
BusinessName: Header.To._,
BusinessName: Header.To._ || 'Pharmacy',
Address: {
AddressLine1: MOCK_VALUE,
City: MOCK_VALUE,
StateProvince: MOCK_VALUE,
PostalCode: MOCK_VALUE,
Country: MOCK_VALUE
CountryCode: 'US'
},
CommunicationNumbers: {
PrimaryTelephone: {
Expand All @@ -135,12 +190,194 @@ export const buildRxFill = newRx => {
}
},
Prescriber: Body.NewRx.Prescriber,
MedicationDispensed: medicationDispensed
}
}
]
}
};
const builder = new XMLBuilder(XML_BUILDER_OPTIONS);
return builder.build(message);
};

/**
* Build NCPDP REMSInitiationRequest
*/
export const buildREMSInitiationRequest = newRx => {
const { Message } = JSON.parse(newRx.serializedJSON);
const { Header, Body } = Message;
const time = new Date();

// Extract NDC from medication (prioritize NDC, fallback to other codes)
const drugCoded = Body.NewRx.MedicationPrescribed.DrugCoded;
const ndcCode =
drugCoded?.NDC || drugCoded?.ProductCode?.Code;
const humanPatient = Body.NewRx.Patient.HumanPatient;
const patient = {
HumanPatient: {
Identification: {},
Names: humanPatient.Names,
GenderAndSex: humanPatient.GenderAndSex,
DateOfBirth: humanPatient.DateOfBirth,
Address: humanPatient.Address
}
};

const message = {
Message: {
'@@DatatypesVersion': '2024011',
'@@TransportVersion': '2024011',
'@@TransactionDomain': 'SCRIPT',
'@@TransactionVersion': '2024011',
'@@StructuresVersion': '2024011',
'@@ECLVersion': '2024011',
Header: [
{
To: {
'#text': ndcCode,
'@@Qualifier': 'ZZZ'
}
},
{
From: {
'#text': Header.To._ || 'PIMS Pharmacy',
'@@Qualifier': 'REMS'
}
},
{ MessageID: uuidv4() },
{ SentTime: time.toISOString() },
{
Security: {
Sender: {
SecondaryIdentification: 'PASSWORDR'
}
}
},
{
SenderSoftware: {
SenderSoftwareDeveloper: 'PIMS',
SenderSoftwareProduct: 'PharmacySystem',
SenderSoftwareVersionRelease: '1'
}
},
{ TestMessage: 'false' }
],
Body: [
{
REMSInitiationRequest: {
REMSReferenceID: uuidv4().replace(/-/g, '').substring(0, 25),
Patient: patient,
Pharmacy: {
Identification: {
NCPDPID: Header.To._ || MOCK_VALUE,
NPI: MOCK_VALUE
},
BusinessName: Header.To._ || 'PIMS Pharmacy',
CommunicationNumbers: {
PrimaryTelephone: {
Number: MOCK_VALUE
}
}
},
Prescriber: Body.NewRx.Prescriber,
MedicationPrescribed: Body.NewRx.MedicationPrescribed
}
}
]
}
};

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

/**
* Build NCPDP REMSRequest
*/
export const buildREMSRequest = (newRx, caseNumber) => {
const { Message } = JSON.parse(newRx.serializedJSON);
const { Header, Body } = Message;
const time = new Date();
const deadlineDate = new Date();
deadlineDate.setDate(deadlineDate.getDate() + 7);

// Extract NDC from medication
const drugCoded = Body.NewRx.MedicationPrescribed.DrugCoded;
const ndcCode =
drugCoded?.NDC || drugCoded?.ProductCode?.Code || '66215050130';

const message = {
Message: {
'@@DatatypesVersion': '2024011',
'@@TransportVersion': '2024011',
'@@TransactionDomain': 'SCRIPT',
'@@TransactionVersion': '2024011',
'@@StructuresVersion': '2024011',
'@@ECLVersion': '2024011',
Header: [
{
To: {
'#text': ndcCode,
'@@Qualifier': 'ZZZ'
}
},
{
From: {
'#text': Header.To._ || 'PIMS Pharmacy',
'@@Qualifier': 'REMS'
}
},
{ MessageID: uuidv4() },
{ SentTime: time.toISOString() },
{
Security: {
Sender: {
SecondaryIdentification: 'PASSWORD'
}
}
},
{
SenderSoftware: {
SenderSoftwareDeveloper: 'PIMS',
SenderSoftwareProduct: 'PharmacySystem',
SenderSoftwareVersionRelease: '1'
}
},
{ TestMessage: 'false' }
],
Body: [
{
REMSRequest: {
REMSReferenceID: uuidv4().replace(/-/g, '').substring(0, 25),
Patient: Body.NewRx.Patient,
Pharmacy: {
Identification: {
NCPDPID: Header.To._ || MOCK_VALUE,
NPI: MOCK_VALUE
},
BusinessName: Header.To._ || 'PIMS Pharmacy',
CommunicationNumbers: {
PrimaryTelephone: {
Number: MOCK_VALUE
}
}
},
Prescriber: Body.NewRx.Prescriber,
MedicationPrescribed: Body.NewRx.MedicationPrescribed,
Request: {
SolicitedModel: {
REMSCaseID: caseNumber,
DeadlineForReply: {
Date: deadlineDate.toISOString().split('T')[0]
}
}
}
}
}
]
}
};

const builder = new XMLBuilder(XML_BUILDER_OPTIONS);
return builder.build(message);
};
Loading
Loading