Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"}]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand All @@ -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
Expand Down
74 changes: 47 additions & 27 deletions dockerRunnerDev.sh
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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=$!
Expand All @@ -68,4 +89,3 @@ cd ..
wait $CONTINUOUS_INSTALL_PID $SERVER_PID $BACKEND_SERVER_PID
EXIT_CODE=$?
echo "application exited with exit code $EXIT_CODE..."

4 changes: 2 additions & 2 deletions frontend/src/views/DataViews/EditPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -208,4 +208,4 @@ const EditPopup = (props) => {
)
};

export default EditPopup;
export default EditPopup;
13 changes: 11 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,6 +38,7 @@ export type Config = {
discoverySplZipUrl: string | undefined;
splZipFileName: string;
ncpdpScriptForwardUrl: string;
ppaPharmacyEndpoints: string;
};
database: {
selected: string;
Expand Down Expand Up @@ -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(),
},
Expand Down
9 changes: 8 additions & 1 deletion src/hooks/hookProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -837,4 +844,4 @@ export async function getServiceConnection(coding: Coding, requester: string | u
return connection;
}
}
}
}
15 changes: 12 additions & 3 deletions src/hooks/hookResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -50,7 +59,7 @@ export function getDrugCodesFromMedicationRequest(medicationRequest: MedicationR
}
});
console.log('Found codes: ' + JSON.stringify(codes));
return codes;
return prioritizeNdc(codes);
}
}
return null;
Expand Down Expand Up @@ -313,4 +322,4 @@ export async function handleHook(
res.json(createErrorCard('No MedicationRequests in ' + hookType + ' hook'));
}
}
}
}
31 changes: 30 additions & 1 deletion src/lib/ncpdpHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -226,4 +255,4 @@ export function ndcToCoding(ndc: string): Coding {
system: 'http://hl7.org/fhir/sid/ndc',
code: ndc
};
}
}
Loading
Loading