From 4db4e55186c469855ac027938d627a2a340ecee4 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 26 Jan 2023 03:56:17 -0500 Subject: [PATCH 01/15] etasu changes --- docker-compose-dev.yml | 4 +- docker-sync.yml | 6 +- package.json | 1 + src/server.ts | 466 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 470 insertions(+), 7 deletions(-) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 475948e6..0cd28758 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -109,7 +109,7 @@ services: container_name: rems_dev_rems ports: # Port binding to host from docker container - - "9020:8090" # Bind port 3000 of host to 3000 of container + - "8090:8090" # Bind port 3000 of host to 3000 of container volumes: - rems_dev_rems-sync:/REMS:nocopy # nocopy is important @@ -184,7 +184,7 @@ volumes: # rems_dev_crd-server-bin: # rems_dev_crd-server-ValueSetCache: # rems_dev_crd-operations-build: - # rems_dev_crd-resources-build: + rems_dev_crd-resources-build: rems_dev_crd-request-generator-nodeModules: rems_dev_crd-request-generator-databaseData: rems_dev_crd-request-generator-build: diff --git a/docker-sync.yml b/docker-sync.yml index 0e24cbfa..9213f811 100644 --- a/docker-sync.yml +++ b/docker-sync.yml @@ -21,9 +21,9 @@ syncs: rems_dev_rems-sync: src: '.' - rems_dev_pharmacy-information-system-sync: - src: '../pharmacy-information-system' - sync_excludes: ['node_modules', 'backend/node_modules', 'logs'] + # rems_dev_pharmacy-information-system-sync: + # src: '../pharmacy-information-system' + # sync_excludes: ['node_modules', 'backend/node_modules', 'logs'] rems_dev_pims-sync: src: '../pims' diff --git a/package.json b/package.json index dafb56ff..55207d90 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "mongodb": "^4.12.1", "morgan": "^1.9.1", "tingodb": "^0.6.1", + "uid": "^2.0.1", "var": "^0.4.0", "winston": "^3.2.1", "winston-daily-rotate-file": "^4.2.1" diff --git a/src/server.ts b/src/server.ts index 6e42122f..b5e46a05 100644 --- a/src/server.ts +++ b/src/server.ts @@ -4,13 +4,20 @@ import container from './lib/winston'; import morgan from 'morgan'; import Hook from './hooks/Hook'; import remsService from './hooks/rems.hook'; +// import etasuService from './services/etasu.service' import { Server } from '@projecttacoma/node-fhir-server-core'; +import { Globals } from './globals'; +import { uid } from 'uid'; + + + const logger = container.get('application'); const initialize = (config: any) => { //const logLevel = _.get(config, 'logging.level'); return new REMSServer(config.fhirServerConfig) + .configureEtasuEndpoints() .configureMiddleware() .configureSession() .configureHelmet() @@ -19,6 +26,7 @@ const initialize = (config: any) => { .setProfileRoutes() .registerCdsHooks(config.server) .setErrorRoutes(); + }; /** @@ -67,8 +75,8 @@ class REMSServer extends Server { log ? log : morgan('combined', { - stream: { write: message => logger.log(level, message) } - }) + stream: { write: message => logger.log(level, message) } + }) ); return this; @@ -98,6 +106,460 @@ class REMSServer extends Server { return this; } + configureEtasuEndpoints() { + // etasu endpoints + + + const db = Globals.database; + + // define schemas + const medicationCollection = db.createCollection("medication-requirements", { + "name": { "type": "string" }, + "codeSystem": { "type": "string" }, + "code": { "type": "string" }, + "requirements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" }, + "questionnaire": { "type": "object" }, + "stakeholderType": { "type": "string" }, + "createNewCase": { "type": "boolean" }, + "resourceId": { "type": "string" } + } + } + } + }, (err: any, collection: any) => { + if (err) console.log(err); + }); + + medicationCollection.createIndex({ name: 1 }, { unique: true }, (err: any) => { + if (err) console.log(err); + }); + + const metRequirementsCollection = db.createCollection("met-requirements", { + "completed": { "type": "boolean" }, + "completedQuestionnaire": { "type": "object" }, + "requirementName": { "type": "string" }, + "drugName": { "type": "string" }, + "stakeholderId": { "type": "string" }, + "duplicationId": { "type": "number" }, + "case_numbers": { "type": "array", "items": { "type": "string" } } + }, (err: any, collection: any) => { + if (err) console.log(err); + }); + + metRequirementsCollection.createIndex({ duplicationId: 1 }, { unique: true }, (err: any) => { + if (err) console.log(err); + }); + + + const remsCaseCollection = db.createCollection("rems-case", { + "case_number": { "type": "string" }, + "status": { "type": "string" }, + "drugName": { "type": "string" }, + "metRequirements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "metRequirementId": { "type": "number" }, + "completed": { "type": "boolean" }, + "stakeholderId": { "type": "string" }, + "requirementName": { "type": "string" }, + } + } + } + }, (err: any, collection: any) => { + if (err) throw err; + }); + + + // prepopulateDB + medicationCollection.insert([{ + name: "Turalio", + codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", + code: "2183126", + requirements: [{ + name: "Patient Enrollment", + description: "Submit Patient Enrollment form to the REMS Administrator", + stakeholderType: "patient", + createNewCase: true, + resourceId: "TuralioRemsPatientEnrollment", + }, + { + name: "Prescriber Enrollment", + description: "Submit Prescriber Enrollment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TuralioPrescriberEnrollmentForm", + }, + { + name: "Prescriber Knowledge Assessment", + description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TuralioPrescriberKnowledgeAssessment", + }, + { + name: "Pharmacist Enrollment", + description: "Submit Pharmacist Enrollment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + }, + ] + }, + { + name: "TIRF", + codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", + code: "1237051", + requirements: [{ + name: "Patient Enrollment", + description: "Submit Patient Enrollment form to the REMS Administrator", + stakeholderType: "patient", + createNewCase: true, + resourceId: "TIRFRemsPatientEnrollment", + }, + { + name: "Prescriber Enrollment", + description: "Submit Prescriber Enrollment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TIRFPrescriberEnrollmentForm", + }, + { + name: "Prescriber Knowledge Assessment", + description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TIRFPrescriberKnowledgeAssessment", + }, + { + name: "Pharmacist Enrollment", + description: "Submit Pharmacist Enrollment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + }, + { + name: "Pharmacist Knowledge Assessment", + description: "Submit Pharmacist Knowledge Assessment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + }, + ] + }, + { + name: "IPledge", + codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", + code: "6064", + requirements: [{ + name: "Patient Enrollment", + description: "Submit Patient Enrollment form to the REMS Administrator", + stakeholderType: "patient", + createNewCase: true, + resourceId: "IPledgeRemsPatientEnrollment", + }, + { + name: "Prescriber Enrollment", + description: "Submit Prescriber Enrollment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "IPledgeRemsPrescriberEnrollmentForm" + }, + { + name: "Pharmacist Enrollment", + description: "Submit Pharmacist Enrollment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + }, + ] + }, + ], (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Drug Information'); + }); + + metRequirementsCollection.insert([{ + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Enrollment", + drugName: "Turalio", + duplicationId: 1 + }, + { + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Enrollment", + drugName: "TIRF", + duplicationId: 2 + }, + { + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Knowledge Assessment", + drugName: "TIRF", + duplicationId: 3 + }, + { + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Enrollment", + drugName: "IPledge", + duplicationId: 4 + }], (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Pharmacist Met Requirements'); + }); + + this.app.get('/etasu/:drug', (req: any, res: { send: (arg0: string) => any }) => { + medicationCollection.findOne({ "name": req.params.drug }, (err: any, drug: any) => { + if (err) throw err; + res.send(drug); + }); + } + ); + + this.app.get('/etasu/met/:caseId', (req: any, res: { send: (arg0: string) => any }) => { + remsCaseCollection.findOne({ "case_number": req.params.caseId }, (err: any, remsCase: any) => { + if (err) throw err; + res.send(remsCase); + }); + } + ); + + this.app.post('/etasu/met', (req: any, res: { send: (arg0: string) => any }) => { + let returnedRemsRequestDoc: any; + let returnedMetReqDoc: any; + let returnRemsRequest = false; + const requestBody = req.body; + + + // extract params and questionnaire response identifier + let params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference.textValue); + let questionnaireResponse = this.getQuestionnaireResponse(requestBody); + let questionnaireStringArray = questionnaireResponse.questionnaire.split("/"); + let requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; + + // stakeholder and medication references + let prescriptionReference = ""; + let practitionerReference = ""; + let pharmacistReference = ""; + let patientReference = ""; + for (let param of params.parameter) { + if (param.name === "prescription") { + prescriptionReference = param.reference; + } + else if (param.name === "prescriber") { + practitionerReference = param.reference; + } + else if (param.name === "pharmacy") { + pharmacistReference = param.reference; + } else if (param.name === "source-patient") { + patientReference = param.reference; + } + } + + // obtain drug information from database + let presciption = this.getResource(requestBody, prescriptionReference); + let prescriptionSystem = presciption.medicationCodeableConcept.coding[0].system; + let prescriptionCode = presciption.medicationCodeableConcept.coding[0].code; + const drug = medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem }); + + // iterate through each requirement of the drug + for (let requirement of drug.requirements) { + // figure out which stakeholder the req corresponds to + let reqStakeholder = requirement.stakeholderType; + let reqStakeholderReference = reqStakeholder.equals("prescriber") ? practitionerReference : (reqStakeholder.equals("pharmacist") ? pharmacistReference : patientReference); + + // if the requirement is the one submitted continue + if (requirement.resourceId.equals(requirementId)) { + + // if the req submitted is a patient enrollment form and requires creating a new case + if (requirement.createNewCase) { + returnRemsRequest = true; + const case_number = uid(); + + // create new rems request and add the created metReq to it + let remsRequestCompletedStatus = "Approved"; + let remsRequest: any = { + case_number: case_number, + status : remsRequestCompletedStatus, + drugName: drug.name, + requirements : [], + }; + returnRemsRequest = true; + + // create the metReq that was submitted + let metReq = { + completed: true, + completedQuestionnaire: questionnaireResponse, + requirementName: requirement.name, + drugName: drug.name, + stakeholderId: reqStakeholderReference, + case_numbers: [case_number], + }; + + const matchedMetReq = metRequirementsCollection.insert(metReq, (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Matched Met Requirement'); + }); + + remsRequest.requirements.push( + { + stakeholderId : matchedMetReq.stakeholderId, + completed : matchedMetReq.completed, + metRequirementId: matchedMetReq._id, + requirementName: matchedMetReq.requirementName, + } + ); + + // iterate through all other reqs again to create corresponding false metReqs / assign to existing + for (let requirement2 of drug.requirements) { + // skip if the req found is the same as in the outer loop and has already been processed + if (!requirement2.resourceId.equals(requirementId)) { + // figure out which stakeholder the req corresponds to + let reqStakeholder2 = requirement2.stakeholderType; + let reqStakeholder2Reference = reqStakeholder2.equals("prescriber") ? practitionerReference : (reqStakeholder2.equals("pharmacist") ? pharmacistReference : patientReference); + + const matchedMetReq2 = metRequirementsCollection.findOne({stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name}); + if (matchedMetReq2) { + remsRequest.requirements.push( + { + stakeholderId : matchedMetReq2.stakeholderId, + completed : matchedMetReq2.completed, + metRequirementId: matchedMetReq2._id, + requirementName: matchedMetReq2.requirementName, + } + ); + if(!matchedMetReq2.completed) { + remsRequestCompletedStatus = "Pending"; + } + matchedMetReq2.case_numbers.push(case_number); + metRequirementsCollection.update({_id: matchedMetReq2._id}, matchedMetReq2); + } else { + // create the metReq that was submitted + let newMetReq = { + completed: false, + completedQuestionnaire: null, + requirementName: requirement2.name, + drugName: drug.name, + stakeholderId: reqStakeholder2Reference, + case_numbers: [case_number], + }; + + remsRequestCompletedStatus = "Pending"; + + const newMetReqDoc = metRequirementsCollection.insert(newMetReq, (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted New Met Requirement'); + }); + + remsRequest.requirements.push( + { + stakeholderId : newMetReqDoc.stakeholderId, + completed : newMetReqDoc.completed, + metRequirementId: newMetReqDoc._id, + requirementName: newMetReqDoc.requirementName, + } + ); + } + } + } + + remsRequest.status = remsRequestCompletedStatus; + returnedRemsRequestDoc = remsCaseCollection.insert(remsRequest, (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Rems Case'); + }); + } else { + const matchedMetReq3 = metRequirementsCollection.findOne({stakeholderId: reqStakeholderReference, requirementName: requirement.name, drugName: drug.name}); + if (matchedMetReq3) { + matchedMetReq3.completed = true; + matchedMetReq3.completedQuestionnaire = questionnaireResponse; + returnedMetReqDoc = metRequirementsCollection.update({_id: matchedMetReq3._id}, matchedMetReq3); + + const remsRequestsToUpdate = remsCaseCollection.find({case_number: {$in: matchedMetReq3.case_numbers}}) + + for (let remsRequestToUpdate of remsRequestsToUpdate) { + let foundUncompleted = false; + remsRequestToUpdate.requirements.forEach((req4: any) => { + if(req4.metRequirementId.equals(matchedMetReq3._id)) { + req4.completed = true; + } + if(!req4.completed){ + foundUncompleted = true; + } + }); + + if(!foundUncompleted && remsRequestToUpdate.status.equals("Pending")) { + remsRequestToUpdate.status = "Approved"; + } + + remsCaseCollection.update({_id: remsRequestToUpdate._id}, remsRequestToUpdate); + + } + + } else { + // create the metReq that was submitted + let newMetReq3 = { + completed: true, + completedQuestionnaire: questionnaireResponse, + requirementName: requirement.name, + drugName: drug.name, + stakeholderId: reqStakeholderReference, + case_numbers: [], + }; + + returnedMetReqDoc = metRequirementsCollection.insert(newMetReq3, (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted New Met Requirement'); + }); + } + } + break; + } + } + + // return MetReq unless a new case is created in which case return the Rems request + if (returnRemsRequest) { + res.send(returnedRemsRequestDoc); + } else { + res.send(returnedRemsRequestDoc); + } + }); + + return this; + } + + getResource(bundle: { entry: any[]; }, resourceReference: string) { + let temp = resourceReference.split("/"); + let _resourceType = temp[0]; + let _id = temp[1]; + + for (let i = 0; i < bundle.entry.length; i++) { + if ((bundle.entry[i].resource.resourceType === _resourceType) + && (bundle.entry[i].resource.id === _id)) { + return bundle.entry[i].resource; + } + } + return null; + } + + getQuestionnaireResponse(bundle: { entry: any[]; }) { + let _resourceType = "QuestionnaireResponse"; + + for (let i = 0; i < bundle.entry.length; i++) { + if ((bundle.entry[i].resource.resourceType === _resourceType)) { + return bundle.entry[i].resource; + } + } + return null; + } + + + /** * @method listen * @description Start listening on the configured port From 18ca68c01437074ce2c1a81fe81cf46e13c30053 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 26 Jan 2023 05:49:16 -0500 Subject: [PATCH 02/15] changed. equal to === and added async/await --- src/server.ts | 85 +++++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/src/server.ts b/src/server.ts index b5e46a05..03a7a901 100644 --- a/src/server.ts +++ b/src/server.ts @@ -4,7 +4,6 @@ import container from './lib/winston'; import morgan from 'morgan'; import Hook from './hooks/Hook'; import remsService from './hooks/rems.hook'; -// import etasuService from './services/etasu.service' import { Server } from '@projecttacoma/node-fhir-server-core'; import { Globals } from './globals'; import { uid } from 'uid'; @@ -17,7 +16,6 @@ const logger = container.get('application'); const initialize = (config: any) => { //const logLevel = _.get(config, 'logging.level'); return new REMSServer(config.fhirServerConfig) - .configureEtasuEndpoints() .configureMiddleware() .configureSession() .configureHelmet() @@ -25,6 +23,7 @@ const initialize = (config: any) => { .setPublicDirectory() .setProfileRoutes() .registerCdsHooks(config.server) + .configureEtasuEndpoints() .setErrorRoutes(); }; @@ -329,15 +328,14 @@ class REMSServer extends Server { } ); - this.app.post('/etasu/met', (req: any, res: { send: (arg0: string) => any }) => { + this.app.post('/etasu/met', async (req: any, res: { send: (arg0: string) => any }) => { let returnedRemsRequestDoc: any; let returnedMetReqDoc: any; let returnRemsRequest = false; const requestBody = req.body; - // extract params and questionnaire response identifier - let params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference.textValue); + let params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference); let questionnaireResponse = this.getQuestionnaireResponse(requestBody); let questionnaireStringArray = questionnaireResponse.questionnaire.split("/"); let requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; @@ -365,16 +363,23 @@ class REMSServer extends Server { let presciption = this.getResource(requestBody, prescriptionReference); let prescriptionSystem = presciption.medicationCodeableConcept.coding[0].system; let prescriptionCode = presciption.medicationCodeableConcept.coding[0].code; - const drug = medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem }); - + + const drug = await medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem } + // , (err: any, result: any) => { + // if (err) console.log(err); + // console.log('Found Drug Info: '); + // console.log(result) + // return result; + // } + ); // iterate through each requirement of the drug for (let requirement of drug.requirements) { // figure out which stakeholder the req corresponds to let reqStakeholder = requirement.stakeholderType; - let reqStakeholderReference = reqStakeholder.equals("prescriber") ? practitionerReference : (reqStakeholder.equals("pharmacist") ? pharmacistReference : patientReference); + let reqStakeholderReference = reqStakeholder === "prescriber" ? practitionerReference : (reqStakeholder === "pharmacist" ? pharmacistReference : patientReference); // if the requirement is the one submitted continue - if (requirement.resourceId.equals(requirementId)) { + if (requirement.resourceId === requirementId) { // if the req submitted is a patient enrollment form and requires creating a new case if (requirement.createNewCase) { @@ -401,10 +406,12 @@ class REMSServer extends Server { case_numbers: [case_number], }; - const matchedMetReq = metRequirementsCollection.insert(metReq, (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted Matched Met Requirement'); - }); + const matchedMetReq = await metRequirementsCollection.insert(metReq + // , (err: any, result: any) => { + // if (err) console.log(err); + // console.log('Inserted Matched Met Requirement'); + // } + ); remsRequest.requirements.push( { @@ -418,12 +425,12 @@ class REMSServer extends Server { // iterate through all other reqs again to create corresponding false metReqs / assign to existing for (let requirement2 of drug.requirements) { // skip if the req found is the same as in the outer loop and has already been processed - if (!requirement2.resourceId.equals(requirementId)) { + if (!requirement2.resourceId === requirementId) { // figure out which stakeholder the req corresponds to let reqStakeholder2 = requirement2.stakeholderType; - let reqStakeholder2Reference = reqStakeholder2.equals("prescriber") ? practitionerReference : (reqStakeholder2.equals("pharmacist") ? pharmacistReference : patientReference); + let reqStakeholder2Reference = reqStakeholder2 === "prescriber" ? practitionerReference : (reqStakeholder2 === "pharmacist" ? pharmacistReference : patientReference); - const matchedMetReq2 = metRequirementsCollection.findOne({stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name}); + const matchedMetReq2 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name}); if (matchedMetReq2) { remsRequest.requirements.push( { @@ -437,7 +444,7 @@ class REMSServer extends Server { remsRequestCompletedStatus = "Pending"; } matchedMetReq2.case_numbers.push(case_number); - metRequirementsCollection.update({_id: matchedMetReq2._id}, matchedMetReq2); + await metRequirementsCollection.update({_id: matchedMetReq2._id}, matchedMetReq2); } else { // create the metReq that was submitted let newMetReq = { @@ -451,10 +458,12 @@ class REMSServer extends Server { remsRequestCompletedStatus = "Pending"; - const newMetReqDoc = metRequirementsCollection.insert(newMetReq, (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted New Met Requirement'); - }); + const newMetReqDoc = await metRequirementsCollection.insert(newMetReq + // , (err: any, result: any) => { + // if (err) console.log(err); + // console.log('Inserted New Met Requirement'); + // } + ); remsRequest.requirements.push( { @@ -469,23 +478,25 @@ class REMSServer extends Server { } remsRequest.status = remsRequestCompletedStatus; - returnedRemsRequestDoc = remsCaseCollection.insert(remsRequest, (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted Rems Case'); - }); + returnedRemsRequestDoc = await remsCaseCollection.insert(remsRequest + // , (err: any, result: any) => { + // if (err) console.log(err); + // console.log('Inserted Rems Case'); + // } + ); } else { - const matchedMetReq3 = metRequirementsCollection.findOne({stakeholderId: reqStakeholderReference, requirementName: requirement.name, drugName: drug.name}); + const matchedMetReq3 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholderReference, requirementName: requirement.name, drugName: drug.name}); if (matchedMetReq3) { matchedMetReq3.completed = true; matchedMetReq3.completedQuestionnaire = questionnaireResponse; - returnedMetReqDoc = metRequirementsCollection.update({_id: matchedMetReq3._id}, matchedMetReq3); + returnedMetReqDoc = await metRequirementsCollection.update({_id: matchedMetReq3._id}, matchedMetReq3); - const remsRequestsToUpdate = remsCaseCollection.find({case_number: {$in: matchedMetReq3.case_numbers}}) + const remsRequestsToUpdate = await remsCaseCollection.find({case_number: {$in: matchedMetReq3.case_numbers}}) for (let remsRequestToUpdate of remsRequestsToUpdate) { let foundUncompleted = false; remsRequestToUpdate.requirements.forEach((req4: any) => { - if(req4.metRequirementId.equals(matchedMetReq3._id)) { + if(req4.metRequirementId === matchedMetReq3._id) { req4.completed = true; } if(!req4.completed){ @@ -493,11 +504,11 @@ class REMSServer extends Server { } }); - if(!foundUncompleted && remsRequestToUpdate.status.equals("Pending")) { + if(!foundUncompleted && remsRequestToUpdate.status === "Pending") { remsRequestToUpdate.status = "Approved"; } - remsCaseCollection.update({_id: remsRequestToUpdate._id}, remsRequestToUpdate); + await remsCaseCollection.update({_id: remsRequestToUpdate._id}, remsRequestToUpdate); } @@ -512,10 +523,12 @@ class REMSServer extends Server { case_numbers: [], }; - returnedMetReqDoc = metRequirementsCollection.insert(newMetReq3, (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted New Met Requirement'); - }); + returnedMetReqDoc = await metRequirementsCollection.insert(newMetReq3 + // , (err: any, result: any) => { + // if (err) console.log(err); + // console.log('Inserted New Met Requirement'); + // } + ); } } break; @@ -526,7 +539,7 @@ class REMSServer extends Server { if (returnRemsRequest) { res.send(returnedRemsRequestDoc); } else { - res.send(returnedRemsRequestDoc); + res.send(returnedMetReqDoc); } }); From 6a5b76a9b3fe0c96bd639020f06f40a00aef3937 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Tue, 7 Feb 2023 12:50:49 -0500 Subject: [PATCH 03/15] add env.json to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 23372bd2..4b5c5735 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ dist/ .idea/ .DS_Store tingo_db/ +env.json \ No newline at end of file From fcc221de6a8cdd58ded3bbb45a062a95f2c77cd2 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 9 Feb 2023 12:31:27 -0500 Subject: [PATCH 04/15] etasu endpoints --- .vscode/launch.json | 31 +++++ docker-compose-dev.yml | 1 + package.json | 2 +- src/fhir/utilities.ts | 220 ++++++++++++++++++++++++++++++ src/main.ts | 1 + src/server.ts | 301 ++++++++++------------------------------- 6 files changed, 329 insertions(+), 227 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..ed4025a6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + // does not work currently + // { + // "name": "Debug REMS Backend (Docker)", + // "port": 8091, + // "request": "attach", + // "skipFiles": [ + // "/**" + // ], + // "type": "node", + // "localRoot": "${workspaceFolder}", + // "remoteRoot": "/REMS", + // "restart": true + // }, + { + "name": "Debug REMS Backend (Local)", + "port": 8091, + "request": "attach", + "skipFiles": [ + "/**" + ], + "type": "node", + "restart": true + } + ] +} \ No newline at end of file diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 1030c9d2..53f5f9ef 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -111,6 +111,7 @@ services: container_name: rems_dev_rems-administrator ports: - "8090:8090" + - "8091:8091" volumes: - rems_dev_rems-sync:/REMS:nocopy # nocopy is important - rems_dev_rems-nodeModules:/REMS/node_modules diff --git a/package.json b/package.json index bf4ed363..e4b88113 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "scripts": { "develop": "node dist/scripts/develop.js", - "start": "ts-node-dev src/scripts/serve.ts", + "start": "ts-node-dev --inspect=8091 src/scripts/serve.ts", "test": "jest --maxWorkers=4 --coverage --detectOpenHandles", "lint": "eslint \"**/*.{js,ts}\"", "lint:fix": "eslint \"**/*.{js,ts}\" --quiet --fix", diff --git a/src/fhir/utilities.ts b/src/fhir/utilities.ts index a4c60d61..21806804 100644 --- a/src/fhir/utilities.ts +++ b/src/fhir/utilities.ts @@ -284,4 +284,224 @@ export class FhirUtilities { }); }); } + + static async populateDB() { + const db = Globals.database; + + + // define schemas + const medicationCollection = await db.collection("medication-requirements" + // , { + // "name": { "type": "string" }, + // "codeSystem": { "type": "string" }, + // "code": { "type": "string" }, + // "requirements": { + // "type": "array", + // "items": { + // "type": "object", + // "properties": { + // "name": { "type": "string" }, + // "description": { "type": "string" }, + // "questionnaire": { "type": "object" }, + // "stakeholderType": { "type": "string" }, + // "createNewCase": { "type": "boolean" }, + // "resourceId": { "type": "string" } + // } + // } + // } + // }, (err: any, collection: any) => { + // if (err) console.log(err); + // } + ); + + + await medicationCollection.createIndex({ name: 1 }, { unique: true }); + + const metRequirementsCollection = await db.collection("met-requirements" + // , { + // "completed": { "type": "boolean" }, + // "completedQuestionnaire": { "type": "object" }, + // "requirementName": { "type": "string" }, + // "requirementDescription": {"type": "string"} + // "drugName": { "type": "string" }, + // "stakeholderId": { "type": "string" }, + // "case_numbers": { "type": "array", "items": { "type": "string" } } + // }, (err: any, collection: any) => { + // if (err) console.log(err); + // } + ); + + + metRequirementsCollection.createIndex({ drugName: 1, requirementName: 1, stakeholderId: 1 }, { unique: true }); + + + const remsCaseCollection = await db.collection("rems-case" + // , { + // "case_number": { "type": "string" }, + // "status": { "type": "string" }, + // "drugName": { "type": "string" }, + // "patientName": { "type": "string" }, + // "metRequirements": { + // "type": "array", + // "items": { + // "type": "object", + // "properties": { + // "metRequirementId": { "type": "number" }, + // "completed": { "type": "boolean" }, + // "stakeholderId": { "type": "string" }, + // "requirementName": { "type": "string" }, + // "requirementDescription": {"type": "string"}, + // } + // } + // } + // }, (err: any, collection: any) => { + // if (err) throw err; + // } + ); + + + // prepopulateDB + medicationCollection.insert([{ + name: "Turalio", + codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", + code: "2183126", + requirements: [{ + name: "Patient Enrollment", + description: "Submit Patient Enrollment form to the REMS Administrator", + stakeholderType: "patient", + createNewCase: true, + resourceId: "TuralioRemsPatientEnrollment", + }, + { + name: "Prescriber Enrollment", + description: "Submit Prescriber Enrollment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TuralioPrescriberEnrollmentForm", + }, + { + name: "Prescriber Knowledge Assessment", + description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TuralioPrescriberKnowledgeAssessment", + }, + { + name: "Pharmacist Enrollment", + description: "Submit Pharmacist Enrollment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + resourceId: "TuralioPharmacistEnrollment", + }, + ] + }, + { + name: "TIRF", + codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", + code: "1237051", + requirements: [{ + name: "Patient Enrollment", + description: "Submit Patient Enrollment form to the REMS Administrator", + stakeholderType: "patient", + createNewCase: true, + resourceId: "TIRFRemsPatientEnrollment", + }, + { + name: "Prescriber Enrollment", + description: "Submit Prescriber Enrollment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TIRFPrescriberEnrollmentForm", + }, + { + name: "Prescriber Knowledge Assessment", + description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "TIRFPrescriberKnowledgeAssessment", + }, + { + name: "Pharmacist Enrollment", + description: "Submit Pharmacist Enrollment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + resourceId: "TIRFPharmacistEnrollmentForm", + }, + { + name: "Pharmacist Knowledge Assessment", + description: "Submit Pharmacist Knowledge Assessment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + resourceId: "TIRFPharmacistKnowledgeAssessment", + }, + ] + }, + { + name: "IPledge", + codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", + code: "6064", + requirements: [{ + name: "Patient Enrollment", + description: "Submit Patient Enrollment form to the REMS Administrator", + stakeholderType: "patient", + createNewCase: true, + resourceId: "IPledgeRemsPatientEnrollment", + }, + { + name: "Prescriber Enrollment", + description: "Submit Prescriber Enrollment form to the REMS Administrator", + stakeholderType: "prescriber", + createNewCase: false, + resourceId: "IPledgeRemsPrescriberEnrollmentForm" + }, + { + name: "Pharmacist Enrollment", + description: "Submit Pharmacist Enrollment form to the REMS Administrator", + stakeholderType: "pharmacist", + createNewCase: false, + resourceId: "IPledgeRemsPharmacistEnrollmentForm" + }, + ] + }, + ], (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Drug Information'); + }); + + metRequirementsCollection.insert([{ + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Enrollment", + drugName: "Turalio", + completedQuestionnaire: null, + case_numbers: [], + }, + { + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Enrollment", + drugName: "TIRF", + completedQuestionnaire: null, + case_numbers: [], + }, + { + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Knowledge Assessment", + drugName: "TIRF", + completedQuestionnaire: null, + case_numbers: [], + }, + { + stakeholderId: "Organization/pharm0111", + completed: true, + requirementName: "Pharmacist Enrollment", + drugName: "IPledge", + completedQuestionnaire: null, + case_numbers: [], + }], (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Pharmacist Met Requirements'); + }); + } } diff --git a/src/main.ts b/src/main.ts index ff0931bd..c2fb6809 100644 --- a/src/main.ts +++ b/src/main.ts @@ -44,6 +44,7 @@ export default async function main() { // load the database with the default resources FhirUtilities.loadResources(config.general.resourcePath); + FhirUtilities.populateDB(); const app = initialize(config); diff --git a/src/server.ts b/src/server.ts index 03a7a901..85e0bd2d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -7,6 +7,7 @@ import remsService from './hooks/rems.hook'; import { Server } from '@projecttacoma/node-fhir-server-core'; import { Globals } from './globals'; import { uid } from 'uid'; +import { FhirUtilities } from './fhir/utilities'; @@ -106,212 +107,13 @@ class REMSServer extends Server { } configureEtasuEndpoints() { - // etasu endpoints - - const db = Globals.database; - // define schemas - const medicationCollection = db.createCollection("medication-requirements", { - "name": { "type": "string" }, - "codeSystem": { "type": "string" }, - "code": { "type": "string" }, - "requirements": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "description": { "type": "string" }, - "questionnaire": { "type": "object" }, - "stakeholderType": { "type": "string" }, - "createNewCase": { "type": "boolean" }, - "resourceId": { "type": "string" } - } - } - } - }, (err: any, collection: any) => { - if (err) console.log(err); - }); - - medicationCollection.createIndex({ name: 1 }, { unique: true }, (err: any) => { - if (err) console.log(err); - }); - - const metRequirementsCollection = db.createCollection("met-requirements", { - "completed": { "type": "boolean" }, - "completedQuestionnaire": { "type": "object" }, - "requirementName": { "type": "string" }, - "drugName": { "type": "string" }, - "stakeholderId": { "type": "string" }, - "duplicationId": { "type": "number" }, - "case_numbers": { "type": "array", "items": { "type": "string" } } - }, (err: any, collection: any) => { - if (err) console.log(err); - }); - - metRequirementsCollection.createIndex({ duplicationId: 1 }, { unique: true }, (err: any) => { - if (err) console.log(err); - }); - - - const remsCaseCollection = db.createCollection("rems-case", { - "case_number": { "type": "string" }, - "status": { "type": "string" }, - "drugName": { "type": "string" }, - "metRequirements": { - "type": "array", - "items": { - "type": "object", - "properties": { - "metRequirementId": { "type": "number" }, - "completed": { "type": "boolean" }, - "stakeholderId": { "type": "string" }, - "requirementName": { "type": "string" }, - } - } - } - }, (err: any, collection: any) => { - if (err) throw err; - }); - - - // prepopulateDB - medicationCollection.insert([{ - name: "Turalio", - codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", - code: "2183126", - requirements: [{ - name: "Patient Enrollment", - description: "Submit Patient Enrollment form to the REMS Administrator", - stakeholderType: "patient", - createNewCase: true, - resourceId: "TuralioRemsPatientEnrollment", - }, - { - name: "Prescriber Enrollment", - description: "Submit Prescriber Enrollment form to the REMS Administrator", - stakeholderType: "prescriber", - createNewCase: false, - resourceId: "TuralioPrescriberEnrollmentForm", - }, - { - name: "Prescriber Knowledge Assessment", - description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", - stakeholderType: "prescriber", - createNewCase: false, - resourceId: "TuralioPrescriberKnowledgeAssessment", - }, - { - name: "Pharmacist Enrollment", - description: "Submit Pharmacist Enrollment form to the REMS Administrator", - stakeholderType: "pharmacist", - createNewCase: false, - }, - ] - }, - { - name: "TIRF", - codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", - code: "1237051", - requirements: [{ - name: "Patient Enrollment", - description: "Submit Patient Enrollment form to the REMS Administrator", - stakeholderType: "patient", - createNewCase: true, - resourceId: "TIRFRemsPatientEnrollment", - }, - { - name: "Prescriber Enrollment", - description: "Submit Prescriber Enrollment form to the REMS Administrator", - stakeholderType: "prescriber", - createNewCase: false, - resourceId: "TIRFPrescriberEnrollmentForm", - }, - { - name: "Prescriber Knowledge Assessment", - description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", - stakeholderType: "prescriber", - createNewCase: false, - resourceId: "TIRFPrescriberKnowledgeAssessment", - }, - { - name: "Pharmacist Enrollment", - description: "Submit Pharmacist Enrollment form to the REMS Administrator", - stakeholderType: "pharmacist", - createNewCase: false, - }, - { - name: "Pharmacist Knowledge Assessment", - description: "Submit Pharmacist Knowledge Assessment form to the REMS Administrator", - stakeholderType: "pharmacist", - createNewCase: false, - }, - ] - }, - { - name: "IPledge", - codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", - code: "6064", - requirements: [{ - name: "Patient Enrollment", - description: "Submit Patient Enrollment form to the REMS Administrator", - stakeholderType: "patient", - createNewCase: true, - resourceId: "IPledgeRemsPatientEnrollment", - }, - { - name: "Prescriber Enrollment", - description: "Submit Prescriber Enrollment form to the REMS Administrator", - stakeholderType: "prescriber", - createNewCase: false, - resourceId: "IPledgeRemsPrescriberEnrollmentForm" - }, - { - name: "Pharmacist Enrollment", - description: "Submit Pharmacist Enrollment form to the REMS Administrator", - stakeholderType: "pharmacist", - createNewCase: false, - }, - ] - }, - ], (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted Drug Information'); - }); - - metRequirementsCollection.insert([{ - stakeholderId: "Organization/pharm0111", - completed: true, - requirementName: "Pharmacist Enrollment", - drugName: "Turalio", - duplicationId: 1 - }, - { - stakeholderId: "Organization/pharm0111", - completed: true, - requirementName: "Pharmacist Enrollment", - drugName: "TIRF", - duplicationId: 2 - }, - { - stakeholderId: "Organization/pharm0111", - completed: true, - requirementName: "Pharmacist Knowledge Assessment", - drugName: "TIRF", - duplicationId: 3 - }, - { - stakeholderId: "Organization/pharm0111", - completed: true, - requirementName: "Pharmacist Enrollment", - drugName: "IPledge", - duplicationId: 4 - }], (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted Pharmacist Met Requirements'); - }); + const medicationCollection = db.collection("medication-requirements"); + const metRequirementsCollection = db.collection("met-requirements"); + const remsCaseCollection = db.collection("rems-case"); + // etasu endpoints this.app.get('/etasu/:drug', (req: any, res: { send: (arg0: string) => any }) => { medicationCollection.findOne({ "name": req.params.drug }, (err: any, drug: any) => { if (err) throw err; @@ -328,6 +130,25 @@ class REMSServer extends Server { } ); + this.app.get('/etasu/met/patient/:patientName/drug/:drugName', (req: any, res: { send: (arg0: string) => any }) => { + remsCaseCollection.findOne({ patientName : req.params.patientName, drugName: req.params.drugName}, (err: any, remsCase: any) => { + if (err) throw err; + res.send(remsCase); + }); + } + ); + + this.app.post('/etasu/reset', (req: any, res: { send: (arg0: string) => any }) => { + console.log("Dropping collections"); + medicationCollection.drop(); + remsCaseCollection.drop(); + metRequirementsCollection.drop(); + console.log("Resetting the database"); + FhirUtilities.populateDB(); + res.send("reset etasu database collections"); + } + ); + this.app.post('/etasu/met', async (req: any, res: { send: (arg0: string) => any }) => { let returnedRemsRequestDoc: any; let returnedMetReqDoc: any; @@ -363,6 +184,8 @@ class REMSServer extends Server { let presciption = this.getResource(requestBody, prescriptionReference); let prescriptionSystem = presciption.medicationCodeableConcept.coding[0].system; let prescriptionCode = presciption.medicationCodeableConcept.coding[0].code; + let patient = this.getResource(requestBody, patientReference); + let patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; const drug = await medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem } // , (err: any, result: any) => { @@ -392,7 +215,8 @@ class REMSServer extends Server { case_number: case_number, status : remsRequestCompletedStatus, drugName: drug.name, - requirements : [], + patientName: patientName, + metRequirements : [], }; returnRemsRequest = true; @@ -401,56 +225,63 @@ class REMSServer extends Server { completed: true, completedQuestionnaire: questionnaireResponse, requirementName: requirement.name, + requirementDescription: requirement.description, drugName: drug.name, stakeholderId: reqStakeholderReference, case_numbers: [case_number], }; - const matchedMetReq = await metRequirementsCollection.insert(metReq + await metRequirementsCollection.insertOne(metReq // , (err: any, result: any) => { // if (err) console.log(err); // console.log('Inserted Matched Met Requirement'); // } ); + + const matchedMetReq = await metRequirementsCollection.findOne(metReq); + - remsRequest.requirements.push( + remsRequest.metRequirements.push( { stakeholderId : matchedMetReq.stakeholderId, completed : matchedMetReq.completed, metRequirementId: matchedMetReq._id, requirementName: matchedMetReq.requirementName, + requirementDescription: matchedMetReq.requirementDescription, } ); // iterate through all other reqs again to create corresponding false metReqs / assign to existing for (let requirement2 of drug.requirements) { // skip if the req found is the same as in the outer loop and has already been processed - if (!requirement2.resourceId === requirementId) { + if (!(requirement2.resourceId === requirementId)) { // figure out which stakeholder the req corresponds to let reqStakeholder2 = requirement2.stakeholderType; let reqStakeholder2Reference = reqStakeholder2 === "prescriber" ? practitionerReference : (reqStakeholder2 === "pharmacist" ? pharmacistReference : patientReference); const matchedMetReq2 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name}); if (matchedMetReq2) { - remsRequest.requirements.push( + remsRequest.metRequirements.push( { stakeholderId : matchedMetReq2.stakeholderId, completed : matchedMetReq2.completed, metRequirementId: matchedMetReq2._id, requirementName: matchedMetReq2.requirementName, + requirementDescription: matchedMetReq2.requirementDescription, } ); if(!matchedMetReq2.completed) { remsRequestCompletedStatus = "Pending"; } - matchedMetReq2.case_numbers.push(case_number); - await metRequirementsCollection.update({_id: matchedMetReq2._id}, matchedMetReq2); + // matchedMetReq2.case_numbers.push(case_number); + await metRequirementsCollection.updateOne(matchedMetReq2, {$addToSet: {case_numbers: case_number}}); } else { // create the metReq that was submitted let newMetReq = { completed: false, completedQuestionnaire: null, requirementName: requirement2.name, + requirementDescription: requirement2.description, drugName: drug.name, stakeholderId: reqStakeholder2Reference, case_numbers: [case_number], @@ -458,19 +289,23 @@ class REMSServer extends Server { remsRequestCompletedStatus = "Pending"; - const newMetReqDoc = await metRequirementsCollection.insert(newMetReq + await metRequirementsCollection.insertOne(newMetReq // , (err: any, result: any) => { // if (err) console.log(err); // console.log('Inserted New Met Requirement'); // } ); - remsRequest.requirements.push( + const newMetReqDoc = await metRequirementsCollection.findOne(newMetReq); + + + remsRequest.metRequirements.push( { stakeholderId : newMetReqDoc.stakeholderId, completed : newMetReqDoc.completed, metRequirementId: newMetReqDoc._id, requirementName: newMetReqDoc.requirementName, + requirementDescription: newMetReqDoc.requirementDescription, } ); } @@ -478,39 +313,51 @@ class REMSServer extends Server { } remsRequest.status = remsRequestCompletedStatus; - returnedRemsRequestDoc = await remsCaseCollection.insert(remsRequest + await remsCaseCollection.insertOne(remsRequest // , (err: any, result: any) => { // if (err) console.log(err); // console.log('Inserted Rems Case'); // } ); + returnedRemsRequestDoc = await remsCaseCollection.findOne(remsRequest); } else { const matchedMetReq3 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholderReference, requirementName: requirement.name, drugName: drug.name}); if (matchedMetReq3) { - matchedMetReq3.completed = true; - matchedMetReq3.completedQuestionnaire = questionnaireResponse; - returnedMetReqDoc = await metRequirementsCollection.update({_id: matchedMetReq3._id}, matchedMetReq3); + // matchedMetReq3.completed = true; + // matchedMetReq3.completedQuestionnaire = questionnaireResponse; + await metRequirementsCollection.updateOne(matchedMetReq3, {$set: {completed: true, completedQuestionnaire: questionnaireResponse}}); + + returnedMetReqDoc = await metRequirementsCollection.findOne({_id: matchedMetReq3._id}); - const remsRequestsToUpdate = await remsCaseCollection.find({case_number: {$in: matchedMetReq3.case_numbers}}) + // this should be an array returned via .find() - tried using $in but could not get it to work - using the first element for now as a work around since we only have one patient + const remsRequestToUpdate = await remsCaseCollection.findOne({ case_number: returnedMetReqDoc.case_numbers[0] }); - for (let remsRequestToUpdate of remsRequestsToUpdate) { + // for (let remsRequestToUpdate of remsRequestsToUpdate) { let foundUncompleted = false; - remsRequestToUpdate.requirements.forEach((req4: any) => { - if(req4.metRequirementId === matchedMetReq3._id) { + let metReqArray = remsRequestToUpdate.metRequirements; + for (let i=0; i < remsRequestToUpdate.metRequirements.length; i++) { + let req4 = remsRequestToUpdate.metRequirements[i]; + // _id comparison would not work for some reason + if(req4.requirementName === matchedMetReq3.requirementName) { + metReqArray[i].completed = true; req4.completed = true; + const update = await remsCaseCollection.updateOne({_id: remsRequestToUpdate._id}, {$set: {metRequirements: metReqArray}}); } if(!req4.completed){ foundUncompleted = true; } - }); + } + // remsRequestToUpdate.metRequirements.forEach(async (req4: any, index: number) => { + + // }); if(!foundUncompleted && remsRequestToUpdate.status === "Pending") { - remsRequestToUpdate.status = "Approved"; + // remsRequestToUpdate.status = "Approved"; + await remsCaseCollection.updateOne(remsRequestToUpdate, {$set: {status: "Approved"}}); } - await remsCaseCollection.update({_id: remsRequestToUpdate._id}, remsRequestToUpdate); - - } + + // } } else { // create the metReq that was submitted @@ -518,17 +365,19 @@ class REMSServer extends Server { completed: true, completedQuestionnaire: questionnaireResponse, requirementName: requirement.name, + requirementDescription: requirement.requirementDescription, drugName: drug.name, stakeholderId: reqStakeholderReference, case_numbers: [], }; - returnedMetReqDoc = await metRequirementsCollection.insert(newMetReq3 + await metRequirementsCollection.insertOne(newMetReq3 // , (err: any, result: any) => { // if (err) console.log(err); // console.log('Inserted New Met Requirement'); // } ); + returnedMetReqDoc = await metRequirementsCollection.findOne(newMetReq3); } } break; From 91905c69f8e14926193c9c2f7feb6ba0a2ad7830 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 9 Feb 2023 15:53:46 -0500 Subject: [PATCH 05/15] double quotes lint to single quotes --- src/fhir/utilities.ts | 214 +++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/src/fhir/utilities.ts b/src/fhir/utilities.ts index 21806804..d81ffbe0 100644 --- a/src/fhir/utilities.ts +++ b/src/fhir/utilities.ts @@ -290,22 +290,22 @@ export class FhirUtilities { // define schemas - const medicationCollection = await db.collection("medication-requirements" + const medicationCollection = await db.collection('medication-requirements' // , { - // "name": { "type": "string" }, - // "codeSystem": { "type": "string" }, - // "code": { "type": "string" }, - // "requirements": { - // "type": "array", - // "items": { - // "type": "object", - // "properties": { - // "name": { "type": "string" }, - // "description": { "type": "string" }, - // "questionnaire": { "type": "object" }, - // "stakeholderType": { "type": "string" }, - // "createNewCase": { "type": "boolean" }, - // "resourceId": { "type": "string" } + // 'name': { 'type': 'string' }, + // 'codeSystem': { 'type': 'string' }, + // 'code': { 'type': 'string' }, + // 'requirements': { + // 'type': 'array', + // 'items': { + // 'type': 'object', + // 'properties': { + // 'name': { 'type': 'string' }, + // 'description': { 'type': 'string' }, + // 'questionnaire': { 'type': 'object' }, + // 'stakeholderType': { 'type': 'string' }, + // 'createNewCase': { 'type': 'boolean' }, + // 'resourceId': { 'type': 'string' } // } // } // } @@ -317,15 +317,15 @@ export class FhirUtilities { await medicationCollection.createIndex({ name: 1 }, { unique: true }); - const metRequirementsCollection = await db.collection("met-requirements" + const metRequirementsCollection = await db.collection('met-requirements' // , { - // "completed": { "type": "boolean" }, - // "completedQuestionnaire": { "type": "object" }, - // "requirementName": { "type": "string" }, - // "requirementDescription": {"type": "string"} - // "drugName": { "type": "string" }, - // "stakeholderId": { "type": "string" }, - // "case_numbers": { "type": "array", "items": { "type": "string" } } + // 'completed': { 'type': 'boolean' }, + // 'completedQuestionnaire': { 'type': 'object' }, + // 'requirementName': { 'type': 'string' }, + // 'requirementDescription': {'type': 'string'} + // 'drugName': { 'type': 'string' }, + // 'stakeholderId': { 'type': 'string' }, + // 'case_numbers': { 'type': 'array', 'items': { 'type': 'string' } } // }, (err: any, collection: any) => { // if (err) console.log(err); // } @@ -335,22 +335,22 @@ export class FhirUtilities { metRequirementsCollection.createIndex({ drugName: 1, requirementName: 1, stakeholderId: 1 }, { unique: true }); - const remsCaseCollection = await db.collection("rems-case" + const remsCaseCollection = await db.collection('rems-case' // , { - // "case_number": { "type": "string" }, - // "status": { "type": "string" }, - // "drugName": { "type": "string" }, - // "patientName": { "type": "string" }, - // "metRequirements": { - // "type": "array", - // "items": { - // "type": "object", - // "properties": { - // "metRequirementId": { "type": "number" }, - // "completed": { "type": "boolean" }, - // "stakeholderId": { "type": "string" }, - // "requirementName": { "type": "string" }, - // "requirementDescription": {"type": "string"}, + // 'case_number': { 'type': 'string' }, + // 'status': { 'type': 'string' }, + // 'drugName': { 'type': 'string' }, + // 'patientName': { 'type': 'string' }, + // 'metRequirements': { + // 'type': 'array', + // 'items': { + // 'type': 'object', + // 'properties': { + // 'metRequirementId': { 'type': 'number' }, + // 'completed': { 'type': 'boolean' }, + // 'stakeholderId': { 'type': 'string' }, + // 'requirementName': { 'type': 'string' }, + // 'requirementDescription': {'type': 'string'}, // } // } // } @@ -362,104 +362,104 @@ export class FhirUtilities { // prepopulateDB medicationCollection.insert([{ - name: "Turalio", - codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", - code: "2183126", + name: 'Turalio', + codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '2183126', requirements: [{ - name: "Patient Enrollment", - description: "Submit Patient Enrollment form to the REMS Administrator", - stakeholderType: "patient", + name: 'Patient Enrollment', + description: 'Submit Patient Enrollment form to the REMS Administrator', + stakeholderType: 'patient', createNewCase: true, - resourceId: "TuralioRemsPatientEnrollment", + resourceId: 'TuralioRemsPatientEnrollment', }, { - name: "Prescriber Enrollment", - description: "Submit Prescriber Enrollment form to the REMS Administrator", - stakeholderType: "prescriber", + name: 'Prescriber Enrollment', + description: 'Submit Prescriber Enrollment form to the REMS Administrator', + stakeholderType: 'prescriber', createNewCase: false, - resourceId: "TuralioPrescriberEnrollmentForm", + resourceId: 'TuralioPrescriberEnrollmentForm', }, { - name: "Prescriber Knowledge Assessment", - description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", - stakeholderType: "prescriber", + name: 'Prescriber Knowledge Assessment', + description: 'Submit Prescriber Knowledge Assessment form to the REMS Administrator', + stakeholderType: 'prescriber', createNewCase: false, - resourceId: "TuralioPrescriberKnowledgeAssessment", + resourceId: 'TuralioPrescriberKnowledgeAssessment', }, { - name: "Pharmacist Enrollment", - description: "Submit Pharmacist Enrollment form to the REMS Administrator", - stakeholderType: "pharmacist", + name: 'Pharmacist Enrollment', + description: 'Submit Pharmacist Enrollment form to the REMS Administrator', + stakeholderType: 'pharmacist', createNewCase: false, - resourceId: "TuralioPharmacistEnrollment", + resourceId: 'TuralioPharmacistEnrollment', }, ] }, { - name: "TIRF", - codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", - code: "1237051", + name: 'TIRF', + codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '1237051', requirements: [{ - name: "Patient Enrollment", - description: "Submit Patient Enrollment form to the REMS Administrator", - stakeholderType: "patient", + name: 'Patient Enrollment', + description: 'Submit Patient Enrollment form to the REMS Administrator', + stakeholderType: 'patient', createNewCase: true, - resourceId: "TIRFRemsPatientEnrollment", + resourceId: 'TIRFRemsPatientEnrollment', }, { - name: "Prescriber Enrollment", - description: "Submit Prescriber Enrollment form to the REMS Administrator", - stakeholderType: "prescriber", + name: 'Prescriber Enrollment', + description: 'Submit Prescriber Enrollment form to the REMS Administrator', + stakeholderType: 'prescriber', createNewCase: false, - resourceId: "TIRFPrescriberEnrollmentForm", + resourceId: 'TIRFPrescriberEnrollmentForm', }, { - name: "Prescriber Knowledge Assessment", - description: "Submit Prescriber Knowledge Assessment form to the REMS Administrator", - stakeholderType: "prescriber", + name: 'Prescriber Knowledge Assessment', + description: 'Submit Prescriber Knowledge Assessment form to the REMS Administrator', + stakeholderType: 'prescriber', createNewCase: false, - resourceId: "TIRFPrescriberKnowledgeAssessment", + resourceId: 'TIRFPrescriberKnowledgeAssessment', }, { - name: "Pharmacist Enrollment", - description: "Submit Pharmacist Enrollment form to the REMS Administrator", - stakeholderType: "pharmacist", + name: 'Pharmacist Enrollment', + description: 'Submit Pharmacist Enrollment form to the REMS Administrator', + stakeholderType: 'pharmacist', createNewCase: false, - resourceId: "TIRFPharmacistEnrollmentForm", + resourceId: 'TIRFPharmacistEnrollmentForm', }, { - name: "Pharmacist Knowledge Assessment", - description: "Submit Pharmacist Knowledge Assessment form to the REMS Administrator", - stakeholderType: "pharmacist", + name: 'Pharmacist Knowledge Assessment', + description: 'Submit Pharmacist Knowledge Assessment form to the REMS Administrator', + stakeholderType: 'pharmacist', createNewCase: false, - resourceId: "TIRFPharmacistKnowledgeAssessment", + resourceId: 'TIRFPharmacistKnowledgeAssessment', }, ] }, { - name: "IPledge", - codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", - code: "6064", + name: 'IPledge', + codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '6064', requirements: [{ - name: "Patient Enrollment", - description: "Submit Patient Enrollment form to the REMS Administrator", - stakeholderType: "patient", + name: 'Patient Enrollment', + description: 'Submit Patient Enrollment form to the REMS Administrator', + stakeholderType: 'patient', createNewCase: true, - resourceId: "IPledgeRemsPatientEnrollment", + resourceId: 'IPledgeRemsPatientEnrollment', }, { - name: "Prescriber Enrollment", - description: "Submit Prescriber Enrollment form to the REMS Administrator", - stakeholderType: "prescriber", + name: 'Prescriber Enrollment', + description: 'Submit Prescriber Enrollment form to the REMS Administrator', + stakeholderType: 'prescriber', createNewCase: false, - resourceId: "IPledgeRemsPrescriberEnrollmentForm" + resourceId: 'IPledgeRemsPrescriberEnrollmentForm' }, { - name: "Pharmacist Enrollment", - description: "Submit Pharmacist Enrollment form to the REMS Administrator", - stakeholderType: "pharmacist", + name: 'Pharmacist Enrollment', + description: 'Submit Pharmacist Enrollment form to the REMS Administrator', + stakeholderType: 'pharmacist', createNewCase: false, - resourceId: "IPledgeRemsPharmacistEnrollmentForm" + resourceId: 'IPledgeRemsPharmacistEnrollmentForm' }, ] }, @@ -469,34 +469,34 @@ export class FhirUtilities { }); metRequirementsCollection.insert([{ - stakeholderId: "Organization/pharm0111", + stakeholderId: 'Organization/pharm0111', completed: true, - requirementName: "Pharmacist Enrollment", - drugName: "Turalio", + requirementName: 'Pharmacist Enrollment', + drugName: 'Turalio', completedQuestionnaire: null, case_numbers: [], }, { - stakeholderId: "Organization/pharm0111", + stakeholderId: 'Organization/pharm0111', completed: true, - requirementName: "Pharmacist Enrollment", - drugName: "TIRF", + requirementName: 'Pharmacist Enrollment', + drugName: 'TIRF', completedQuestionnaire: null, case_numbers: [], }, { - stakeholderId: "Organization/pharm0111", + stakeholderId: 'Organization/pharm0111', completed: true, - requirementName: "Pharmacist Knowledge Assessment", - drugName: "TIRF", + requirementName: 'Pharmacist Knowledge Assessment', + drugName: 'TIRF', completedQuestionnaire: null, case_numbers: [], }, { - stakeholderId: "Organization/pharm0111", + stakeholderId: 'Organization/pharm0111', completed: true, - requirementName: "Pharmacist Enrollment", - drugName: "IPledge", + requirementName: 'Pharmacist Enrollment', + drugName: 'IPledge', completedQuestionnaire: null, case_numbers: [], }], (err: any, result: any) => { From ce6505e611eee6a1013cf483a2e5acd465af45b9 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 9 Feb 2023 15:57:22 -0500 Subject: [PATCH 06/15] linting change double quotes to single --- src/server.ts | 54 +++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/server.ts b/src/server.ts index 85e0bd2d..c3018ae0 100644 --- a/src/server.ts +++ b/src/server.ts @@ -109,13 +109,13 @@ class REMSServer extends Server { configureEtasuEndpoints() { const db = Globals.database; - const medicationCollection = db.collection("medication-requirements"); - const metRequirementsCollection = db.collection("met-requirements"); - const remsCaseCollection = db.collection("rems-case"); + const medicationCollection = db.collection('medication-requirements'); + const metRequirementsCollection = db.collection('met-requirements'); + const remsCaseCollection = db.collection('rems-case'); // etasu endpoints this.app.get('/etasu/:drug', (req: any, res: { send: (arg0: string) => any }) => { - medicationCollection.findOne({ "name": req.params.drug }, (err: any, drug: any) => { + medicationCollection.findOne({ 'name': req.params.drug }, (err: any, drug: any) => { if (err) throw err; res.send(drug); }); @@ -123,7 +123,7 @@ class REMSServer extends Server { ); this.app.get('/etasu/met/:caseId', (req: any, res: { send: (arg0: string) => any }) => { - remsCaseCollection.findOne({ "case_number": req.params.caseId }, (err: any, remsCase: any) => { + remsCaseCollection.findOne({ 'case_number': req.params.caseId }, (err: any, remsCase: any) => { if (err) throw err; res.send(remsCase); }); @@ -139,13 +139,13 @@ class REMSServer extends Server { ); this.app.post('/etasu/reset', (req: any, res: { send: (arg0: string) => any }) => { - console.log("Dropping collections"); + console.log('Dropping collections'); medicationCollection.drop(); remsCaseCollection.drop(); metRequirementsCollection.drop(); - console.log("Resetting the database"); + console.log('Resetting the database'); FhirUtilities.populateDB(); - res.send("reset etasu database collections"); + res.send('reset etasu database collections'); } ); @@ -158,24 +158,24 @@ class REMSServer extends Server { // extract params and questionnaire response identifier let params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference); let questionnaireResponse = this.getQuestionnaireResponse(requestBody); - let questionnaireStringArray = questionnaireResponse.questionnaire.split("/"); + let questionnaireStringArray = questionnaireResponse.questionnaire.split('/'); let requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; // stakeholder and medication references - let prescriptionReference = ""; - let practitionerReference = ""; - let pharmacistReference = ""; - let patientReference = ""; + let prescriptionReference = ''; + let practitionerReference = ''; + let pharmacistReference = ''; + let patientReference = ''; for (let param of params.parameter) { - if (param.name === "prescription") { + if (param.name === 'prescription') { prescriptionReference = param.reference; } - else if (param.name === "prescriber") { + else if (param.name === 'prescriber') { practitionerReference = param.reference; } - else if (param.name === "pharmacy") { + else if (param.name === 'pharmacy') { pharmacistReference = param.reference; - } else if (param.name === "source-patient") { + } else if (param.name === 'source-patient') { patientReference = param.reference; } } @@ -199,7 +199,7 @@ class REMSServer extends Server { for (let requirement of drug.requirements) { // figure out which stakeholder the req corresponds to let reqStakeholder = requirement.stakeholderType; - let reqStakeholderReference = reqStakeholder === "prescriber" ? practitionerReference : (reqStakeholder === "pharmacist" ? pharmacistReference : patientReference); + let reqStakeholderReference = reqStakeholder === 'prescriber' ? practitionerReference : (reqStakeholder === 'pharmacist' ? pharmacistReference : patientReference); // if the requirement is the one submitted continue if (requirement.resourceId === requirementId) { @@ -210,7 +210,7 @@ class REMSServer extends Server { const case_number = uid(); // create new rems request and add the created metReq to it - let remsRequestCompletedStatus = "Approved"; + let remsRequestCompletedStatus = 'Approved'; let remsRequest: any = { case_number: case_number, status : remsRequestCompletedStatus, @@ -257,7 +257,7 @@ class REMSServer extends Server { if (!(requirement2.resourceId === requirementId)) { // figure out which stakeholder the req corresponds to let reqStakeholder2 = requirement2.stakeholderType; - let reqStakeholder2Reference = reqStakeholder2 === "prescriber" ? practitionerReference : (reqStakeholder2 === "pharmacist" ? pharmacistReference : patientReference); + let reqStakeholder2Reference = reqStakeholder2 === 'prescriber' ? practitionerReference : (reqStakeholder2 === 'pharmacist' ? pharmacistReference : patientReference); const matchedMetReq2 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name}); if (matchedMetReq2) { @@ -271,7 +271,7 @@ class REMSServer extends Server { } ); if(!matchedMetReq2.completed) { - remsRequestCompletedStatus = "Pending"; + remsRequestCompletedStatus = 'Pending'; } // matchedMetReq2.case_numbers.push(case_number); await metRequirementsCollection.updateOne(matchedMetReq2, {$addToSet: {case_numbers: case_number}}); @@ -287,7 +287,7 @@ class REMSServer extends Server { case_numbers: [case_number], }; - remsRequestCompletedStatus = "Pending"; + remsRequestCompletedStatus = 'Pending'; await metRequirementsCollection.insertOne(newMetReq // , (err: any, result: any) => { @@ -351,9 +351,9 @@ class REMSServer extends Server { // }); - if(!foundUncompleted && remsRequestToUpdate.status === "Pending") { - // remsRequestToUpdate.status = "Approved"; - await remsCaseCollection.updateOne(remsRequestToUpdate, {$set: {status: "Approved"}}); + if(!foundUncompleted && remsRequestToUpdate.status === 'Pending') { + // remsRequestToUpdate.status = 'Approved'; + await remsCaseCollection.updateOne(remsRequestToUpdate, {$set: {status: 'Approved'}}); } @@ -396,7 +396,7 @@ class REMSServer extends Server { } getResource(bundle: { entry: any[]; }, resourceReference: string) { - let temp = resourceReference.split("/"); + let temp = resourceReference.split('/'); let _resourceType = temp[0]; let _id = temp[1]; @@ -410,7 +410,7 @@ class REMSServer extends Server { } getQuestionnaireResponse(bundle: { entry: any[]; }) { - let _resourceType = "QuestionnaireResponse"; + let _resourceType = 'QuestionnaireResponse'; for (let i = 0; i < bundle.entry.length; i++) { if ((bundle.entry[i].resource.resourceType === _resourceType)) { From f7132ba43871e835b19a23f755b63a72846bf29f Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 9 Feb 2023 16:02:01 -0500 Subject: [PATCH 07/15] linting --- src/server.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/server.ts b/src/server.ts index c3018ae0..e084b42b 100644 --- a/src/server.ts +++ b/src/server.ts @@ -156,17 +156,17 @@ class REMSServer extends Server { const requestBody = req.body; // extract params and questionnaire response identifier - let params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference); - let questionnaireResponse = this.getQuestionnaireResponse(requestBody); - let questionnaireStringArray = questionnaireResponse.questionnaire.split('/'); - let requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; + const params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference); + const questionnaireResponse = this.getQuestionnaireResponse(requestBody); + const questionnaireStringArray = questionnaireResponse.questionnaire.split('/'); + const requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; // stakeholder and medication references let prescriptionReference = ''; let practitionerReference = ''; let pharmacistReference = ''; let patientReference = ''; - for (let param of params.parameter) { + for (const param of params.parameter) { if (param.name === 'prescription') { prescriptionReference = param.reference; } @@ -181,11 +181,11 @@ class REMSServer extends Server { } // obtain drug information from database - let presciption = this.getResource(requestBody, prescriptionReference); - let prescriptionSystem = presciption.medicationCodeableConcept.coding[0].system; - let prescriptionCode = presciption.medicationCodeableConcept.coding[0].code; - let patient = this.getResource(requestBody, patientReference); - let patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; + const presciption = this.getResource(requestBody, prescriptionReference); + const prescriptionSystem = presciption.medicationCodeableConcept.coding[0].system; + const prescriptionCode = presciption.medicationCodeableConcept.coding[0].code; + const patient = this.getResource(requestBody, patientReference); + const patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; const drug = await medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem } // , (err: any, result: any) => { From e45faf0c45e0a4bac7c2f3fa83637dcc83e9eeec Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 9 Feb 2023 16:09:03 -0500 Subject: [PATCH 08/15] linting --- src/server.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/server.ts b/src/server.ts index e084b42b..573ca2d1 100644 --- a/src/server.ts +++ b/src/server.ts @@ -196,10 +196,10 @@ class REMSServer extends Server { // } ); // iterate through each requirement of the drug - for (let requirement of drug.requirements) { + for (const requirement of drug.requirements) { // figure out which stakeholder the req corresponds to - let reqStakeholder = requirement.stakeholderType; - let reqStakeholderReference = reqStakeholder === 'prescriber' ? practitionerReference : (reqStakeholder === 'pharmacist' ? pharmacistReference : patientReference); + const reqStakeholder = requirement.stakeholderType; + const reqStakeholderReference = reqStakeholder === 'prescriber' ? practitionerReference : (reqStakeholder === 'pharmacist' ? pharmacistReference : patientReference); // if the requirement is the one submitted continue if (requirement.resourceId === requirementId) { @@ -211,7 +211,7 @@ class REMSServer extends Server { // create new rems request and add the created metReq to it let remsRequestCompletedStatus = 'Approved'; - let remsRequest: any = { + const remsRequest: any = { case_number: case_number, status : remsRequestCompletedStatus, drugName: drug.name, @@ -221,7 +221,7 @@ class REMSServer extends Server { returnRemsRequest = true; // create the metReq that was submitted - let metReq = { + const metReq = { completed: true, completedQuestionnaire: questionnaireResponse, requirementName: requirement.name, @@ -252,12 +252,12 @@ class REMSServer extends Server { ); // iterate through all other reqs again to create corresponding false metReqs / assign to existing - for (let requirement2 of drug.requirements) { + for (const requirement2 of drug.requirements) { // skip if the req found is the same as in the outer loop and has already been processed if (!(requirement2.resourceId === requirementId)) { // figure out which stakeholder the req corresponds to - let reqStakeholder2 = requirement2.stakeholderType; - let reqStakeholder2Reference = reqStakeholder2 === 'prescriber' ? practitionerReference : (reqStakeholder2 === 'pharmacist' ? pharmacistReference : patientReference); + const reqStakeholder2 = requirement2.stakeholderType; + const reqStakeholder2Reference = reqStakeholder2 === 'prescriber' ? practitionerReference : (reqStakeholder2 === 'pharmacist' ? pharmacistReference : patientReference); const matchedMetReq2 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name}); if (matchedMetReq2) { @@ -277,7 +277,7 @@ class REMSServer extends Server { await metRequirementsCollection.updateOne(matchedMetReq2, {$addToSet: {case_numbers: case_number}}); } else { // create the metReq that was submitted - let newMetReq = { + const newMetReq = { completed: false, completedQuestionnaire: null, requirementName: requirement2.name, @@ -334,7 +334,7 @@ class REMSServer extends Server { // for (let remsRequestToUpdate of remsRequestsToUpdate) { let foundUncompleted = false; - let metReqArray = remsRequestToUpdate.metRequirements; + const metReqArray = remsRequestToUpdate.metRequirements; for (let i=0; i < remsRequestToUpdate.metRequirements.length; i++) { let req4 = remsRequestToUpdate.metRequirements[i]; // _id comparison would not work for some reason From 333bdc3a31f9779582ba63aad13fbcd58885e90c Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Thu, 9 Feb 2023 16:16:27 -0500 Subject: [PATCH 09/15] linting --- src/server.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/server.ts b/src/server.ts index 573ca2d1..677d0b43 100644 --- a/src/server.ts +++ b/src/server.ts @@ -336,7 +336,7 @@ class REMSServer extends Server { let foundUncompleted = false; const metReqArray = remsRequestToUpdate.metRequirements; for (let i=0; i < remsRequestToUpdate.metRequirements.length; i++) { - let req4 = remsRequestToUpdate.metRequirements[i]; + const req4 = remsRequestToUpdate.metRequirements[i]; // _id comparison would not work for some reason if(req4.requirementName === matchedMetReq3.requirementName) { metReqArray[i].completed = true; @@ -361,7 +361,7 @@ class REMSServer extends Server { } else { // create the metReq that was submitted - let newMetReq3 = { + const newMetReq3 = { completed: true, completedQuestionnaire: questionnaireResponse, requirementName: requirement.name, @@ -396,9 +396,9 @@ class REMSServer extends Server { } getResource(bundle: { entry: any[]; }, resourceReference: string) { - let temp = resourceReference.split('/'); - let _resourceType = temp[0]; - let _id = temp[1]; + const temp = resourceReference.split('/'); + const _resourceType = temp[0]; + const _id = temp[1]; for (let i = 0; i < bundle.entry.length; i++) { if ((bundle.entry[i].resource.resourceType === _resourceType) @@ -410,7 +410,7 @@ class REMSServer extends Server { } getQuestionnaireResponse(bundle: { entry: any[]; }) { - let _resourceType = 'QuestionnaireResponse'; + const _resourceType = 'QuestionnaireResponse'; for (let i = 0; i < bundle.entry.length; i++) { if ((bundle.entry[i].resource.resourceType === _resourceType)) { From 239c6ede545262ef9943d4255b35008900e366b3 Mon Sep 17 00:00:00 2001 From: Zach Robin Date: Fri, 10 Feb 2023 12:59:56 -0800 Subject: [PATCH 10/15] updated names of iso from ipledge --- src/fhir/utilities.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fhir/utilities.ts b/src/fhir/utilities.ts index 21806804..8e4b19a3 100644 --- a/src/fhir/utilities.ts +++ b/src/fhir/utilities.ts @@ -437,7 +437,7 @@ export class FhirUtilities { ] }, { - name: "IPledge", + name: "Isotretinoin", codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", code: "6064", requirements: [{ @@ -496,7 +496,7 @@ export class FhirUtilities { stakeholderId: "Organization/pharm0111", completed: true, requirementName: "Pharmacist Enrollment", - drugName: "IPledge", + drugName: "Isotretinoin", completedQuestionnaire: null, case_numbers: [], }], (err: any, result: any) => { From 6ffc3c0dcb947b4aacdcde9e5fe9f54f81096edb Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Tue, 14 Feb 2023 14:31:07 -0500 Subject: [PATCH 11/15] docker / workspace configs + comments --- DeveloperSetupGuide.md | 33 ++- Dockerfile.tmpl | 33 +-- REMS.code-workspace | 20 +- SimpleSetupGuide.md | 34 +-- docker-compose-dev.yml | 71 +------ docker-compose-porter.yml | 49 ++--- docker-compose.yml | 53 ++--- docker-sync.yml | 8 - env.json | 4 +- src/fhir/utilities.ts | 131 ++++++------ src/server.ts | 431 ++++++++++++++++++-------------------- 11 files changed, 350 insertions(+), 517 deletions(-) diff --git a/DeveloperSetupGuide.md b/DeveloperSetupGuide.md index b49bfc4b..ed124317 100644 --- a/DeveloperSetupGuide.md +++ b/DeveloperSetupGuide.md @@ -169,15 +169,12 @@ Reference: https://github.com/rbenv/rbenv 2. Now clone the DRLS component repositories from Github: ```bash cd - git clone https://github.com/mcode/CRD.git CRD git clone https://github.com/mcode/test-ehr.git test-ehr git clone https://github.com/mcode/crd-request-generator.git crd-request-generator git clone https://github.com/mcode/dtr.git dtr git clone https://github.com/mcode/REMS.git REMS - git clone https://github.com/mcode/pharmacy-information-system.git pharmacy-information-system + git clone https://github.com/mcode/pims.git pims - cd CRD/server - git clone https://github.com/mcode/CDS-Library.git CDS-Library ``` # Open DRLS REMS as VsCode workspace @@ -299,21 +296,23 @@ Reference: https://docker-sync.readthedocs.io/en/latest/getting-started/commands 3. Find **Jon Snow** in the list of patients and click the dropdown menu next to his name. 4. Select **2183126 - Turalio 200 MG Oral Capsule** in the dropdown menu. 5. Click anywhere in the row to select Jon Snow. -6. Click **Submit to CRD** at the bottom of the page. -7. After several seconds you should receive a response in the form of two **CDS cards**: +6. Click **Send Rx to PIMS** at the bottom of the page to send a prescription to the Pharmacist. +7. Click **Submit to REMS-Admin** at the bottom of the page. +8. After several seconds you should receive a response in the form of two **CDS cards**: - **Drug Has REMS: Documentation Required.** -8. Select **Patient Enrollment Form** on the returned CDS card with summary **Drug Has REMS: Documentation Required**. -9. If you are asked for login credentials, use **alice** for username and **alice** for password. -10. A webpage should open in a new tab, and after a few seconds, a questionnaire should appear. -11. Fill out questionnaire and hit **Submit REMS Bundle**. -12. A new UI will appear with REMS Admin Status and Pharmacy Status. -13. Go to http://localhost:4200 and play the role of a pharmacist. -14. Click on **Log in as Admin** in the top right of the page -15. Sign in with the pre-configured user Suzy: +9. Select **Patient Enrollment Form** on the returned CDS card with summary **Drug Has REMS: Documentation Required**. +10. If you are asked for login credentials, use **alice** for username and **alice** for password. +11. A webpage should open in a new tab, and after a few seconds, a questionnaire should appear. +12. Fill out questionnaire and hit **Submit REMS Bundle**. +13. A new UI will appear with REMS Admin Status and Pharmacy Status. +14. Go to http://localhost:5050 and play the role of a pharmacist. + + +15. Click **Doctor Orders** in the top hand navigation menu on the screen +16. See the Doctor Order that was sent to the pharmacist from the prescriber. +17. Repeat steps 9-12 for submitting the Prescriber Enrollment and Prescriber Knowledge Assessment Forms and check how ETASU statuses change in both the PIMS prescription UI and the Prescriber status page. Congratulations! DRLS is fully installed and ready for you to use! diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl index 404ca1e6..e0ba4b9e 100644 --- a/Dockerfile.tmpl +++ b/Dockerfile.tmpl @@ -5,38 +5,7 @@ ARG BUNDLE_DIR ARG DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive -# RUN apt-get update && apt-get install -y ca-certificates && apt-get install -y curl - -# RUN curl http://pki.mitre.org/MITRE%20BA%20ROOT.crt >> /etc/ssl/certs/ca-certificates.crt && \ -# curl http://pki.mitre.org/MITRE%20BA%20NPE%20CA-3.crt >> /etc/ssl/certs/ca-certificates.crt && \ -# curl http://pki.mitre.org/MITRE%20BA%20NPE%20CA-4.crt >> /etc/ssl/certs/ca-certificates.crt && \ -# update-ca-certificates - -# WORKDIR /pki -# COPY Zscaler_Root_CA.pem . -# RUN cat Zscaler_Root_CA.pem >> /etc/ssl/certs/ca-certificates.crt - - - -# # Install Git from Source to get around TLS errors with Zscaler, -# # explicitly using openssl instead of gnutls -# # RUN cp /etc/apt/sources.list /etc/apt/sources.list~ -# RUN sed -i -- 's/# deb-src/deb-src/' /etc/apt/sources.list -# RUN apt-get update && \ -# apt-get install build-essential fakeroot dpkg-dev -y && \ -# apt-get install git-man -y && \ -# apt-get -f build-dep git -y && \ -# apt-get install libcurl4-openssl-dev -y - -# WORKDIR /sourcegit - -# RUN apt-get source git && \ -# cd git-2.*.*/ && \ -# sed -i -- 's/libcurl4-gnutls-dev/libcurl4-openssl-dev/' ./debian/control && \ -# sed -i -- '/TEST\s*=\s*test/d' ./debian/rules && \ -# dpkg-buildpackage -rfakeroot -b -uc -us && \ -# dpkg -i ../git_*ubuntu*.deb - +COPY ./mongo-init.js ${BUNDLE_DIR}/mongo-init.js COPY ./.cnab/app/porter.yaml ${BUNDLE_DIR}/porter.yaml COPY ./docker-compose-porter.yml ${BUNDLE_DIR}/docker-compose-porter.yml COPY ./.env ${BUNDLE_DIR}/.env diff --git a/REMS.code-workspace b/REMS.code-workspace index 6bee4879..7659d66d 100644 --- a/REMS.code-workspace +++ b/REMS.code-workspace @@ -3,13 +3,6 @@ { "path": "../test-ehr" }, - { - "name": "CRD-CDS-Library", - "path": "../CRD/server/CDS-Library" - }, - { - "path": "../CRD" - }, { "path": "../crd-request-generator" }, @@ -19,9 +12,6 @@ { "path": "." }, - { - "path": "../pharmacy-information-system" - }, { "path": "../pims" } @@ -42,13 +32,11 @@ "stopAll": true, "preLaunchTask": "Launch Chrome in Debug Mode", "configurations": [ - "Debug CRD (Local + Docker)", "Debug DTR Backend (Docker)", "Debug Test-EHR (Local + Docker)", "Debug DTR Frontend (Attach Local + Docker)", "Debug CRD-Request-Generator (Attach Docker)", - "Debug Pharmacy-Information-System Backend (Docker)", - "Debug Pharmacy-Information-System Frontend (Attach Local + Docker)", + // ToDO: Add in PIMS Debugging and REMS debugging in docker "Post Debug Task - Terminate Chrome (This is not a Debugger)" ], } @@ -61,13 +49,13 @@ "type": "shell", "label": "Launch Chrome in Debug Mode", "linux": { - "command": "google-chrome http://localhost:3000 http://localhost:4200 http://localhost:3005/register --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug" + "command": "google-chrome http://localhost:3000 http://localhost:5050 http://localhost:3005/register --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug" }, "osx": { - "command": "/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome http://localhost:3000 http://localhost:4200 http://localhost:3005/register --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug" + "command": "/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome http://localhost:3000 http://localhost:5050 http://localhost:3005/register --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug" }, "windows": { - "command": "for /f \"usebackq tokens=1,2,3,4,5\" %a in (`reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ /s /f \\chrome.exe ^| findstr Application`) do set CHROMEPATH=%c%d%e & set CHROMEPATH=%CHROMEPATH:ProgramFiles=Program Files% & \"%CHROMEPATH%\" http://localhost:3000 http://localhost:4200 http://localhost:3005/register --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug" + "command": "for /f \"usebackq tokens=1,2,3,4,5\" %a in (`reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ /s /f \\chrome.exe ^| findstr Application`) do set CHROMEPATH=%c%d%e & set CHROMEPATH=%CHROMEPATH:ProgramFiles=Program Files% & \"%CHROMEPATH%\" http://localhost:3000 http://localhost:5050 http://localhost:3005/register --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug" }, "presentation": { "close": true, diff --git a/SimpleSetupGuide.md b/SimpleSetupGuide.md index 490485c1..b977ac98 100644 --- a/SimpleSetupGuide.md +++ b/SimpleSetupGuide.md @@ -73,7 +73,9 @@ Your computer must have these minimum requirements: ``` #### Windows -> Note: The install on Windows requires additional steps in order to expose the WSL Docker Daemon to Porter. The way to do this is to run the porter commands inside an additional windows specific container running in interactive mode, which exposes that container's terminal instance. +> Note: The Porter Installation on Windows is currently broken, to run the REMS prototype on Windows please refer to the [Running Docker Compose without Porter](#docker-compose-without-porter) section of this guide. + + ### 4. Verify everything is working @@ -110,21 +112,23 @@ Your computer must have these minimum requirements: 3. Find **Jon Snow** in the list of patients and click the dropdown menu next to his name. 4. Select **2183126 - Turalio 200 MG Oral Capsule** in the dropdown menu. 5. Click anywhere in the row to select Jon Snow. -6. Click **Submit to CRD** at the bottom of the page. -7. After several seconds you should receive a response in the form of two **CDS cards**: +6. Click **Send Rx to PIMS** at the bottom of the page to send a prescription to the Pharmacist. +7. Click **Submit to REMS-Admin** at the bottom of the page. +8. After several seconds you should receive a response in the form of two **CDS cards**: - **Drug Has REMS: Documentation Required.** -8. Select **Patient Enrollment Form** on the returned CDS card with summary **Drug Has REMS: Documentation Required**. -9. If you are asked for login credentials, use **alice** for username and **alice** for password. -10. A webpage should open in a new tab, and after a few seconds, a questionnaire should appear. -11. Fill out questionnaire and hit **Submit REMS Bundle**. -12. A new UI will appear with REMS Admin Status and Pharmacy Status. -13. Go to http://localhost:4200 and play the role of a pharmacist. -14. Click on **Log in as Admin** in the top right of the page -15. Sign in with the pre-configured user Suzy: +9. Select **Patient Enrollment Form** on the returned CDS card with summary **Drug Has REMS: Documentation Required**. +10. If you are asked for login credentials, use **alice** for username and **alice** for password. +11. A webpage should open in a new tab, and after a few seconds, a questionnaire should appear. +12. Fill out questionnaire and hit **Submit REMS Bundle**. +13. A new UI will appear with REMS Admin Status and Pharmacy Status. +14. Go to http://localhost:5050 and play the role of a pharmacist. + + +15. Click **Doctor Orders** in the top hand navigation menu on the screen +16. See the Doctor Order that was sent to the pharmacist from the prescriber. +17. Repeat steps 9-12 for submitting the Prescriber Enrollment and Prescriber Knowledge Assessment Forms and check how ETASU statuses change in both the PIMS prescription UI and the Prescriber status page. Congratulations! DRLS is fully installed and ready for you to use! diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 53f5f9ef..6808865c 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -48,31 +48,6 @@ services: - pims_remsadmin_mongo:/data/db - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js - - # Create crd container - # crd: - # # Name of our service - # build: - # context: ../CRD - # dockerfile: Dockerfile.dev - # container_name: rems_dev_crd - # ports: - # # Port binding to host from docker container - # - "8090:8090" # Bind port 3000 of host to 3000 of container - # - "8091:8091" - # environment: - # VSAC_API_KEY: ${VSAC_API_KEY} - # volumes: - # - rems_dev_crd-sync:/CRD:nocopy # nocopy is important - # - rems_dev_crd-logs:/CRD/logs - # - rems_dev_crd-gradle:/CRD/.gradle - # - rems_dev_crd-server-gradle:/CRD/server/.gradle - # - rems_dev_crd-server-build:/CRD/server/build - # - rems_dev_crd-server-bin:/CRD/server/bin - # - rems_dev_crd-server-ValueSetCache:/CRD/server/ValueSetCache - # - rems_dev_crd-operations-build:/CRD/operations/build - # - rems_dev_crd-resources-build:/CRD/resources/build - crd-request-generator: build: context: ../crd-request-generator @@ -112,30 +87,13 @@ services: ports: - "8090:8090" - "8091:8091" + environment: + VSAC_API_KEY: ${VSAC_API_KEY} volumes: - rems_dev_rems-sync:/REMS:nocopy # nocopy is important - rems_dev_rems-nodeModules:/REMS/node_modules - rems_dev_rems-logs:/REMS/logs - # pharmacy-information-system: # Name of our service - # build: - # context: ../pharmacy-information-system - # dockerfile: Dockerfile.dev - # container_name: rems_dev_pharmacy-information-system - # environment: - # - PORT=3010 - # - MONGODB_CONNSTRING=mongodb://pharmacy-information-root:pharmacy-information-password@pharmacy-information-system-database:27017?retryWrites=true&w=majority - # - CRD_BASE_URL=http://crd:8090/ - # ports: # Port binding to host from docker container - # - "4200:4200" - # - "3010:3010" - # - "3011:3011" - # volumes: - # - rems_dev_pharmacy-information-system-sync:/home/node/app/pharmacy-information-system:nocopy # nocopy is important - # - rems_dev_pharmacy-information-system-nodeModules:/home/node/app/pharmacy-information-system/node_modules - # - rems_dev_pharmacy-information-system-backend-nodeModules:/home/node/app/pharmacy-information-system/backend/node_modules - # - rems_dev_pharmacy-information-system-logs:/home/node/app/pharmacy-information-system/logs - pims: build: context: ../pims @@ -149,24 +107,10 @@ services: - rems_dev_pims-nodeModules:/home/node/app/pims/node_modules - rems_dev_pims-logs:/home/node/app/pims/logs - # pharmacy-information-system-database: # Name of our service - # image: mongo - # container_name: rems_dev_pharmacy-information-system-database - # environment: - # MONGO_INITDB_ROOT_USERNAME: pharmacy-information-root - # MONGO_INITDB_ROOT_PASSWORD: pharmacy-information-password - # expose: - # - "27017" - # ports: # Port binding to host from docker container - # - "27017:27017" - # volumes: - # - rems_dev_pharmacy-infomation-system-database:/data/db volumes: rems_dev_test-ehr-sync: external: true - # rems_dev_crd-sync: - # external: true rems_dev_crd-request-generator-sync: external: true rems_dev_dtr-sync: @@ -183,13 +127,6 @@ volumes: rems_dev_test-ehr-build: rems_dev_test-ehr-target: rems_dev_test-ehr-logs: - # rems_dev_crd-logs: - # rems_dev_crd-gradle: - # rems_dev_crd-server-gradle: - # rems_dev_crd-server-build: - # rems_dev_crd-server-bin: - # rems_dev_crd-server-ValueSetCache: - # rems_dev_crd-operations-build: rems_dev_crd-resources-build: rems_dev_crd-request-generator-nodeModules: rems_dev_crd-request-generator-databaseData: @@ -198,8 +135,8 @@ volumes: rems_dev_dtr-nodeModules: rems_dev_dtr-databaseData: rems_dev_dtr-logs: - rems_dev_pims-logs: # rems_dev_pims-database: - rems_dev_pims-nodeModules: # rems_dev_pims-backend-nodeModules: + rems_dev_pims-logs: + rems_dev_pims-nodeModules: rems_dev_rems-nodeModules: rems_dev_rems-logs: diff --git a/docker-compose-porter.yml b/docker-compose-porter.yml index a44ccd4d..66300301 100644 --- a/docker-compose-porter.yml +++ b/docker-compose-porter.yml @@ -24,18 +24,6 @@ services: extra_hosts: - "host.docker.internal:host-gateway" - - # Create crd container - crd: # Name of our service - image: codexrems/crd:REMSvCurrent - container_name: rems_porter_crd - ports: # Port binding to host from docker container - - "8090:8090" # Bind port 3000 of host to 3000 of container - environment: - VSAC_API_KEY: ${VSAC_API_KEY} - volumes: - - rems_porter_crd-server-ValueSetCache:/CRD/server/ValueSetCache - # Create crd request generator container crd-request-generator: # Name of our service image: codexrems/crd-request-generator:REMSvCurrent @@ -61,31 +49,24 @@ services: ports: # Port binding to host from docker container - "9015:9015" # Bind port 3000 of host to 3000 of container - pharmacy-information-system: # Name of our service - image: codexrems/pharmacy-information-system:REMSvCurrent - container_name: rems_porter_pharmacy-information-system - environment: - - PORT=3010 - - MONGODB_CONNSTRING=mongodb://pharmacy-information-root:pharmacy-information-password@pharmacy-information-system-database:27017?retryWrites=true&w=majority - - CRD_BASE_URL=http://crd:8090/ - ports: # Port binding to host from docker container - - "4200:4200" - - "3010:3010" - - pharmacy-information-system-database: # Name of our service + pims_remsadmin_mongo: image: mongo - container_name: rems_porter_pharmacy-information-system-database + container_name: rems_dev_pims-remsadmin-mongo + ports: + - '27017:27017' environment: - MONGO_INITDB_ROOT_USERNAME: pharmacy-information-root - MONGO_INITDB_ROOT_PASSWORD: pharmacy-information-password - expose: - - "27017" - ports: # Port binding to host from docker container - - "27017:27017" + MONGO_INITDB_ROOT_USERNAME: rems-admin-pims-root + MONGO_INITDB_ROOT_PASSWORD: rems-admin-pims-password volumes: - - rems_porter_pharmacy-infomation-system-database:/data/db + - pims_remsadmin_mongo:/data/db + - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js + + pims: + image: codexrems/pims:REMSvCurrent + container_name: rems_dev_pims + ports: + - "5050:5050" + - "5051:5051" volumes: rems_porter_keycloak-data: - rems_porter_pharmacy-infomation-system-database: - rems_porter_crd-server-ValueSetCache: diff --git a/docker-compose.yml b/docker-compose.yml index 4ed19355..9e735f2b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,18 +25,6 @@ services: - "host.docker.internal:host-gateway" - # Create crd container - crd: # Name of our service - image: codexrems/crd:REMSvCurrent - container_name: rems_prod_crd - ports: # Port binding to host from docker container - - "8090:8090" # Bind port 3000 of host to 3000 of container - environment: - VSAC_API_KEY: ${VSAC_API_KEY} - volumes: - - rems_prod_crd-server-ValueSetCache:/CRD/server/ValueSetCache - - # Create crd request generator container crd-request-generator: # Name of our service image: codexrems/crd-request-generator:REMSvCurrent @@ -47,7 +35,6 @@ services: - "3000:3000" # Bind port 3000 of host to 3000 of container - "3001:3001" - # Create dtr container dtr: # Name of our service image: codexrems/dtr:REMSvCurrent @@ -62,32 +49,28 @@ services: ports: # Port binding to host from docker container - "9015:9015" # Bind port 3000 of host to 3000 of container - pharmacy-information-system: # Name of our service - image: codexrems/pharmacy-information-system:REMSvCurrent - container_name: rems_prod_pharmacy-information-system - environment: - - PORT=3010 - - MONGODB_CONNSTRING=mongodb://pharmacy-information-root:pharmacy-information-password@pharmacy-information-system-database:27017?retryWrites=true&w=majority - - CRD_BASE_URL=http://crd:8090/ - ports: # Port binding to host from docker container - - "4200:4200" - - "3010:3010" - - pharmacy-information-system-database: # Name of our service + pims_remsadmin_mongo: image: mongo - container_name: rems_dev_pharmacy-information-system-database + container_name: rems_dev_pims-remsadmin-mongo + ports: + - '27017:27017' environment: - MONGO_INITDB_ROOT_USERNAME: pharmacy-information-root - MONGO_INITDB_ROOT_PASSWORD: pharmacy-information-password - expose: - - "27017" - ports: # Port binding to host from docker container - - "27017:27017" + MONGO_INITDB_ROOT_USERNAME: rems-admin-pims-root + MONGO_INITDB_ROOT_PASSWORD: rems-admin-pims-password volumes: - - rems_porter_pharmacy-infomation-system-database:/data/db + - pims_remsadmin_mongo:/data/db + - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js + + pims: + image: codexrems/pims:REMSvCurrent + container_name: rems_dev_pims + ports: + - "5050:5050" + - "5051:5051" + + volumes: rems_prod_keycloak-data: - rems_porter_pharmacy-infomation-system-database: - rems_prod_crd-server-ValueSetCache: + diff --git a/docker-sync.yml b/docker-sync.yml index c6120d9c..26f8d4d9 100644 --- a/docker-sync.yml +++ b/docker-sync.yml @@ -6,10 +6,6 @@ syncs: src: ../test-ehr sync_excludes: ['.gradle', 'bin', 'build', 'target', 'logs'] - # rems_dev_crd-sync: - # src: '../CRD' - # sync_excludes: ['logs', '.gradle', 'server/.gradle', 'server/bin', 'server/build', 'server/ValueSetCache', 'operations/build', 'resources/build'] - rems_dev_crd-request-generator-sync: src: '../crd-request-generator' sync_excludes: ['node_modules', 'build', 'databaseData', 'logs'] @@ -21,10 +17,6 @@ syncs: rems_dev_rems-sync: src: '.' sync_excludes: ['node_modules', 'logs'] - - # rems_dev_pharmacy-information-system-sync: - # src: '../pharmacy-information-system' - # sync_excludes: ['node_modules', 'backend/node_modules', 'logs'] rems_dev_pims-sync: src: '../pims' diff --git a/env.json b/env.json index c6c4f58b..6846e7cb 100644 --- a/env.json +++ b/env.json @@ -1,7 +1,7 @@ { "MONGO_HOSTNAME": { "type": "string", - "default": "localhost", + "default": "rems-admin-pims-root:rems-admin-pims-password@pims_remsadmin_mongo:27017", "required": true }, "MONGO_DB_NAME": { @@ -33,6 +33,6 @@ }, "VSAC_KEY": { "type": "string", - "default": "changeMe" + "default": "f6486e93-5f75-481c-a5c1-b6395d7a217d" } } diff --git a/src/fhir/utilities.ts b/src/fhir/utilities.ts index 82975636..158447aa 100644 --- a/src/fhir/utilities.ts +++ b/src/fhir/utilities.ts @@ -290,73 +290,70 @@ export class FhirUtilities { // define schemas + + // leave comments in of structure in for now as they will be useful to reference during the mongoose transition const medicationCollection = await db.collection('medication-requirements' - // , { - // 'name': { 'type': 'string' }, - // 'codeSystem': { 'type': 'string' }, - // 'code': { 'type': 'string' }, - // 'requirements': { - // 'type': 'array', - // 'items': { - // 'type': 'object', - // 'properties': { - // 'name': { 'type': 'string' }, - // 'description': { 'type': 'string' }, - // 'questionnaire': { 'type': 'object' }, - // 'stakeholderType': { 'type': 'string' }, - // 'createNewCase': { 'type': 'boolean' }, - // 'resourceId': { 'type': 'string' } - // } - // } - // } - // }, (err: any, collection: any) => { - // if (err) console.log(err); - // } + // , { + // 'name': { 'type': 'string' }, + // 'codeSystem': { 'type': 'string' }, + // 'code': { 'type': 'string' }, + // 'requirements': { + // 'type': 'array', + // 'items': { + // 'type': 'object', + // 'properties': { + // 'name': { 'type': 'string' }, + // 'description': { 'type': 'string' }, + // 'questionnaire': { 'type': 'object' }, + // 'stakeholderType': { 'type': 'string' }, + // 'createNewCase': { 'type': 'boolean' }, + // 'resourceId': { 'type': 'string' } + // } + // } + // } + // } ); await medicationCollection.createIndex({ name: 1 }, { unique: true }); + // leave comments of structure in for now as they will be useful to reference during the mongoose transition const metRequirementsCollection = await db.collection('met-requirements' - // , { - // 'completed': { 'type': 'boolean' }, - // 'completedQuestionnaire': { 'type': 'object' }, - // 'requirementName': { 'type': 'string' }, - // 'requirementDescription': {'type': 'string'} - // 'drugName': { 'type': 'string' }, - // 'stakeholderId': { 'type': 'string' }, - // 'case_numbers': { 'type': 'array', 'items': { 'type': 'string' } } - // }, (err: any, collection: any) => { - // if (err) console.log(err); - // } + // , { + // 'completed': { 'type': 'boolean' }, + // 'completedQuestionnaire': { 'type': 'object' }, + // 'requirementName': { 'type': 'string' }, + // 'requirementDescription': {'type': 'string'} + // 'drugName': { 'type': 'string' }, + // 'stakeholderId': { 'type': 'string' }, + // 'case_numbers': { 'type': 'array', 'items': { 'type': 'string' } } + // } ); metRequirementsCollection.createIndex({ drugName: 1, requirementName: 1, stakeholderId: 1 }, { unique: true }); - + // leave comments of structure in for now as they will be useful to reference during the mongoose transition const remsCaseCollection = await db.collection('rems-case' - // , { - // 'case_number': { 'type': 'string' }, - // 'status': { 'type': 'string' }, - // 'drugName': { 'type': 'string' }, - // 'patientName': { 'type': 'string' }, - // 'metRequirements': { - // 'type': 'array', - // 'items': { - // 'type': 'object', - // 'properties': { - // 'metRequirementId': { 'type': 'number' }, - // 'completed': { 'type': 'boolean' }, - // 'stakeholderId': { 'type': 'string' }, - // 'requirementName': { 'type': 'string' }, - // 'requirementDescription': {'type': 'string'}, - // } - // } - // } - // }, (err: any, collection: any) => { - // if (err) throw err; - // } + // , { + // 'case_number': { 'type': 'string' }, + // 'status': { 'type': 'string' }, + // 'drugName': { 'type': 'string' }, + // 'patientName': { 'type': 'string' }, + // 'metRequirements': { + // 'type': 'array', + // 'items': { + // 'type': 'object', + // 'properties': { + // 'metRequirementId': { 'type': 'number' }, + // 'completed': { 'type': 'boolean' }, + // 'stakeholderId': { 'type': 'string' }, + // 'requirementName': { 'type': 'string' }, + // 'requirementDescription': {'type': 'string'}, + // } + // } + // } + // } ); @@ -437,9 +434,9 @@ export class FhirUtilities { ] }, { - name: "Isotretinoin", - codeSystem: "http://www.nlm.nih.gov/research/umls/rxnorm", - code: "6064", + name: 'Isotretinoin', + codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '6064', requirements: [{ name: 'Patient Enrollment', description: 'Submit Patient Enrollment form to the REMS Administrator', @@ -473,32 +470,32 @@ export class FhirUtilities { completed: true, requirementName: 'Pharmacist Enrollment', drugName: 'Turalio', - completedQuestionnaire: null, - case_numbers: [], + completedQuestionnaire: null, + case_numbers: [], }, { stakeholderId: 'Organization/pharm0111', completed: true, requirementName: 'Pharmacist Enrollment', drugName: 'TIRF', - completedQuestionnaire: null, - case_numbers: [], + completedQuestionnaire: null, + case_numbers: [], }, { stakeholderId: 'Organization/pharm0111', completed: true, requirementName: 'Pharmacist Knowledge Assessment', drugName: 'TIRF', - completedQuestionnaire: null, - case_numbers: [], + completedQuestionnaire: null, + case_numbers: [], }, { stakeholderId: 'Organization/pharm0111', completed: true, - requirementName: "Pharmacist Enrollment", - drugName: "Isotretinoin", - completedQuestionnaire: null, - case_numbers: [], + requirementName: 'Pharmacist Enrollment', + drugName: 'Isotretinoin', + completedQuestionnaire: null, + case_numbers: [], }], (err: any, result: any) => { if (err) console.log(err); console.log('Inserted Pharmacist Met Requirements'); diff --git a/src/server.ts b/src/server.ts index 677d0b43..7046f7dd 100644 --- a/src/server.ts +++ b/src/server.ts @@ -131,267 +131,250 @@ class REMSServer extends Server { ); this.app.get('/etasu/met/patient/:patientName/drug/:drugName', (req: any, res: { send: (arg0: string) => any }) => { - remsCaseCollection.findOne({ patientName : req.params.patientName, drugName: req.params.drugName}, (err: any, remsCase: any) => { + remsCaseCollection.findOne({ patientName: req.params.patientName, drugName: req.params.drugName }, (err: any, remsCase: any) => { if (err) throw err; res.send(remsCase); }); } ); - this.app.post('/etasu/reset', (req: any, res: { send: (arg0: string) => any }) => { + this.app.post('/etasu/reset', async (req: any, res: { send: (arg0: string) => any }) => { console.log('Dropping collections'); - medicationCollection.drop(); - remsCaseCollection.drop(); - metRequirementsCollection.drop(); + await medicationCollection.deleteMany({}); + await remsCaseCollection.deleteMany({}); + await metRequirementsCollection.deleteMany({}); console.log('Resetting the database'); - FhirUtilities.populateDB(); + await FhirUtilities.populateDB(); res.send('reset etasu database collections'); } ); this.app.post('/etasu/met', async (req: any, res: { send: (arg0: string) => any }) => { - let returnedRemsRequestDoc: any; - let returnedMetReqDoc: any; - let returnRemsRequest = false; - const requestBody = req.body; - - // extract params and questionnaire response identifier - const params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference); - const questionnaireResponse = this.getQuestionnaireResponse(requestBody); - const questionnaireStringArray = questionnaireResponse.questionnaire.split('/'); - const requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; - - // stakeholder and medication references - let prescriptionReference = ''; - let practitionerReference = ''; - let pharmacistReference = ''; - let patientReference = ''; - for (const param of params.parameter) { - if (param.name === 'prescription') { - prescriptionReference = param.reference; - } - else if (param.name === 'prescriber') { - practitionerReference = param.reference; - } - else if (param.name === 'pharmacy') { - pharmacistReference = param.reference; - } else if (param.name === 'source-patient') { - patientReference = param.reference; + try { + let returnedRemsRequestDoc: any; + let returnedMetReqDoc: any; + let returnRemsRequest = false; + const requestBody = req.body; + + // extract params and questionnaire response identifier + const params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference); + const questionnaireResponse = this.getQuestionnaireResponse(requestBody); + const questionnaireStringArray = questionnaireResponse.questionnaire.split('/'); + const requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; + + // stakeholder and medication references + let prescriptionReference = ''; + let practitionerReference = ''; + let pharmacistReference = ''; + let patientReference = ''; + for (const param of params.parameter) { + if (param.name === 'prescription') { + prescriptionReference = param.reference; + } + else if (param.name === 'prescriber') { + practitionerReference = param.reference; + } + else if (param.name === 'pharmacy') { + pharmacistReference = param.reference; + } else if (param.name === 'source-patient') { + patientReference = param.reference; + } } - } - // obtain drug information from database - const presciption = this.getResource(requestBody, prescriptionReference); - const prescriptionSystem = presciption.medicationCodeableConcept.coding[0].system; - const prescriptionCode = presciption.medicationCodeableConcept.coding[0].code; - const patient = this.getResource(requestBody, patientReference); - const patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; - - const drug = await medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem } - // , (err: any, result: any) => { - // if (err) console.log(err); - // console.log('Found Drug Info: '); - // console.log(result) - // return result; - // } - ); - // iterate through each requirement of the drug - for (const requirement of drug.requirements) { - // figure out which stakeholder the req corresponds to - const reqStakeholder = requirement.stakeholderType; - const reqStakeholderReference = reqStakeholder === 'prescriber' ? practitionerReference : (reqStakeholder === 'pharmacist' ? pharmacistReference : patientReference); - - // if the requirement is the one submitted continue - if (requirement.resourceId === requirementId) { - - // if the req submitted is a patient enrollment form and requires creating a new case - if (requirement.createNewCase) { - returnRemsRequest = true; - const case_number = uid(); - - // create new rems request and add the created metReq to it - let remsRequestCompletedStatus = 'Approved'; - const remsRequest: any = { - case_number: case_number, - status : remsRequestCompletedStatus, - drugName: drug.name, - patientName: patientName, - metRequirements : [], - }; - returnRemsRequest = true; - - // create the metReq that was submitted - const metReq = { - completed: true, - completedQuestionnaire: questionnaireResponse, - requirementName: requirement.name, - requirementDescription: requirement.description, - drugName: drug.name, - stakeholderId: reqStakeholderReference, - case_numbers: [case_number], - }; - - await metRequirementsCollection.insertOne(metReq - // , (err: any, result: any) => { - // if (err) console.log(err); - // console.log('Inserted Matched Met Requirement'); - // } - ); - - const matchedMetReq = await metRequirementsCollection.findOne(metReq); - - - remsRequest.metRequirements.push( - { - stakeholderId : matchedMetReq.stakeholderId, - completed : matchedMetReq.completed, - metRequirementId: matchedMetReq._id, - requirementName: matchedMetReq.requirementName, - requirementDescription: matchedMetReq.requirementDescription, - } - ); - - // iterate through all other reqs again to create corresponding false metReqs / assign to existing - for (const requirement2 of drug.requirements) { - // skip if the req found is the same as in the outer loop and has already been processed - if (!(requirement2.resourceId === requirementId)) { - // figure out which stakeholder the req corresponds to - const reqStakeholder2 = requirement2.stakeholderType; - const reqStakeholder2Reference = reqStakeholder2 === 'prescriber' ? practitionerReference : (reqStakeholder2 === 'pharmacist' ? pharmacistReference : patientReference); - - const matchedMetReq2 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name}); - if (matchedMetReq2) { - remsRequest.metRequirements.push( - { - stakeholderId : matchedMetReq2.stakeholderId, - completed : matchedMetReq2.completed, - metRequirementId: matchedMetReq2._id, - requirementName: matchedMetReq2.requirementName, - requirementDescription: matchedMetReq2.requirementDescription, + // obtain drug information from database + const presciption = this.getResource(requestBody, prescriptionReference); + const prescriptionSystem = presciption.medicationCodeableConcept.coding[0].system; + const prescriptionCode = presciption.medicationCodeableConcept.coding[0].code; + const patient = this.getResource(requestBody, patientReference); + const patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; + + const drug = await medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem }); + // iterate through each requirement of the drug + for (const requirement of drug.requirements) { + // figure out which stakeholder the req corresponds to + const reqStakeholder = requirement.stakeholderType; + const reqStakeholderReference = reqStakeholder === 'prescriber' ? practitionerReference : (reqStakeholder === 'pharmacist' ? pharmacistReference : patientReference); + + // if the requirement is the one submitted continue + if (requirement.resourceId === requirementId) { + + // if the req submitted is a patient enrollment form and requires creating a new case + if (requirement.createNewCase) { + returnRemsRequest = true; + const case_number = uid(); + + // create new rems request and add the created metReq to it + let remsRequestCompletedStatus = 'Approved'; + const remsRequest: any = { + case_number: case_number, + status: remsRequestCompletedStatus, + drugName: drug.name, + patientName: patientName, + metRequirements: [], + }; + returnRemsRequest = true; + + // create the metReq that was submitted + const metReq = { + completed: true, + completedQuestionnaire: questionnaireResponse, + requirementName: requirement.name, + requirementDescription: requirement.description, + drugName: drug.name, + stakeholderId: reqStakeholderReference, + case_numbers: [case_number], + }; + + await metRequirementsCollection.insertOne(metReq); + + const matchedMetReq = await metRequirementsCollection.findOne(metReq); + + + remsRequest.metRequirements.push( + { + stakeholderId: matchedMetReq.stakeholderId, + completed: matchedMetReq.completed, + metRequirementId: matchedMetReq._id, + requirementName: matchedMetReq.requirementName, + requirementDescription: matchedMetReq.requirementDescription, + } + ); + + // iterate through all other reqs again to create corresponding false metReqs / assign to existing + for (const requirement2 of drug.requirements) { + // skip if the req found is the same as in the outer loop and has already been processed + if (!(requirement2.resourceId === requirementId)) { + // figure out which stakeholder the req corresponds to + const reqStakeholder2 = requirement2.stakeholderType; + const reqStakeholder2Reference = reqStakeholder2 === 'prescriber' ? practitionerReference : (reqStakeholder2 === 'pharmacist' ? pharmacistReference : patientReference); + + const matchedMetReq2 = await metRequirementsCollection.findOne({ stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name }); + if (matchedMetReq2) { + remsRequest.metRequirements.push( + { + stakeholderId: matchedMetReq2.stakeholderId, + completed: matchedMetReq2.completed, + metRequirementId: matchedMetReq2._id, + requirementName: matchedMetReq2.requirementName, + requirementDescription: matchedMetReq2.requirementDescription, + } + ); + if (!matchedMetReq2.completed) { + remsRequestCompletedStatus = 'Pending'; } - ); - if(!matchedMetReq2.completed) { - remsRequestCompletedStatus = 'Pending'; - } - // matchedMetReq2.case_numbers.push(case_number); - await metRequirementsCollection.updateOne(matchedMetReq2, {$addToSet: {case_numbers: case_number}}); - } else { - // create the metReq that was submitted - const newMetReq = { - completed: false, - completedQuestionnaire: null, - requirementName: requirement2.name, - requirementDescription: requirement2.description, - drugName: drug.name, - stakeholderId: reqStakeholder2Reference, - case_numbers: [case_number], - }; + // matchedMetReq2.case_numbers.push(case_number); + await metRequirementsCollection.updateOne(matchedMetReq2, { $addToSet: { case_numbers: case_number } }); + } else { + // create the metReq that was submitted + const newMetReq = { + completed: false, + completedQuestionnaire: null, + requirementName: requirement2.name, + requirementDescription: requirement2.description, + drugName: drug.name, + stakeholderId: reqStakeholder2Reference, + case_numbers: [case_number], + }; - remsRequestCompletedStatus = 'Pending'; + remsRequestCompletedStatus = 'Pending'; - await metRequirementsCollection.insertOne(newMetReq - // , (err: any, result: any) => { - // if (err) console.log(err); - // console.log('Inserted New Met Requirement'); - // } - ); + await metRequirementsCollection.insertOne(newMetReq); - const newMetReqDoc = await metRequirementsCollection.findOne(newMetReq); + const newMetReqDoc = await metRequirementsCollection.findOne(newMetReq); - remsRequest.metRequirements.push( - { - stakeholderId : newMetReqDoc.stakeholderId, - completed : newMetReqDoc.completed, - metRequirementId: newMetReqDoc._id, - requirementName: newMetReqDoc.requirementName, - requirementDescription: newMetReqDoc.requirementDescription, + remsRequest.metRequirements.push( + { + stakeholderId: newMetReqDoc.stakeholderId, + completed: newMetReqDoc.completed, + metRequirementId: newMetReqDoc._id, + requirementName: newMetReqDoc.requirementName, + requirementDescription: newMetReqDoc.requirementDescription, + } + ); } - ); } - } - } + } + + remsRequest.status = remsRequestCompletedStatus; + await remsCaseCollection.insertOne(remsRequest); + returnedRemsRequestDoc = await remsCaseCollection.findOne(remsRequest); + } else { + const matchedMetReq3 = await metRequirementsCollection.findOne({ stakeholderId: reqStakeholderReference, requirementName: requirement.name, drugName: drug.name }); + if (matchedMetReq3) { + // matchedMetReq3.completed = true; + // matchedMetReq3.completedQuestionnaire = questionnaireResponse; + if (!matchedMetReq3.completed) { + await metRequirementsCollection.updateOne(matchedMetReq3, { $set: { completed: true, completedQuestionnaire: questionnaireResponse } }); + + returnedMetReqDoc = await metRequirementsCollection.findOne({ _id: matchedMetReq3._id }); + + // this should be an array returned via .find() - tried using $in but could not get it to work - using the first element for now as a work around since we only have one patient + const remsRequestToUpdate = await remsCaseCollection.findOne({ case_number: returnedMetReqDoc.case_numbers[0] }); - remsRequest.status = remsRequestCompletedStatus; - await remsCaseCollection.insertOne(remsRequest - // , (err: any, result: any) => { - // if (err) console.log(err); - // console.log('Inserted Rems Case'); - // } - ); - returnedRemsRequestDoc = await remsCaseCollection.findOne(remsRequest); - } else { - const matchedMetReq3 = await metRequirementsCollection.findOne({stakeholderId: reqStakeholderReference, requirementName: requirement.name, drugName: drug.name}); - if (matchedMetReq3) { - // matchedMetReq3.completed = true; - // matchedMetReq3.completedQuestionnaire = questionnaireResponse; - await metRequirementsCollection.updateOne(matchedMetReq3, {$set: {completed: true, completedQuestionnaire: questionnaireResponse}}); - - returnedMetReqDoc = await metRequirementsCollection.findOne({_id: matchedMetReq3._id}); - - // this should be an array returned via .find() - tried using $in but could not get it to work - using the first element for now as a work around since we only have one patient - const remsRequestToUpdate = await remsCaseCollection.findOne({ case_number: returnedMetReqDoc.case_numbers[0] }); - - // for (let remsRequestToUpdate of remsRequestsToUpdate) { - let foundUncompleted = false; - const metReqArray = remsRequestToUpdate.metRequirements; - for (let i=0; i < remsRequestToUpdate.metRequirements.length; i++) { - const req4 = remsRequestToUpdate.metRequirements[i]; - // _id comparison would not work for some reason - if(req4.requirementName === matchedMetReq3.requirementName) { - metReqArray[i].completed = true; - req4.completed = true; - const update = await remsCaseCollection.updateOne({_id: remsRequestToUpdate._id}, {$set: {metRequirements: metReqArray}}); + + + // ToDO: iterate over multiple remsRequests - right now there will only be one that matches, but with multiple patients in the system there could be more + + // for (let remsRequestToUpdate of remsRequestsToUpdate) { + let foundUncompleted = false; + const metReqArray = remsRequestToUpdate.metRequirements; + for (let i = 0; i < remsRequestToUpdate.metRequirements.length; i++) { + const req4 = remsRequestToUpdate.metRequirements[i]; + // _id comparison would not work for some reason + if (req4.requirementName === matchedMetReq3.requirementName) { + metReqArray[i].completed = true; + req4.completed = true; + const update = await remsCaseCollection.updateOne({ _id: remsRequestToUpdate._id }, { $set: { metRequirements: metReqArray } }); + } + if (!req4.completed) { + foundUncompleted = true; + } } - if(!req4.completed){ - foundUncompleted = true; + + + if (!foundUncompleted && remsRequestToUpdate.status === 'Pending') { + await remsCaseCollection.updateOne(remsRequestToUpdate, { $set: { status: 'Approved' } }); } - } - // remsRequestToUpdate.metRequirements.forEach(async (req4: any, index: number) => { - - // }); - if(!foundUncompleted && remsRequestToUpdate.status === 'Pending') { - // remsRequestToUpdate.status = 'Approved'; - await remsCaseCollection.updateOne(remsRequestToUpdate, {$set: {status: 'Approved'}}); + + // } } - - // } - } else { - // create the metReq that was submitted - const newMetReq3 = { - completed: true, - completedQuestionnaire: questionnaireResponse, - requirementName: requirement.name, - requirementDescription: requirement.requirementDescription, - drugName: drug.name, - stakeholderId: reqStakeholderReference, - case_numbers: [], - }; - - await metRequirementsCollection.insertOne(newMetReq3 - // , (err: any, result: any) => { - // if (err) console.log(err); - // console.log('Inserted New Met Requirement'); - // } - ); - returnedMetReqDoc = await metRequirementsCollection.findOne(newMetReq3); + + } else { + // create the metReq that was submitted + const newMetReq3 = { + completed: true, + completedQuestionnaire: questionnaireResponse, + requirementName: requirement.name, + requirementDescription: requirement.requirementDescription, + drugName: drug.name, + stakeholderId: reqStakeholderReference, + case_numbers: [], + }; + + await metRequirementsCollection.insertOne(newMetReq3); + returnedMetReqDoc = await metRequirementsCollection.findOne(newMetReq3); + } } + break; } - break; } - } - // return MetReq unless a new case is created in which case return the Rems request - if (returnRemsRequest) { - res.send(returnedRemsRequestDoc); - } else { - res.send(returnedMetReqDoc); + // return MetReq unless a new case is created in which case return the Rems request + if (returnRemsRequest) { + res.send(returnedRemsRequestDoc); + } else { + res.send(returnedMetReqDoc); + } + } catch (error) { + console.log(error); } }); + return this; } From 938f8370e10000f5ecafbd262a93a8e35d8056d7 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Tue, 14 Feb 2023 14:51:13 -0500 Subject: [PATCH 12/15] environment variables --- docker-compose-dev.yml | 2 ++ docker-compose-porter.yml | 3 +++ docker-compose.yml | 3 +++ env.json | 4 ++-- src/config.ts | 4 ++-- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 6808865c..5d1f80ae 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -89,6 +89,8 @@ services: - "8091:8091" environment: VSAC_API_KEY: ${VSAC_API_KEY} + MONGO_HOSTNAME: mongodb://rems-admin-pims-root:rems-admin-pims-password@pims_remsadmin_mongo:27017 + volumes: - rems_dev_rems-sync:/REMS:nocopy # nocopy is important - rems_dev_rems-nodeModules:/REMS/node_modules diff --git a/docker-compose-porter.yml b/docker-compose-porter.yml index 66300301..67f11560 100644 --- a/docker-compose-porter.yml +++ b/docker-compose-porter.yml @@ -48,6 +48,9 @@ services: container_name: rems_porter_rems ports: # Port binding to host from docker container - "9015:9015" # Bind port 3000 of host to 3000 of container + environment: + VSAC_API_KEY: ${VSAC_API_KEY} + MONGO_HOSTNAME: mongodb://rems-admin-pims-root:rems-admin-pims-password@pims_remsadmin_mongo:27017 pims_remsadmin_mongo: image: mongo diff --git a/docker-compose.yml b/docker-compose.yml index 9e735f2b..53be10d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,6 +48,9 @@ services: container_name: rems_prod_rems ports: # Port binding to host from docker container - "9015:9015" # Bind port 3000 of host to 3000 of container + environment: + VSAC_API_KEY: ${VSAC_API_KEY} + MONGO_HOSTNAME: mongodb://rems-admin-pims-root:rems-admin-pims-password@pims_remsadmin_mongo:27017 pims_remsadmin_mongo: image: mongo diff --git a/env.json b/env.json index 6846e7cb..075cf5db 100644 --- a/env.json +++ b/env.json @@ -1,7 +1,7 @@ { "MONGO_HOSTNAME": { "type": "string", - "default": "rems-admin-pims-root:rems-admin-pims-password@pims_remsadmin_mongo:27017", + "default": "mongodb://rems-admin-pims-root:rems-admin-pims-password@localhost:27017", "required": true }, "MONGO_DB_NAME": { @@ -33,6 +33,6 @@ }, "VSAC_KEY": { "type": "string", - "default": "f6486e93-5f75-481c-a5c1-b6395d7a217d" + "default": "changeMe" } } diff --git a/src/config.ts b/src/config.ts index 55f1f20a..8fbdf8f0 100644 --- a/src/config.ts +++ b/src/config.ts @@ -23,7 +23,7 @@ export default { }, general: { resourcePath: 'src/cds-library/CRD-DTR', - VsacApiKey: env.VSAC_KEY + VsacApiKey: env.VSAC_API_KEY }, database: { selected: 'mongo', @@ -32,7 +32,7 @@ export default { options: '' }, mongoConfig: { - location: `mongodb://${env.MONGO_HOSTNAME}`, + location: env.MONGO_HOSTNAME, db_name: env.MONGO_DB_NAME, options: { //auto_reconnect: true, From 0f1b12280a190e5778bb18f4ee95e47bc2703922 Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Tue, 14 Feb 2023 15:13:39 -0500 Subject: [PATCH 13/15] run prettier --- src/fhir/utilities.ts | 318 ++++++++++++++++++++++-------------------- src/server.ts | 196 ++++++++++++++------------ 2 files changed, 272 insertions(+), 242 deletions(-) diff --git a/src/fhir/utilities.ts b/src/fhir/utilities.ts index 158447aa..4ff1b630 100644 --- a/src/fhir/utilities.ts +++ b/src/fhir/utilities.ts @@ -288,11 +288,11 @@ export class FhirUtilities { static async populateDB() { const db = Globals.database; - // define schemas - // leave comments in of structure in for now as they will be useful to reference during the mongoose transition - const medicationCollection = await db.collection('medication-requirements' + // leave comments in of structure in for now as they will be useful to reference during the mongoose transition + const medicationCollection = await db.collection( + 'medication-requirements' // , { // 'name': { 'type': 'string' }, // 'codeSystem': { 'type': 'string' }, @@ -314,11 +314,11 @@ export class FhirUtilities { // } ); - await medicationCollection.createIndex({ name: 1 }, { unique: true }); - // leave comments of structure in for now as they will be useful to reference during the mongoose transition - const metRequirementsCollection = await db.collection('met-requirements' + // leave comments of structure in for now as they will be useful to reference during the mongoose transition + const metRequirementsCollection = await db.collection( + 'met-requirements' // , { // 'completed': { 'type': 'boolean' }, // 'completedQuestionnaire': { 'type': 'object' }, @@ -330,11 +330,14 @@ export class FhirUtilities { // } ); + metRequirementsCollection.createIndex( + { drugName: 1, requirementName: 1, stakeholderId: 1 }, + { unique: true } + ); - metRequirementsCollection.createIndex({ drugName: 1, requirementName: 1, stakeholderId: 1 }, { unique: true }); - - // leave comments of structure in for now as they will be useful to reference during the mongoose transition - const remsCaseCollection = await db.collection('rems-case' + // leave comments of structure in for now as they will be useful to reference during the mongoose transition + const remsCaseCollection = await db.collection( + 'rems-case' // , { // 'case_number': { 'type': 'string' }, // 'status': { 'type': 'string' }, @@ -356,149 +359,160 @@ export class FhirUtilities { // } ); - // prepopulateDB - medicationCollection.insert([{ - name: 'Turalio', - codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', - code: '2183126', - requirements: [{ - name: 'Patient Enrollment', - description: 'Submit Patient Enrollment form to the REMS Administrator', - stakeholderType: 'patient', - createNewCase: true, - resourceId: 'TuralioRemsPatientEnrollment', - }, - { - name: 'Prescriber Enrollment', - description: 'Submit Prescriber Enrollment form to the REMS Administrator', - stakeholderType: 'prescriber', - createNewCase: false, - resourceId: 'TuralioPrescriberEnrollmentForm', - }, - { - name: 'Prescriber Knowledge Assessment', - description: 'Submit Prescriber Knowledge Assessment form to the REMS Administrator', - stakeholderType: 'prescriber', - createNewCase: false, - resourceId: 'TuralioPrescriberKnowledgeAssessment', - }, - { - name: 'Pharmacist Enrollment', - description: 'Submit Pharmacist Enrollment form to the REMS Administrator', - stakeholderType: 'pharmacist', - createNewCase: false, - resourceId: 'TuralioPharmacistEnrollment', - }, - ] - }, - { - name: 'TIRF', - codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', - code: '1237051', - requirements: [{ - name: 'Patient Enrollment', - description: 'Submit Patient Enrollment form to the REMS Administrator', - stakeholderType: 'patient', - createNewCase: true, - resourceId: 'TIRFRemsPatientEnrollment', - }, - { - name: 'Prescriber Enrollment', - description: 'Submit Prescriber Enrollment form to the REMS Administrator', - stakeholderType: 'prescriber', - createNewCase: false, - resourceId: 'TIRFPrescriberEnrollmentForm', - }, - { - name: 'Prescriber Knowledge Assessment', - description: 'Submit Prescriber Knowledge Assessment form to the REMS Administrator', - stakeholderType: 'prescriber', - createNewCase: false, - resourceId: 'TIRFPrescriberKnowledgeAssessment', - }, - { - name: 'Pharmacist Enrollment', - description: 'Submit Pharmacist Enrollment form to the REMS Administrator', - stakeholderType: 'pharmacist', - createNewCase: false, - resourceId: 'TIRFPharmacistEnrollmentForm', - }, - { - name: 'Pharmacist Knowledge Assessment', - description: 'Submit Pharmacist Knowledge Assessment form to the REMS Administrator', - stakeholderType: 'pharmacist', - createNewCase: false, - resourceId: 'TIRFPharmacistKnowledgeAssessment', - }, - ] - }, - { - name: 'Isotretinoin', - codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', - code: '6064', - requirements: [{ - name: 'Patient Enrollment', - description: 'Submit Patient Enrollment form to the REMS Administrator', - stakeholderType: 'patient', - createNewCase: true, - resourceId: 'IPledgeRemsPatientEnrollment', - }, - { - name: 'Prescriber Enrollment', - description: 'Submit Prescriber Enrollment form to the REMS Administrator', - stakeholderType: 'prescriber', - createNewCase: false, - resourceId: 'IPledgeRemsPrescriberEnrollmentForm' - }, - { - name: 'Pharmacist Enrollment', - description: 'Submit Pharmacist Enrollment form to the REMS Administrator', - stakeholderType: 'pharmacist', - createNewCase: false, - resourceId: 'IPledgeRemsPharmacistEnrollmentForm' - }, - ] - }, - ], (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted Drug Information'); - }); + medicationCollection.insert( + [ + { + name: 'Turalio', + codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '2183126', + requirements: [ + { + name: 'Patient Enrollment', + description: 'Submit Patient Enrollment form to the REMS Administrator', + stakeholderType: 'patient', + createNewCase: true, + resourceId: 'TuralioRemsPatientEnrollment' + }, + { + name: 'Prescriber Enrollment', + description: 'Submit Prescriber Enrollment form to the REMS Administrator', + stakeholderType: 'prescriber', + createNewCase: false, + resourceId: 'TuralioPrescriberEnrollmentForm' + }, + { + name: 'Prescriber Knowledge Assessment', + description: 'Submit Prescriber Knowledge Assessment form to the REMS Administrator', + stakeholderType: 'prescriber', + createNewCase: false, + resourceId: 'TuralioPrescriberKnowledgeAssessment' + }, + { + name: 'Pharmacist Enrollment', + description: 'Submit Pharmacist Enrollment form to the REMS Administrator', + stakeholderType: 'pharmacist', + createNewCase: false, + resourceId: 'TuralioPharmacistEnrollment' + } + ] + }, + { + name: 'TIRF', + codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '1237051', + requirements: [ + { + name: 'Patient Enrollment', + description: 'Submit Patient Enrollment form to the REMS Administrator', + stakeholderType: 'patient', + createNewCase: true, + resourceId: 'TIRFRemsPatientEnrollment' + }, + { + name: 'Prescriber Enrollment', + description: 'Submit Prescriber Enrollment form to the REMS Administrator', + stakeholderType: 'prescriber', + createNewCase: false, + resourceId: 'TIRFPrescriberEnrollmentForm' + }, + { + name: 'Prescriber Knowledge Assessment', + description: 'Submit Prescriber Knowledge Assessment form to the REMS Administrator', + stakeholderType: 'prescriber', + createNewCase: false, + resourceId: 'TIRFPrescriberKnowledgeAssessment' + }, + { + name: 'Pharmacist Enrollment', + description: 'Submit Pharmacist Enrollment form to the REMS Administrator', + stakeholderType: 'pharmacist', + createNewCase: false, + resourceId: 'TIRFPharmacistEnrollmentForm' + }, + { + name: 'Pharmacist Knowledge Assessment', + description: 'Submit Pharmacist Knowledge Assessment form to the REMS Administrator', + stakeholderType: 'pharmacist', + createNewCase: false, + resourceId: 'TIRFPharmacistKnowledgeAssessment' + } + ] + }, + { + name: 'Isotretinoin', + codeSystem: 'http://www.nlm.nih.gov/research/umls/rxnorm', + code: '6064', + requirements: [ + { + name: 'Patient Enrollment', + description: 'Submit Patient Enrollment form to the REMS Administrator', + stakeholderType: 'patient', + createNewCase: true, + resourceId: 'IPledgeRemsPatientEnrollment' + }, + { + name: 'Prescriber Enrollment', + description: 'Submit Prescriber Enrollment form to the REMS Administrator', + stakeholderType: 'prescriber', + createNewCase: false, + resourceId: 'IPledgeRemsPrescriberEnrollmentForm' + }, + { + name: 'Pharmacist Enrollment', + description: 'Submit Pharmacist Enrollment form to the REMS Administrator', + stakeholderType: 'pharmacist', + createNewCase: false, + resourceId: 'IPledgeRemsPharmacistEnrollmentForm' + } + ] + } + ], + (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Drug Information'); + } + ); - metRequirementsCollection.insert([{ - stakeholderId: 'Organization/pharm0111', - completed: true, - requirementName: 'Pharmacist Enrollment', - drugName: 'Turalio', - completedQuestionnaire: null, - case_numbers: [], - }, - { - stakeholderId: 'Organization/pharm0111', - completed: true, - requirementName: 'Pharmacist Enrollment', - drugName: 'TIRF', - completedQuestionnaire: null, - case_numbers: [], - }, - { - stakeholderId: 'Organization/pharm0111', - completed: true, - requirementName: 'Pharmacist Knowledge Assessment', - drugName: 'TIRF', - completedQuestionnaire: null, - case_numbers: [], - }, - { - stakeholderId: 'Organization/pharm0111', - completed: true, - requirementName: 'Pharmacist Enrollment', - drugName: 'Isotretinoin', - completedQuestionnaire: null, - case_numbers: [], - }], (err: any, result: any) => { - if (err) console.log(err); - console.log('Inserted Pharmacist Met Requirements'); - }); + metRequirementsCollection.insert( + [ + { + stakeholderId: 'Organization/pharm0111', + completed: true, + requirementName: 'Pharmacist Enrollment', + drugName: 'Turalio', + completedQuestionnaire: null, + case_numbers: [] + }, + { + stakeholderId: 'Organization/pharm0111', + completed: true, + requirementName: 'Pharmacist Enrollment', + drugName: 'TIRF', + completedQuestionnaire: null, + case_numbers: [] + }, + { + stakeholderId: 'Organization/pharm0111', + completed: true, + requirementName: 'Pharmacist Knowledge Assessment', + drugName: 'TIRF', + completedQuestionnaire: null, + case_numbers: [] + }, + { + stakeholderId: 'Organization/pharm0111', + completed: true, + requirementName: 'Pharmacist Enrollment', + drugName: 'Isotretinoin', + completedQuestionnaire: null, + case_numbers: [] + } + ], + (err: any, result: any) => { + if (err) console.log(err); + console.log('Inserted Pharmacist Met Requirements'); + } + ); } } diff --git a/src/server.ts b/src/server.ts index 7046f7dd..6250eddf 100644 --- a/src/server.ts +++ b/src/server.ts @@ -9,9 +9,6 @@ import { Globals } from './globals'; import { uid } from 'uid'; import { FhirUtilities } from './fhir/utilities'; - - - const logger = container.get('application'); const initialize = (config: any) => { @@ -26,7 +23,6 @@ const initialize = (config: any) => { .registerCdsHooks(config.server) .configureEtasuEndpoints() .setErrorRoutes(); - }; /** @@ -75,8 +71,8 @@ class REMSServer extends Server { log ? log : morgan('combined', { - stream: { write: message => logger.log(level, message) } - }) + stream: { write: message => logger.log(level, message) } + }) ); return this; @@ -113,29 +109,32 @@ class REMSServer extends Server { const metRequirementsCollection = db.collection('met-requirements'); const remsCaseCollection = db.collection('rems-case'); - // etasu endpoints + // etasu endpoints this.app.get('/etasu/:drug', (req: any, res: { send: (arg0: string) => any }) => { - medicationCollection.findOne({ 'name': req.params.drug }, (err: any, drug: any) => { + medicationCollection.findOne({ name: req.params.drug }, (err: any, drug: any) => { if (err) throw err; res.send(drug); }); - } - ); + }); this.app.get('/etasu/met/:caseId', (req: any, res: { send: (arg0: string) => any }) => { - remsCaseCollection.findOne({ 'case_number': req.params.caseId }, (err: any, remsCase: any) => { + remsCaseCollection.findOne({ case_number: req.params.caseId }, (err: any, remsCase: any) => { if (err) throw err; res.send(remsCase); }); - } - ); + }); - this.app.get('/etasu/met/patient/:patientName/drug/:drugName', (req: any, res: { send: (arg0: string) => any }) => { - remsCaseCollection.findOne({ patientName: req.params.patientName, drugName: req.params.drugName }, (err: any, remsCase: any) => { - if (err) throw err; - res.send(remsCase); - }); - } + this.app.get( + '/etasu/met/patient/:patientName/drug/:drugName', + (req: any, res: { send: (arg0: string) => any }) => { + remsCaseCollection.findOne( + { patientName: req.params.patientName, drugName: req.params.drugName }, + (err: any, remsCase: any) => { + if (err) throw err; + res.send(remsCase); + } + ); + } ); this.app.post('/etasu/reset', async (req: any, res: { send: (arg0: string) => any }) => { @@ -146,8 +145,7 @@ class REMSServer extends Server { console.log('Resetting the database'); await FhirUtilities.populateDB(); res.send('reset etasu database collections'); - } - ); + }); this.app.post('/etasu/met', async (req: any, res: { send: (arg0: string) => any }) => { try { @@ -157,7 +155,10 @@ class REMSServer extends Server { const requestBody = req.body; // extract params and questionnaire response identifier - const params = this.getResource(requestBody, requestBody.entry[0].resource.focus.parameters.reference); + const params = this.getResource( + requestBody, + requestBody.entry[0].resource.focus.parameters.reference + ); const questionnaireResponse = this.getQuestionnaireResponse(requestBody); const questionnaireStringArray = questionnaireResponse.questionnaire.split('/'); const requirementId = questionnaireStringArray[questionnaireStringArray.length - 1]; @@ -170,11 +171,9 @@ class REMSServer extends Server { for (const param of params.parameter) { if (param.name === 'prescription') { prescriptionReference = param.reference; - } - else if (param.name === 'prescriber') { + } else if (param.name === 'prescriber') { practitionerReference = param.reference; - } - else if (param.name === 'pharmacy') { + } else if (param.name === 'pharmacy') { pharmacistReference = param.reference; } else if (param.name === 'source-patient') { patientReference = param.reference; @@ -188,16 +187,23 @@ class REMSServer extends Server { const patient = this.getResource(requestBody, patientReference); const patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; - const drug = await medicationCollection.findOne({ code: prescriptionCode, codeSystem: prescriptionSystem }); + const drug = await medicationCollection.findOne({ + code: prescriptionCode, + codeSystem: prescriptionSystem + }); // iterate through each requirement of the drug for (const requirement of drug.requirements) { - // figure out which stakeholder the req corresponds to + // figure out which stakeholder the req corresponds to const reqStakeholder = requirement.stakeholderType; - const reqStakeholderReference = reqStakeholder === 'prescriber' ? practitionerReference : (reqStakeholder === 'pharmacist' ? pharmacistReference : patientReference); + const reqStakeholderReference = + reqStakeholder === 'prescriber' + ? practitionerReference + : reqStakeholder === 'pharmacist' + ? pharmacistReference + : patientReference; // if the requirement is the one submitted continue if (requirement.resourceId === requirementId) { - // if the req submitted is a patient enrollment form and requires creating a new case if (requirement.createNewCase) { returnRemsRequest = true; @@ -210,7 +216,7 @@ class REMSServer extends Server { status: remsRequestCompletedStatus, drugName: drug.name, patientName: patientName, - metRequirements: [], + metRequirements: [] }; returnRemsRequest = true; @@ -222,48 +228,54 @@ class REMSServer extends Server { requirementDescription: requirement.description, drugName: drug.name, stakeholderId: reqStakeholderReference, - case_numbers: [case_number], + case_numbers: [case_number] }; await metRequirementsCollection.insertOne(metReq); const matchedMetReq = await metRequirementsCollection.findOne(metReq); + remsRequest.metRequirements.push({ + stakeholderId: matchedMetReq.stakeholderId, + completed: matchedMetReq.completed, + metRequirementId: matchedMetReq._id, + requirementName: matchedMetReq.requirementName, + requirementDescription: matchedMetReq.requirementDescription + }); - remsRequest.metRequirements.push( - { - stakeholderId: matchedMetReq.stakeholderId, - completed: matchedMetReq.completed, - metRequirementId: matchedMetReq._id, - requirementName: matchedMetReq.requirementName, - requirementDescription: matchedMetReq.requirementDescription, - } - ); - - // iterate through all other reqs again to create corresponding false metReqs / assign to existing + // iterate through all other reqs again to create corresponding false metReqs / assign to existing for (const requirement2 of drug.requirements) { // skip if the req found is the same as in the outer loop and has already been processed if (!(requirement2.resourceId === requirementId)) { - // figure out which stakeholder the req corresponds to + // figure out which stakeholder the req corresponds to const reqStakeholder2 = requirement2.stakeholderType; - const reqStakeholder2Reference = reqStakeholder2 === 'prescriber' ? practitionerReference : (reqStakeholder2 === 'pharmacist' ? pharmacistReference : patientReference); - - const matchedMetReq2 = await metRequirementsCollection.findOne({ stakeholderId: reqStakeholder2Reference, requirementName: requirement2.name, drugName: drug.name }); + const reqStakeholder2Reference = + reqStakeholder2 === 'prescriber' + ? practitionerReference + : reqStakeholder2 === 'pharmacist' + ? pharmacistReference + : patientReference; + + const matchedMetReq2 = await metRequirementsCollection.findOne({ + stakeholderId: reqStakeholder2Reference, + requirementName: requirement2.name, + drugName: drug.name + }); if (matchedMetReq2) { - remsRequest.metRequirements.push( - { - stakeholderId: matchedMetReq2.stakeholderId, - completed: matchedMetReq2.completed, - metRequirementId: matchedMetReq2._id, - requirementName: matchedMetReq2.requirementName, - requirementDescription: matchedMetReq2.requirementDescription, - } - ); + remsRequest.metRequirements.push({ + stakeholderId: matchedMetReq2.stakeholderId, + completed: matchedMetReq2.completed, + metRequirementId: matchedMetReq2._id, + requirementName: matchedMetReq2.requirementName, + requirementDescription: matchedMetReq2.requirementDescription + }); if (!matchedMetReq2.completed) { remsRequestCompletedStatus = 'Pending'; } // matchedMetReq2.case_numbers.push(case_number); - await metRequirementsCollection.updateOne(matchedMetReq2, { $addToSet: { case_numbers: case_number } }); + await metRequirementsCollection.updateOne(matchedMetReq2, { + $addToSet: { case_numbers: case_number } + }); } else { // create the metReq that was submitted const newMetReq = { @@ -273,7 +285,7 @@ class REMSServer extends Server { requirementDescription: requirement2.description, drugName: drug.name, stakeholderId: reqStakeholder2Reference, - case_numbers: [case_number], + case_numbers: [case_number] }; remsRequestCompletedStatus = 'Pending'; @@ -282,16 +294,13 @@ class REMSServer extends Server { const newMetReqDoc = await metRequirementsCollection.findOne(newMetReq); - - remsRequest.metRequirements.push( - { - stakeholderId: newMetReqDoc.stakeholderId, - completed: newMetReqDoc.completed, - metRequirementId: newMetReqDoc._id, - requirementName: newMetReqDoc.requirementName, - requirementDescription: newMetReqDoc.requirementDescription, - } - ); + remsRequest.metRequirements.push({ + stakeholderId: newMetReqDoc.stakeholderId, + completed: newMetReqDoc.completed, + metRequirementId: newMetReqDoc._id, + requirementName: newMetReqDoc.requirementName, + requirementDescription: newMetReqDoc.requirementDescription + }); } } } @@ -300,19 +309,27 @@ class REMSServer extends Server { await remsCaseCollection.insertOne(remsRequest); returnedRemsRequestDoc = await remsCaseCollection.findOne(remsRequest); } else { - const matchedMetReq3 = await metRequirementsCollection.findOne({ stakeholderId: reqStakeholderReference, requirementName: requirement.name, drugName: drug.name }); + const matchedMetReq3 = await metRequirementsCollection.findOne({ + stakeholderId: reqStakeholderReference, + requirementName: requirement.name, + drugName: drug.name + }); if (matchedMetReq3) { // matchedMetReq3.completed = true; // matchedMetReq3.completedQuestionnaire = questionnaireResponse; if (!matchedMetReq3.completed) { - await metRequirementsCollection.updateOne(matchedMetReq3, { $set: { completed: true, completedQuestionnaire: questionnaireResponse } }); + await metRequirementsCollection.updateOne(matchedMetReq3, { + $set: { completed: true, completedQuestionnaire: questionnaireResponse } + }); - returnedMetReqDoc = await metRequirementsCollection.findOne({ _id: matchedMetReq3._id }); + returnedMetReqDoc = await metRequirementsCollection.findOne({ + _id: matchedMetReq3._id + }); // this should be an array returned via .find() - tried using $in but could not get it to work - using the first element for now as a work around since we only have one patient - const remsRequestToUpdate = await remsCaseCollection.findOne({ case_number: returnedMetReqDoc.case_numbers[0] }); - - + const remsRequestToUpdate = await remsCaseCollection.findOne({ + case_number: returnedMetReqDoc.case_numbers[0] + }); // ToDO: iterate over multiple remsRequests - right now there will only be one that matches, but with multiple patients in the system there could be more @@ -325,24 +342,24 @@ class REMSServer extends Server { if (req4.requirementName === matchedMetReq3.requirementName) { metReqArray[i].completed = true; req4.completed = true; - const update = await remsCaseCollection.updateOne({ _id: remsRequestToUpdate._id }, { $set: { metRequirements: metReqArray } }); + const update = await remsCaseCollection.updateOne( + { _id: remsRequestToUpdate._id }, + { $set: { metRequirements: metReqArray } } + ); } if (!req4.completed) { foundUncompleted = true; } } - if (!foundUncompleted && remsRequestToUpdate.status === 'Pending') { - await remsCaseCollection.updateOne(remsRequestToUpdate, { $set: { status: 'Approved' } }); + await remsCaseCollection.updateOne(remsRequestToUpdate, { + $set: { status: 'Approved' } + }); } - // } } - - - } else { // create the metReq that was submitted const newMetReq3 = { @@ -352,7 +369,7 @@ class REMSServer extends Server { requirementDescription: requirement.requirementDescription, drugName: drug.name, stakeholderId: reqStakeholderReference, - case_numbers: [], + case_numbers: [] }; await metRequirementsCollection.insertOne(newMetReq3); @@ -374,37 +391,36 @@ class REMSServer extends Server { } }); - return this; } - getResource(bundle: { entry: any[]; }, resourceReference: string) { + getResource(bundle: { entry: any[] }, resourceReference: string) { const temp = resourceReference.split('/'); const _resourceType = temp[0]; const _id = temp[1]; for (let i = 0; i < bundle.entry.length; i++) { - if ((bundle.entry[i].resource.resourceType === _resourceType) - && (bundle.entry[i].resource.id === _id)) { + if ( + bundle.entry[i].resource.resourceType === _resourceType && + bundle.entry[i].resource.id === _id + ) { return bundle.entry[i].resource; } } return null; } - getQuestionnaireResponse(bundle: { entry: any[]; }) { + getQuestionnaireResponse(bundle: { entry: any[] }) { const _resourceType = 'QuestionnaireResponse'; for (let i = 0; i < bundle.entry.length; i++) { - if ((bundle.entry[i].resource.resourceType === _resourceType)) { + if (bundle.entry[i].resource.resourceType === _resourceType) { return bundle.entry[i].resource; } } return null; } - - /** * @method listen * @description Start listening on the configured port From aae33107d71bc18ad1e091a2fc9fa4b0697ca5bb Mon Sep 17 00:00:00 2001 From: Sahil Malhotra Date: Tue, 14 Feb 2023 15:36:16 -0500 Subject: [PATCH 14/15] environment variables for pims --- docker-compose-dev.yml | 4 +++- docker-compose-porter.yml | 3 +++ docker-compose.yml | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 5d1f80ae..852873e9 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -90,7 +90,6 @@ services: environment: VSAC_API_KEY: ${VSAC_API_KEY} MONGO_HOSTNAME: mongodb://rems-admin-pims-root:rems-admin-pims-password@pims_remsadmin_mongo:27017 - volumes: - rems_dev_rems-sync:/REMS:nocopy # nocopy is important - rems_dev_rems-nodeModules:/REMS/node_modules @@ -104,6 +103,9 @@ services: ports: - "5050:5050" - "5051:5051" + environment: + REMS_ADMIN_BASE: http://rems-administrator:8090 + MONGO_HOSTNAME: mongodb://pims_remsadmin_mongo:27017/pims volumes: - rems_dev_pims-sync:/home/node/app/pims:nocopy - rems_dev_pims-nodeModules:/home/node/app/pims/node_modules diff --git a/docker-compose-porter.yml b/docker-compose-porter.yml index 67f11560..d1dd0031 100644 --- a/docker-compose-porter.yml +++ b/docker-compose-porter.yml @@ -67,6 +67,9 @@ services: pims: image: codexrems/pims:REMSvCurrent container_name: rems_dev_pims + environment: + REMS_ADMIN_BASE: http://rems-administrator:8090 + MONGO_HOSTNAME: mongodb://pims_remsadmin_mongo:27017/pims ports: - "5050:5050" - "5051:5051" diff --git a/docker-compose.yml b/docker-compose.yml index 53be10d3..c592b796 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -67,6 +67,9 @@ services: pims: image: codexrems/pims:REMSvCurrent container_name: rems_dev_pims + environment: + REMS_ADMIN_BASE: http://rems-administrator:8090 + MONGO_HOSTNAME: mongodb://pims_remsadmin_mongo:27017/pims ports: - "5050:5050" - "5051:5051" From a222850d790e16544c74d716df73eb9b9be28d94 Mon Sep 17 00:00:00 2001 From: kghoreshi Date: Tue, 14 Feb 2023 15:37:45 -0500 Subject: [PATCH 15/15] fix test --- src/server.test.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/server.test.ts b/src/server.test.ts index 0a8724ae..bdf4fa88 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -1,9 +1,25 @@ import { initialize, REMSServer } from './server'; import config from './config'; - +import { Globals } from './globals'; +import { Db, MongoClient } from 'mongodb'; describe('REMSServer class', () => { let server: REMSServer; + let connection: MongoClient; + let db: Db; + + beforeAll(async () => { + if (process.env.MONGO_URL) { + connection = await MongoClient.connect(process.env.MONGO_URL, {}); + db = await connection.db(process.env.MONGO_DB_NAME); + Globals.database = db; + } + }); + + afterAll(async () => { + await connection.close(); + }); + beforeEach(() => { jest.mock('morgan', () => jest.fn());