Skip to content

Commit 99dff0f

Browse files
Merge pull request #1281 from AMPATH/ml-weekly-predictions
ML weekly predictions API endpoint for patient list
2 parents a4f3a04 + 295bb0c commit 99dff0f

File tree

8 files changed

+579
-0
lines changed

8 files changed

+579
-0
lines changed

app/reporting-framework/base-mysql.report.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ import * as hiv_cervical_cancer_monthly_summary_lesions_pcf_aggregate from './js
225225
import * as defaulter_list_aggregate from './json-reports/defaulter-list-aggregate.json';
226226
import * as defaulter_list_base from './json-reports/defaulter-list-base.json';
227227

228+
// ML Weekly Predictions
229+
import * as ml_weekly_predictions_aggregate from './json-reports/ml-predictions/ml-weekly-predictions-aggregate.json';
230+
import * as ml_weekly_predictions_base from './json-reports/ml-predictions/ml-weekly-predictions-base.json';
231+
228232
//clinic clow report
229233
import * as clinic_flow_provider_statistics_aggregate from './json-reports/clinic-flow-provider-statistics-aggregate.json';
230234
import * as clinic_flow_provider_statistics_base from './json-reports/clinic-flow-provider-statistics-base.json';
@@ -1272,6 +1276,14 @@ export class BaseMysqlReport {
12721276
defaulterListBase: this.cloneJsonSchema(defaulter_list_base)
12731277
});
12741278
break;
1279+
case 'mlWeeklyPredictionsAggregate':
1280+
resolve({
1281+
main: this.cloneJsonSchema(ml_weekly_predictions_aggregate),
1282+
mlWeeklyPredictionsBase: this.cloneJsonSchema(
1283+
ml_weekly_predictions_base
1284+
)
1285+
});
1286+
break;
12751287
case 'clinicFlowProviderStatisticsAggregate':
12761288
resolve({
12771289
main: this.cloneJsonSchema(
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"name": "mlWeeklyPredictionsAggregate",
3+
"version": "1.0",
4+
"tag": "",
5+
"description": "",
6+
"uses": [
7+
{
8+
"name": "mlWeeklyPredictionsBase",
9+
"version": "1.0",
10+
"type": "dataset_def"
11+
}
12+
],
13+
"sources": [
14+
{
15+
"dataSet": "mlWeeklyPredictionsBase",
16+
"alias": "t2"
17+
}
18+
],
19+
"columns": [
20+
{
21+
"type": "simple_column",
22+
"alias": "person_id",
23+
"column": "t2.person_id"
24+
},
25+
{
26+
"type": "simple_column",
27+
"alias": "total_predictions",
28+
"column": "count(distinct t2.person_id)"
29+
}
30+
],
31+
"groupBy": {
32+
"groupParam": "groupByParam",
33+
"columns": ["person_id"],
34+
"excludeParam": "excludeParam"
35+
},
36+
"dynamicJsonQueryGenerationDirectives": {
37+
"patientListGenerator": {
38+
"useTemplate": "patient-list-template",
39+
"useTemplateVersion": "1.0",
40+
"generatingDirectives": {
41+
"joinDirectives": {
42+
"joinType": "INNER",
43+
"joinCondition": "<<base_column>> = <<template_column>>",
44+
"baseColumn": "person_id",
45+
"templateColumn": "person_id"
46+
}
47+
}
48+
}
49+
}
50+
}
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
{
2+
"name": "mlWeeklyPredictionsBase",
3+
"version": "1.0",
4+
"tag": "",
5+
"description": "",
6+
"uses": [],
7+
"sources": [
8+
{
9+
"table": "predictions.ml_weekly_predictions",
10+
"alias": "ml"
11+
},
12+
{
13+
"table": "etl.flat_hiv_summary_v15b",
14+
"alias": "de",
15+
"join": {
16+
"type": "LEFT",
17+
"joinCondition": "de.encounter_id = ml.encounter_id"
18+
}
19+
},
20+
{
21+
"table": "etl.flat_patient_identifiers_v1",
22+
"alias": "fi",
23+
"join": {
24+
"type": "LEFT",
25+
"joinCondition": "de.person_id = fi.patient_id"
26+
}
27+
},
28+
{
29+
"table": "etl.program_visit_map",
30+
"alias": "pm",
31+
"join": {
32+
"type": "LEFT",
33+
"joinCondition": "de.visit_type = pm.visit_type_id"
34+
}
35+
},
36+
{
37+
"table": "amrs.program",
38+
"alias": "p",
39+
"join": {
40+
"type": "LEFT",
41+
"joinCondition": "p.program_id = pm.program_type_id"
42+
}
43+
},
44+
{
45+
"table": "etl.pre_appointment_summary",
46+
"alias": "pre",
47+
"join": {
48+
"type": "LEFT",
49+
"joinCondition": "pre.person_id = ml.person_id"
50+
}
51+
}
52+
],
53+
"columns": [
54+
{
55+
"type": "simple_column",
56+
"alias": "person_id",
57+
"column": "ml.person_id"
58+
},
59+
{
60+
"type": "simple_column",
61+
"alias": "ccc_number",
62+
"column": "fi.ccc"
63+
},
64+
{
65+
"type": "simple_column",
66+
"alias": "ovcid_id",
67+
"column": "fi.ovcid"
68+
},
69+
{
70+
"type": "simple_column",
71+
"alias": "upi_number",
72+
"column": "fi.nupi"
73+
},
74+
{
75+
"type": "simple_column",
76+
"alias": "program",
77+
"column": "p.name"
78+
},
79+
{
80+
"type": "simple_column",
81+
"alias": "predicted_risk",
82+
"column": "ml.predicted_risk"
83+
},
84+
{
85+
"type": "simple_column",
86+
"alias": "week",
87+
"column": "ml.week"
88+
},
89+
{
90+
"type": "simple_column",
91+
"alias": "predicted_prob_disengage",
92+
"column": "ml.predicted_prob_disengage"
93+
},
94+
{
95+
"type": "simple_column",
96+
"alias": "prediction_generated_date",
97+
"column": "DATE_FORMAT(ml.prediction_generated_date,'%Y-%m-%d')"
98+
},
99+
{
100+
"type": "simple_column",
101+
"alias": "rtc_date",
102+
"column": "DATE_FORMAT(ml.rtc_date,'%Y-%m-%d')"
103+
},
104+
{
105+
"type": "simple_column",
106+
"alias": "follow_up_type",
107+
"column": "pre.follow_up_type"
108+
},
109+
{
110+
"type": "simple_column",
111+
"alias": "follow_up_reason",
112+
"column": "pre.follow_up_reason"
113+
},
114+
{
115+
"type": "simple_column",
116+
"alias": "rescheduled_date",
117+
"column": "pre.rescheduled_date"
118+
},
119+
{
120+
"type": "simple_column",
121+
"alias": "reschedule_appointment",
122+
"column": "pre.reschedule_appointment"
123+
},
124+
{
125+
"type": "simple_column",
126+
"alias": "contact_reached",
127+
"column": "pre.contact_reached_phone_follow_up"
128+
},
129+
{
130+
"type": "simple_column",
131+
"alias": "attempted_home_visit",
132+
"column": "pre.attempted_home_visit"
133+
},
134+
{
135+
"type": "simple_column",
136+
"alias": "reason_not_attempted_home_visit",
137+
"column": "pre.reason_not_attempted_home_visit"
138+
},
139+
{
140+
"type": "simple_column",
141+
"alias": "was_client_found",
142+
"column": "pre.was_client_found"
143+
},
144+
{
145+
"type": "simple_column",
146+
"alias": "reason_client_not_found",
147+
"column": "pre.reason_client_not_found"
148+
},
149+
{
150+
"type": "simple_column",
151+
"alias": "home_visit_personnel",
152+
"column": "pre.home_visit_personnel"
153+
},
154+
{
155+
"type": "derived_column",
156+
"alias": "was_follow_up_successful",
157+
"expressionType": "simple_expression",
158+
"expressionOptions": {
159+
"expression": "if((pre.is_successful_phone_follow_up = 'YES' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'YES')), 1, 0)"
160+
}
161+
},
162+
{
163+
"type": "simple_column",
164+
"alias": "comments",
165+
"column": "pre.comments"
166+
}
167+
],
168+
"filters": {
169+
"conditionJoinOperator": "and",
170+
"conditions": [
171+
{
172+
"filterType": "tableColumns",
173+
"conditionExpression": "ml.location_id in (?)",
174+
"parameterName": "locations"
175+
},
176+
{
177+
"filterType": "tableColumns",
178+
"conditionExpression": "ml.week = ?",
179+
"parameterName": "yearWeek"
180+
},
181+
{
182+
"filterType": "tableColumns",
183+
"conditionExpression": "(if((pre.is_successful_phone_follow_up = 'YES' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'YES')), 1, 0)) = ?",
184+
"parameterName": "successfulOutcome"
185+
},
186+
{
187+
"filterType": "tableColumns",
188+
"conditionExpression": "(if((pre.is_successful_phone_follow_up = 'NO' OR (pre.attempted_home_visit = 'YES' AND pre.was_client_found = 'NO')), 1, 0)) = ?",
189+
"parameterName": "failedOutcome"
190+
},
191+
{
192+
"filterType": "tableColumns",
193+
"conditionExpression": "ml.predicted_risk is not null"
194+
}
195+
]
196+
},
197+
"orderBy": {
198+
"orderByParam": "orderByParam",
199+
"columns": [
200+
{
201+
"column": "ml.predicted_prob_disengage",
202+
"order": "desc"
203+
},
204+
{
205+
"column": "ml.prediction_generated_date",
206+
"order": "desc"
207+
},
208+
{
209+
"column": "pre.encounter_datetime",
210+
"order": "desc"
211+
}
212+
]
213+
}
214+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const preRequest = require('../../pre-request-processing');
2+
const etlHelpers = require('../../etl-helpers');
3+
const Boom = require('boom');
4+
5+
const {
6+
MlWeeklyPredictionsService
7+
} = require('../../service/ml-weekly-predictions.service');
8+
9+
const routes = [];
10+
11+
exports.routes = (server) => server.route(routes);

etl-routes.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ import { DefaulterListService } from './service/defaulter-list-service';
7979
import { ClinicFlowService } from './service/clinic-flow-service';
8080
import { getPatientCovidVaccinationStatus } from './service/covid-19/covid-19-vaccination-summary';
8181
import { Covid19MonthlyReport } from './service/covid-19/covid-19-monthly-report';
82+
import { MlWeeklyPredictionsService } from './service/ml-weekly-predictions.service';
83+
import { getPatientPredictedScore } from './service/predictions/ml-prediction-service';
8284

8385
module.exports = (function () {
8486
var routes = [
@@ -6211,6 +6213,85 @@ module.exports = (function () {
62116213
'Returns patient list of vaccinated i.e fully,partial and not vaccinated',
62126214
tags: ['api']
62136215
}
6216+
},
6217+
{
6218+
method: 'GET',
6219+
path: '/etl/ml-weekly-predictions',
6220+
config: {
6221+
auth: 'simple',
6222+
handler: function (request, reply) {
6223+
if (request.query.locationUuids) {
6224+
request.query.reportName = 'defaulter-list';
6225+
preRequest.resolveLocationIdsToLocationUuids(request, function () {
6226+
let requestParams = Object.assign(
6227+
{},
6228+
request.query,
6229+
request.params
6230+
);
6231+
6232+
const mlWeeklyPredictionsService = new MlWeeklyPredictionsService();
6233+
6234+
mlWeeklyPredictionsService
6235+
.getPatientListReport(requestParams)
6236+
.then((results) => {
6237+
_.each(results.result, (item) => {
6238+
item.cur_meds = etlHelpers.getARVNames(item.cur_meds);
6239+
});
6240+
reply(results);
6241+
})
6242+
.catch((err) => {
6243+
reply(Boom.internal('An error occured', err));
6244+
});
6245+
});
6246+
}
6247+
},
6248+
plugins: {
6249+
hapiAuthorization: {
6250+
role: privileges.canViewClinicDashBoard
6251+
},
6252+
openmrsLocationAuthorizer: {
6253+
locationParameter: [
6254+
{
6255+
type: 'query',
6256+
name: 'locationUuids' //name of the location parameter
6257+
}
6258+
]
6259+
}
6260+
},
6261+
description: "Get a location's ml weekly predictions list.",
6262+
notes: "Returns a location's ml weekly predictions list.",
6263+
tags: ['api'],
6264+
validate: {
6265+
options: {
6266+
allowUnknown: true
6267+
}
6268+
}
6269+
}
6270+
},
6271+
{
6272+
method: 'GET',
6273+
path: '/etl/predicted-score',
6274+
config: {
6275+
auth: 'simple',
6276+
plugins: {},
6277+
handler: function (request, reply) {
6278+
if (request.query.patientUuid) {
6279+
const patientUuid = request.query.patientUuid;
6280+
getPatientPredictedScore(patientUuid)
6281+
.then((results) => {
6282+
reply(results);
6283+
})
6284+
.catch((error) => {
6285+
reply(Boom.internal('An error occured', error));
6286+
});
6287+
} else {
6288+
reply(Boom.internal('Request misssing patient uuid'));
6289+
}
6290+
},
6291+
description: 'Patient predicted score of missing appointment.',
6292+
notes: 'Returns the patients predictions data.',
6293+
tags: ['api']
6294+
}
62146295
}
62156296
];
62166297

0 commit comments

Comments
 (0)