diff --git a/src/hooks/hookResources.ts b/src/hooks/hookResources.ts index 29f6fdda..ff7588f6 100644 --- a/src/hooks/hookResources.ts +++ b/src/hooks/hookResources.ts @@ -1,8 +1,22 @@ -import { MedicationRequest, Coding } from 'fhir/r4'; -import { Link } from '../cards/Card'; -import { TypedRequestBody } from '../rems-cds-hooks/resources/HookTypes'; -import axios from 'axios'; +import { MedicationRequest, Coding, FhirResource, Identifier } from 'fhir/r4'; +import Card, { Link } from '../cards/Card'; +import { + HookPrefetch, + OrderSignPrefetch, + TypedRequestBody +} from '../rems-cds-hooks/resources/HookTypes'; +import config from '../config'; +import { medicationCollection, remsCaseCollection } from '../fhir/models'; +import axios from 'axios'; +import { ServicePrefetch } from '../rems-cds-hooks/resources/CdsService'; +import { hydrate } from '../rems-cds-hooks/prefetch/PrefetchHydrator'; +type HandleCallback = ( + res: any, + hydratedPrefetch: HookPrefetch | undefined, + contextRequest: FhirResource | undefined, + patient: FhirResource | undefined +) => Promise; export interface CardRule { links: Link[]; summary?: string; @@ -189,21 +203,10 @@ export const validCodes: Coding[] = [ system: 'http://www.nlm.nih.gov/research/umls/rxnorm' } ]; - -export function getFhirResource(token: string, req: TypedRequestBody) { - const ehrUrl = `${req.body.fhirServer}/${token}`; - const access_token = req.body.fhirAuthorization?.access_token; - const options = { - method: 'GET', - headers: { - Authorization: `Bearer ${access_token}` - } - }; - const response = axios(ehrUrl, options); - return response.then(e => { - return e.data; - }); -} +const source = { + label: 'MCODE REMS Administrator Prototype', + url: new URL('https://github.com/mcode/rems-admin') +}; /* * Retrieve the coding for the medication from the medicationCodeableConcept if available. @@ -230,3 +233,233 @@ export function getDrugCodeFromMedicationRequest(medicationRequest: MedicationRe } return null; } +export function getFhirResource(token: string, req: TypedRequestBody) { + const ehrUrl = `${req.body.fhirServer}/${token}`; + const access_token = req.body.fhirAuthorization?.access_token; + const options = { + method: 'GET', + headers: { + Authorization: `Bearer ${access_token}` + } + }; + const response = axios(ehrUrl, options); + return response.then(e => { + return e.data; + }); +} +export function createSmartLink( + requirementName: string, + appContext: string, + request: MedicationRequest | undefined +) { + const newLink: Link = { + label: requirementName + ' Form', + url: new URL(config.smart.endpoint), + type: 'smart', + appContext: `${appContext}&order=${JSON.stringify(request)}&coverage=${ + request?.insurance?.[0].reference + }` + }; + return newLink; +} +export function buildErrorCard(reason: string) { + const errorCard = new Card('Bad Request', reason, source, 'warning'); + const cards = { + cards: [errorCard.card] + }; + return cards; +} + +// handles order-sign and order-select currently +export async function handleCardOrder( + res: any, + hydratedPrefetch: HookPrefetch | undefined, + contextRequest: FhirResource | undefined, + patient: FhirResource | undefined +) { + const prefetchRequest = hydratedPrefetch?.request; + console.log(' MedicationRequest: ' + prefetchRequest?.id); + // verify there is a contextRequest + if (!contextRequest) { + res.json(buildErrorCard('DraftOrders does not contain a request')); + return; + } + + // verify a MedicationRequest was sent + if (contextRequest && contextRequest.resourceType !== 'MedicationRequest') { + res.json(buildErrorCard('DraftOrders does not contain a MedicationRequest')); + return; + } + if ( + prefetchRequest?.id && + contextRequest && + contextRequest.id && + prefetchRequest.id.replace('MedicationRequest/', '') !== + contextRequest.id.replace('MedicationRequest/', '') + ) { + res.json(buildErrorCard('Context draftOrder does not match prefetch MedicationRequest ID')); + return; + } + + const medicationCode = + contextRequest && + contextRequest.resourceType === 'MedicationRequest' && + getDrugCodeFromMedicationRequest(contextRequest); + if (!medicationCode) { + return; + } + if (medicationCode && medicationCode?.code) { + // find the drug in the medicationCollection to get the smart links + const drug = await medicationCollection + .findOne({ + code: medicationCode.code, + codeSystem: medicationCode.system + }) + .exec(); + + // find a matching rems case for the patient and this drug to only return needed results + const patientName = patient?.resourceType === 'Patient' ? patient?.name?.[0] : undefined; + const patientBirth = patient?.resourceType === 'Patient' ? patient?.birthDate : undefined; + const etasu = await remsCaseCollection.findOne({ + patientFirstName: patientName?.given?.[0], + patientLastName: patientName?.family, + patientDOB: patientBirth, + drugCode: medicationCode?.code + }); + + const returnCard = validCodes.some(e => { + return e.code === medicationCode.code && e.system === medicationCode.system; + }); + if (returnCard) { + const cardArray: Card[] = []; + const codeRule = codeMap[medicationCode.code]; + for (const rule of codeRule) { + const card = new Card( + rule.summary || medicationCode.display || 'Rems', + CARD_DETAILS, + source, + 'info' + ); + rule.links.forEach(function (e) { + if (e.type == 'absolute') { + // no construction needed + card.addLink(e); + } + }); + + let smartLinkCount = 0; + + // process the smart links from the medicationCollection + // TODO: smart links should be built with discovered questionnaires, not hard coded ones + if (drug) { + for (const requirement of drug.requirements) { + if (requirement.stakeholderType == rule.stakeholderType) { + // only add the link if the form has not already been processed / received + if (etasu) { + let found = false; + for (const metRequirement of etasu.metRequirements) { + if (metRequirement.requirementName == requirement.name) { + found = true; + if (!metRequirement.completed) { + card.addLink( + createSmartLink(requirement.name, requirement.appContext, contextRequest) + ); + smartLinkCount++; + } + } + } + if (!found) { + card.addLink( + createSmartLink(requirement.name, requirement.appContext, contextRequest) + ); + smartLinkCount++; + } + } else { + // add all the required to dispense links if no etasu to check + if (requirement.requiredToDispense) { + card.addLink( + createSmartLink(requirement.name, requirement.appContext, contextRequest) + ); + smartLinkCount++; + } + } + } + } + } + + // only add the card if there are smart links to needed forms + if (smartLinkCount > 0) { + cardArray.push(card); + } + } + res.json({ + cards: cardArray + }); + } else { + res.json(buildErrorCard('Unsupported code')); + } + } else { + res.json(buildErrorCard('MedicationRequest does not contain a code')); + } +} + +// handles preliminary card creation. ALL hooks should go through this function. +// make sure code here is applicable to all supported hooks. +export async function handleCard( + req: TypedRequestBody, + res: any, + hydratedPrefetch: HookPrefetch, + contextRequest: FhirResource | undefined, + callback: HandleCallback +) { + const context = req.body.context; + const patient = hydratedPrefetch?.patient; + const practitioner = hydratedPrefetch?.practitioner; + + console.log(' Patient: ' + patient?.id); + + // verify ids + if ( + patient?.id && + patient.id.replace('Patient/', '') !== context.patientId.replace('Patient/', '') + ) { + res.json(buildErrorCard('Context patientId does not match prefetch Patient ID')); + return; + } + if ( + practitioner?.id && + practitioner.id.replace('Practitioner/', '') !== context.userId.replace('Practitioner/', '') + ) { + res.json(buildErrorCard('Context userId does not match prefetch Practitioner ID')); + return; + } + return callback(res, hydratedPrefetch, contextRequest, patient); +} + +// handles all hooks, any supported hook should pass through this function +export function handleHook( + req: TypedRequestBody, + res: any, + hookPrefetch: ServicePrefetch, + contextRequest: FhirResource | undefined, + callback: HandleCallback +) { + try { + const fhirUrl = req.body.fhirServer; + const fhirAuth = req.body.fhirAuthorization; + if (fhirUrl && fhirAuth && fhirAuth.access_token) { + hydrate(getFhirResource, hookPrefetch, req.body).then(hydratedPrefetch => { + handleCard(req, res, hydratedPrefetch, contextRequest, callback); + }); + } else { + if (req.body.prefetch) { + handleCard(req, res, req.body.prefetch, contextRequest, callback); + } else { + handleCard(req, res, {}, contextRequest, callback); + } + } + } catch (error) { + console.log(error); + res.json(buildErrorCard('Unknown Error')); + } +} diff --git a/src/hooks/rems.orderselect.ts b/src/hooks/rems.orderselect.ts index 636a4aee..9300c1bd 100644 --- a/src/hooks/rems.orderselect.ts +++ b/src/hooks/rems.orderselect.ts @@ -1,22 +1,6 @@ -import Card from '../cards/Card'; -import { - SupportedHooks, - OrderSelectPrefetch, - OrderSelectHook -} from '../rems-cds-hooks/resources/HookTypes'; -import { medicationCollection, remsCaseCollection } from '../fhir/models'; +import { SupportedHooks, OrderSelectHook } from '../rems-cds-hooks/resources/HookTypes'; import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService'; -import { MedicationRequest } from 'fhir/r4'; -import { Link } from '../cards/Card'; -import config from '../config'; -import { hydrate } from '../rems-cds-hooks/prefetch/PrefetchHydrator'; -import { - validCodes, - codeMap, - CARD_DETAILS, - getDrugCodeFromMedicationRequest -} from './hookResources'; -import axios from 'axios'; +import { handleCardOrder, handleHook } from './hookResources'; interface TypedRequestBody extends Express.Request { body: OrderSelectHook; @@ -33,223 +17,17 @@ const definition: CdsService = { description: 'REMS Requirement Lookup', prefetch: hookPrefetch }; -const source = { - label: 'MCODE REMS Administrator Prototype', - url: new URL('https://github.com/mcode/rems-admin') -}; -function buildErrorCard(reason: string) { - const errorCard = new Card('Bad Request', reason, source, 'warning'); - const cards = { - cards: [errorCard.card] - }; - return cards; -} const handler = (req: TypedRequestBody, res: any) => { - function getFhirResource(token: string) { - const ehrUrl = `${req.body.fhirServer}/${token}`; - const access_token = req.body.fhirAuthorization?.access_token; - const options = { - method: 'GET', - headers: { - Authorization: `Bearer ${access_token}` - } - }; - const response = axios(ehrUrl, options); - return response.then(e => { - return e.data; - }); - } - - function createSmartLink( - requirementName: string, - appContext: string, - request: MedicationRequest - ) { - const newLink: Link = { - label: requirementName + ' Form', - url: new URL(config.smart.endpoint), - type: 'smart', - appContext: `${appContext}&order=${JSON.stringify(request)}&coverage=${ - request.insurance?.[0].reference - }` - }; - return newLink; - } - - async function handleCard(hydratedPrefetch: OrderSelectPrefetch) { - console.log(hydratedPrefetch); - const context = req.body.context; - // const contextRequest = context.draftOrders?.entry?.[0].resource; - const selection = context.selections?.[0]; - const contextRequest = context.draftOrders?.entry?.filter(entry => { - if (entry.resource) { - return selection === `${entry.resource.resourceType}/${entry.resource.id}`; - } - })[0].resource; - const patient = hydratedPrefetch?.patient; - const prefetchRequest = context.draftOrders?.entry?.[0].resource; - const practitioner = hydratedPrefetch?.practitioner; - const npi = practitioner?.identifier; - - console.log(' MedicationRequest: ' + prefetchRequest?.id); - console.log(' Practitioner: ' + practitioner?.id + ' NPI: ' + npi); - console.log(' Patient: ' + patient?.id); - - // verify there is a contextRequest - if (!contextRequest) { - res.json(buildErrorCard('DraftOrders does not contain a request')); - return; - } - - // verify a MedicationRequest was sent - if (contextRequest && contextRequest.resourceType !== 'MedicationRequest') { - res.json(buildErrorCard('DraftOrders does not contain a MedicationRequest')); - return; - } - - // verify ids - if ( - patient?.id && - patient.id.replace('Patient/', '') !== context.patientId.replace('Patient/', '') - ) { - res.json(buildErrorCard('Context patientId does not match prefetch Patient ID')); - return; - } - if ( - practitioner?.id && - practitioner.id.replace('Practitioner/', '') !== context.userId.replace('Practitioner/', '') - ) { - res.json(buildErrorCard('Context userId does not match prefetch Practitioner ID')); - return; - } - if ( - prefetchRequest?.id && - contextRequest && - contextRequest.id && - prefetchRequest.id.replace('MedicationRequest/', '') !== - contextRequest.id.replace('MedicationRequest/', '') - ) { - res.json(buildErrorCard('Context draftOrder does not match prefetch MedicationRequest ID')); - return; - } - - const medicationCode = getDrugCodeFromMedicationRequest(contextRequest); - if (medicationCode && medicationCode.code) { - // find the drug in the medicationCollection to get the smart links - const drug = await medicationCollection - .findOne({ - code: medicationCode.code, - codeSystem: medicationCode.system - }) - .exec(); - - // find a matching rems case for the patient and this drug to only return needed results - const patientName = patient?.name?.[0]; - const etasu = await remsCaseCollection.findOne({ - patientFirstName: patientName?.given?.[0], - patientLastName: patientName?.family, - patientDOB: patient?.birthDate, - drugCode: medicationCode?.code - }); - - const returnCard = validCodes.some(e => { - return e.code === medicationCode.code && e.system === medicationCode.system; - }); - if (returnCard) { - const cardArray: Card[] = []; - const codeRule = codeMap[medicationCode.code]; - for (const rule of codeRule) { - const card = new Card( - rule.summary || medicationCode.display || 'Rems', - CARD_DETAILS, - source, - 'info' - ); - rule.links.forEach(function (e) { - if (e.type == 'absolute') { - // no construction needed - card.addLink(e); - } - }); - - let smartLinkCount = 0; - - // process the smart links from the medicationCollection - // TODO: smart links should be built with discovered questionnaires, not hard coded ones - if (drug) { - for (const requirement of drug.requirements) { - if (requirement.stakeholderType == rule.stakeholderType) { - // only add the link if the form has not already been processed / received - if (etasu) { - let found = false; - for (const metRequirement of etasu.metRequirements) { - if (metRequirement.requirementName == requirement.name) { - found = true; - if (!metRequirement.completed) { - card.addLink( - createSmartLink(requirement.name, requirement.appContext, contextRequest) - ); - smartLinkCount++; - } - } - } - if (!found) { - card.addLink( - createSmartLink(requirement.name, requirement.appContext, contextRequest) - ); - smartLinkCount++; - } - } else { - // add all the required to dispense links if no etasu to check - if (requirement.requiredToDispense) { - card.addLink( - createSmartLink(requirement.name, requirement.appContext, contextRequest) - ); - smartLinkCount++; - } - } - } - } - } - - // only add the card if there are smart links to needed forms - if (smartLinkCount > 0) { - cardArray.push(card); - } - } - res.json({ - cards: cardArray - }); - } else { - res.json(buildErrorCard('Unsupported code')); - } - } else { - res.json(buildErrorCard('MedicationRequest does not contain a code')); - } - } - console.log('REMS order-select hook'); - try { - const fhirUrl = req.body.fhirServer; - const fhirAuth = req.body.fhirAuthorization; - if (fhirUrl && fhirAuth && fhirAuth.access_token) { - hydrate(getFhirResource, hookPrefetch, req.body).then( - (hydratedPrefetch: OrderSelectPrefetch) => { - handleCard(hydratedPrefetch); - } - ); - } else { - if (req.body.prefetch) { - handleCard(req.body.prefetch); - } else { - handleCard({}); - } + const context = req.body.context; + const selection = context.selections?.[0]; + const contextRequest = context.draftOrders?.entry?.filter(entry => { + if (entry.resource) { + return selection === `${entry.resource.resourceType}/${entry.resource.id}`; } - } catch (error) { - console.log(error); - res.json(buildErrorCard('Unknown Error')); - } + })[0].resource; + handleHook(req, res, hookPrefetch, contextRequest, handleCardOrder); }; export default { definition, handler }; diff --git a/src/hooks/rems.ordersign.ts b/src/hooks/rems.ordersign.ts index 2e621aea..3e0fedc0 100644 --- a/src/hooks/rems.ordersign.ts +++ b/src/hooks/rems.ordersign.ts @@ -1,22 +1,6 @@ -import Card from '../cards/Card'; -import { - OrderSignHook, - SupportedHooks, - OrderSignPrefetch -} from '../rems-cds-hooks/resources/HookTypes'; -import { medicationCollection, remsCaseCollection } from '../fhir/models'; +import { OrderSignHook, SupportedHooks } from '../rems-cds-hooks/resources/HookTypes'; import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService'; -import { MedicationRequest } from 'fhir/r4'; -import { Link } from '../cards/Card'; -import config from '../config'; -import { hydrate } from '../rems-cds-hooks/prefetch/PrefetchHydrator'; -import { - validCodes, - codeMap, - CARD_DETAILS, - getDrugCodeFromMedicationRequest -} from './hookResources'; -import axios from 'axios'; +import { handleCardOrder, handleHook } from './hookResources'; interface TypedRequestBody extends Express.Request { body: OrderSignHook; @@ -33,225 +17,11 @@ const definition: CdsService = { description: 'REMS Requirement Lookup', prefetch: hookPrefetch }; -const source = { - label: 'MCODE REMS Administrator Prototype', - url: new URL('https://github.com/mcode/rems-admin') -}; -function buildErrorCard(reason: string) { - const errorCard = new Card('Bad Request', reason, source, 'warning'); - const cards = { - cards: [errorCard.card] - }; - return cards; -} const handler = (req: TypedRequestBody, res: any) => { - async function getFhirResource(token: string) { - const ehrUrl = `${req.body.fhirServer}/${token}`; - const access_token = req.body.fhirAuthorization?.access_token; - const options = { - method: 'GET', - headers: { - Authorization: `Bearer ${access_token}` - } - }; - // application errors out here if you can't reach out to the EHR and results in server stopping and subsequent requests failing - let response = { data: {} }; - try { - response = await axios(ehrUrl, options); - } catch (error: any) { - console.warn('Could not connect to EHR Server: ' + error); - response = error; - } - return response?.data; - } - - function createSmartLink( - requirementName: string, - appContext: string, - request: MedicationRequest - ) { - const newLink: Link = { - label: requirementName + ' Form', - url: new URL(config.smart.endpoint), - type: 'smart', - appContext: `${appContext}&order=${JSON.stringify(request)}&coverage=${ - request.insurance?.[0].reference - }` - }; - return newLink; - } - - async function handleCard(hydratedPrefetch: OrderSignPrefetch) { - console.log(hydratedPrefetch); - const context = req.body.context; - const contextRequest = context.draftOrders?.entry?.[0].resource; - const patient = hydratedPrefetch?.patient; - const prefetchRequest = hydratedPrefetch?.request; - const practitioner = hydratedPrefetch?.practitioner; - const npi = practitioner?.identifier; - - console.log(' MedicationRequest: ' + prefetchRequest?.id); - console.log(' Practitioner: ' + practitioner?.id + ' NPI: ' + npi); - console.log(' Patient: ' + patient?.id); - - // verify there is a contextRequest - if (!contextRequest) { - res.json(buildErrorCard('DraftOrders does not contain a request')); - return; - } - - // verify a MedicationRequest was sent - if (contextRequest && contextRequest.resourceType !== 'MedicationRequest') { - res.json(buildErrorCard('DraftOrders does not contain a MedicationRequest')); - return; - } - - // verify ids - if ( - patient?.id && - patient.id.replace('Patient/', '') !== context.patientId.replace('Patient/', '') - ) { - res.json(buildErrorCard('Context patientId does not match prefetch Patient ID')); - return; - } - if ( - practitioner?.id && - practitioner.id.replace('Practitioner/', '') !== context.userId.replace('Practitioner/', '') - ) { - res.json(buildErrorCard('Context userId does not match prefetch Practitioner ID')); - return; - } - if ( - prefetchRequest?.id && - contextRequest && - contextRequest.id && - prefetchRequest.id.replace('MedicationRequest/', '') !== - contextRequest.id.replace('MedicationRequest/', '') - ) { - res.json(buildErrorCard('Context draftOrder does not match prefetch MedicationRequest ID')); - return; - } - - const medicationCode = getDrugCodeFromMedicationRequest(contextRequest); - if (!medicationCode) { - return; - } - if (medicationCode && medicationCode?.code) { - // find the drug in the medicationCollection to get the smart links - const drug = await medicationCollection - .findOne({ - code: medicationCode.code, - codeSystem: medicationCode.system - }) - .exec(); - - // find a matching rems case for the patient and this drug to only return needed results - const patientName = patient?.name?.[0]; - const etasu = await remsCaseCollection.findOne({ - patientFirstName: patientName?.given?.[0], - patientLastName: patientName?.family, - patientDOB: patient?.birthDate, - drugCode: medicationCode?.code - }); - - const returnCard = validCodes.some(e => { - return e.code === medicationCode.code && e.system === medicationCode.system; - }); - if (returnCard) { - const cardArray: Card[] = []; - const codeRule = codeMap[medicationCode.code]; - for (const rule of codeRule) { - const card = new Card( - rule.summary || medicationCode.display || 'Rems', - CARD_DETAILS, - source, - 'info' - ); - rule.links.forEach(function (e) { - if (e.type == 'absolute') { - // no construction needed - card.addLink(e); - } - }); - - let smartLinkCount = 0; - - // process the smart links from the medicationCollection - // TODO: smart links should be built with discovered questionnaires, not hard coded ones - if (drug) { - for (const requirement of drug.requirements) { - if (requirement.stakeholderType == rule.stakeholderType) { - // only add the link if the form has not already been processed / received - if (etasu) { - let found = false; - for (const metRequirement of etasu.metRequirements) { - if (metRequirement.requirementName == requirement.name) { - found = true; - if (!metRequirement.completed) { - card.addLink( - createSmartLink(requirement.name, requirement.appContext, contextRequest) - ); - smartLinkCount++; - } - } - } - if (!found) { - card.addLink( - createSmartLink(requirement.name, requirement.appContext, contextRequest) - ); - smartLinkCount++; - } - } else { - // add all the required to dispense links if no etasu to check - if (requirement.requiredToDispense) { - card.addLink( - createSmartLink(requirement.name, requirement.appContext, contextRequest) - ); - smartLinkCount++; - } - } - } - } - } - - // only add the card if there are smart links to needed forms - if (smartLinkCount > 0) { - cardArray.push(card); - } - } - res.json({ - cards: cardArray - }); - } else { - res.json(buildErrorCard('Unsupported code')); - } - } else { - res.json(buildErrorCard('MedicationRequest does not contain a code')); - } - } - console.log('REMS order-sign hook'); - try { - const fhirUrl = req.body.fhirServer; - const fhirAuth = req.body.fhirAuthorization; - if (fhirUrl && fhirAuth && fhirAuth.access_token) { - hydrate(getFhirResource, hookPrefetch, req.body).then( - (hydratedPrefetch: OrderSignPrefetch) => { - handleCard(hydratedPrefetch); - } - ); - } else { - if (req.body.prefetch) { - handleCard(req.body.prefetch); - } else { - handleCard({}); - } - } - } catch (error) { - console.log(error); - res.json(buildErrorCard('Unknown Error')); - } + const contextRequest = req.body.context.draftOrders?.entry?.[0]?.resource; + handleHook(req, res, hookPrefetch, contextRequest, handleCardOrder); }; export default { definition, handler }; diff --git a/src/hooks/rems.patientview.ts b/src/hooks/rems.patientview.ts index b84e6dbb..da123210 100644 --- a/src/hooks/rems.patientview.ts +++ b/src/hooks/rems.patientview.ts @@ -2,15 +2,22 @@ import Card from '../cards/Card'; import { PatientViewHook, SupportedHooks, - PatientViewPrefetch + PatientViewPrefetch, + HookPrefetch } from '../rems-cds-hooks/resources/HookTypes'; import { medicationCollection, remsCaseCollection } from '../fhir/models'; import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService'; -import { Bundle, MedicationRequest } from 'fhir/r4'; +import { Bundle, FhirResource, MedicationRequest } from 'fhir/r4'; import { Link } from '../cards/Card'; import config from '../config'; import { hydrate } from '../rems-cds-hooks/prefetch/PrefetchHydrator'; -import { codeMap, CARD_DETAILS, getDrugCodeFromMedicationRequest } from './hookResources'; +import { + codeMap, + CARD_DETAILS, + getDrugCodeFromMedicationRequest, + createSmartLink, + handleHook +} from './hookResources'; import axios from 'axios'; interface TypedRequestBody extends Express.Request { @@ -43,37 +50,6 @@ function buildErrorCard(reason: string) { } const handler = (req: TypedRequestBody, res: any) => { - function getFhirResource(token: string) { - const ehrUrl = `${req.body.fhirServer}/${token}`; - const access_token = req.body.fhirAuthorization?.access_token; - const options = { - method: 'GET', - headers: { - Authorization: `Bearer ${access_token}` - } - }; - const response = axios(ehrUrl, options); - return response.then(e => { - return e.data; - }); - } - - function createSmartLink( - requirementName: string, - appContext: string, - request: MedicationRequest | undefined - ) { - const newLink: Link = { - label: requirementName + ' Form', - url: new URL(config.smart.endpoint), - type: 'smart', - appContext: `${appContext}&order=${JSON.stringify(request)}&coverage=${ - request?.insurance?.[0].reference - }` - }; - return newLink; - } - // process the MedicationRequests to add the Medication into contained resources function processMedicationRequests(medicationRequestsBundle: Bundle) { medicationRequestsBundle?.entry?.forEach(entry => { @@ -117,44 +93,28 @@ const handler = (req: TypedRequestBody, res: any) => { }); } - async function handleCard(hydratedPrefetch: PatientViewPrefetch) { - console.log(hydratedPrefetch); - const context = req.body.context; - const patient = hydratedPrefetch?.patient; - const practitioner = hydratedPrefetch?.practitioner; - const medicationRequestsBundle = hydratedPrefetch?.medicationRequests; - const npi = practitioner?.identifier; - - console.log(' Practitioner: ' + practitioner?.id + ' NPI: ' + npi); - console.log(' Patient: ' + patient?.id); - - // verify ids - if ( - patient?.id && - patient.id.replace('Patient/', '') !== context.patientId.replace('Patient/', '') - ) { - res.json(buildErrorCard('Context patientId does not match prefetch Patient ID')); - return; - } - if ( - practitioner?.id && - practitioner.id.replace('Practitioner/', '') !== context.userId.replace('Practitioner/', '') - ) { - res.json(buildErrorCard('Context userId does not match prefetch Practitioner ID')); - return; - } - + async function handleCard( + res: any, + hookPrefetch: HookPrefetch | undefined, + contextRequest: FhirResource | undefined, + patient: FhirResource | undefined + ) { //TODO: should we add the other pdf information links to the card, or just have the smart links? + const medResource = hookPrefetch?.medicationRequests; + const medicationRequestsBundle = + medResource?.resourceType === 'Bundle' ? medResource : undefined; + // create empty card array const cardArray: Card[] = []; // find all matching rems cases for the patient - const patientName = patient?.name?.[0]; + const patientName = patient?.resourceType === 'Patient' ? patient?.name?.[0] : undefined; + const patientBirth = patient?.resourceType === 'Patient' ? patient?.birthDate : undefined; const remsCaseList = await remsCaseCollection.find({ patientFirstName: patientName?.given?.[0], patientLastName: patientName?.family, - patientDOB: patient?.birthDate + patientDOB: patientBirth }); // loop through all the rems cases in the list @@ -238,27 +198,8 @@ const handler = (req: TypedRequestBody, res: any) => { }); } - console.log('REMS patient-view hook'); - try { - const fhirUrl = req.body.fhirServer; - const fhirAuth = req.body.fhirAuthorization; - if (fhirUrl && fhirAuth && fhirAuth.access_token) { - hydrate(getFhirResource, hookPrefetch, req.body).then( - (hydratedPrefetch: PatientViewPrefetch) => { - handleCard(hydratedPrefetch); - } - ); - } else { - if (req.body.prefetch) { - handleCard(req.body.prefetch); - } else { - handleCard({}); - } - } - } catch (error) { - console.log(error); - res.json(buildErrorCard('Unknown Error')); - } + // contextRequest is undefined + handleHook(req, res, hookPrefetch, undefined, handleCard); }; export default { definition, handler }; diff --git a/src/rems-cds-hooks b/src/rems-cds-hooks index da1a46d2..94a78e8c 160000 --- a/src/rems-cds-hooks +++ b/src/rems-cds-hooks @@ -1 +1 @@ -Subproject commit da1a46d22b1d5ded3afe1be73dde06d20d080b53 +Subproject commit 94a78e8cd27734938ec41858f8d0ca4028da5f21