From a3e0c1625e6987e01855640cd9d4c850f28d05d0 Mon Sep 17 00:00:00 2001 From: kantush Date: Thu, 26 Oct 2023 13:16:31 +0300 Subject: [PATCH 01/16] Add OTZ program --- departments/department-programs-config.json | 4 ++ programs/patient-program-config.json | 42 +++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/departments/department-programs-config.json b/departments/department-programs-config.json index 295306e43..69e171fa4 100755 --- a/departments/department-programs-config.json +++ b/departments/department-programs-config.json @@ -69,6 +69,10 @@ { "uuid": "03552f68-8233-4793-8353-3db1847bb617", "name": "NUTRITION PROGRAM" + }, + { + "uuid": "203571d6-a4f2-4953-9e8b-e1105e2340f5", + "name": "OTZ PROGRAM" } ] }, diff --git a/programs/patient-program-config.json b/programs/patient-program-config.json index 49deeab16..a3000d3cb 100755 --- a/programs/patient-program-config.json +++ b/programs/patient-program-config.json @@ -2078,6 +2078,48 @@ } ] }, + "203571d6-a4f2-4953-9e8b-e1105e2340f5": { + "name": "OTZ PROGRAM", + "enrollmentOptions": { + "requiredProgramQuestions": [], + "allowMultipleEnrollment": false, + "stateChangeEncounterTypes": { + "enrollment": [], + "transfer": [ + { + "uuid": "cbe2d31d-2201-44ce-b52e-fbd5dc7cff33", + "name": "AMPATH POC Transfer Out Form v0.01", + "required": true + } + ], + "discharge": [ + { + "uuid": "c2380050-5e55-4d93-9f4f-cc4cd9d59dc0", + "name": "AMPATH POC OTZ Exit Form V1.0", + "required": true + } + ] + } + }, + "dataDependencies": [ + "patient", + "enrollment", + "hivLastTenClinicalEncounters" + ], + "incompatibleWith": [], + "visitTypes": [ + { + "uuid": "6eeb09be-040f-4018-ab03-c42bb1aadf58", + "name": "OTZ Visit ", + "encounterTypes": [ + { + "uuid": "a44ad5e2-b3ec-42e7-8cfa-8ba3dbcf5ed7", + "display": "OTZENROLLMENTFORM" + } + ] + } + ] + }, "781d8768-1359-11df-a1f1-0026b9348837": { "name": "DERMATOLOGY PROGRAM", "enrollmentOptions": { From e680ab08f7499e6ab939c9a7cb2bb4c327ae0fca Mon Sep 17 00:00:00 2001 From: sainingo Date: Mon, 6 Nov 2023 16:46:18 +0300 Subject: [PATCH 02/16] Add otz val --- programs/patient-program-config.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/programs/patient-program-config.json b/programs/patient-program-config.json index a3000d3cb..7183c0e02 100755 --- a/programs/patient-program-config.json +++ b/programs/patient-program-config.json @@ -2109,12 +2109,13 @@ "incompatibleWith": [], "visitTypes": [ { - "uuid": "6eeb09be-040f-4018-ab03-c42bb1aadf58", + "uuid": "d3d5fd4a-508c-4610-97b7-5197a0bdb88d", "name": "OTZ Visit ", + "groupVisit": true, "encounterTypes": [ { - "uuid": "a44ad5e2-b3ec-42e7-8cfa-8ba3dbcf5ed7", - "display": "OTZENROLLMENTFORM" + "uuid": "76680613-2974-4d89-9b85-6b0a4bf56267", + "display": "OTZACTIVITY" } ] } From 611dab78977b8b77bf938564762ca87df8d3ef7d Mon Sep 17 00:00:00 2001 From: sainingo Date: Mon, 20 Nov 2023 01:52:36 +0300 Subject: [PATCH 03/16] wip --- app/otz/cohort-module.service.js | 157 +++++++++++++++++++++++++++ etl-routes.js | 26 +++++ programs/patient-program-config.json | 2 + 3 files changed, 185 insertions(+) create mode 100644 app/otz/cohort-module.service.js diff --git a/app/otz/cohort-module.service.js b/app/otz/cohort-module.service.js new file mode 100644 index 000000000..2262ade3b --- /dev/null +++ b/app/otz/cohort-module.service.js @@ -0,0 +1,157 @@ +var db = require('../../etl-db'); +var obs_service = require('../../service/openmrs-rest/obs.service'); + +export class CohortModuleService { + getCohortOtzModules = (cohortUuid) => { + return new Promise((resolve, reject) => { + let queryParts = {}; + const sql = `SELECT + b.patient_id, + b.uuid, + MAX(b.mod1) AS mod1, + MAX(b.mod2) AS mod2, + MAX(b.mod3) AS mod3, + MAX(b.mod4) AS mod4, + MAX(b.mod5) AS mod5, + MAX(b.mod6) AS mod6, + MAX(b.mod7) AS mod7, + MAX(b.mod8) AS mod8 +FROM + (SELECT + c.cohort_id, + c.name AS cohort_name, + cm.patient_id, + en.encounter_id, + en.encounter_datetime, + ob.value_coded, + ob.value_text, + ob.concept_id, + p.uuid, + CASE + WHEN + ob.concept_id = 11032 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 11032 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod1', + CASE + WHEN + ob.concept_id = 11033 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 11033 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod2', + CASE + WHEN + ob.concept_id = 11034 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 11034 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod3', + CASE + WHEN + ob.concept_id = 11035 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 11035 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod4', + CASE + WHEN + ob.concept_id = 9302 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 9302 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod5', + CASE + WHEN + ob.concept_id = 11037 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 11037 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod6', + CASE + WHEN + ob.concept_id = 11038 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 11038 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod7', + CASE + WHEN + ob.concept_id = 11039 + AND ob.value_coded = 1065 + THEN + TRUE + WHEN + ob.concept_id = 11039 + AND ob.value_coded = 1066 + THEN + FALSE + ELSE FALSE + END AS 'mod8' + FROM + amrs.cohort c + INNER JOIN amrs.cohort_member cm ON c.cohort_id = cm.cohort_id + INNER JOIN amrs.encounter en ON (en.patient_id = cm.patient_id + AND en.encounter_type = 284) + INNER JOIN amrs.obs ob ON ob.encounter_id = en.encounter_id + INNER JOIN amrs.person p ON p.person_id = cm.patient_id + WHERE + c.uuid = '${cohortUuid}' + AND en.voided = 0 + AND ob.concept_id IN (11032 , 11033, 11034, 11035, 11036, 11037, 11038, 11039)) b +GROUP BY b.patient_id;`; + + queryParts = { + sql: sql + }; + + return db.queryServer(queryParts, function (result) { + result.sql = sql; + resolve(result); + }); + }); + }; +} diff --git a/etl-routes.js b/etl-routes.js index feffa7dab..e63aab8ea 100755 --- a/etl-routes.js +++ b/etl-routes.js @@ -81,6 +81,7 @@ import { getPatientCovidVaccinationStatus } from './service/covid-19/covid-19-va 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'; module.exports = (function () { var routes = [ @@ -6291,6 +6292,31 @@ module.exports = (function () { notes: 'Returns the patients predictions data.', tags: ['api'] } + }, + { + method: 'GET', + path: '/etl/cohort-modules/{cohortUuid}', + config: { + auth: 'simple', + plugins: {}, + handler: function (request, reply) { + const { cohortUuid } = request.params; + console.log('req', cohortUuid); + const cohortService = new CohortModuleService(); + cohortService + .getCohortOtzModules(cohortUuid) + .then(function (cohortUsers) { + reply(cohortUsers); + }) + .catch(function (error) { + reply(new Boom(500, 'Internal server error.', '', '', error)); + }); + }, + description: 'Get cohort modules for otz cohort group', + notes: + 'Api endpoint that returns cohort users based on the cohort uuid', + tags: ['api'] + } } ]; diff --git a/programs/patient-program-config.json b/programs/patient-program-config.json index 7183c0e02..f056ed9d3 100755 --- a/programs/patient-program-config.json +++ b/programs/patient-program-config.json @@ -2112,6 +2112,8 @@ "uuid": "d3d5fd4a-508c-4610-97b7-5197a0bdb88d", "name": "OTZ Visit ", "groupVisit": true, + "allowedIf": "age >= 9 && age <= 19", + "message": "Patient has to be between the age of 9 and 19", "encounterTypes": [ { "uuid": "76680613-2974-4d89-9b85-6b0a4bf56267", From f298ca146457d4c60be7ea1eaf000266de180914 Mon Sep 17 00:00:00 2001 From: derrick rono Date: Thu, 16 Nov 2023 10:50:54 +0300 Subject: [PATCH 04/16] Revert viremia changes and add new ml locations --- programs/patient-program-config.json | 6 +++--- programs/scope-builder.service.js | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/programs/patient-program-config.json b/programs/patient-program-config.json index f056ed9d3..928159979 100755 --- a/programs/patient-program-config.json +++ b/programs/patient-program-config.json @@ -4489,7 +4489,7 @@ { "uuid": "8d5b2be0-c2cc-11de-8d13-0010c6dffd0f", "display": "ADULTRETURN", - "allowedIf": "!isViremicHighVL && age > 24", + "allowedIf": "age > 24", "errors": { "viremiaError": "To access clinical forms kindly fill Enhanced Adherence Encounter Form" } @@ -4497,7 +4497,7 @@ { "uuid": "4e7553b4-373d-452f-bc89-3f4ad9a01ce7", "display": "YOUTHRETURN", - "allowedIf": "!isViremicHighVL && age >= 10 && age <= 24", + "allowedIf": "age >= 10 && age <= 24", "errors": { "viremiaError": "To access clinical forms kindly fill Enhanced Adherence Encounter Form" } @@ -4505,7 +4505,7 @@ { "uuid": "8d5b3108-c2cc-11de-8d13-0010c6dffd0f", "display": "PEDSRETURN", - "allowedIf": "!isViremicHighVL && age <= 14", + "allowedIf": "age <= 14", "errors": { "viremiaError": "To access clinical forms kindly fill Enhanced Adherence Encounter Form" } diff --git a/programs/scope-builder.service.js b/programs/scope-builder.service.js index c9e8f4dfb..60e7c3101 100755 --- a/programs/scope-builder.service.js +++ b/programs/scope-builder.service.js @@ -29,7 +29,13 @@ function buildScope(dataDictionary) { 'db2bdd7c-5fe6-4ea3-adc1-d2d8dfb3d658', '17c97881-90e5-43c8-b8a3-cc0322f89a89', 'e9f515c2-7c48-4099-ac76-41db9977f96f', - 'f7aabb83-7915-4c24-88b2-bcde8b3a9977' + 'f7aabb83-7915-4c24-88b2-bcde8b3a9977', + '08feae7c-1352-11df-a1f1-0026b9348838', + '1ce5034b-f05d-46b6-910f-fc959e091641', + '29124daf-6422-4896-b70e-daad3b252c9d', + '08fec42a-1352-11df-a1f1-0026b9348838', + 'a36c86bb-7ca3-4319-8674-28c66ba14deb', + '345514ae-8f37-42fc-9bbe-993828c2910d' ].includes(dataDictionary.intendedVisitLocationUuid); if (dataDictionary.patient) { buildPatientScopeMembers(scope, dataDictionary.patient); @@ -93,7 +99,13 @@ function buildScope(dataDictionary) { 'db2bdd7c-5fe6-4ea3-adc1-d2d8dfb3d658', '17c97881-90e5-43c8-b8a3-cc0322f89a89', 'e9f515c2-7c48-4099-ac76-41db9977f96f', - 'f7aabb83-7915-4c24-88b2-bcde8b3a9977' + 'f7aabb83-7915-4c24-88b2-bcde8b3a9977', + '08feae7c-1352-11df-a1f1-0026b9348838', + '1ce5034b-f05d-46b6-910f-fc959e091641', + '29124daf-6422-4896-b70e-daad3b252c9d', + '08fec42a-1352-11df-a1f1-0026b9348838', + 'a36c86bb-7ca3-4319-8674-28c66ba14deb', + '345514ae-8f37-42fc-9bbe-993828c2910d' ].includes(dataDictionary.intendedVisitLocationUuid); } From b159d9e7ee2701543f7375bcc40f009aade5e141 Mon Sep 17 00:00:00 2001 From: Saningo Lekalantula Date: Wed, 15 Nov 2023 12:44:13 +0300 Subject: [PATCH 05/16] Prep line Lists to populate data on the columns (#1338) Co-authored-by: kantush --- .../patient-list-with-contacts-template.json | 114 ++++++++++++++++++ .../new/new-for-prep-base.json | 31 ++++- 2 files changed, 142 insertions(+), 3 deletions(-) diff --git a/app/reporting-framework/json-reports/patient-list-with-contacts-template.json b/app/reporting-framework/json-reports/patient-list-with-contacts-template.json index f7ac08f90..0dc61d894 100755 --- a/app/reporting-framework/json-reports/patient-list-with-contacts-template.json +++ b/app/reporting-framework/json-reports/patient-list-with-contacts-template.json @@ -103,6 +103,14 @@ "type": "LEFT", "joinCondition": "delivery_report.person_id = t1.person_id and DATE_FORMAT(delivery_report.date_created, '%Y-%m-%d')='{startDate}'" } + }, + { + "table": "etl.flat_prep_summary_v1_1", + "alias": "fps", + "join": { + "type": "LEFT", + "joinCondition": "t1.person_id = fps.person_id AND fps.next_encounter_datetime IS NULL AND fps.encounter_type NOT IN (99999)" + } } ], "columns": [ @@ -142,6 +150,112 @@ "expression": "extract(year from (from_days(datediff(now(),t1.birthdate))))" } }, + { + "type": "simple_column", + "alias": "prev_rtc_date", + "column": "date_format(fps.prev_rtc_date, '%Y-%m-%d')" + }, + { + "type": "simple_column", + "alias": "cur_prep_meds_names", + "column": "fps.cur_prep_meds_names" + }, + { + "type": "simple_column", + "alias": "rapid_test_date", + "column": "date_format(fps.hiv_rapid_test_date, '%Y-%m-%d')" + }, + { + "type": "derived_column", + "alias": "hiv_rapid_test", + "expressionType": "case_statement", + "expressionOptions": { + "caseOptions": [ + { + "condition": "fps.hiv_rapid_test_result = 703", + "value": "Positive" + }, + { + "condition": "fps.hiv_rapid_test_result = 664", + "value": "Negative" + }, + { + "condition": "fps.hiv_rapid_test_result = 1138", + "value": "Indeterminate" + }, + { + "condition": "fps.hiv_rapid_test_result = 1304", + "value": "Poor sample quality" + }, + { + "condition": "fps.hiv_rapid_test_result = 1067", + "value": "Unknown" + } + ] + } + }, + { + "type": "derived_column", + "alias": "population_type_category", + "expressionType": "case_statement", + "expressionOptions": { + "caseOptions": [ + { + "condition": "fps.sub_population_type = 1", + "value": "MSM" + }, + { + "condition": "fps.sub_population_type = 2", + "value": "MSW" + }, + { + "condition": "fps.sub_population_type = 3", + "value": "FSW" + }, + { + "condition": "fps.sub_population_type = 4", + "value": "IDU" + }, + { + "condition": "fps.sub_population_type = 5", + "value": "TRANS WOMAN" + }, + { + "condition": "fps.sub_population_type = 6", + "value": "TRANS MAN" + }, + { + "condition": "fps.sub_population_type = 7", + "value": "FISHER FOLK" + }, + { + "condition": "fps.sub_population_type = 8", + "value": "CSW" + }, + { + "condition": "fps.sub_population_type = 9", + "value": "DISPLACED PERSONS" + }, + { + "condition": "fps.sub_population_type = 10", + "value": "Military and other" + }, + { + "condition": "fps.sub_population_type = 12", + "value": "TRUCK/LORRY DRIVER" + }, + { + "condition": "fps.sub_population_type = 13", + "value": "NIDU" + } + ] + } + }, + { + "type": "simple_column", + "alias": "enrollment_date", + "column": "date_format(fps.enrollment_date, '%Y-%m-%d')" + }, { "type": "derived_column", "alias": "person_name", diff --git a/app/reporting-framework/json-reports/prep-monthly/disaggregations/new/new-for-prep-base.json b/app/reporting-framework/json-reports/prep-monthly/disaggregations/new/new-for-prep-base.json index b0880c767..aa31e79ce 100644 --- a/app/reporting-framework/json-reports/prep-monthly/disaggregations/new/new-for-prep-base.json +++ b/app/reporting-framework/json-reports/prep-monthly/disaggregations/new/new-for-prep-base.json @@ -43,7 +43,7 @@ { "type": "simple_column", "alias": "ccc_number", - "column": "fi.ccc" + "column": "IFNULL(fi.ccc, 'No CCC')" }, { "type": "simple_column", @@ -60,6 +60,11 @@ "alias": "age", "column": "pd.age" }, + { + "type": "simple_column", + "alias": "latest_rtc_date", + "column": "date_format(pd.rtc_date, '%Y-%m-%d')" + }, { "type": "simple_column", "alias": "location_id", @@ -76,9 +81,29 @@ "column": "l.uuid" }, { - "type": "simple_column", + "type": "derived_column", "alias": "population_type", - "column": "pd.population_type" + "expressionType": "case_statement", + "expressionOptions": { + "caseOptions": [ + { + "condition": "pd.population_type = 1", + "value": "discordant" + }, + { + "condition": "pd.population_type = 2", + "value": "priority" + }, + { + "condition": "pd.population_type = 3 or pd.population_type is null", + "value": "general" + }, + { + "condition": "pd.population_type = 4", + "value": "key" + } + ] + } }, { "type": "derived_column", From d082b0d94e3a059815f807928d2fac94a9e54097 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:19:13 +0300 Subject: [PATCH 06/16] POC-584a (#1343) * display patient intervention status based on latest pre-follow-up form * pre.encounter --------- Co-authored-by: Drizzentic --- .../ml-weekly-predictions-base.json | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json b/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json index f2fa4b3a7..847dff7fa 100644 --- a/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json +++ b/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json @@ -46,7 +46,16 @@ "alias": "pre", "join": { "type": "LEFT", - "joinCondition": "pre.person_id = ml.person_id" + "joinCondition": "pre.person_id = ml.person_id and(DATEDIFF(ml.start_date, pre.encounter_datetime) <= 7)" + } + }, + + { + "table": "( select max(is_successful_phone_follow_up) as latest_phone_follow_up, person_id, follow_up_type from etl.pre_appointment_summary group by person_id )", + "alias": "s", + "join": { + "type": "LEFT", + "joinCondition": "pre.person_id = s.person_id" } } ], @@ -180,12 +189,12 @@ }, { "filterType": "tableColumns", - "conditionExpression": "(if((pre.is_successful_phone_follow_up = 'YES' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'YES')), 1, 0)) = ?", + "conditionExpression": "(if((latest_phone_follow_up = 'YES' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'YES')), 1, 0)) = ?", "parameterName": "successfulOutcome" }, { "filterType": "tableColumns", - "conditionExpression": "(if((pre.is_successful_phone_follow_up = 'NO' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'NO')), 1, 0)) = ?", + "conditionExpression": "(if((latest_phone_follow_up = 'NO' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'NO')), 1, 0)) = ?", "parameterName": "failedOutcome" }, { From 771c6197c3a6e0849a5d04d6e2772348bb868cc0 Mon Sep 17 00:00:00 2001 From: Faith Kamau <121166087+hiqedme@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:46:35 +0300 Subject: [PATCH 07/16] Poc 549 (#1341) * POC-549: change TPT reminder * changed IPT to TPT --------- Co-authored-by: Drizzentic --- service/patient-reminder.service.js | 42 ++++++++--------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/service/patient-reminder.service.js b/service/patient-reminder.service.js index f52fd9f7b..582953566 100755 --- a/service/patient-reminder.service.js +++ b/service/patient-reminder.service.js @@ -424,6 +424,12 @@ function TPTReminders(data) { data.inh_treatment_days_remaining < 150 ) { showReminder = true; + } else if ( + data.is_on_inh_treatment && + data.inh_treatment_days_remaining <= 30 && + data.inh_treatment_days_remaining > 0 + ) { + showReminder = true; } // INH Treatment Reminder - last month try { @@ -432,7 +438,7 @@ function TPTReminders(data) { message: 'Patient started ' + months + - ' months' + + ' months ' + treatment + ' treatment on (' + Moment(data.ipt_start_date).format('DD-MM-YYYY') + @@ -442,7 +448,7 @@ function TPTReminders(data) { '). ' + data.inh_treatment_days_remaining + ' days remaining.', - title: 'INH Treatment Reminder', + title: 'TPT Treatment Reminder', type: 'danger', display: { banner: true, @@ -453,32 +459,6 @@ function TPTReminders(data) { } catch (e) { console.log(e); } - // INH Treatment Reminder - last month - if ( - data.is_on_inh_treatment && - data.inh_treatment_days_remaining <= 30 && - data.inh_treatment_days_remaining > 0 - ) { - reminders.push({ - message: - 'Patient started ' + - months + - ' month ' + - treatment + - 'treatment since (' + - Moment(data.ipt_start_date).format('DD-MM-YYYY') + - '). Expected to end on (' + - Moment(data.ipt_completion_date).format('DD-MM-YYYY') + - ') ', - title: 'INH Treatment Reminder', - type: 'danger', - display: { - banner: true, - toast: true - } - }); - } - // TPT Reminders if ( calculateAge(data.birth_date) >= 1 && @@ -761,11 +741,11 @@ function getIptCompletionReminder(data) { message: 'Patient started ' + months + - ' month IPT on ' + + ' month TPT on ' + Moment(data.ipt_start_date).format('DD-MM-YYYY') + ' and was supposed to be completed on ' + Moment(data.ipt_start_date).add(months, 'months').format('DD-MM-YYYY'), - title: 'IPT Completion Reminder', + title: 'TPT Completion Reminder', type: 'danger', display: { banner: true, @@ -773,7 +753,7 @@ function getIptCompletionReminder(data) { } }); } else { - console.info.call('No IPT Completion Reminder For Selected Patient'); + console.info.call('No TPT Completion Reminder For Selected Patient'); } return reminders; From 5c2a03d6852ad16f36b5ccd11b2d2f7cc57b79ab Mon Sep 17 00:00:00 2001 From: Henry Korir <5462699+henrykorir@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:28:45 +0300 Subject: [PATCH 08/16] POC-583: Stop display of the Reminder To Start TPT when the Client is on TB Treatment (#1347) --- .../clinical-reminder-report.json | 30 +++++++++++++++++++ service/patient-reminder.service.js | 3 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/reporting-framework/json-reports/clinical-reminder-report.json b/app/reporting-framework/json-reports/clinical-reminder-report.json index af46abd99..4af7a002a 100644 --- a/app/reporting-framework/json-reports/clinical-reminder-report.json +++ b/app/reporting-framework/json-reports/clinical-reminder-report.json @@ -229,6 +229,36 @@ "alias": "latest_CD4_Date", "column": "ls.cd4_1_date" }, + { + "type": "simple_column", + "alias": "ipt_start_date", + "column": "ls.ipt_start_date" + }, + { + "type": "simple_column", + "alias": "ipt_stop_date", + "column": "ls.ipt_stop_date" + }, + { + "type": "simple_column", + "alias": "on_ipt", + "column": "ls.on_ipt" + }, + { + "type": "simple_column", + "alias": "ipt_completion_date", + "column": "ls.ipt_completion_date" + }, + { + "type": "simple_column", + "alias": "tb_tx_start_date", + "column": "ls.tb_tx_start_date" + }, + { + "type": "simple_column", + "alias": "tb_tx_end_date", + "column": "ls.tb_tx_end_date" + }, { "type": "simple_column", "alias": "on_tb_tx", diff --git a/service/patient-reminder.service.js b/service/patient-reminder.service.js index 582953566..37cac3049 100755 --- a/service/patient-reminder.service.js +++ b/service/patient-reminder.service.js @@ -463,7 +463,8 @@ function TPTReminders(data) { if ( calculateAge(data.birth_date) >= 1 && !data.ipt_start_date && - !data.on_tb_tx + !data.on_tb_tx && + !(data.tb_tx_start_date && !data.tb_tx_end_date) ) { reminders.push({ message: From 9c63b45f7a94ace070a9988025628976776e12b1 Mon Sep 17 00:00:00 2001 From: Faith Kamau <121166087+hiqedme@users.noreply.github.com> Date: Tue, 21 Nov 2023 13:26:48 +0300 Subject: [PATCH 09/16] Added turbo new sites --- service/eid/eid-facility-mappings.json | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/service/eid/eid-facility-mappings.json b/service/eid/eid-facility-mappings.json index 5c46b9a0b..719daf228 100755 --- a/service/eid/eid-facility-mappings.json +++ b/service/eid/eid-facility-mappings.json @@ -2834,6 +2834,33 @@ "cityVillage": "", "eidDisplay": "" }, + "0cc1e6c8-69a5-4b78-932d-6170fcfb98fe": { + "mrsId": 496, + "mrsDisplay": "Bravo Module-Turbo", + "description": "Bravo Module-Turbo", + "mflCode": "15753", + "county": "Uasin Gishu County", + "cityVillage": "", + "eidDisplay": "" + }, + "a844aa95-e9a6-416b-942b-ac07c1ef84fe": { + "mrsId": 497, + "mrsDisplay": "Maisha Module-Turbo", + "description": "Maisha Module-Turbo", + "mflCode": "15753", + "county": "Uasin Gishu County", + "cityVillage": "", + "eidDisplay": "" + }, + "c22318da-d854-43fa-bd1e-8cb7d1d16ebf": { + "mrsId": 498, + "mrsDisplay": "Victor's Module-Turbo", + "description": "Victor's Module-Turbo", + "mflCode": "15753", + "county": "Uasin Gishu County", + "cityVillage": "", + "eidDisplay": "" + }, "469bb74e-18a4-4d74-872e-55fcebe12dc7": { "mrsId": 328, "mrsDisplay": "Soy MCH", From d1f01542dc89914f28cdf02e5df3a92516d700c2 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Wed, 29 Nov 2023 09:53:42 +0300 Subject: [PATCH 10/16] failed follow-up attempt checks latest pre-appointment encounter (#1353) --- .../json-reports/ml-predictions/ml-weekly-predictions-base.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json b/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json index 847dff7fa..657e44139 100644 --- a/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json +++ b/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json @@ -165,7 +165,7 @@ "alias": "was_follow_up_successful", "expressionType": "simple_expression", "expressionOptions": { - "expression": "if((pre.is_successful_phone_follow_up = 'YES' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'YES')), 1, 0)" + "expression": "if((latest_phone_follow_up = 'YES' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'YES')), 1, 0)" } }, { From 97776d1f0d7f999415b1c9e9387a092de4a763fe Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:12:11 +0300 Subject: [PATCH 11/16] POC-570: remove reminder after patient has made clinical visit (#1350) * remove reminder after patient has made clinical visit * POC-570: worked on query to select clinical encounters only --------- Co-authored-by: Drizzentic --- .../json-reports/clinical-reminder-report.json | 2 +- service/patient-reminder.service.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/reporting-framework/json-reports/clinical-reminder-report.json b/app/reporting-framework/json-reports/clinical-reminder-report.json index 4af7a002a..c5e0f3be0 100644 --- a/app/reporting-framework/json-reports/clinical-reminder-report.json +++ b/app/reporting-framework/json-reports/clinical-reminder-report.json @@ -222,7 +222,7 @@ { "type": "simple_column", "alias": "last_encounter_date", - "column": "ls.encounter_datetime" + "column": "t1.encounter_datetime" }, { "type": "simple_column", diff --git a/service/patient-reminder.service.js b/service/patient-reminder.service.js index 37cac3049..74498f2b2 100755 --- a/service/patient-reminder.service.js +++ b/service/patient-reminder.service.js @@ -945,7 +945,10 @@ function getFPExpiryDate(data) { function generateAppointmentNoShowUpRiskReminder(data) { let reminders = []; const predicted_score = (data.predicted_prob_disengage * 100).toFixed(2); - if (data.predicted_risk) { + if ( + data.predicted_risk && + data.last_encounter_date < data.prediction_generated_date + ) { if (data.predicted_risk === 'Medium Risk') { reminders.push({ message: From 1afc416263a3c4f7ce2748fadd37f2c50e525eaa Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:35:26 +0300 Subject: [PATCH 12/16] POC-492: added query to track failed phone attempts (#1340) * POC-492: added query to track failed phone attempts * added query to indicate number of failed phone attempts within prediction cycle * POC-492:added query to indicate number of failed phone attempts within prediction cycle --------- Co-authored-by: Drizzentic --- .../ml-predictions/ml-weekly-predictions-base.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json b/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json index 657e44139..39d5293e8 100644 --- a/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json +++ b/app/reporting-framework/json-reports/ml-predictions/ml-weekly-predictions-base.json @@ -49,7 +49,6 @@ "joinCondition": "pre.person_id = ml.person_id and(DATEDIFF(ml.start_date, pre.encounter_datetime) <= 7)" } }, - { "table": "( select max(is_successful_phone_follow_up) as latest_phone_follow_up, person_id, follow_up_type from etl.pre_appointment_summary group by person_id )", "alias": "s", @@ -57,6 +56,14 @@ "type": "LEFT", "joinCondition": "pre.person_id = s.person_id" } + }, + { + "table": "(SELECT et.person_id, SUM(CASE WHEN et.is_successful_phone_follow_up = 'YES' THEN 0 WHEN et.is_successful_phone_follow_up = 'NO' THEN 1 ELSE 0 END) AS counter FROM etl.pre_appointment_summary et left join predictions.ml_weekly_predictions mwl on et.person_id = mwl.person_id WHERE et.encounter_datetime BETWEEN mwl.prediction_generated_date AND DATE_ADD(mwl.prediction_generated_date, INTERVAL 14 DAY) GROUP BY et.person_id)", + "alias": "etc", + "join": { + "type": "LEFT", + "joinCondition": "ml.person_id = etc.person_id" + } } ], "columns": [ @@ -168,6 +175,11 @@ "expression": "if((latest_phone_follow_up = 'YES' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'YES')), 1, 0)" } }, + { + "type": "simple_column", + "alias": "number_of_failed_phone_attempts", + "column": "etc.counter" + }, { "type": "simple_column", "alias": "comments", From d0dc9ccb371e465418cf0a43eade49d89d8b483d Mon Sep 17 00:00:00 2001 From: Saningo Lekalantula Date: Wed, 29 Nov 2023 13:04:17 +0300 Subject: [PATCH 13/16] POC-560 (#1335) * Validate ART Preparion Form * Add validation in art prepartion form for Adult, Youth and Ped clients --------- Co-authored-by: kantush Co-authored-by: Drizzentic --- programs/patient-program-config.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/programs/patient-program-config.json b/programs/patient-program-config.json index 928159979..1b7747b1d 100755 --- a/programs/patient-program-config.json +++ b/programs/patient-program-config.json @@ -125,6 +125,10 @@ { "uuid": "37770eca-8a2f-48d6-b3c8-54af0fa989c2", "display": "MENTALHEALTHSCREENING" + }, + { + "uuid": "61ad56ae-a2c3-4ddb-a351-8c8ae253378c", + "display": "ADULTARTPREPARATION" } ] }, @@ -319,6 +323,10 @@ { "uuid": "37770eca-8a2f-48d6-b3c8-54af0fa989c2", "display": "MENTALHEALTHSCREENING" + }, + { + "uuid": "bda00ff3-c811-4223-a602-3eb31c96d1f2", + "display": "PEDARTPREPARATION" } ] }, @@ -498,6 +506,10 @@ { "uuid": "37770eca-8a2f-48d6-b3c8-54af0fa989c2", "display": "MENTALHEALTHSCREENING" + }, + { + "uuid": "a400ea27-7052-4745-b51f-d9370aaef4dc", + "display": "YOUTHARTPREPARATION" } ] }, From 320cc1ad8a02b69955626072a4c4081e3fd78134 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Thu, 30 Nov 2023 09:03:13 +0300 Subject: [PATCH 14/16] added reminders for patients who wish to reschedule appointments (#1349) Co-authored-by: Drizzentic --- .../clinical-reminder-report.json | 18 +++++++++++ service/patient-reminder.service.js | 31 +++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/app/reporting-framework/json-reports/clinical-reminder-report.json b/app/reporting-framework/json-reports/clinical-reminder-report.json index c5e0f3be0..5b738f5f1 100644 --- a/app/reporting-framework/json-reports/clinical-reminder-report.json +++ b/app/reporting-framework/json-reports/clinical-reminder-report.json @@ -79,6 +79,14 @@ "joinCondition": "mwl.person_id = t1.person_id" } }, + { + "table": "etl.pre_appointment_summary", + "alias": "pre_s", + "join": { + "type": "left", + "joinCondition": "mwl.person_id = pre_s.person_id " + } + }, { "table": "amrs.relationship", "alias": "t6", @@ -335,6 +343,16 @@ "alias": "prediction_generated_date", "column": "mwl.prediction_generated_date" }, + { + "type": "simple_column", + "alias": "reschedule_appointment", + "column": "pre_s.reschedule_appointment" + }, + { + "type": "simple_column", + "alias": "rescheduled_date", + "column": "pre_s.rescheduled_date" + }, { "type": "simple_column", "alias": "test_date", diff --git a/service/patient-reminder.service.js b/service/patient-reminder.service.js index 74498f2b2..06932baeb 100755 --- a/service/patient-reminder.service.js +++ b/service/patient-reminder.service.js @@ -985,8 +985,27 @@ function generateAppointmentNoShowUpRiskReminder(data) { return reminders; } +function generateAppointmentRescheduledReminder(data) { + let reminders = []; + if (data.reschedule_appointment && data.reschedule_appointment === 'YES') { + if (data.last_encounter_date < data.prediction_generated_date) { + reminders.push({ + message: + 'Promised to come date is ' + + Moment(data.rescheduled_date).format('DD-MM-YYYY'), + title: 'Appointment reschedule request', + type: 'ml', + display: { + banner: true, + toast: true + } + }); + } + } + return reminders; +} + async function generateReminders(etlResults, eidResults) { - // console.log('REMINDERS generateReminders'); let reminders = []; let patientReminder; if (etlResults && etlResults.length > 0) { @@ -1028,6 +1047,9 @@ async function generateReminders(etlResults, eidResults) { let appointmentNoShowUpRiskReminder = generateAppointmentNoShowUpRiskReminder( data ); + let appointmentRescheduledRiskReminder = generateAppointmentRescheduledReminder( + data + ); let currentReminder = []; if (pending_vl_lab_result.length > 0) { @@ -1056,8 +1078,11 @@ async function generateReminders(etlResults, eidResults) { reminders = reminders.concat(currentReminder); - // Add appointment no show up risk reminder - reminders = reminders.concat(appointmentNoShowUpRiskReminder); + // Add appointment no show up risk reminder and + reminders = reminders.concat( + appointmentNoShowUpRiskReminder, + appointmentRescheduledRiskReminder + ); patientReminder.reminders = reminders; return patientReminder; From 9e0eb60ddf4aad303f94ad7d865cc45b1908e42c Mon Sep 17 00:00:00 2001 From: sainingo Date: Thu, 7 Dec 2023 11:16:22 +0300 Subject: [PATCH 15/16] wip --- dao/patient/etl-patient-dao.js | 102 ++++++++++++++++++++++++++- etl-routes.js | 35 +++++++++ programs/patient-program-config.json | 4 +- 3 files changed, 138 insertions(+), 3 deletions(-) diff --git a/dao/patient/etl-patient-dao.js b/dao/patient/etl-patient-dao.js index ea647f6a0..808a55c54 100755 --- a/dao/patient/etl-patient-dao.js +++ b/dao/patient/etl-patient-dao.js @@ -718,6 +718,104 @@ module.exports = (function () { }); } + function getPatientsLatestHivSummmary(request, callback) { + return new Promise(function (resolve, reject) { + const uuid = request.query.uuid ? request.query.uuid.split(',') : []; + + const whereClause = [ + 't1.uuid in ? and t1.next_encounter_datetime_hiv is null', + uuid + ]; + const queryParts = { + columns: + request.query.fields || + ' t1.vl_1 as latest_vl, t1.vl_1_date as latest_vl_date, t2.rtc_date, t1.cur_arv_adherence as adherence, t1.encounter_datetime as latest_appointment, t1.uuid', + table: 'etl.flat_hiv_summary_v15b', + where: whereClause, + leftOuterJoins: [ + [ + 'etl.flat_hiv_summary_v15b', + 't2', + 't1.person_id = t2.person_id and t2.next_clinical_datetime_hiv is null and t2.is_clinical_encounter = 1' + ] + ] + }; + + db.queryDb(queryParts) + .then(function (data) { + resolve(data.result); + }) + .catch((error) => { + reject(error); + }); + }); + } + + function getPatientsSuppressionRate1(request, callback) { + return new Promise(function (resolve, reject) { + const uuid = request.query.uuid ? request.query.uuid.split(',') : []; + + const whereClause = [ + 't1.uuid in ? and t1.next_encounter_datetime_hiv is null', + uuid + ]; + const queryParts = { + columns: + request.query.fields || + 't1.vl_1 as latest_vl, (COUNT(CASE WHEN vl_1 < 200 THEN 1 END) / COUNT(*)) * 100 AS suppression_rate', + table: 'etl.flat_hiv_summary_v15b', + where: whereClause + }; + + db.queryDb(queryParts) + .then(function (data) { + console.log('data', data); + resolve(data.result); + }) + .catch((error) => { + reject(error); + }); + }); + } + + function getPatientsSuppressionRate(request, callback) { + return new Promise(function (resolve, reject) { + const uuid = request.query.uuid ? request.query.uuid.split(',') : []; + + const whereClause = ['c.uuid in ?', uuid]; + const queryParts = { + columns: + request.query.fields || + 'c.uuid, CASE WHEN COUNT(DISTINCT cm.patient_id) = 0 THEN 0 ELSE SUM(CASE WHEN fl.hiv_viral_load < 2000 THEN 1 ELSE 0 END) / COUNT(DISTINCT cm.patient_id) * 100 END AS suppression_rate_percentage', + table: 'amrs.cohort c', + where: whereClause, + group: ['c.cohort_id'], + joins: [ + ['amrs.cohort_member', 'cm', 'c.cohort_id = cm.cohort_id'], + [ + '(SELECT person_id, MAX(test_datetime) AS latest_test_datetime FROM etl.flat_labs_and_imaging WHERE hiv_viral_load IS NOT NULL GROUP BY person_id) AS latest_tests', + 'latest_tests ON cm.patient_id = latest_tests.person_id' + ], + [ + 'etl.flat_labs_and_imaging', + 'fl', + 'latest_tests.person_id = fl.person_id', + 'and', + 'latest_tests.latest_test_datetime = fl.test_datetime' + ] + ] + }; + + db.queryDb(queryParts) + .then(function (data) { + console.log('data', data); + resolve(data.result); + }) + .catch((error) => { + reject(error); + }); + }); + } return { getPatientHivSummary: getPatientHivSummary, getPatientOncologySummary: getPatientOncologySummary, @@ -728,6 +826,8 @@ module.exports = (function () { getHivPatientClinicalSummary: getHivPatientClinicalSummary, getPatientCountGroupedByLocation: getPatientCountGroupedByLocation, getPatientDetailsGroupedByLocation: getPatientDetailsGroupedByLocation, - getHivNegativesPatientSummary: getHivNegativesPatientSummary + getHivNegativesPatientSummary: getHivNegativesPatientSummary, + getPatientsLatestHivSummmary: getPatientsLatestHivSummmary, + getPatientsSuppressionRate: getPatientsSuppressionRate }; })(); diff --git a/etl-routes.js b/etl-routes.js index e63aab8ea..fed36a007 100755 --- a/etl-routes.js +++ b/etl-routes.js @@ -6317,6 +6317,41 @@ module.exports = (function () { 'Api endpoint that returns cohort users based on the cohort uuid', tags: ['api'] } + }, + { + method: 'GET', + path: '/etl/hiv-latest-summaries', + config: { + auth: 'simple', + plugins: {}, + handler: function (request, reply) { + dao.getPatientsLatestHivSummmary(request).then((summary) => { + reply(summary); + }); + }, + description: 'Get cohort modules for otz cohort group', + notes: + 'Api endpoint that returns cohort users based on the cohort uuid', + tags: ['api'] + } + }, + { + method: 'GET', + path: '/etl/viral-load-suppression-rate', + config: { + auth: 'simple', + plugins: {}, + handler: function (request, reply) { + dao.getPatientsSuppressionRate(request).then((summary) => { + console.log('summary', summary); + reply(summary); + }); + }, + description: 'Get cohort modules for otz cohort group', + notes: + 'Api endpoint that returns cohort users based on the cohort uuid', + tags: ['api'] + } } ]; diff --git a/programs/patient-program-config.json b/programs/patient-program-config.json index 1b7747b1d..dd34d9eba 100755 --- a/programs/patient-program-config.json +++ b/programs/patient-program-config.json @@ -2124,8 +2124,8 @@ "uuid": "d3d5fd4a-508c-4610-97b7-5197a0bdb88d", "name": "OTZ Visit ", "groupVisit": true, - "allowedIf": "age >= 9 && age <= 19", - "message": "Patient has to be between the age of 9 and 19", + "allowedIf": "age > 9 && age <= 24", + "message": "Patient has to be between the age of 10 and 24", "encounterTypes": [ { "uuid": "76680613-2974-4d89-9b85-6b0a4bf56267", From c6188aad48c860a935e6073fe1acb1428c706f5f Mon Sep 17 00:00:00 2001 From: sainingo Date: Wed, 13 Dec 2023 10:10:11 +0300 Subject: [PATCH 16/16] Add viral load suppression rate endpoint --- app/otz/cohort-module.service.js | 167 ++++++------------------------- dao/patient/etl-patient-dao.js | 68 +------------ etl-routes.js | 49 +++------ 3 files changed, 46 insertions(+), 238 deletions(-) diff --git a/app/otz/cohort-module.service.js b/app/otz/cohort-module.service.js index 2262ade3b..5e7c14f14 100644 --- a/app/otz/cohort-module.service.js +++ b/app/otz/cohort-module.service.js @@ -1,148 +1,43 @@ var db = require('../../etl-db'); -var obs_service = require('../../service/openmrs-rest/obs.service'); export class CohortModuleService { - getCohortOtzModules = (cohortUuid) => { + getCohortSummary = (cohortUuids) => { + const uuids = cohortUuids + .split(',') + .map((s) => { + return `"${s}"`; + }) + .join(','); return new Promise((resolve, reject) => { let queryParts = {}; const sql = `SELECT - b.patient_id, - b.uuid, - MAX(b.mod1) AS mod1, - MAX(b.mod2) AS mod2, - MAX(b.mod3) AS mod3, - MAX(b.mod4) AS mod4, - MAX(b.mod5) AS mod5, - MAX(b.mod6) AS mod6, - MAX(b.mod7) AS mod7, - MAX(b.mod8) AS mod8 -FROM - (SELECT - c.cohort_id, - c.name AS cohort_name, - cm.patient_id, - en.encounter_id, - en.encounter_datetime, - ob.value_coded, - ob.value_text, - ob.concept_id, - p.uuid, - CASE - WHEN - ob.concept_id = 11032 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 11032 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod1', - CASE - WHEN - ob.concept_id = 11033 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 11033 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod2', - CASE - WHEN - ob.concept_id = 11034 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 11034 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod3', - CASE - WHEN - ob.concept_id = 11035 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 11035 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod4', - CASE - WHEN - ob.concept_id = 9302 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 9302 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod5', - CASE - WHEN - ob.concept_id = 11037 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 11037 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod6', - CASE - WHEN - ob.concept_id = 11038 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 11038 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod7', - CASE - WHEN - ob.concept_id = 11039 - AND ob.value_coded = 1065 - THEN - TRUE - WHEN - ob.concept_id = 11039 - AND ob.value_coded = 1066 - THEN - FALSE - ELSE FALSE - END AS 'mod8' + c.uuid, + COUNT(DISTINCT cm.patient_id) AS total_patients, + IFNULL(SUM(CASE + WHEN fl.hiv_viral_load < 200 THEN 1 + ELSE 0 + END) / NULLIF(COUNT(DISTINCT cm.patient_id), 0) * 100, + 0) AS suppression_rate_percentage FROM amrs.cohort c - INNER JOIN amrs.cohort_member cm ON c.cohort_id = cm.cohort_id - INNER JOIN amrs.encounter en ON (en.patient_id = cm.patient_id - AND en.encounter_type = 284) - INNER JOIN amrs.obs ob ON ob.encounter_id = en.encounter_id - INNER JOIN amrs.person p ON p.person_id = cm.patient_id + INNER JOIN + amrs.cohort_member cm ON c.cohort_id = cm.cohort_id + LEFT JOIN + (SELECT + person_id, MAX(test_datetime) AS latest_test_datetime + FROM + etl.flat_labs_and_imaging + WHERE + hiv_viral_load IS NOT NULL + GROUP BY person_id) AS latest_tests ON cm.patient_id = latest_tests.person_id + LEFT JOIN + etl.flat_labs_and_imaging fl ON latest_tests.person_id = fl.person_id + AND latest_tests.latest_test_datetime = fl.test_datetime WHERE - c.uuid = '${cohortUuid}' - AND en.voided = 0 - AND ob.concept_id IN (11032 , 11033, 11034, 11035, 11036, 11037, 11038, 11039)) b -GROUP BY b.patient_id;`; + c.uuid in (${uuids}) + GROUP BY c.cohort_id; + + `; queryParts = { sql: sql diff --git a/dao/patient/etl-patient-dao.js b/dao/patient/etl-patient-dao.js index 808a55c54..39a632892 100755 --- a/dao/patient/etl-patient-dao.js +++ b/dao/patient/etl-patient-dao.js @@ -751,71 +751,6 @@ module.exports = (function () { }); } - function getPatientsSuppressionRate1(request, callback) { - return new Promise(function (resolve, reject) { - const uuid = request.query.uuid ? request.query.uuid.split(',') : []; - - const whereClause = [ - 't1.uuid in ? and t1.next_encounter_datetime_hiv is null', - uuid - ]; - const queryParts = { - columns: - request.query.fields || - 't1.vl_1 as latest_vl, (COUNT(CASE WHEN vl_1 < 200 THEN 1 END) / COUNT(*)) * 100 AS suppression_rate', - table: 'etl.flat_hiv_summary_v15b', - where: whereClause - }; - - db.queryDb(queryParts) - .then(function (data) { - console.log('data', data); - resolve(data.result); - }) - .catch((error) => { - reject(error); - }); - }); - } - - function getPatientsSuppressionRate(request, callback) { - return new Promise(function (resolve, reject) { - const uuid = request.query.uuid ? request.query.uuid.split(',') : []; - - const whereClause = ['c.uuid in ?', uuid]; - const queryParts = { - columns: - request.query.fields || - 'c.uuid, CASE WHEN COUNT(DISTINCT cm.patient_id) = 0 THEN 0 ELSE SUM(CASE WHEN fl.hiv_viral_load < 2000 THEN 1 ELSE 0 END) / COUNT(DISTINCT cm.patient_id) * 100 END AS suppression_rate_percentage', - table: 'amrs.cohort c', - where: whereClause, - group: ['c.cohort_id'], - joins: [ - ['amrs.cohort_member', 'cm', 'c.cohort_id = cm.cohort_id'], - [ - '(SELECT person_id, MAX(test_datetime) AS latest_test_datetime FROM etl.flat_labs_and_imaging WHERE hiv_viral_load IS NOT NULL GROUP BY person_id) AS latest_tests', - 'latest_tests ON cm.patient_id = latest_tests.person_id' - ], - [ - 'etl.flat_labs_and_imaging', - 'fl', - 'latest_tests.person_id = fl.person_id', - 'and', - 'latest_tests.latest_test_datetime = fl.test_datetime' - ] - ] - }; - - db.queryDb(queryParts) - .then(function (data) { - console.log('data', data); - resolve(data.result); - }) - .catch((error) => { - reject(error); - }); - }); - } return { getPatientHivSummary: getPatientHivSummary, getPatientOncologySummary: getPatientOncologySummary, @@ -827,7 +762,6 @@ module.exports = (function () { getPatientCountGroupedByLocation: getPatientCountGroupedByLocation, getPatientDetailsGroupedByLocation: getPatientDetailsGroupedByLocation, getHivNegativesPatientSummary: getHivNegativesPatientSummary, - getPatientsLatestHivSummmary: getPatientsLatestHivSummmary, - getPatientsSuppressionRate: getPatientsSuppressionRate + getPatientsLatestHivSummmary: getPatientsLatestHivSummmary }; })(); diff --git a/etl-routes.js b/etl-routes.js index fed36a007..5afebd42c 100755 --- a/etl-routes.js +++ b/etl-routes.js @@ -6293,31 +6293,6 @@ module.exports = (function () { tags: ['api'] } }, - { - method: 'GET', - path: '/etl/cohort-modules/{cohortUuid}', - config: { - auth: 'simple', - plugins: {}, - handler: function (request, reply) { - const { cohortUuid } = request.params; - console.log('req', cohortUuid); - const cohortService = new CohortModuleService(); - cohortService - .getCohortOtzModules(cohortUuid) - .then(function (cohortUsers) { - reply(cohortUsers); - }) - .catch(function (error) { - reply(new Boom(500, 'Internal server error.', '', '', error)); - }); - }, - description: 'Get cohort modules for otz cohort group', - notes: - 'Api endpoint that returns cohort users based on the cohort uuid', - tags: ['api'] - } - }, { method: 'GET', path: '/etl/hiv-latest-summaries', @@ -6329,9 +6304,8 @@ module.exports = (function () { reply(summary); }); }, - description: 'Get cohort modules for otz cohort group', - notes: - 'Api endpoint that returns cohort users based on the cohort uuid', + description: 'Get cohort hiv summaries', + notes: 'Api endpoint that returns cohort hiv summaries', tags: ['api'] } }, @@ -6342,14 +6316,19 @@ module.exports = (function () { auth: 'simple', plugins: {}, handler: function (request, reply) { - dao.getPatientsSuppressionRate(request).then((summary) => { - console.log('summary', summary); - reply(summary); - }); + const { uuid } = request.query; + const cohortService = new CohortModuleService(); + cohortService + .getCohortSummary(uuid) + .then(function (cohortUsers) { + reply(cohortUsers); + }) + .catch(function (error) { + reply(new Boom(500, 'Internal server error.', '', '', error)); + }); }, - description: 'Get cohort modules for otz cohort group', - notes: - 'Api endpoint that returns cohort users based on the cohort uuid', + description: 'Get cohort viral load suppression rate', + notes: 'Api endpoint that returns cohort viral load suppression rate', tags: ['api'] } }