diff --git a/package.json b/package.json index 82aee2b..b15462c 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "@types/fhir": "^0.0.35", "@types/glob": "^8.1.0", "axios": "^1.2.1", - "body-parser": "^1.19.0", + "body-parser": "^1.20.2", + "body-parser-xml": "^2.0.5", "conventional-changelog-cli": "^2.0.34", "cors": "^2.8.5", "dotenv": "^16.3.1", @@ -50,6 +51,7 @@ "winston-daily-rotate-file": "^4.2.1" }, "devDependencies": { + "@types/body-parser-xml": "^2.0.5", "@types/chai": "^4.3.4", "@types/cors": "^2.8.12", "@types/express": "^4.17.14", diff --git a/src/fhir/models.ts b/src/fhir/models.ts index 566f5e2..c5615be 100644 --- a/src/fhir/models.ts +++ b/src/fhir/models.ts @@ -34,6 +34,7 @@ export interface RemsCase extends Document { case_number: string; auth_number: string; status: string; + dispenseStatus: string; drugName: string; drugCode: string; patientFirstName: string; @@ -91,6 +92,7 @@ const remsCaseCollectionSchema = new Schema({ case_number: { type: String }, auth_number: { type: String }, status: { type: String }, + dispenseStatus: { type: String }, drugName: { type: String }, patientFirstName: { type: String }, patientLastName: { type: String }, diff --git a/src/hooks/hookResources.ts b/src/hooks/hookResources.ts index 89aa268..4d435a4 100644 --- a/src/hooks/hookResources.ts +++ b/src/hooks/hookResources.ts @@ -9,11 +9,7 @@ import { BundleEntry } from 'fhir/r4'; import Card, { Link, Suggestion, Action } from '../cards/Card'; -import { - HookPrefetch, - TypedRequestBody, - TypedResponseBody -} from '../rems-cds-hooks/resources/HookTypes'; +import { HookPrefetch, TypedRequestBody } from '../rems-cds-hooks/resources/HookTypes'; import config from '../config'; import { RemsCase, @@ -28,7 +24,7 @@ import { ServicePrefetch } from '../rems-cds-hooks/resources/CdsService'; import { hydrate } from '../rems-cds-hooks/prefetch/PrefetchHydrator'; type HandleCallback = ( - res: TypedResponseBody, + res: any, hydratedPrefetch: HookPrefetch | undefined, contextRequest: FhirResource | undefined, patient: FhirResource | undefined @@ -360,7 +356,7 @@ const getErrorCard = ( // handles order-sign and order-select currently export const handleCardOrder = async ( - res: TypedResponseBody, + res: any, hydratedPrefetch: HookPrefetch | undefined, contextRequest: FhirResource | undefined, resource: FhirResource | undefined @@ -485,7 +481,7 @@ const getSuggestions = ( // make sure code here is applicable to all supported hooks. export async function handleCard( req: TypedRequestBody, - res: TypedResponseBody, + res: any, hydratedPrefetch: HookPrefetch, contextRequest: FhirResource | undefined, callback: HandleCallback @@ -517,7 +513,7 @@ export async function handleCard( // handles all hooks, any supported hook should pass through this function export function handleHook( req: TypedRequestBody, - res: TypedResponseBody, + res: any, hookPrefetch: ServicePrefetch, contextRequest: FhirResource | undefined, callback: HandleCallback @@ -732,7 +728,7 @@ const getSuggestionOrEmptyArray = // handles patient-view and encounter-start currently export const handleCardEncounter = async ( - res: TypedResponseBody, + res: any, hookPrefetch: HookPrefetch | undefined, _contextRequest: FhirResource | undefined, resource: FhirResource | undefined diff --git a/src/hooks/rems.encounterstart.ts b/src/hooks/rems.encounterstart.ts index 8b56250..ca11070 100644 --- a/src/hooks/rems.encounterstart.ts +++ b/src/hooks/rems.encounterstart.ts @@ -1,8 +1,4 @@ -import { - EncounterStartHook, - SupportedHooks, - TypedResponseBody -} from '../rems-cds-hooks/resources/HookTypes'; +import { EncounterStartHook, SupportedHooks } from '../rems-cds-hooks/resources/HookTypes'; import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService'; import { handleCardEncounter, handleHook } from './hookResources'; @@ -24,7 +20,7 @@ const definition: CdsService = { prefetch: hookPrefetch }; -const handler = (req: TypedRequestBody, res: TypedResponseBody) => { +const handler = (req: TypedRequestBody, res: any) => { console.log('REMS encounter-start hook'); const contextRequest = undefined; handleHook(req, res, hookPrefetch, contextRequest, handleCardEncounter); diff --git a/src/hooks/rems.orderselect.ts b/src/hooks/rems.orderselect.ts index 6ba60e9..b3b2c63 100644 --- a/src/hooks/rems.orderselect.ts +++ b/src/hooks/rems.orderselect.ts @@ -1,8 +1,4 @@ -import { - SupportedHooks, - TypedResponseBody, - OrderSelectHook -} from '../rems-cds-hooks/resources/HookTypes'; +import { SupportedHooks, OrderSelectHook } from '../rems-cds-hooks/resources/HookTypes'; import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService'; import { handleCardOrder, handleHook } from './hookResources'; @@ -22,7 +18,7 @@ const definition: CdsService = { prefetch: hookPrefetch }; -const handler = (req: TypedRequestBody, res: TypedResponseBody) => { +const handler = (req: TypedRequestBody, res: any) => { console.log('REMS order-select hook'); const context = req.body.context; const selection = context.selections?.[0]; diff --git a/src/hooks/rems.ordersign.ts b/src/hooks/rems.ordersign.ts index d15798a..3e0fedc 100644 --- a/src/hooks/rems.ordersign.ts +++ b/src/hooks/rems.ordersign.ts @@ -1,8 +1,4 @@ -import { - OrderSignHook, - SupportedHooks, - TypedResponseBody -} from '../rems-cds-hooks/resources/HookTypes'; +import { OrderSignHook, SupportedHooks } from '../rems-cds-hooks/resources/HookTypes'; import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService'; import { handleCardOrder, handleHook } from './hookResources'; @@ -22,7 +18,7 @@ const definition: CdsService = { prefetch: hookPrefetch }; -const handler = (req: TypedRequestBody, res: TypedResponseBody) => { +const handler = (req: TypedRequestBody, res: any) => { console.log('REMS order-sign hook'); const contextRequest = req.body.context.draftOrders?.entry?.[0]?.resource; handleHook(req, res, hookPrefetch, contextRequest, handleCardOrder); diff --git a/src/hooks/rems.patientview.ts b/src/hooks/rems.patientview.ts index a3e9a6d..007e3ee 100644 --- a/src/hooks/rems.patientview.ts +++ b/src/hooks/rems.patientview.ts @@ -1,8 +1,4 @@ -import { - PatientViewHook, - SupportedHooks, - TypedResponseBody -} from '../rems-cds-hooks/resources/HookTypes'; +import { PatientViewHook, SupportedHooks } from '../rems-cds-hooks/resources/HookTypes'; import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService'; import { handleCardEncounter, handleHook } from './hookResources'; @@ -24,7 +20,7 @@ const definition: CdsService = { prefetch: hookPrefetch }; -const handler = (req: TypedRequestBody, res: TypedResponseBody) => { +const handler = (req: TypedRequestBody, res: any) => { console.log('REMS patient-view hook'); const contextRequest = undefined; handleHook(req, res, hookPrefetch, contextRequest, handleCardEncounter); diff --git a/src/lib/etasu.ts b/src/lib/etasu.ts index a397c2a..a65f57d 100644 --- a/src/lib/etasu.ts +++ b/src/lib/etasu.ts @@ -226,11 +226,13 @@ const createMetRequirementAndNewCase = async ( // create new rems request and add the created metReq to it let remsRequestCompletedStatus = 'Approved'; + const dispenseStatusDefault = 'Pending'; const remsRequest: Pick< RemsCase, | 'case_number' | 'auth_number' | 'status' + | 'dispenseStatus' | 'drugName' | 'drugCode' | 'patientFirstName' @@ -241,6 +243,7 @@ const createMetRequirementAndNewCase = async ( case_number: case_number, auth_number: '', status: remsRequestCompletedStatus, + dispenseStatus: dispenseStatusDefault, drugName: drug?.name, drugCode: drug?.code, patientFirstName: patientFirstName, diff --git a/src/ncpdp/script.ts b/src/ncpdp/script.ts new file mode 100644 index 0000000..df4c210 --- /dev/null +++ b/src/ncpdp/script.ts @@ -0,0 +1,40 @@ +import { Router, Request } from 'express'; +import { remsCaseCollection } from '../fhir/models'; +const router = Router(); + +router.post('/ncpdp/script', async (req: Request) => { + try { + const requestBody = req.body; + if (requestBody.message?.body?.rxfill) { + // call to handle rxfill + handleRxFill(requestBody); + } else { + // do nothing for now + } + } catch (error) { + console.log(error); + throw error; + } +}); + +const handleRxFill = async (bundle: any) => { + const rxfill = bundle.message?.body?.rxfill; + + const fillStatus = rxfill?.fillstatus?.dispensed?.note; + const patient = rxfill?.patient; + const code = rxfill?.medicationprescribed?.drugcoded?.drugdbcode?.code; + + await remsCaseCollection.findOneAndUpdate( + { + patientFirstName: patient?.humanpatient?.name?.firstname, + patientLastName: patient?.humanpatient?.name?.lastname, + patientDOB: patient?.humanpatient?.dateofbirth?.date, + drugCode: code + }, + { dispenseStatus: fillStatus }, + { new: true } + ); + return fillStatus; +}; + +export default router; diff --git a/src/server.ts b/src/server.ts index b9c816f..a2e2f8f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -9,9 +9,11 @@ import patientViewService from './hooks/rems.patientview'; import encounterStartService from './hooks/rems.encounterstart'; import { Server } from '@projecttacoma/node-fhir-server-core'; import Etasu from './lib/etasu'; +import Ncpdp from './ncpdp/script'; import env from 'env-var'; import https from 'https'; import fs from 'fs'; +import bodyParserXml from 'body-parser-xml'; const logger = container.get('application'); @@ -26,6 +28,7 @@ const initialize = (config: any) => { .setProfileRoutes() .registerCdsHooks(config.server) .configureEtasuEndpoints() + .configureNCPDPEndpoints() .setErrorRoutes(); }; @@ -116,6 +119,22 @@ class REMSServer extends Server { return this; } + configureNCPDPEndpoints() { + bodyParserXml(bodyParser); + this.app.use( + bodyParser.xml({ + limit: '1MB', + xmlParseOptions: { + normalize: true, + normalizeTags: true, + explicitArray: false + } + }) + ); + this.app.use('/', Ncpdp); + return this; + } + /** * @method listen * @description Start listening on the configured port