Skip to content

Commit

Permalink
Merge pull request #144 from mcode/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
smalho01 authored May 20, 2024
2 parents ab544f3 + ef93800 commit dbeed9b
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 174 deletions.
4 changes: 3 additions & 1 deletion src/fhir/guidanceResponseUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class GuidanceResponseUtilities {
etasu: Pick<
RemsCase,
| 'drugName'
| 'auth_number'
| 'status'
| 'drugCode'
| 'patientFirstName'
Expand Down Expand Up @@ -77,14 +78,15 @@ export class GuidanceResponseUtilities {
outputParameters.parameter?.push(parameter);
}
});

outputParameters.parameter?.push({ name: 'auth_number', valueString: etasu?.auth_number });
return outputParameters;
}

static createEtasuGuidanceResponse(
etasu: Pick<
RemsCase,
| 'drugName'
| 'auth_number'
| 'status'
| 'drugCode'
| 'patientFirstName'
Expand Down
2 changes: 2 additions & 0 deletions src/fhir/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface MetRequirements extends Document {

export interface RemsCase extends Document {
case_number: string;
auth_number: string;
status: string;
drugName: string;
drugCode: string;
Expand Down Expand Up @@ -88,6 +89,7 @@ export const metRequirementsCollection = model<MetRequirements>(

const remsCaseCollectionSchema = new Schema<RemsCase>({
case_number: { type: String },
auth_number: { type: String },
status: { type: String },
drugName: { type: String },
patientFirstName: { type: String },
Expand Down
150 changes: 149 additions & 1 deletion src/hooks/hookResources.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MedicationRequest, Coding, FhirResource, Task, Patient } from 'fhir/r4';
import { MedicationRequest, Coding, FhirResource, Task, Patient, Bundle } from 'fhir/r4';
import Card, { Link, Suggestion, Action } from '../cards/Card';
import { HookPrefetch, TypedRequestBody } from '../rems-cds-hooks/resources/HookTypes';
import config from '../config';
Expand Down Expand Up @@ -503,6 +503,154 @@ export function handleHook(
}
}

// process the MedicationRequests to add the Medication into contained resources
function processMedicationRequests(medicationRequestsBundle: Bundle) {
medicationRequestsBundle?.entry?.forEach(entry => {
if (entry?.resource?.resourceType === 'MedicationRequest') {
if (entry?.resource?.medicationReference) {
const medicationReference = entry?.resource?.medicationReference;
medicationRequestsBundle?.entry?.forEach(e => {
if (e?.resource?.resourceType === 'Medication') {
if (
e?.resource?.resourceType + '/' + e?.resource?.id ===
medicationReference?.reference
) {
if (entry) {
if (entry.resource) {
const reference = e?.resource;
const request = entry.resource as MedicationRequest;

// add the reference as a contained resource to the request
if (!request?.contained) {
request.contained = [];
request.contained.push(reference);
} else {
// only add to contained if not already in there
let found = false;
request.contained.forEach(c => {
if (c.id === reference.id) {
found = true;
}
});
if (!found) {
request.contained.push(reference);
}
}
}
}
}
}
});
}
}
});
}

// handles order-sign and order-select currently
export async function handleCardEncounter(
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?.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: patientBirth
});

// loop through all the rems cases in the list
for (const remsCase of remsCaseList) {
// find the drug in the medicationCollection that matches the REMS case to get the smart links
const drug = await medicationCollection
.findOne({
code: remsCase.drugCode,
name: remsCase.drugName
})
.exec();

// get the rule summary from the codemap
const codeRule = codeMap[remsCase.drugCode];
let summary = '';
for (const rule of codeRule) {
if (rule.stakeholderType === 'patient') {
summary = rule.summary || remsCase.drugName || 'Rems';
}
}

// create the card
let smartLinkCount = 0;
const card = new Card(summary, CARD_DETAILS, source, 'info');

// process the MedicationRequests to add the Medication into contained resources
if (medicationRequestsBundle) {
processMedicationRequests(medicationRequestsBundle);
}

// find the matching MedicationRequest for the context
const request = medicationRequestsBundle?.entry?.find(entry => {
if (entry.resource) {
if (entry.resource.resourceType === 'MedicationRequest') {
const medReq: MedicationRequest = entry.resource;
const medicationCode = getDrugCodeFromMedicationRequest(medReq);
return remsCase.drugCode === medicationCode?.code;
}
}
})?.resource;

// if no valid request or not a MedicationRequest found skip this REMS case
if (!request || (request && request.resourceType !== 'MedicationRequest')) {
continue;
}

// loop through all of the ETASU requirements for this drug
const requirements = drug?.requirements || [];
for (const requirement of requirements) {
// find all of the matching patient forms
if (requirement?.stakeholderType === 'patient') {
let found = false;
// match the requirement to the metRequirement of the REMS case
for (const metRequirement of remsCase.metRequirements) {
// only add the link if the form is still needed to be completed
if (metRequirement.requirementName === requirement.name) {
found = true;
if (!metRequirement.completed) {
card.addLink(createSmartLink(requirement.name, requirement.appContext, request));
smartLinkCount++;
}
}
}

// if not in the list of metRequirements, add it as well
if (!found) {
card.addLink(createSmartLink(requirement.name, requirement.appContext, request));
smartLinkCount++;
}
}
}

// only add the card to the list if there is a link
if (smartLinkCount > 0) {
cardArray.push(card);
}
}

res.json({
cards: cardArray
});
}

export function createQuestionnaireSuggestion(
card: Card,
requirement: Requirement,
Expand Down
29 changes: 29 additions & 0 deletions src/hooks/rems.encounterstart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { EncounterStartHook, SupportedHooks } from '../rems-cds-hooks/resources/HookTypes';
import { ServicePrefetch, CdsService } from '../rems-cds-hooks/resources/CdsService';
import { handleCardEncounter, handleHook } from './hookResources';

interface TypedRequestBody extends Express.Request {
body: EncounterStartHook;
}

const hookPrefetch: ServicePrefetch = {
patient: 'Patient/{{context.patientId}}',
practitioner: '{{context.userId}}',
medicationRequests:
'MedicationRequest?subject={{context.patientId}}&_include=MedicationRequest:medication'
};
const definition: CdsService = {
id: 'rems-encounter-start',
hook: SupportedHooks.ENCOUNTER_START,
title: 'REMS Requirement Lookup',
description: 'REMS Requirement Lookup',
prefetch: hookPrefetch
};

const handler = (req: TypedRequestBody, res: any) => {
console.log('REMS encounter-start hook');
const contextRequest = undefined;
handleHook(req, res, hookPrefetch, contextRequest, handleCardEncounter);
};

export default { definition, handler };
Loading

0 comments on commit dbeed9b

Please sign in to comment.