Skip to content

Commit dbeed9b

Browse files
authored
Merge pull request #144 from mcode/dev
Dev
2 parents ab544f3 + ef93800 commit dbeed9b

9 files changed

Lines changed: 202 additions & 174 deletions

File tree

src/fhir/guidanceResponseUtilities.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class GuidanceResponseUtilities {
2828
etasu: Pick<
2929
RemsCase,
3030
| 'drugName'
31+
| 'auth_number'
3132
| 'status'
3233
| 'drugCode'
3334
| 'patientFirstName'
@@ -77,14 +78,15 @@ export class GuidanceResponseUtilities {
7778
outputParameters.parameter?.push(parameter);
7879
}
7980
});
80-
81+
outputParameters.parameter?.push({ name: 'auth_number', valueString: etasu?.auth_number });
8182
return outputParameters;
8283
}
8384

8485
static createEtasuGuidanceResponse(
8586
etasu: Pick<
8687
RemsCase,
8788
| 'drugName'
89+
| 'auth_number'
8890
| 'status'
8991
| 'drugCode'
9092
| 'patientFirstName'

src/fhir/models.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface MetRequirements extends Document {
3232

3333
export interface RemsCase extends Document {
3434
case_number: string;
35+
auth_number: string;
3536
status: string;
3637
drugName: string;
3738
drugCode: string;
@@ -88,6 +89,7 @@ export const metRequirementsCollection = model<MetRequirements>(
8889

8990
const remsCaseCollectionSchema = new Schema<RemsCase>({
9091
case_number: { type: String },
92+
auth_number: { type: String },
9193
status: { type: String },
9294
drugName: { type: String },
9395
patientFirstName: { type: String },

src/hooks/hookResources.ts

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MedicationRequest, Coding, FhirResource, Task, Patient } from 'fhir/r4';
1+
import { MedicationRequest, Coding, FhirResource, Task, Patient, Bundle } from 'fhir/r4';
22
import Card, { Link, Suggestion, Action } from '../cards/Card';
33
import { HookPrefetch, TypedRequestBody } from '../rems-cds-hooks/resources/HookTypes';
44
import config from '../config';
@@ -503,6 +503,154 @@ export function handleHook(
503503
}
504504
}
505505

506+
// process the MedicationRequests to add the Medication into contained resources
507+
function processMedicationRequests(medicationRequestsBundle: Bundle) {
508+
medicationRequestsBundle?.entry?.forEach(entry => {
509+
if (entry?.resource?.resourceType === 'MedicationRequest') {
510+
if (entry?.resource?.medicationReference) {
511+
const medicationReference = entry?.resource?.medicationReference;
512+
medicationRequestsBundle?.entry?.forEach(e => {
513+
if (e?.resource?.resourceType === 'Medication') {
514+
if (
515+
e?.resource?.resourceType + '/' + e?.resource?.id ===
516+
medicationReference?.reference
517+
) {
518+
if (entry) {
519+
if (entry.resource) {
520+
const reference = e?.resource;
521+
const request = entry.resource as MedicationRequest;
522+
523+
// add the reference as a contained resource to the request
524+
if (!request?.contained) {
525+
request.contained = [];
526+
request.contained.push(reference);
527+
} else {
528+
// only add to contained if not already in there
529+
let found = false;
530+
request.contained.forEach(c => {
531+
if (c.id === reference.id) {
532+
found = true;
533+
}
534+
});
535+
if (!found) {
536+
request.contained.push(reference);
537+
}
538+
}
539+
}
540+
}
541+
}
542+
}
543+
});
544+
}
545+
}
546+
});
547+
}
548+
549+
// handles order-sign and order-select currently
550+
export async function handleCardEncounter(
551+
res: any,
552+
hookPrefetch: HookPrefetch | undefined,
553+
contextRequest: FhirResource | undefined,
554+
patient: FhirResource | undefined
555+
) {
556+
//TODO: should we add the other pdf information links to the card, or just have the smart links?
557+
558+
const medResource = hookPrefetch?.medicationRequests;
559+
const medicationRequestsBundle = medResource?.resourceType === 'Bundle' ? medResource : undefined;
560+
561+
// create empty card array
562+
const cardArray: Card[] = [];
563+
564+
// find all matching rems cases for the patient
565+
const patientName = patient?.resourceType === 'Patient' ? patient?.name?.[0] : undefined;
566+
const patientBirth = patient?.resourceType === 'Patient' ? patient?.birthDate : undefined;
567+
const remsCaseList = await remsCaseCollection.find({
568+
patientFirstName: patientName?.given?.[0],
569+
patientLastName: patientName?.family,
570+
patientDOB: patientBirth
571+
});
572+
573+
// loop through all the rems cases in the list
574+
for (const remsCase of remsCaseList) {
575+
// find the drug in the medicationCollection that matches the REMS case to get the smart links
576+
const drug = await medicationCollection
577+
.findOne({
578+
code: remsCase.drugCode,
579+
name: remsCase.drugName
580+
})
581+
.exec();
582+
583+
// get the rule summary from the codemap
584+
const codeRule = codeMap[remsCase.drugCode];
585+
let summary = '';
586+
for (const rule of codeRule) {
587+
if (rule.stakeholderType === 'patient') {
588+
summary = rule.summary || remsCase.drugName || 'Rems';
589+
}
590+
}
591+
592+
// create the card
593+
let smartLinkCount = 0;
594+
const card = new Card(summary, CARD_DETAILS, source, 'info');
595+
596+
// process the MedicationRequests to add the Medication into contained resources
597+
if (medicationRequestsBundle) {
598+
processMedicationRequests(medicationRequestsBundle);
599+
}
600+
601+
// find the matching MedicationRequest for the context
602+
const request = medicationRequestsBundle?.entry?.find(entry => {
603+
if (entry.resource) {
604+
if (entry.resource.resourceType === 'MedicationRequest') {
605+
const medReq: MedicationRequest = entry.resource;
606+
const medicationCode = getDrugCodeFromMedicationRequest(medReq);
607+
return remsCase.drugCode === medicationCode?.code;
608+
}
609+
}
610+
})?.resource;
611+
612+
// if no valid request or not a MedicationRequest found skip this REMS case
613+
if (!request || (request && request.resourceType !== 'MedicationRequest')) {
614+
continue;
615+
}
616+
617+
// loop through all of the ETASU requirements for this drug
618+
const requirements = drug?.requirements || [];
619+
for (const requirement of requirements) {
620+
// find all of the matching patient forms
621+
if (requirement?.stakeholderType === 'patient') {
622+
let found = false;
623+
// match the requirement to the metRequirement of the REMS case
624+
for (const metRequirement of remsCase.metRequirements) {
625+
// only add the link if the form is still needed to be completed
626+
if (metRequirement.requirementName === requirement.name) {
627+
found = true;
628+
if (!metRequirement.completed) {
629+
card.addLink(createSmartLink(requirement.name, requirement.appContext, request));
630+
smartLinkCount++;
631+
}
632+
}
633+
}
634+
635+
// if not in the list of metRequirements, add it as well
636+
if (!found) {
637+
card.addLink(createSmartLink(requirement.name, requirement.appContext, request));
638+
smartLinkCount++;
639+
}
640+
}
641+
}
642+
643+
// only add the card to the list if there is a link
644+
if (smartLinkCount > 0) {
645+
cardArray.push(card);
646+
}
647+
}
648+
649+
res.json({
650+
cards: cardArray
651+
});
652+
}
653+
506654
export function createQuestionnaireSuggestion(
507655
card: Card,
508656
requirement: Requirement,

src/hooks/rems.encounterstart.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { EncounterStartHook, SupportedHooks } from '../rems-cds-hooks/resources/HookTypes';
2+
import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService';
3+
import { handleCardEncounter, handleHook } from './hookResources';
4+
5+
interface TypedRequestBody extends Express.Request {
6+
body: EncounterStartHook;
7+
}
8+
9+
const hookPrefetch: ServicePrefetch = {
10+
patient: 'Patient/{{context.patientId}}',
11+
practitioner: '{{context.userId}}',
12+
medicationRequests:
13+
'MedicationRequest?subject={{context.patientId}}&_include=MedicationRequest:medication'
14+
};
15+
const definition: CdsService = {
16+
id: 'rems-encounter-start',
17+
hook: SupportedHooks.ENCOUNTER_START,
18+
title: 'REMS Requirement Lookup',
19+
description: 'REMS Requirement Lookup',
20+
prefetch: hookPrefetch
21+
};
22+
23+
const handler = (req: TypedRequestBody, res: any) => {
24+
console.log('REMS encounter-start hook');
25+
const contextRequest = undefined;
26+
handleHook(req, res, hookPrefetch, contextRequest, handleCardEncounter);
27+
};
28+
29+
export default { definition, handler };

0 commit comments

Comments
 (0)