From de54beac8e75123e687eb35f9a1c74848669a32c Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Fri, 26 Jun 2026 14:36:37 -0400 Subject: [PATCH] add ppa support --- .env | 5 +- README.md | 2 + dockerRunnerDev.sh | 74 +++++++---- frontend/src/views/DataViews/EditPopup.tsx | 4 +- src/config.ts | 13 +- src/hooks/hookProxy.ts | 9 +- src/hooks/hookResources.ts | 15 ++- src/lib/ncpdpHelpers.ts | 31 ++++- src/server.ts | 147 ++++++++++++++++++++- src/services/guidanceresponse.service.ts | 22 ++- 10 files changed, 263 insertions(+), 59 deletions(-) diff --git a/.env b/.env index 39bb68e..2aeae7a 100644 --- a/.env +++ b/.env @@ -17,7 +17,7 @@ VITE_CLIENT = app-login VITE_SCOPE_ID = intermediary REMS_ADMIN_HOOK_PATH=http://localhost:8090/cds-services/rems- REMS_ADMIN_FHIR_PATH=http://localhost:8090/4_0_0 -REMS_ADMIN_NCPDP_PATH=http://localhost:8090/4_0_0 +REMS_ADMIN_NCPDP_PATH=http://localhost:8090 FRONTEND_PORT = 9080 BACKEND_API_BASE = http://localhost:3003 EHR_URL = http://localhost:8080/test-ehr/r4 @@ -27,5 +27,4 @@ DIRECTORY_API_PATH = /drug/ndc.json DIRECTORY_SPL_PATH = /drugs/spl.zip SPL_ZIP_FILE_NAME=TESTDATA_rems_document_and_rems_indexing_spl_files.zip NCPDP_SCRIPT_FORWARD_URL=http://localhost:5051/ncpdp/script - - +PPA_PHARMACY_ENDPOINTS=[{"id":"Pharmacy123","url":"http://localhost:5051/ncpdp/script","scriptUrl":"http://localhost:5051/ncpdp/script"},{"id":"Pharmacy456","url":"http://localhost:5151/ncpdp/script","scriptUrl":"http://localhost:5151/ncpdp/script"}] diff --git a/README.md b/README.md index 8f19b15..8b5f488 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ Following are a list of modifiable paths: | VITE_CLIENT | `app-login` | Client used for connecting to keycloak authentication server. | | REMS_ADMIN_HOOK_PATH | `http://localhost:8090/cds-services/rems-` | REMS Administrator default base path for CDS Hooks. | | REMS_ADMIN_FHIR_PATH | `http://localhost:8090/4_0_0` | REMS Administrator default base path for the FHIR Server | +| REMS_ADMIN_NCPDP_PATH | `http://localhost:8090` | REMS Administrator default base URL used to build the `/ncpdp/script` endpoint when directory lookup is unavailable. | | FRONTEND_PORT | `9080` | Port that the frontend server should run on, change if there are conflicts with port usage. | | BACKEND_API_BASE | `http://localhost:3003` | Base URL for the backend server of the intermediary | | EHR_URL | `http://localhost:8080/test-ehr/r4` | URL for the EHR System | @@ -127,6 +128,7 @@ Following are a list of modifiable paths: | DIRECTORY_API_PATH | `/drug/ndc.json` | API path for querying the directory service. | | DIRECTORY_SPL_PATH | `/drugs/spl.zip` | Path for downloading SPL zip files from directory service. | | NCPDP_SCRIPT_FORWARD_URL | `http://localhost:5051/ncpdp/script` | URL for forwarding NCPDP Script messages to pharmacy system. | +| PPA_PHARMACY_ENDPOINTS | `[{...Pharmacy123...},{...Pharmacy456...}]` | JSON array of pharmacy routes keyed by the PPA `Header.To` value. Each entry should include `id` and a `/ncpdp/script` `url` or `scriptUrl`; `scriptUrl` is used for both PPA JSON forwarding and selected-pharmacy NewRx forwarding when present. | # Data Rights diff --git a/dockerRunnerDev.sh b/dockerRunnerDev.sh index 7395bf6..1e38004 100755 --- a/dockerRunnerDev.sh +++ b/dockerRunnerDev.sh @@ -1,9 +1,9 @@ #!/bin/sh # Handle closing application on signal interrupt (ctrl + c) -trap 'kill $CONTINUOUS_INSTALL_PID $SERVER_PID $BACKEND_SERVER_PID; exit' INT +trap 'kill $CONTINUOUS_INSTALL_PID $SERVER_PID $BACKEND_SERVER_PID 2>/dev/null; exit' INT TERM -mkdir logs +mkdir -p logs touch ./logs/frontend_installer.log touch ./logs/frontend_runner.log touch ./logs/backend_installer.log @@ -12,54 +12,75 @@ touch ./logs/backend_runner.log # Reset log file content for new application boot echo "*** Logs for continuous frontend installer ***" > ./logs/frontend_installer.log echo "*** Logs for frontend 'npm run start' ***" > ./logs/frontend_runner.log - echo "*** Logs for continuous backend installer ***" > ./logs/backend_installer.log echo "*** Logs for backend 'npm run start' ***" > ./logs/backend_runner.log # Print that the application is starting in watch mode echo "starting application in watch mode..." -# Start the continious build listener process +clear_frontend_vite_cache() { + rm -rf frontend/node_modules/.vite frontend/node_modules/.cache/vite 2>/dev/null || true +} + +# Start the continuous build listener process echo "starting continuous installers..." -cd frontend -npm install | tee ./logs/frontend_installer.log -cd .. -npm install | tee ./logs/backend_installer.log +if [ ! -d frontend/node_modules ]; then + cd frontend + npm install | tee ../logs/frontend_installer.log + cd .. + clear_frontend_vite_cache +fi + +if [ ! -d node_modules ]; then + npm install | tee ./logs/backend_installer.log +fi -( package_modify_time=$(stat -c %Y frontend/package.json) -package_lock_modify_time=$(stat -c %Y frontend/package-lock.json) -backend_modify_time=$(stat -c %Y package.json) -backend_lock_modify_time=$(stat -c %Y package-lock.json) +( file_hash() { + cksum "$1" 2>/dev/null || echo "missing $1" +} + +frontend_package_hash=$(file_hash frontend/package.json) +frontend_lock_hash=$(file_hash frontend/package-lock.json) +backend_package_hash=$(file_hash package.json) +backend_lock_hash=$(file_hash package-lock.json) while sleep 1 do - new_package_modify_time=$(stat -c %Y frontend/package.json) - new_package_lock_modify_time=$(stat -c %Y frontend/package-lock.json) - new_backend_modify_time=$(stat -c %Y package.json) - new_backend_lock_modify_time=$(stat -c %Y package-lock.json) + new_frontend_package_hash=$(file_hash frontend/package.json) + new_frontend_lock_hash=$(file_hash frontend/package-lock.json) + new_backend_package_hash=$(file_hash package.json) + new_backend_lock_hash=$(file_hash package-lock.json) - if [[ "$package_modify_time" != "$new_package_modify_time" ]] || [[ "$package_lock_modify_time" != "$new_package_lock_modify_time" ]] || [[ "$backend_lock_modify_time" != "$new_backend_lock_modify_time" ]]|| [[ "$backend_modify_time" != "$new_backend_modify_time" ]] + if [ "$frontend_package_hash" != "$new_frontend_package_hash" ] || [ "$frontend_lock_hash" != "$new_frontend_lock_hash" ] then - echo "running frontent npm install..." + echo "running frontend npm install..." cd frontend - npm install | tee ./logs/frontend_installer.log + npm install | tee ../logs/frontend_installer.log cd .. - elif [[ "$backend_lock_modify_time" != "$new_backend_lock_modify_time" ]]|| [[ "$backend_modify_time" != "$new_backend_modify_time" ]] + clear_frontend_vite_cache + new_frontend_package_hash=$(file_hash frontend/package.json) + new_frontend_lock_hash=$(file_hash frontend/package-lock.json) + fi + + if [ "$backend_package_hash" != "$new_backend_package_hash" ] || [ "$backend_lock_hash" != "$new_backend_lock_hash" ] then echo "running backend npm install..." npm install | tee ./logs/backend_installer.log + new_backend_package_hash=$(file_hash package.json) + new_backend_lock_hash=$(file_hash package-lock.json) fi - package_modify_time=$new_package_modify_time - package_lock_modify_time=$new_package_lock_modify_time - backend_modify_time=$new_backend_modify_time - backend_lock_modify_time=$new_backend_lock_modify_time + frontend_package_hash=$new_frontend_package_hash + frontend_lock_hash=$new_frontend_lock_hash + backend_package_hash=$new_backend_package_hash + backend_lock_hash=$new_backend_lock_hash done ) & CONTINUOUS_INSTALL_PID=$! -# Start server process once initial build finishes +# Start server process once initial build finishes +clear_frontend_vite_cache cd frontend -( npm run start | tee ./logs/frontend_runner.log ) & SERVER_PID=$! +( npm run start | tee ../logs/frontend_runner.log ) & SERVER_PID=$! cd .. ( npm run start | tee ./logs/backend_runner.log ) & BACKEND_SERVER_PID=$! @@ -68,4 +89,3 @@ cd .. wait $CONTINUOUS_INSTALL_PID $SERVER_PID $BACKEND_SERVER_PID EXIT_CODE=$? echo "application exited with exit code $EXIT_CODE..." - diff --git a/frontend/src/views/DataViews/EditPopup.tsx b/frontend/src/views/DataViews/EditPopup.tsx index 0c44fca..404d719 100644 --- a/frontend/src/views/DataViews/EditPopup.tsx +++ b/frontend/src/views/DataViews/EditPopup.tsx @@ -60,7 +60,7 @@ const EditPopup = (props) => { const fieldsFilled = () => { return (updatedConnection?.code && updatedConnection?.system - && updatedConnection?.to && updatedConnection?.toEtasu); + && updatedConnection?.to && updatedConnection?.toEtasu && updatedConnection?.toNcpdp); } return ( @@ -208,4 +208,4 @@ const EditPopup = (props) => { ) }; -export default EditPopup; \ No newline at end of file +export default EditPopup; diff --git a/src/config.ts b/src/config.ts index ad1d45e..7355aef 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,6 +8,13 @@ const whitelistEnv = env.get('WHITELIST').asArray() || false; // If no whitelist is present, disable CORS const whitelist = whitelistEnv && whitelistEnv.length === 1 ? whitelistEnv[0] : whitelistEnv; +const trimTrailingSlash = (value: string | undefined) => value?.replace(/\/+$/, ''); +const remsAdminFhirPath = env.get('REMS_ADMIN_FHIR_PATH').asString(); +const remsAdminNcpdpBase = + trimTrailingSlash(env.get('REMS_ADMIN_NCPDP_PATH').asString()) || + trimTrailingSlash(remsAdminFhirPath?.replace(/\/4_0_0\/?$/, '')) || + 'http://localhost:8090'; + export type Config = { server: { port: number | undefined; @@ -31,6 +38,7 @@ export type Config = { discoverySplZipUrl: string | undefined; splZipFileName: string; ncpdpScriptForwardUrl: string; + ppaPharmacyEndpoints: string; }; database: { selected: string; @@ -92,8 +100,9 @@ const config: Config = { remsAdminHookPath: env.get('REMS_ADMIN_HOOK_PATH').asString(), splZipFileName: env.get('SPL_ZIP_FILE_NAME').asString() || 'TESTDATA_rems_document_and_rems_indexing_spl_files.zip', ncpdpScriptForwardUrl: env.get('NCPDP_SCRIPT_FORWARD_URL').asString() || 'http://localhost:5051/ncpdp/script', - remsAdminFhirEtasuPath: env.get('REMS_ADMIN_FHIR_PATH').asString() + '/GuidanceResponse/$rems-etasu', - remsAdminNcpdpPath: env.get('REMS_ADMIN_NCPDP_PATH').asString() + '/ncpdp/scripts', + ppaPharmacyEndpoints: env.get('PPA_PHARMACY_ENDPOINTS').asString() || '[{"id":"Pharmacy123","url":"http://localhost:5051/ncpdp/script"}]', + remsAdminFhirEtasuPath: remsAdminFhirPath + '/GuidanceResponse/$rems-etasu', + remsAdminNcpdpPath: remsAdminNcpdpBase + '/ncpdp/script', ehrUrl: env.get('EHR_URL').asString(), ehrBaseUrl: env.get('EHR_BASE_URL').asString(), }, diff --git a/src/hooks/hookProxy.ts b/src/hooks/hookProxy.ts index 81db7ed..c29ef77 100644 --- a/src/hooks/hookProxy.ts +++ b/src/hooks/hookProxy.ts @@ -92,6 +92,13 @@ const phonebook = [ generic_name: "PEXIDARTINIB HYDROCHLORIDE", from: [EHRWhitelist.any] }, + { + code: '99999-407-20', // Generic pexidartinib + system: 'http://hl7.org/fhir/sid/ndc', + brand_name: "Pexidartinib Hydrochloride", + generic_name: "PEXIDARTINIB HYDROCHLORIDE", + from: [EHRWhitelist.any] + }, { code: '58604-214-30', // Addyi system: 'http://hl7.org/fhir/sid/ndc', @@ -837,4 +844,4 @@ export async function getServiceConnection(coding: Coding, requester: string | u return connection; } } -} \ No newline at end of file +} diff --git a/src/hooks/hookResources.ts b/src/hooks/hookResources.ts index e8c7bb3..e4393a2 100644 --- a/src/hooks/hookResources.ts +++ b/src/hooks/hookResources.ts @@ -34,10 +34,19 @@ export function buildErrorCard(reason: string) { } export function getDrugCodesFromMedicationRequest(medicationRequest: MedicationRequest) { + const prioritizeNdc = (codings: any[] | undefined | null) => { + if (!codings) return codings; + return [...codings].sort((first, second) => { + const firstIsNdc = first?.system?.toLowerCase().endsWith('/ndc') ? 1 : 0; + const secondIsNdc = second?.system?.toLowerCase().endsWith('/ndc') ? 1 : 0; + return secondIsNdc - firstIsNdc; + }); + }; + if (medicationRequest) { if (medicationRequest?.medicationCodeableConcept) { console.log('Get Medication codes from CodeableConcept'); - return medicationRequest?.medicationCodeableConcept?.coding; + return prioritizeNdc(medicationRequest?.medicationCodeableConcept?.coding); } else if (medicationRequest?.medicationReference) { const reference = medicationRequest?.medicationReference; let codes = null; @@ -50,7 +59,7 @@ export function getDrugCodesFromMedicationRequest(medicationRequest: MedicationR } }); console.log('Found codes: ' + JSON.stringify(codes)); - return codes; + return prioritizeNdc(codes); } } return null; @@ -313,4 +322,4 @@ export async function handleHook( res.json(createErrorCard('No MedicationRequests in ' + hookType + ' hook')); } } -} \ No newline at end of file +} diff --git a/src/lib/ncpdpHelpers.ts b/src/lib/ncpdpHelpers.ts index 7ec9107..fb647ae 100644 --- a/src/lib/ncpdpHelpers.ts +++ b/src/lib/ncpdpHelpers.ts @@ -75,6 +75,35 @@ export function getToQualifier(xmlData: string | any): Qualifier { } } +/** + * Determine the NCPDP Header.To identifier from the message XML. + */ +export function getHeaderTo(xmlData: string | any): string | undefined { + 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; + const header = message?.Header || message?.header; + const to = header?.To || header?.to; + + if (typeof to === 'string') { + return to; + } + + return to?.['#text'] || to?._ || undefined; + } catch (error) { + console.error('Error determining NCPDP Header.To:', error); + return undefined; + } +} + /** * Determine NCPDP message type from parsed XML */ @@ -226,4 +255,4 @@ export function ndcToCoding(ndc: string): Coding { system: 'http://hl7.org/fhir/sid/ndc', code: ndc }; -} \ No newline at end of file +} diff --git a/src/server.ts b/src/server.ts index 51ba7ef..dd3bfc1 100644 --- a/src/server.ts +++ b/src/server.ts @@ -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, Qualifier, getToQualifier } from './lib/ncpdpHelpers'; +import { extractDrugFromNcpdp, ndcToCoding, getMessageType, Qualifier, getToQualifier, getHeaderTo } from './lib/ncpdpHelpers'; import { getServiceConnection } from './hooks/hookProxy'; import { HookSession } from './lib/schemas/HookSession'; import { Communication } from 'fhir/r4'; @@ -306,13 +306,138 @@ class REMSIntermediary extends Server { } - registerNcpdpScript({ ncpdpScriptForwardUrl, ehrBaseUrl }: Config['general']) { + registerNcpdpScript({ ncpdpScriptForwardUrl, ehrBaseUrl, ppaPharmacyEndpoints }: Config['general']) { console.log('Registering NCPDP SCRIPT endpoint with intelligent routing'); + + const getPharmacyRoute = (pharmacyId: string | undefined, fallbackUrl: string) => { + if (!pharmacyId) return fallbackUrl; + + try { + const endpoints = JSON.parse(ppaPharmacyEndpoints || '[]'); + const endpoint = endpoints.find((entry: any) => entry.id === pharmacyId); + return endpoint?.scriptUrl || endpoint?.ncpdpScriptUrl || endpoint?.url || fallbackUrl; + } catch (error: any) { + console.error('Could not parse pharmacy routing config:', error.message); + return fallbackUrl; + } + }; + + const getPpaMessage = (body: any) => body?.Message || body?.MessageType; + + const getPpaTo = (body: any): string | undefined => { + const to = getPpaMessage(body)?.Header?.To; + if (typeof to === 'string') return to; + return to?.['#text'] || to?._; + }; + + const isPpaRequest = (body: any) => Boolean(getPpaMessage(body)?.Body?.PPARequest); + const isPpaMessage = (body: any) => + getPpaMessage(body)?.['@TransactionDomain'] === 'PPA' || isPpaRequest(body); + + const validatePpaRequest = (body: any) => { + const message = getPpaMessage(body); + const errors: string[] = []; + + if (!message) { + return ['Missing Message']; + } + + if (message['@TransactionDomain'] !== 'PPA') { + errors.push('Message TransactionDomain must be PPA'); + } + if (message['@TransactionVersion'] !== '2.0') { + errors.push('Message TransactionVersion must be 2.0'); + } + if (!message.Body?.PPARequest) { + errors.push('Missing Body.PPARequest'); + } + + const header = message.Header; + if (!header) { + errors.push('Missing Header'); + } else { + ['To', 'From', 'MessageID', 'SentTime'].forEach(key => { + if (!header[key]) errors.push(`Missing Header.${key}`); + }); + [ + 'SenderSoftwareDeveloper', + 'SenderSoftwareProduct', + 'SenderSoftwareVersionRelease', + 'SenderSoftwareOperator' + ].forEach(key => { + if (!header.SenderSoftware?.[key]) errors.push(`Missing Header.SenderSoftware.${key}`); + }); + } + + return errors; + }; + + const buildPpaError = (body: any, code: string, description: string) => { + const header = getPpaMessage(body)?.Header || {}; + return { + Message: { + '@TransactionDomain': 'PPA', + '@TransactionVersion': '2.0', + Header: { + To: header.From || 'Unknown', + From: 'Intermediary', + MessageID: `PPAError-${Date.now()}`, + RelatesToMessageID: header.MessageID, + SentTime: new Date().toISOString(), + SenderSoftware: { + SenderSoftwareDeveloper: 'REMS Prototype', + SenderSoftwareProduct: 'REMS Intermediary', + SenderSoftwareVersionRelease: '1', + SenderSoftwareOperator: 'Intermediary' + } + }, + Body: { + Error: { + TransactionErrorCode: code, + Description: description + } + } + } + }; + }; + + const forwardPpaRequest = async (req: any, res: any, routeName: string) => { + const message = getPpaMessage(req.body); + const to = getPpaTo(req.body); + + const validationErrors = validatePpaRequest(req.body); + if (validationErrors.length > 0) { + return res.status(400).json(buildPpaError(req.body, '602', validationErrors.join('; '))); + } + + const endpoints = JSON.parse(ppaPharmacyEndpoints || '[]'); + const endpoint = endpoints.find((entry: any) => entry.id === to); + const ppaUrl = endpoint?.scriptUrl || endpoint?.ncpdpScriptUrl || endpoint?.url; + + if (!ppaUrl) { + return res + .status(404) + .json(buildPpaError(req.body, '601', `No pharmacy PPA route configured for ${to}`)); + } + + console.log(`Forwarding PPARequest from ${routeName} to pharmacy ${to}: ${ppaUrl}`); + const response = await axios.post(ppaUrl, req.body, { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }); + return res.status(response.status).json(response.data); + }; this.app.post('/ncpdp/script', async (req: any, res: any) => { try { console.log('Processing NCPDP SCRIPT message'); + if (isPpaMessage(req.body)) { + return forwardPpaRequest(req, res, '/ncpdp/script'); + } + const ehrEndpoint = ehrBaseUrl + '/ncpdp/script' // Determine message type @@ -320,7 +445,9 @@ class REMSIntermediary extends Server { console.log(`Message type: ${messageType}`); if (messageType === 'NewRx') { - console.log(`Forwarding NewRx to pharmacy: ${ncpdpScriptForwardUrl}`); + const pharmacyId = getHeaderTo(req.body); + const pharmacyEndpoint = getPharmacyRoute(pharmacyId, ncpdpScriptForwardUrl); + console.log(`Forwarding NewRx to pharmacy ${pharmacyId || 'default'}: ${pharmacyEndpoint}`); const options = { method: 'POST', @@ -328,7 +455,7 @@ class REMSIntermediary extends Server { headers: req.headers }; - const response = await axios(ncpdpScriptForwardUrl, options); + const response = await axios(pharmacyEndpoint, options); return res.send(response.data); } @@ -408,10 +535,13 @@ class REMSIntermediary extends Server { } catch (error: any) { console.error('Error processing NCPDP message:', error.message); + if (isPpaMessage(req.body)) { + return res.status(500).json(buildPpaError(req.body, '601', error.message)); + } return res.status(500).send('Error processing NCPDP message: ' + error.message); } }); - + return this; } @@ -485,9 +615,12 @@ class REMSIntermediary extends Server { const resource = new model({ to: req.body.to, toEtasu: req.body.toEtasu, + toNcpdp: req.body.toNcpdp, from: req.body.from || [EHRWhitelist.any], code: req.body.code, - system: req.body.system + system: req.body.system, + brand_name: req.body.brand_name || req.body.brandName || req.body.code, + generic_name: req.body.generic_name || req.body.genericName }); resource .save() @@ -585,4 +718,4 @@ class REMSIntermediary extends Server { // Start the application -export { REMSIntermediary, initialize }; \ No newline at end of file +export { REMSIntermediary, initialize }; diff --git a/src/services/guidanceresponse.service.ts b/src/services/guidanceresponse.service.ts index 128682a..ea68278 100644 --- a/src/services/guidanceresponse.service.ts +++ b/src/services/guidanceresponse.service.ts @@ -5,21 +5,18 @@ import axios from 'axios'; const getMedicationCode = ( medication: Medication | MedicationRequest | undefined ): Coding | undefined => { - // grab the medication drug code from the Medication resource - let drugCode; + const selectRoutingCode = (codings: Coding[] | undefined) => { + const ndc = codings?.find(medCode => medCode?.system?.toLowerCase().endsWith('/ndc')); + if (ndc) return ndc; + + return codings?.find(medCode => medCode?.system?.toLowerCase().includes('rxnorm')); + }; + if (medication?.resourceType == 'Medication') { - medication?.code?.coding?.forEach((medCode: Coding) => { - if (medCode?.system?.endsWith('rxnorm')) { - drugCode = medCode; - } - }); + return selectRoutingCode(medication?.code?.coding); } else { if (medication?.medicationCodeableConcept) { - medication?.medicationCodeableConcept?.coding?.forEach((medCode: Coding) => { - if (medCode.system?.endsWith('rxnorm')) { - drugCode = medCode; - } - }); + return selectRoutingCode(medication?.medicationCodeableConcept?.coding); } else if (medication?.medicationReference) { const ref = medication.medicationReference.reference; if (ref?.startsWith('#')) { @@ -33,7 +30,6 @@ const getMedicationCode = ( } } } - return drugCode; }; module.exports.remsEtasu = async (args: any, context: any, logger: any) => {