diff --git a/app/lab-integration/lab-sync-pre-processor.service.js b/app/lab-integration/lab-sync-pre-processor.service.js new file mode 100644 index 000000000..40588cc91 --- /dev/null +++ b/app/lab-integration/lab-sync-pre-processor.service.js @@ -0,0 +1,241 @@ +'use strict'; +var rp = require('../../request-config'); +var config = require('../../conf/config'); +var moment = require('moment'); +var db = require('../../etl-db'); + +var definition = { + processLabSyncReqest: processLabSyncReqest, + getRestResource: getRestResource, + isBatchMode: isBatchMode, + getPersonAttributes: getPersonAttributes, + hasVisitStartedToday: hasVisitStartedToday, + getPatientVisits: getPatientVisits, + savePendingLabResults: savePendingLabResults, + getCachedPendingLabResults: getCachedPendingLabResults, + processPendingLabResultRequest: processPendingLabResultRequest, + hasPendingVLOrder: hasPendingVLOrder +}; + +module.exports = definition; + +function processLabSyncReqest(params) { + const hasVisitStartedEnabled = + config.eid.filterOptions.hasVisitStartedEnabled; + return new Promise(function (resolve, reject) { + determineIfTestPatient(params.patientUuId) + .then((result) => { + if (result === false) { + const isBatch = isBatchMode(params); + if (isBatch === true) { + resolve(true); + } else { + if (hasVisitStartedEnabled) { + hasVisitStartedToday(params.patientUuId) + .then((result) => { + if (result === true) { + resolve(true); + } else { + resolve(false); + } + }) + .catch((error) => { + reject(error); + }); + } else { + resolve(true); + } + } + } else { + reject('ERROR: is a TestPatient'); + } + }) + .catch((error) => { + reject('ERROR: isTestPatient', error); + }); + }); +} + +function getRestResource(path) { + var link = config.openmrs.host + ':' + config.openmrs.port + path; + if (config.openmrs.https === true) { + link = 'https://' + link; + } else { + link = 'http://' + link; + } + return link; +} + +function isBatchMode(params) { + if (params.mode) { + const mode = params.mode; + if (mode === 'batch') { + return true; + } + } else { + return false; + } +} + +function getPersonAttributes(patientUuid) { + var uri = getRestResource( + '/' + config.openmrs.applicationName + '/ws/rest/v1/person/' + patientUuid + ); + var queryString = { + v: 'custom:(attributes:(uuid,display,value,attributeType:(uuid,display))' + }; + return new Promise(function (resolve, reject) { + rp.getRequestPromise(queryString, uri) + .then(function (response) { + resolve(response.attributes); + }) + .catch(function (error) { + reject(error); + }); + }); +} + +function hasVisitStartedToday(patientUuId) { + return new Promise(function (resolve, reject) { + getPatientVisits(patientUuId) + .then((visits) => { + var hastodaysVisits = visits.some((visit) => { + return ( + moment(visit.startDatetime).format('YYYY-MM-DD') === + moment().format('YYYY-MM-DD') + ); + }); + resolve(hastodaysVisits); + }) + .catch((error) => { + reject(error); + }); + }); +} + +function getPatientVisits(patientUuid) { + var uri = getRestResource( + '/' + config.openmrs.applicationName + '/ws/rest/v1/visit' + ); + var queryString = { + v: 'custom:(uuid,startDatetime,stopDatetime)', + patient: patientUuid + }; + return new Promise(function (resolve, reject) { + rp.getRequestPromise(queryString, uri) + .then(function (response) { + resolve(response.results); + }) + .catch(function (error) { + reject(error); + }); + }); +} + +function savePendingLabResults(eidResults, personUuid) { + return new Promise((resolve, reject) => { + let queryParts = {}; + let sql = ''; + + sql = + "replace into etl.eid_pending_results (person_uuid,pending_result) values ('" + + personUuid + + "','" + + eidResults + + "');"; + queryParts = { + sql: sql + }; + db.queryServer(queryParts, function (result) { + result.sql = sql; + resolve(result); + }); + }); +} + +function getCachedPendingLabResults(personUuid) { + return new Promise((resolve, reject) => { + let queryParts = {}; + let sql = ''; + + sql = + "select * from etl.eid_pending_results where person_uuid = '" + + personUuid + + "' AND DATE(date_created) = DATE(CURDATE()) order by date_created limit 1;"; + queryParts = { + sql: sql + }; + db.queryServer(queryParts, function (result) { + result.sql = sql; + resolve(result); + }); + }); +} + +function processPendingLabResultRequest(patientUuid) { + return new Promise((resolve, reject) => { + determineIfTestPatient(patientUuid) + .then((result) => { + if (result === false) { + getCachedPendingLabResults(patientUuid) + .then((cachedResults) => { + let cachedEidResult = []; + if (cachedResults.size > 0) { + cachedEidResult = JSON.parse( + cachedResults.result[0].pending_result + ); + resolve(cachedEidResult); + } else { + resolve(cachedEidResult); + } + }) + .catch((error) => { + reject(error); + }); + } else { + reject('Is Test Patient'); + } + }) + .catch((error) => { + reject(error); + }); + }); +} + +function hasPendingVLOrder(personUuid) { + return new Promise((resolve, reject) => { + let queryParts = {}; + let sql = ''; + + sql = + "SELECT t3.uuid FROM amrs.orders t1 INNER JOIN amrs.person t3 ON t3.person_id = t1.patient_id LEFT OUTER JOIN amrs.obs t2 ON t1.order_id = t2.order_id where t2.order_id IS NULL AND t1.date_activated >= DATE('2020-01-01') AND t3.uuid = '" + + personUuid + + "';"; + queryParts = { + sql: sql + }; + db.queryServer(queryParts, function (result) { + result.sql = sql; + resolve(result); + }); + }); +} + +function determineIfTestPatient(personUuid) { + var testPatientAttributeTypeUuid = '1e38f1ca-4257-4a03-ad5d-f4d972074e69'; + return new Promise((resolve, reject) => { + getPersonAttributes(personUuid) + .then((result) => { + const isTestPatient = result.some((attribute) => { + return ( + attribute.attributeType.uuid === testPatientAttributeTypeUuid && + attribute.value === true + ); + }); + resolve(isTestPatient); + }) + .catch((error) => { + reject(error); + }); + }); +} diff --git a/app/lab-integration/lab-sync-service.js b/app/lab-integration/lab-sync-service.js index c7078e280..9b59008c5 100644 --- a/app/lab-integration/lab-sync-service.js +++ b/app/lab-integration/lab-sync-service.js @@ -12,25 +12,39 @@ import { VLAdapter } from './adapters/vl-adapter'; import { DNAPCRAdapter } from './adapters/dnapcr-adpater'; import { CD4Adapter } from './adapters/cd4-adapter'; import { EidCompareOperator } from './utils/eid-compare-operator'; +import { PatientLastOrderLocationService } from '../../service/eid/eid-patient-last-order-location.service'; export class LabSyncService { syncAllLabsByPatientUuid(patientUuid, reply) { let tasks = []; - Object.keys(config.hivLabSystem).forEach((labLocation) => { - tasks.push((cb) => { - // delay alupe for a few ms - cb( - null, - this.syncLabsByPatientUuid( - patientUuid, - labLocation, - labLocation === 'alupe' ? 50 : 0 - ).then((result) => { - return result; - }) - ); + const service = new PatientLastOrderLocationService(); + service + .isPatientLastOrderLocationAffliatedToAlupe(patientUuid) + .then((isAffliated) => { + Object.keys(config.hivLabSystem).forEach((labLocation) => { + tasks.push((cb) => { + // delay alupe for a few ms + cb( + null, + this.syncLabsByPatientUuid( + patientUuid, + labLocation, + labLocation === 'alupe' ? 50 : 0 + ) + .then((result) => { + return result; + }) + .catch((error) => { + return error; + }) + ); + }); + }); + this.syncLabsParallel(tasks, reply); }); - }); + } + + syncLabsParallel(tasks, reply) { async.parallel(async.reflectAll(tasks), (err, results) => { // currently we have duplicate data in db. Try to remove here Promise.all(results.map((result) => result.value)) @@ -44,7 +58,6 @@ export class LabSyncService { reply(_lab_data); }) .catch((err) => { - console.log('sync service error', err); reply(Boom.notFound('Sorry, sync service temporarily unavailable.')); }); }); @@ -73,7 +86,7 @@ export class LabSyncService { }; }) .catch((error) => { - console.log('ERROR', error); + return Promise.reject(error); }); } else { return this.syncAndGetPatientLabResults(patientUuid, labLocation) @@ -81,7 +94,7 @@ export class LabSyncService { return this.syncLabsByPatientUuid(patientUuid, labLocation); }) .catch((err) => { - console.log('ERROR Getting results', err); + return Promise.reject(err); }); } } else { @@ -90,12 +103,13 @@ export class LabSyncService { return this.syncLabsByPatientUuid(patientUuid, labLocation); }) .catch((error) => { - console.log('ERROR', error); + return Promise.reject(error); }); } }) .catch((error) => { console.error('getLabSyncLog error', error); + return Promise.reject(error); }); } @@ -240,19 +254,30 @@ export class LabSyncService { return eidService .saveEidSyncLog(table, fields, savedObs) .catch((error) => { - console.log('ERROR saving logs', error); + return Promise.reject(error); }); }) .catch((error) => { - console.error('ERROR : combineObsPostPromises', error); + return new Promise((resolve, reject) => { + fields[0].status = 1; + fields[0].message = error.toString(); + eidService + .saveEidSyncLog(table, fields, []) + .then((result) => { + reject(error); + }) + .catch((error) => { + reject(error); + }); + }); }); }) .catch((error) => { - console.error('ERROR : labResultsPromises', error); + return Promise.reject(error); }); }) .catch((error) => { - console.error('ERROR : Fetching results', error); + return Promise.reject(error); }); }); } diff --git a/dao/eid/eid-patient-last-order-location.js b/dao/eid/eid-patient-last-order-location.js new file mode 100644 index 000000000..37658324e --- /dev/null +++ b/dao/eid/eid-patient-last-order-location.js @@ -0,0 +1,28 @@ +import QueryService from '../../app/database-access/query.service'; + +export class PatientLastOrderLocationDao { + constructor() {} + + getPatientLastOrderLocation(patientUuid) { + let queryRunner = new QueryService(); + + let sqlQuery = + `SELECT e.location_id as location FROM amrs.encounter e + LEFT JOIN amrs.orders o on o.encounter_id = e.encounter_id + INNER JOIN amrs.person p on o.patient_id = p.person_id + WHERE p.uuid = '` + + patientUuid + + `' ORDER BY e.encounter_datetime DESC LIMIT 1;`; + + return new Promise((resolve, reject) => { + queryRunner + .executeQuery(sqlQuery) + .then((results) => { + resolve(results); + }) + .catch((error) => { + reject(error); + }); + }); + } +} diff --git a/etl-routes.js b/etl-routes.js index 54e6ee606..eacdb4dea 100755 --- a/etl-routes.js +++ b/etl-routes.js @@ -74,6 +74,7 @@ import { PrepReminderService } from './service/prep-reminder/prep-reminder.servi import { HIVGainsAndLossesService } from './service/gains-and-losses/hiv-gains-losses-service'; const cervicalCancerScreeningService = require('./service/cervical-cancer-screening-service'); import { MOH412Service } from './service/moh-412/moh-412'; +const syncPreproc = require('./app/lab-integration/lab-sync-pre-processor.service'); import { DefaulterListService } from './service/defaulter-list-service'; import { ClinicFlowService } from './service/clinic-flow-service'; @@ -4003,10 +4004,22 @@ module.exports = (function () { handler: function (request, reply) { if (config.eidSyncOn === true) { const labSyncService = new LabSyncService(); - labSyncService.syncAllLabsByPatientUuid( - request.query.patientUuId, - reply - ); + syncPreproc + .processLabSyncReqest(request.query) + .then((validRequest) => { + if (validRequest) { + labSyncService.syncAllLabsByPatientUuid( + request.query.patientUuId, + reply + ); + } else { + reply(validRequest); + } + }) + .catch((error) => { + console.error('ERROR: ', error); + reply(error); + }); } else { reply( Boom.notImplemented( diff --git a/service/eid/eid-patient-last-order-location.service.js b/service/eid/eid-patient-last-order-location.service.js new file mode 100644 index 000000000..042addc0c --- /dev/null +++ b/service/eid/eid-patient-last-order-location.service.js @@ -0,0 +1,48 @@ +import { PatientLastOrderLocationDao } from '../../dao/eid/eid-patient-last-order-location'; + +const config = require('../../conf/config'); + +export class PatientLastOrderLocationService { + constructor() {} + + getPatientLastOrderLocation(patientUuid) { + const dao = this.getDao(); + + return new Promise((resolve, reject) => { + return dao + .getPatientLastOrderLocation(patientUuid) + .then((results) => resolve(results)) + .catch((error) => reject(error)); + }); + } + + isPatientLastOrderLocationAffliatedToAlupe(patientUuid) { + //Busia, Busia MCH, port victoria, Bumala A, Bumala B, Osieko, Matayos, Mukhubola, Teso, Malaba, + //Kamolo, Angurai, Changara, Mt. Elgon, Cheptais + const alupeLabLocations = config.eid.alupe.facilityIds; + + return new Promise((resolve, reject) => { + this.getPatientLastOrderLocation(patientUuid) + .then((results) => { + if (results.length > 0) { + const lastOrderLocation = results[0].location; + if (lastOrderLocation) { + resolve(alupeLabLocations.includes(lastOrderLocation)); + } else { + //If lastOrderLocation === undefined or 0 should resolve true + resolve(true); + } + } else { + resolve(true); + } + }) + .catch((error) => { + reject(error); + }); + }); + } + + getDao() { + return new PatientLastOrderLocationDao(); + } +}