Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ REMS_ADMIN_NCPDP_PATH=http://localhost:8090/4_0_0
FRONTEND_PORT = 9080
BACKEND_API_BASE = http://localhost:3003
EHR_URL = http://localhost:8080/test-ehr/r4
EHR_BASE_URL = http://localhost:8080/test-ehr
DIRECTORY_SERVICE_URL=http://localhost:3323
DIRECTORY_API_PATH = /drug/ndc.json
DIRECTORY_SPL_PATH = /drugs/spl.zip
Expand Down
2 changes: 2 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type Config = {
remsAdminFhirEtasuPath: string;
remsAdminNcpdpPath: string;
ehrUrl: string | undefined;
ehrBaseUrl: string | undefined;
discoveryBaseUrl: string | undefined;
discoveryApiUrl: string | undefined;
discoverySplZipUrl: string | undefined;
Expand Down Expand Up @@ -94,6 +95,7 @@ const config: Config = {
remsAdminFhirEtasuPath: env.get('REMS_ADMIN_FHIR_PATH').asString() + '/GuidanceResponse/$rems-etasu',
remsAdminNcpdpPath: env.get('REMS_ADMIN_NCPDP_PATH').asString() + '/ncpdp/scripts',
ehrUrl: env.get('EHR_URL').asString(),
ehrBaseUrl: env.get('EHR_BASE_URL').asString(),
},
database: {
selected: 'mongo',
Expand Down
61 changes: 61 additions & 0 deletions src/lib/ncpdpHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,67 @@ interface NcpdpDrugInfo {
description?: string;
}

export enum Qualifier {
Pharmacy = "P", // Pharmacy
Clinic = "C", // Clinic
Mailbox = "M", // Mailbox
Prescriber = "P", // Prescriber
CentralFillFacility = "CF", // Central Fill Facility
MutuallyDefined = "ZZZ", // Mutually Defined
Payer = "PY", // Payer
DirectIDSecureEmailAddress = "DIRECT",// Direct ID secure email address
REMSAdministrator="REMS", // REMS Administrator
Unknown="?" // Unknown / Error
}

/**
*
* Determine the to:qualifier from the NCPDP message xml
*/
export function getToQualifier(xmlData: string | any): Qualifier {
try {
let parsedXml;

if (typeof xmlData === 'object') {
parsedXml = xmlData;
} else {
const parser = new XMLParser(XML_PARSER_OPTIONS);
parsedXml = parser.parse(xmlData);
}

const message = parsedXml?.Message || parsedXml?.message;
if (!message) {
console.log('Error: NCPDP XML missing Message')
return Qualifier.Unknown;
}

const header = message?.Header || message?.header;
if (!header) {
console.log('Error: NCPDP XML missing Header')
return Qualifier.Unknown;
}

const to = header?.To || header?.to;
if (!to) {
console.log('Error: NCPDP XML missing To')
return Qualifier.Unknown;
}

const qualifier = to['@_Qualifier'];

if (!qualifier) {
console.log('Error: NCPDP XML missing Qualifier')
return Qualifier.Unknown;
}

return qualifier;

} catch (error) {
console.error('Error determining NCPDP To Qualifier:', error);
return Qualifier.Unknown;
}
}

/**
* Determine NCPDP message type from parsed XML
*/
Expand Down
55 changes: 26 additions & 29 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import path from 'path';
import { Connection } from './lib/schemas/Phonebook';
import { EHRWhitelist, loadPhonebook } from './hooks/hookProxy';
import cookieParser from 'cookie-parser';
import { extractDrugFromNcpdp, ndcToCoding, getMessageType} from './lib/ncpdpHelpers';
import { extractDrugFromNcpdp, ndcToCoding, getMessageType, Qualifier, getToQualifier } from './lib/ncpdpHelpers';
import { getServiceConnection } from './hooks/hookProxy';

const logger = container.get('application');
Expand Down Expand Up @@ -131,14 +131,14 @@ class REMSIntermediary extends Server {
return this;
}

registerNcpdpScript({ ncpdpScriptForwardUrl, ehrUrl }: Config['general']) {
registerNcpdpScript({ ncpdpScriptForwardUrl, ehrBaseUrl }: Config['general']) {
console.log('Registering NCPDP SCRIPT endpoint with intelligent routing');

this.app.post('/ncpdp/script', async (req: any, res: any) => {
try {
console.log('Processing NCPDP SCRIPT message');

const ehrEndpoint = ehrUrl + '/script'
const ehrEndpoint = ehrBaseUrl + '/ncpdp/script'

// Determine message type
const messageType = getMessageType(req.body);
Expand Down Expand Up @@ -195,38 +195,35 @@ class REMSIntermediary extends Server {
console.log('Processing RxFill message');

const drugInfo = extractDrugFromNcpdp(req.body);
const promises = [];

// Send to EHR

console.log(`Sending RxFill to EHR: ${ehrEndpoint}`);
promises.push(
axios.post(ehrEndpoint, req.body, { headers: req.headers })
.then(() => console.log('✓ RxFill sent to EHR'))
.catch(err => console.error('✗ Error sending RxFill to EHR:', err.message))
);

// grab the qualifier from the to
const qualifier = getToQualifier(req.body);

// Send to REMS Admin if REMS drug
if (drugInfo && drugInfo.ndc) {
const coding = ndcToCoding(drugInfo.ndc);
const serviceConnection = await getServiceConnection(coding, undefined);

if (serviceConnection && serviceConnection.toNcpdp) {
console.log(`Sending RxFill to REMS Admin: ${serviceConnection.toNcpdp}`);
console.log(` Drug: ${drugInfo.description || 'Unknown'} (${drugInfo.ndc})`);
if (qualifier == Qualifier.Clinic || qualifier == Qualifier.Prescriber) {
// Send to EHR
console.log(`Sending RxFill to EHR: ${ehrEndpoint}`);

await axios.post(ehrEndpoint, req.body, { headers: req.headers })
.then(() => console.log('✓ RxFill sent to EHR'))
.catch(err => console.error('✗ Error sending RxFill to EHR:', err.message));

} else if (qualifier == Qualifier.REMSAdministrator) {
// Send to REMS Admin if REMS drug
if (drugInfo && drugInfo.ndc) {
const coding = ndcToCoding(drugInfo.ndc);
const serviceConnection = await getServiceConnection(coding, undefined);

promises.push(
axios.post(serviceConnection.toNcpdp, req.body, { headers: req.headers })
.then(() => console.log('✓ RxFill sent to REMS Admin'))
.catch(err => console.error('✗ Error sending RxFill to REMS Admin:', err.message))
);
if (serviceConnection && serviceConnection.toNcpdp) {
console.log(`Sending RxFill to REMS Admin: ${serviceConnection.toNcpdp}`);
console.log(` Drug: ${drugInfo.description || 'Unknown'} (${drugInfo.ndc})`);

await axios.post(serviceConnection.toNcpdp, req.body, { headers: req.headers })
.then(() => console.log('✓ RxFill sent to REMS Admin'))
.catch(err => console.error('✗ Error sending RxFill to REMS Admin:', err.message));
}
}
}

// Wait for all sends to complete
await Promise.all(promises);

// Return success status
return res.send({ status: 'success', message: 'RxFill processed' });
}
Expand Down