diff --git a/etl-routes.js b/etl-routes.js index 907807096..b06da97e2 100755 --- a/etl-routes.js +++ b/etl-routes.js @@ -79,9 +79,11 @@ import { DefaulterListService } from './service/defaulter-list-service'; import { ClinicFlowService } from './service/clinic-flow-service'; import { getPatientCovidVaccinationStatus } from './service/covid-19/covid-19-vaccination-summary'; import { Covid19MonthlyReport } from './service/covid-19/covid-19-monthly-report'; -import { MlWeeklyPredictionsService } from './service/ml-weekly-predictions.service'; import { getPatientPredictedScore } from './service/predictions/ml-prediction-service'; import { CohortModuleService } from './app/otz/cohort-module.service'; +const { + default: MlWeeklyPredictionsService +} = require('./service/ml-weekly-predictions.service'); module.exports = (function () { var routes = [ diff --git a/programs/patient-data-resolver.service.js b/programs/patient-data-resolver.service.js index 8a04056cc..99385ff4e 100755 --- a/programs/patient-data-resolver.service.js +++ b/programs/patient-data-resolver.service.js @@ -6,7 +6,11 @@ const etlHivSummary = require('../dao/patient/etl-patient-hiv-summary-dao'); const encounterService = require('../service/openmrs-rest/encounter'); const dcPatientvisitEvaluator = require('../service/dc-patient-visit-evaluator'); const covidAssessmentService = require('../service/covid-assessment-service'); +const weeklyPredictionsService = require('../service/ml-weekly-predictions.service'); var _ = require('underscore'); +const { + default: MlWeeklyPredictionsService +} = require('../service/ml-weekly-predictions.service'); const availableKeys = { patient: getPatient, @@ -20,7 +24,8 @@ const availableKeys = { dcQualifedVisits: getQualifiedDcVisits, validateMedicationRefill: getMedicationRefillVisits, latestCovidAssessment: getLatestCovidAssessment, - isViremicHighVL: getLatestVL + isViremicHighVL: getLatestVL, + weeklyPredictedPatients: getWeeklyPredictedPatients }; const def = { @@ -35,7 +40,8 @@ const def = { dcQualifedVisits: getQualifiedDcVisits, validateMedicationRefill: getMedicationRefillVisits, getLatestCovidAssessment: getLatestCovidAssessment, - isViremicHighVL: getLatestVL + isViremicHighVL: getLatestVL, + getWeeklyPredictedPatients: getWeeklyPredictedPatients }; module.exports = def; @@ -257,3 +263,20 @@ function getLatestVL(patientUuid) { }); }); } + +function getWeeklyPredictedPatients(patientUuid) { + return new Promise((resolve, reject) => { + let ml = new MlWeeklyPredictionsService(); + ml.getPatientsWithPredictions(patientUuid) + .then((result) => { + if (result.length > 0) { + resolve(result); + } else { + resolve([]); + } + }) + .catch((error) => { + reject(error); + }); + }); +} diff --git a/programs/patient-program-config.json b/programs/patient-program-config.json index 93955e2cc..b95fa7c39 100755 --- a/programs/patient-program-config.json +++ b/programs/patient-program-config.json @@ -6,7 +6,8 @@ "enrollment", "patientEncounters", "isPatientTransferredOut", - "latestCovidAssessment" + "latestCovidAssessment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -806,7 +807,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "programLocation === intendedVisitLocationUuid && MlLocations", + "allowedIf": "programLocation === intendedVisitLocationUuid && inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -1258,7 +1259,8 @@ "patientEnrollment", "patientEncounters", "isPatientTransferredOut", - "latestCovidAssessment" + "latestCovidAssessment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "enrollIf": "gender === 'F'", @@ -1968,7 +1970,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "programLocation === intendedVisitLocationUuid && MlLocations", + "allowedIf": "programLocation === intendedVisitLocationUuid && inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -2214,7 +2216,8 @@ "enrollment", "hivLastTenClinicalEncounters", "patientEncounters", - "latestCovidAssessment" + "latestCovidAssessment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -2383,7 +2386,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "programLocation === intendedVisitLocationUuid && MlLocations", + "allowedIf": "programLocation === intendedVisitLocationUuid && inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -2419,6 +2422,7 @@ } ] }, + "c19aec66-1a40-4588-9b03-b6be55a8dd1d": { "name": "PrEP PROGRAM", "dataDependencies": [ @@ -2426,7 +2430,9 @@ "enrollment", "hivLastTenClinicalEncounters", "patientEncounters", - "latestCovidAssessment" + "latestCovidAssessment", + "weeklyPredictedPatients", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -2611,7 +2617,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "MlLocations", + "allowedIf": "inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -2649,7 +2655,8 @@ "patient", "enrollment", "hivLastTenClinicalEncounters", - "latestCovidAssessment" + "latestCovidAssessment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -2812,7 +2819,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "MlLocations", + "allowedIf": "inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -2907,7 +2914,8 @@ "isPatientTransferredOut", "dcQualifedVisits", "validateMedicationRefill", - "latestCovidAssessment" + "latestCovidAssessment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -3189,7 +3197,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "programLocation === intendedVisitLocationUuid && MlLocations", + "allowedIf": "programLocation === intendedVisitLocationUuid && inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -4108,7 +4116,8 @@ "dataDependencies": [ "patient", "enrollment", - "hivLastTenClinicalEncounters" + "hivLastTenClinicalEncounters", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -4212,7 +4221,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "programLocation === intendedVisitLocationUuid && MlLocations", + "allowedIf": "programLocation === intendedVisitLocationUuid && inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -4245,7 +4254,8 @@ "dataDependencies": [ "patient", "enrollment", - "hivLastTenClinicalEncounters" + "hivLastTenClinicalEncounters", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -4351,7 +4361,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "MlLocations", + "allowedIf": "inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -4487,7 +4497,8 @@ "isPatientTransferredOut", "patientEncounters", "latestCovidAssessment", - "isViremicHighVL" + "isViremicHighVL", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -4725,7 +4736,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "MlLocations", + "allowedIf": "inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -4766,7 +4777,8 @@ "dataDependencies": [ "patient", "enrollment", - "hivLastTenClinicalEncounters" + "hivLastTenClinicalEncounters", + "weeklyPredictedPatients" ], "enrollmentOptions": { "stateChangeEncounterTypes": { @@ -4832,7 +4844,8 @@ "dataDependencies": [ "patient", "enrollment", - "hivLastTenClinicalEncounters" + "hivLastTenClinicalEncounters", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -4978,7 +4991,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "MlLocations", + "allowedIf": "inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -5047,7 +5060,8 @@ "dataDependencies": [ "patient", "enrollment", - "hivLastTenClinicalEncounters" + "hivLastTenClinicalEncounters", + "weeklyPredictedPatients" ], "incompatibleWith": [], "visitTypes": [ @@ -5082,7 +5096,7 @@ { "uuid": "6bdec0cd-d3fb-41da-9ef3-20076f349dc1", "name": "Pre Appointment Follow Up Visit", - "allowedIf": "programLocation === intendedVisitLocationUuid && MlLocations", + "allowedIf": "programLocation === intendedVisitLocationUuid && inPrediction", "encounterTypes": [ { "uuid": "d5e2d3b3-2061-4721-86f1-5852cde6475a", @@ -5441,7 +5455,8 @@ "patient", "enrollment", "patientEncounters", - "isPatientTransferredOut" + "isPatientTransferredOut", + "weeklyPredictedPatients" ], "enrollmentOptions": { "requiredProgramQuestions": [ @@ -5507,7 +5522,8 @@ "patient", "enrollment", "patientEncounters", - "patientEnrollment" + "patientEnrollment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "enrollIf": "gender === 'F'" @@ -5599,7 +5615,8 @@ "patient", "enrollment", "patientEncounters", - "patientEnrollment" + "patientEnrollment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "enrollIf": "gender === 'F'" @@ -5703,7 +5720,8 @@ "patient", "enrollment", "patientEncounters", - "patientEnrollment" + "patientEnrollment", + "weeklyPredictedPatients" ], "enrollmentOptions": { "enrollIf": "gender === 'F'" diff --git a/programs/scope-builder.service.js b/programs/scope-builder.service.js index a11505f5b..2c797e5ef 100755 --- a/programs/scope-builder.service.js +++ b/programs/scope-builder.service.js @@ -18,10 +18,18 @@ function buildScope(dataDictionary) { screenedForCovidToday: false, isViremicHighVL: false, isEligibleForMedicationRefill: false, - isEligibleForCommunityVisit: false + isEligibleForCommunityVisit: false, + inPrediction: false }; + let isStandardDcVisit = false; + if ( + dataDictionary.weeklyPredictedPatients && + dataDictionary.weeklyPredictedPatients.length > 0 + ) { + scope.inPrediction = true; + } // Restrict to Pilot locations scope.MlLocations = [ '08feb8ae-1352-11df-a1f1-0026b9348838', diff --git a/service/ml-weekly-predictions.service.js b/service/ml-weekly-predictions.service.js index 8ac737610..02827b2f9 100644 --- a/service/ml-weekly-predictions.service.js +++ b/service/ml-weekly-predictions.service.js @@ -1,8 +1,9 @@ const Promise = require('bluebird'); +const db = require('../etl-db'); import { BaseMysqlReport } from '../app/reporting-framework/base-mysql.report'; import { PatientlistMysqlReport } from '../app/reporting-framework/patientlist-mysql.report'; -export class MlWeeklyPredictionsService { +export default class MlWeeklyPredictionsService { getAggregateReport(reportParams) { return new Promise(function (resolve, reject) { const report = new BaseMysqlReport( @@ -44,4 +45,51 @@ export class MlWeeklyPredictionsService { }); }); } + + getPatientsWithPredictions(patientUuId) { + return new Promise((resolve, reject) => { + const week = this.getNextWeek(); + const predictedPatients = `SELECT + ml.person_id AS person_id, + ml.predicted_risk AS predicted_risk, + ml.week AS week +FROM + predictions.ml_weekly_predictions ml + LEFT JOIN + etl.pre_appointment_summary pre ON (pre.person_id = ml.person_id) + INNER JOIN + amrs.person t1 ON (ml.person_id = t1.person_id) +WHERE + t1.uuid = '${patientUuId}' + AND (ml.week = '${week}' ) + AND (ml.predicted_risk IS NOT NULL) +GROUP BY t1.person_id + `; + const queryParts = { + sql: predictedPatients + }; + db.queryServer(queryParts, function (result) { + result.sql = predictedPatients; + resolve(result.result); + }); + }); + } + getNextWeek() { + const currentDate = new Date(); + currentDate.setDate(currentDate.getDate()); // Add 7 days + + const year = currentDate.getFullYear(); + const weekNumber = this.getISOWeek(currentDate); + + return `${year}-W${weekNumber.toString().padStart(2, '0')}`; + } + + // Helper function to get ISO week number + getISOWeek(date) { + const dayOfWeek = date.getUTCDay() || 7; + date.setUTCDate(date.getUTCDate() + 4 - dayOfWeek); + const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1)); + const weekNumber = Math.ceil(((date - yearStart) / 86400000 + 1) / 7); + return weekNumber; + } }