malawi_hiv_program_reports 1.1.16 → 1.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/services/malawi_hiv_program_reports/cohort/disaggregated.rb +57 -47
- data/app/services/malawi_hiv_program_reports/moh/cumulative_cohort.rb +62 -1
- data/app/services/malawi_hiv_program_reports/pepfar/maternal_status.rb +103 -1
- data/app/services/malawi_hiv_program_reports/pepfar/tb_prev3.rb +214 -172
- data/app/services/malawi_hiv_program_reports/pepfar/tx_curr_mmd.rb +63 -25
- data/app/services/malawi_hiv_program_reports/pepfar/tx_ml.rb +137 -41
- data/app/services/malawi_hiv_program_reports/pepfar/tx_new.rb +51 -64
- data/app/services/malawi_hiv_program_reports/pepfar/tx_rtt.rb +91 -47
- data/app/services/malawi_hiv_program_reports/pepfar/tx_tb.rb +188 -135
- data/app/services/malawi_hiv_program_reports/report_map.rb +1 -1
- data/lib/malawi_hiv_program_reports/version.rb +1 -1
- metadata +3 -3
@@ -6,9 +6,8 @@ module MalawiHivProgramReports
|
|
6
6
|
# Patients who started TPT just before the start of the current
|
7
7
|
# and have finished within the current reporting period.
|
8
8
|
class TbPrev3
|
9
|
+
attr_reader :start_date, :end_date, :check_date, :cut_off_point, :occupation, :location, :report
|
9
10
|
|
10
|
-
attr_reader :start_date, :end_date, :check_date, :cut_off_point, :occupation, :location
|
11
|
-
|
12
11
|
include MalawiHivProgramReports::Adapters::Moh::Custom
|
13
12
|
include Utils
|
14
13
|
include MalawiHivProgramReports::Utils::CommonSqlQueryUtils
|
@@ -23,56 +22,160 @@ module MalawiHivProgramReports
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def find_report
|
26
|
-
|
25
|
+
process_data
|
26
|
+
flatten_the_report
|
27
|
+
rescue StandardError => e
|
28
|
+
Rails.logger.error("Error generating TB Prev3 report: #{e.message}")
|
29
|
+
Rails.logger.error(e.backtrace.join("\n"))
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch_individual_report(patient_id)
|
34
|
+
individual_tpt_report(patient_id)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def init_report
|
40
|
+
pepfar_age_groups.each_with_object({}) do |age_group, report|
|
41
|
+
report[age_group] = %w[Male Female].each_with_object({}) do |gender, gender_sub_report|
|
42
|
+
gender_sub_report[gender] = %w[6H 3HP].each_with_object({}) do |tpt, tpt_sub_report|
|
43
|
+
tpt_sub_report[tpt] = initialize_tpt_metrics
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_data
|
50
|
+
@report = init_report
|
51
|
+
addittional_groups
|
27
52
|
patients = group_patients_by_tpt_course(patients_on_tpt)
|
28
53
|
|
29
|
-
load_patients_into_report(
|
54
|
+
load_patients_into_report(patients.six_h, '6H') do |patient|
|
30
55
|
# 6H has a constant dosage of 1 pill per day
|
31
56
|
patient_completed_tpt?(patient, '6H')
|
32
57
|
end
|
33
58
|
|
34
|
-
load_patients_into_report(
|
59
|
+
load_patients_into_report(patients.three_hp, '3HP') do |patient|
|
35
60
|
# 3HP daily dosages vary by patient weight can't use easily use pills
|
36
61
|
# to determine course completion
|
37
62
|
patient_completed_tpt?(patient, '3HP')
|
38
63
|
end
|
39
|
-
|
40
|
-
report
|
41
64
|
end
|
42
65
|
|
43
|
-
def
|
44
|
-
|
66
|
+
def initialize_tpt_metrics
|
67
|
+
{
|
68
|
+
started_new_on_art: [],
|
69
|
+
started_previously_on_art: [],
|
70
|
+
completed_new_on_art: [],
|
71
|
+
completed_previously_on_art: []
|
72
|
+
}
|
45
73
|
end
|
46
74
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
gender_sub_report[gender] = %w[6H 3HP].each_with_object({}) do |tpt, tpt_sub_report|
|
53
|
-
tpt_sub_report[tpt] = {
|
54
|
-
started_new_on_art: [],
|
55
|
-
started_previously_on_art: [],
|
56
|
-
completed_new_on_art: [],
|
57
|
-
completed_previously_on_art: []
|
58
|
-
}
|
59
|
-
end
|
75
|
+
def addittional_groups
|
76
|
+
@report['All'] = {}
|
77
|
+
%w[Male FP FNP FBf].each do |key|
|
78
|
+
@report['All'][key] = %w[6H 3HP].each_with_object({}) do |tpt, tpt_sub_report|
|
79
|
+
tpt_sub_report[tpt] = initialize_tpt_metrics
|
60
80
|
end
|
61
81
|
end
|
62
82
|
end
|
63
83
|
|
64
|
-
def load_patients_into_report(
|
84
|
+
def load_patients_into_report(patients, tpt, &patient_has_completed_tpt)
|
65
85
|
patients.each do |patient|
|
66
86
|
next if patient['transfer_in'] == 1 && !patient_has_completed_tpt[patient]
|
67
87
|
|
68
88
|
age_group = patient['age_group']
|
69
|
-
gender = patient['gender']
|
89
|
+
gender = patient['gender']
|
70
90
|
tpt_states = find_patient_tpt_state(patient, &patient_has_completed_tpt)
|
71
91
|
|
72
92
|
tpt_states.each do |tpt_state|
|
73
|
-
|
93
|
+
add_to_report(age_group, gender, tpt, tpt_state, patient)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def flatten_the_report
|
99
|
+
result = []
|
100
|
+
@report.each do |age_group, genders|
|
101
|
+
genders.each do |gender, tpts|
|
102
|
+
tpts.each do |tpt, states|
|
103
|
+
result << process_age_group_report(age_group, gender, tpt, states)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
combined = combine_entries(result)
|
108
|
+
sort_flattened_report(combined)
|
109
|
+
end
|
110
|
+
|
111
|
+
def combine_entries(flattened_report)
|
112
|
+
## currently we will have two entries of age_group and gender
|
113
|
+
## we need to combine them into one
|
114
|
+
## example [{age_group: '20-25 years', gender: 'Female', 3hp_started_new_on_art: [10] ...}, {age_group: '20-25 years', gender: 'Female', 6hp_started_new_on_art: [10] ...}]
|
115
|
+
## should be combined to [{age_group: '20-25 years', gender: 'Female', 3hp_started_new_on_art: [10], 6hp_started_new_on_art: [10] ...}]
|
116
|
+
|
117
|
+
result = {}
|
118
|
+
|
119
|
+
flattened_report.each do |entry|
|
120
|
+
age_group = entry[:age_group]
|
121
|
+
gender = entry[:gender]
|
122
|
+
key = "#{age_group}_#{gender}"
|
123
|
+
|
124
|
+
if result.key?(key)
|
125
|
+
entry.each do |k, v|
|
126
|
+
next if %i[age_group gender].include?(k)
|
127
|
+
|
128
|
+
result[key][k] ||= []
|
129
|
+
result[key][k] += v
|
130
|
+
end
|
131
|
+
else
|
132
|
+
result[key] = entry.dup
|
74
133
|
end
|
75
134
|
end
|
135
|
+
|
136
|
+
result.values
|
137
|
+
end
|
138
|
+
|
139
|
+
def sort_flattened_report(result)
|
140
|
+
new_group = pepfar_age_groups.map { |age_group| age_group }
|
141
|
+
new_group << 'All'
|
142
|
+
gender_scores = { 'Female' => 0, 'Male' => 1, 'FNP' => 3, 'FP' => 2, 'FBf' => 4 }
|
143
|
+
result_scores = result.sort_by do |item|
|
144
|
+
gender_score = gender_scores[item[:gender]] || 999
|
145
|
+
age_group_score = new_group.index(item[:age_group]) || 999
|
146
|
+
[gender_score, age_group_score]
|
147
|
+
end
|
148
|
+
# remove all unknown age groups
|
149
|
+
result_scores.reject { |item| item[:age_group].match?(/unknown/i) }
|
150
|
+
end
|
151
|
+
|
152
|
+
def process_age_group_report(age_group, gender, tpt, states)
|
153
|
+
{
|
154
|
+
age_group:,
|
155
|
+
gender:,
|
156
|
+
"#{tpt}_started_new_on_art": states[:started_new_on_art],
|
157
|
+
"#{tpt}_started_previously_on_art": states[:started_previously_on_art],
|
158
|
+
"#{tpt}_completed_new_on_art": states[:completed_new_on_art],
|
159
|
+
"#{tpt}_completed_previously_on_art": states[:completed_previously_on_art]
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
def add_to_report(age_group, gender, tpt, tpt_state, patient)
|
164
|
+
@report[age_group][gender][tpt][tpt_state] << patient['patient_id']
|
165
|
+
if gender == 'Male'
|
166
|
+
report['All'][gender][tpt][tpt_state] << patient['patient_id']
|
167
|
+
return
|
168
|
+
end
|
169
|
+
|
170
|
+
maternal_status = patient['maternal_status']
|
171
|
+
case maternal_status
|
172
|
+
when 'FP'
|
173
|
+
@report['All']['FP'][tpt][tpt_state] << patient['patient_id']
|
174
|
+
when 'FBf'
|
175
|
+
@report['All']['FBf'][tpt][tpt_state] << patient['patient_id']
|
176
|
+
else
|
177
|
+
@report['All']['FNP'][tpt][tpt_state] << patient['patient_id']
|
178
|
+
end
|
76
179
|
end
|
77
180
|
|
78
181
|
def find_patient_tpt_state(patient, &patient_has_completed_tpt)
|
@@ -121,97 +224,42 @@ module MalawiHivProgramReports
|
|
121
224
|
|
122
225
|
def fetch_patients_on_tpt
|
123
226
|
ActiveRecord::Base.connection.select_all <<~SQL
|
124
|
-
SELECT
|
125
|
-
patient_identifier.identifier AS arv_number,
|
227
|
+
SELECT denominator_patient.patient_id,
|
126
228
|
DATE(MIN(orders.start_date)) AS tpt_initiation_date,
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
LEFT JOIN
|
139
|
-
#{
|
140
|
-
INNER JOIN(
|
141
|
-
SELECT denominator_encounter.patient_id AS patient_id, patient_state.start_date AS start_date
|
142
|
-
FROM person #{current_partition}
|
143
|
-
INNER JOIN patient_program #{current_partition}
|
144
|
-
ON patient_program.patient_id = person.person_id
|
145
|
-
AND #{in_manager(column: 'patient_program.program_id', values: "(SELECT program_id FROM program #{current_partition} WHERE name = 'HIV PROGRAM')")}
|
146
|
-
AND patient_program.voided = 0
|
147
|
-
INNER JOIN patient_state #{current_partition}
|
148
|
-
ON patient_state.patient_program_id = patient_program.patient_program_id
|
149
|
-
AND patient_state.state = 7 /* State: 7 == On antiretrovirals */
|
150
|
-
AND patient_state.start_date < DATE(#{start_date})
|
151
|
-
AND patient_state.voided = 0
|
152
|
-
INNER JOIN encounter #{current_partition} AS denominator_encounter
|
153
|
-
ON denominator_encounter.patient_id = patient_program.patient_id
|
154
|
-
AND #{in_manager(column: 'denominator_encounter.program_id', values: "(SELECT program_id FROM program #{current_partition} WHERE name = 'HIV PROGRAM')")}
|
155
|
-
AND #{in_manager(column: 'denominator_encounter.encounter_type', values: "(SELECT encounter_type_id FROM encounter_type WHERE name = 'Treatment')")}
|
156
|
-
AND denominator_encounter.encounter_datetime >= #{interval_manager(date: start_date, value: 6, interval: 'MONTH', operator: '-')}
|
157
|
-
AND denominator_encounter.encounter_datetime <= DATE(#{start_date})
|
158
|
-
AND denominator_encounter.voided = 0
|
159
|
-
#{site_manager(operator: 'AND', column: 'patient_program.site_id', location: @location)}
|
160
|
-
GROUP BY denominator_encounter.patient_id, patient_state.start_date
|
161
|
-
) AS denominator_patient ON denominator_patient.patient_id = person.person_id
|
229
|
+
denominator_patient.earliest_start_date AS art_start_date,
|
230
|
+
outcome.cum_outcome,
|
231
|
+
CASE denominator_patient.gender
|
232
|
+
WHEN 'M' THEN 'Male'
|
233
|
+
WHEN 'F' THEN 'Female'
|
234
|
+
ELSE 'Unknown'
|
235
|
+
END gender,
|
236
|
+
c.maternal_status,
|
237
|
+
denominator_patient.birthdate,
|
238
|
+
disaggregated_age_group(denominator_patient.birthdate, DATE(#{end_date})) AS age_group
|
239
|
+
FROM cdr_temp_cohort_members #{current_partition} denominator_patient
|
240
|
+
LEFT JOIN cdr_temp_maternal_status #{current_partition} c ON c.patient_id = denominator_patient.patient_id
|
241
|
+
INNER JOIN cdr_temp_patient_outcomes #{current_partition} outcome ON denominator_patient.patient_id = outcome.patient_id
|
162
242
|
INNER JOIN encounter #{current_partition} AS prescription_encounter
|
163
243
|
ON prescription_encounter.patient_id = denominator_patient.patient_id
|
164
|
-
AND prescription_encounter.program_id = 1
|
165
|
-
AND
|
166
|
-
AND prescription_encounter.encounter_datetime >= #{
|
244
|
+
AND prescription_encounter.program_id = 1 /* HIV Program */
|
245
|
+
AND prescription_encounter.encounter_type = (SELECT encounter_type_id FROM encounter_type WHERE name = 'Treatment' LIMIT 1)
|
246
|
+
AND prescription_encounter.encounter_datetime >= DATE(#{start_date}) - INTERVAL 6 MONTH
|
167
247
|
AND prescription_encounter.encounter_datetime <= DATE(#{end_date})
|
168
248
|
AND prescription_encounter.voided = 0
|
169
|
-
INNER JOIN orders #{current_partition}
|
249
|
+
INNER JOIN orders #{current_partition} AS orders
|
170
250
|
ON orders.encounter_id = prescription_encounter.encounter_id
|
171
|
-
AND
|
172
|
-
AND orders.start_date >= #{
|
173
|
-
AND orders.start_date <=
|
251
|
+
AND orders.order_type_id = (SELECT order_type_id FROM order_type WHERE name = 'Drug order' LIMIT 1)
|
252
|
+
AND orders.start_date >= DATE(#{start_date}) - INTERVAL 6 MONTH
|
253
|
+
AND orders.start_date <= DATE(#{end_date})
|
174
254
|
AND orders.voided = 0
|
175
|
-
INNER JOIN concept_name
|
255
|
+
INNER JOIN concept_name
|
176
256
|
ON concept_name.concept_id = orders.concept_id
|
177
|
-
AND
|
178
|
-
INNER JOIN drug_order #{current_partition}
|
257
|
+
AND concept_name.name IN ('Rifapentine', 'Isoniazid', 'Isoniazid/Rifapentine')
|
258
|
+
INNER JOIN drug_order #{current_partition} AS drug_order
|
179
259
|
ON drug_order.order_id = orders.order_id
|
180
260
|
AND drug_order.quantity > 0
|
181
|
-
WHERE
|
182
|
-
|
183
|
-
AND person.person_id NOT IN (
|
184
|
-
/* External consultations */
|
185
|
-
SELECT DISTINCT registration_encounter.patient_id
|
186
|
-
FROM patient_program #{current_partition} pp
|
187
|
-
INNER JOIN program #{current_partition} p ON p.program_id = pp.program_id AND p.name = 'HIV PROGRAM' AND p.retired = 0
|
188
|
-
INNER JOIN encounter #{current_partition} AS registration_encounter
|
189
|
-
ON registration_encounter.patient_id = pp.patient_id
|
190
|
-
AND registration_encounter.program_id = pp.program_id
|
191
|
-
AND registration_encounter.encounter_datetime < #{interval_manager(date: end_date, value: 1, interval: 'MONTH', operator: '+')}
|
192
|
-
AND registration_encounter.voided = 0
|
193
|
-
INNER JOIN (
|
194
|
-
SELECT MAX(encounter.encounter_datetime) AS encounter_datetime, encounter.patient_id
|
195
|
-
FROM encounter #{current_partition}
|
196
|
-
INNER JOIN encounter_type
|
197
|
-
ON encounter_type.encounter_type_id = encounter.encounter_type
|
198
|
-
AND encounter_type.name = 'Registration'
|
199
|
-
INNER JOIN program #{current_partition}
|
200
|
-
ON program.program_id = encounter.program_id
|
201
|
-
AND program.name = 'HIV PROGRAM'
|
202
|
-
WHERE encounter.encounter_datetime < CAST(#{end_date} AS DATE) AND encounter.voided = 0
|
203
|
-
GROUP BY encounter.patient_id
|
204
|
-
) AS max_registration_encounter
|
205
|
-
ON max_registration_encounter.patient_id = registration_encounter.patient_id
|
206
|
-
AND max_registration_encounter.encounter_datetime = registration_encounter.encounter_datetime
|
207
|
-
INNER JOIN obs #{current_partition} AS patient_type_obs
|
208
|
-
ON patient_type_obs.encounter_id = registration_encounter.encounter_id
|
209
|
-
AND #{in_manager(column: 'patient_type_obs.concept_id', values: "(SELECT concept_id FROM concept_name #{current_partition} WHERE name = 'Type of patient' AND voided = 0)")}
|
210
|
-
AND #{in_manager(column: 'patient_type_obs.value_coded', values: "(SELECT concept_id FROM concept_name #{current_partition} WHERE name IN ('Drug refill', 'External consultation') AND voided = 0)")}
|
211
|
-
AND patient_type_obs.voided = 0
|
212
|
-
WHERE pp.voided = 0
|
213
|
-
)
|
214
|
-
GROUP BY person.person_id #{group_by_columns('patient_identifier.identifier, person.gender, person.birthdate, denominator_patient.start_date')}
|
261
|
+
WHERE denominator_patient.date_enrolled < DATE(#{start_date}) AND denominator_patient.gender IN ('M', 'F')
|
262
|
+
GROUP BY denominator_patient.patient_id
|
215
263
|
SQL
|
216
264
|
end
|
217
265
|
|
@@ -220,41 +268,39 @@ module MalawiHivProgramReports
|
|
220
268
|
c_start_date = ActiveRecord::Base.connection.quote(result[:start_date])
|
221
269
|
c_end_date = ActiveRecord::Base.connection.quote(client_tpt_end_date(patient_id, c_start_date))
|
222
270
|
ActiveRecord::Base.connection.select_one <<-SQL
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
AND o.patient_id = #{patient_id}
|
257
|
-
GROUP BY o.patient_id
|
271
|
+
SELECT
|
272
|
+
CASE
|
273
|
+
WHEN tpt_transfer_in_obs.value_datetime IS NULL THEN DATE(MIN(o.start_date))
|
274
|
+
WHEN tpt_transfer_in_obs.value_datetime > MIN(o.start_date) THEN DATE(MIN(o.start_date))
|
275
|
+
ELSE DATE(tpt_transfer_in_obs.value_datetime)
|
276
|
+
END AS tpt_initiation_date,
|
277
|
+
COUNT(DISTINCT(DATE(o.start_date))) AS months_on_tpt,
|
278
|
+
SUM(dor.quantity) + SUM(CASE WHEN tpt_transfer_in_obs.value_numeric IS NOT NULL THEN tpt_transfer_in_obs.value_numeric ELSE 0 END) AS total_pills_taken,
|
279
|
+
SUM(DATEDIFF(o.auto_expire_date, o.start_date)) + SUM(CASE WHEN tpt_transfer_in_obs.value_datetime IS NOT NULL THEN DATEDIFF(tpt_transfer_in_obs.obs_datetime, tpt_transfer_in_obs.value_datetime) ElSE 0 END) AS total_days_on_medication,
|
280
|
+
GROUP_CONCAT(DISTINCT o.concept_id SEPARATOR ',') AS drug_concepts,
|
281
|
+
CASE
|
282
|
+
WHEN tpt_transfer_in_obs.value_numeric IS NOT NULL THEN 1
|
283
|
+
ELSE 0
|
284
|
+
END AS transfer_in,
|
285
|
+
MAX(o.start_date) AS last_dispensed_date,
|
286
|
+
MAX(o.auto_expire_date) AS auto_expire_date
|
287
|
+
FROM orders #{current_partition} o
|
288
|
+
INNER JOIN concept_name cn
|
289
|
+
ON cn.concept_id = o.concept_id
|
290
|
+
AND cn.name IN ('Rifapentine', 'Isoniazid', 'Isoniazid/Rifapentine')
|
291
|
+
LEFT JOIN obs #{current_partition} tpt_transfer_in_obs
|
292
|
+
ON tpt_transfer_in_obs.person_id = o.patient_id
|
293
|
+
AND tpt_transfer_in_obs.concept_id = #{ConceptName.find_by_name('TPT Drugs Received').concept_id}
|
294
|
+
AND tpt_transfer_in_obs.voided = 0
|
295
|
+
AND tpt_transfer_in_obs.value_drug IN (SELECT drug_id FROM drug WHERE concept_id IN (SELECT concept_id FROM concept_name WHERE name IN ('Rifapentine', 'Isoniazid', 'Isoniazid/Rifapentine')))
|
296
|
+
INNER JOIN drug_order #{current_partition} dor
|
297
|
+
ON dor.order_id = o.order_id
|
298
|
+
AND dor.quantity > 0
|
299
|
+
WHERE DATE(o.start_date) BETWEEN DATE(#{c_start_date}) AND DATE(#{c_end_date})
|
300
|
+
AND o.order_type_id IN (SELECT order_type_id FROM order_type WHERE name = 'Drug order')
|
301
|
+
AND o.voided = 0
|
302
|
+
AND o.patient_id = #{patient_id}
|
303
|
+
GROUP BY o.patient_id
|
258
304
|
SQL
|
259
305
|
end
|
260
306
|
|
@@ -292,13 +338,12 @@ module MalawiHivProgramReports
|
|
292
338
|
ELSE '6H'
|
293
339
|
END AS course
|
294
340
|
FROM obs #{current_partition} o
|
295
|
-
WHERE o.concept_id = #{
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
AND DATE(o.obs_datetime) <= DATE(#{start_date})
|
341
|
+
WHERE o.concept_id = #{ConceptName.find_by_name('TPT Drugs Received').concept_id}
|
342
|
+
AND o.voided = 0
|
343
|
+
AND o.value_drug IN (SELECT drug_id FROM drug WHERE concept_id IN (SELECT concept_id FROM concept_name WHERE name IN ('Rifapentine', 'Isoniazid', 'Isoniazid/Rifapentine')))
|
344
|
+
AND o.person_id = #{patient_id}
|
345
|
+
AND o.value_numeric IS NOT NULL
|
346
|
+
AND DATE(o.obs_datetime) <= DATE(#{start_date})
|
302
347
|
GROUP BY DATE(o.obs_datetime)
|
303
348
|
ORDER BY DATE(o.obs_datetime) DESC
|
304
349
|
)
|
@@ -313,15 +358,14 @@ module MalawiHivProgramReports
|
|
313
358
|
ELSE '6H'
|
314
359
|
END AS course
|
315
360
|
FROM orders #{current_partition} o
|
316
|
-
INNER JOIN encounter #{current_partition} e ON e.encounter_id = o.encounter_id AND e.voided = 0 AND e.program_id = 1 /* HIV
|
361
|
+
INNER JOIN encounter #{current_partition} e ON e.encounter_id = o.encounter_id AND e.voided = 0 AND e.program_id = 1 /* HIV Program */
|
317
362
|
INNER JOIN drug_order #{current_partition} dor ON dor.order_id = o.order_id AND dor.quantity > 0
|
318
|
-
WHERE o.order_type_id
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
AND DATE(o.start_date) <= DATE(#{start_date})
|
363
|
+
WHERE o.order_type_id = (SELECT order_type_id FROM order_type WHERE name = 'Drug order' LIMIT 1)
|
364
|
+
AND o.voided = 0
|
365
|
+
AND o.concept_id IN (#{ConceptName.where(name: ['Rifapentine', 'Isoniazid', 'Isoniazid/Rifapentine']).select(:concept_id).to_sql})
|
366
|
+
AND o.patient_id = #{patient_id}
|
367
|
+
AND o.auto_expire_date IS NOT NULL
|
368
|
+
AND DATE(o.start_date) <= DATE(#{start_date})
|
325
369
|
GROUP BY DATE(o.start_date)
|
326
370
|
ORDER BY DATE(o.start_date) DESC
|
327
371
|
)
|
@@ -341,13 +385,12 @@ module MalawiHivProgramReports
|
|
341
385
|
ELSE '6H'
|
342
386
|
END AS course
|
343
387
|
FROM obs #{current_partition} o
|
344
|
-
WHERE o.concept_id = #{
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
AND DATE(o.obs_datetime) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
|
388
|
+
WHERE o.concept_id = #{ConceptName.find_by_name('TPT Drugs Received').concept_id}
|
389
|
+
AND o.voided = 0
|
390
|
+
AND o.value_drug IN (SELECT drug_id FROM drug WHERE concept_id IN (SELECT concept_id FROM concept_name WHERE name IN ('Rifapentine', 'Isoniazid', 'Isoniazid/Rifapentine')))
|
391
|
+
AND o.person_id = #{patient_id}
|
392
|
+
AND o.value_numeric IS NOT NULL
|
393
|
+
AND DATE(o.obs_datetime) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
|
351
394
|
GROUP BY DATE(o.obs_datetime)
|
352
395
|
ORDER BY DATE(o.obs_datetime) DESC
|
353
396
|
)
|
@@ -362,15 +405,14 @@ module MalawiHivProgramReports
|
|
362
405
|
ELSE '6H'
|
363
406
|
END AS course
|
364
407
|
FROM orders #{current_partition} o
|
365
|
-
INNER JOIN encounter #{current_partition} e ON e.encounter_id = o.encounter_id AND e.voided = 0 AND e.program_id = 1 /* HIV
|
408
|
+
INNER JOIN encounter #{current_partition} e ON e.encounter_id = o.encounter_id AND e.voided = 0 AND e.program_id = 1 /* HIV Program */
|
366
409
|
INNER JOIN drug_order #{current_partition} dor ON dor.order_id = o.order_id AND dor.quantity > 0
|
367
|
-
WHERE o.order_type_id
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
AND DATE(o.start_date) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
|
410
|
+
WHERE o.order_type_id = (SELECT order_type_id FROM order_type WHERE name = 'Drug order' LIMIT 1)
|
411
|
+
AND o.voided = 0
|
412
|
+
AND o.concept_id IN (#{ConceptName.where(name: ['Rifapentine', 'Isoniazid', 'Isoniazid/Rifapentine']).select(:concept_id).to_sql})
|
413
|
+
AND o.patient_id = #{patient_id}
|
414
|
+
AND o.auto_expire_date IS NOT NULL
|
415
|
+
AND DATE(o.start_date) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
|
374
416
|
GROUP BY DATE(o.start_date)
|
375
417
|
ORDER BY DATE(o.start_date) DESC
|
376
418
|
)
|
@@ -414,7 +456,7 @@ module MalawiHivProgramReports
|
|
414
456
|
end
|
415
457
|
|
416
458
|
def isoniazid_rifapentine_drug
|
417
|
-
@isoniazid_rifapentine_drug ||=
|
459
|
+
@isoniazid_rifapentine_drug ||= Drug.find_by!(concept_id: isoniazid_rifapentine_concept.concept_id)
|
418
460
|
end
|
419
461
|
end
|
420
462
|
end
|
@@ -20,6 +20,7 @@ module MalawiHivProgramReports
|
|
20
20
|
raise 'Location is required' if @location.blank?
|
21
21
|
|
22
22
|
@report = init_report
|
23
|
+
addittional_groups
|
23
24
|
end
|
24
25
|
|
25
26
|
def find_report
|
@@ -33,20 +34,31 @@ module MalawiHivProgramReports
|
|
33
34
|
|
34
35
|
private
|
35
36
|
|
36
|
-
GENDER = %w[Male Female
|
37
|
+
GENDER = %w[Male Female].freeze
|
37
38
|
|
38
39
|
def init_report
|
39
40
|
pepfar_age_groups.each_with_object({}) do |age_group, report|
|
40
41
|
report[age_group] = GENDER.each_with_object({}) do |gender, age_group_report|
|
41
|
-
age_group_report[gender] =
|
42
|
-
less_than_three_months: [],
|
43
|
-
three_to_five_months: [],
|
44
|
-
greater_than_six_months: []
|
45
|
-
}
|
42
|
+
age_group_report[gender] = initialize_gender_metrics
|
46
43
|
end
|
47
44
|
end
|
48
45
|
end
|
49
46
|
|
47
|
+
def addittional_groups
|
48
|
+
@report['All'] = {}
|
49
|
+
%w[Male FP FNP FBf].each do |key|
|
50
|
+
@report['All'][key] = initialize_gender_metrics
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize_gender_metrics
|
55
|
+
{
|
56
|
+
less_than_three_months: [],
|
57
|
+
three_to_five_months: [],
|
58
|
+
greater_than_six_months: []
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
50
62
|
def process_age_group_report(age_group, gender, age_group_report)
|
51
63
|
{
|
52
64
|
age_group:,
|
@@ -60,7 +72,11 @@ module MalawiHivProgramReports
|
|
60
72
|
def flatten_the_report
|
61
73
|
result = []
|
62
74
|
report.each do |age_group, age_group_report|
|
75
|
+
next if age_group == 'Unknown'
|
76
|
+
|
63
77
|
age_group_report.each_key do |gender|
|
78
|
+
next if gender == 'Unknown' # skip unknown
|
79
|
+
|
64
80
|
result << process_age_group_report(age_group, gender, age_group_report[gender])
|
65
81
|
end
|
66
82
|
end
|
@@ -77,24 +93,7 @@ module MalawiHivProgramReports
|
|
77
93
|
result_scores.reject { |item| item[:age_group].match?(/unknown/i) }
|
78
94
|
end
|
79
95
|
|
80
|
-
def
|
81
|
-
patients = ActiveRecord::Base.connection.select_all <<~SQL
|
82
|
-
SELECT tesd.patient_id,
|
83
|
-
CASE tesd.gender
|
84
|
-
WHEN 'M' THEN 'Male'
|
85
|
-
WHEN 'F' THEN 'Female'
|
86
|
-
ELSE 'Unknown'
|
87
|
-
END gender,
|
88
|
-
disaggregated_age_group(tesd.birthdate, '#{end_date}') age_group,
|
89
|
-
TIMESTAMPDIFF(DAY, tcm.start_date, tcm.auto_expire_date) prescribed_days
|
90
|
-
FROM cdr_temp_cohort_members #{current_partition} tesd#{' '}
|
91
|
-
INNER JOIN cdr_temp_patient_outcomes #{current_partition} tpo ON tpo.patient_id = tesd.patient_id AND tpo.cum_outcome = 'On antiretrovirals'
|
92
|
-
INNER JOIN cdr_temp_min_auto_expire_date #{current_partition} tcm ON tcm.patient_id = tesd.patient_id
|
93
|
-
WHERE tesd.date_enrolled <= '#{end_date}'
|
94
|
-
SQL
|
95
|
-
|
96
|
-
return report if patients.blank?
|
97
|
-
|
96
|
+
def process_indicators(patients)
|
98
97
|
patients.each do |patient|
|
99
98
|
prescribe_days = patient['prescribed_days'].to_i
|
100
99
|
age_group = patient['age_group']
|
@@ -110,8 +109,47 @@ module MalawiHivProgramReports
|
|
110
109
|
|
111
110
|
report[age_group][gender][indicator.to_sym] << patient['patient_id']
|
112
111
|
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def aggregation(age_group, gender, indicator, patient)
|
115
|
+
report[age_group][gender][indicator.to_sym] << patient['patient_id']
|
116
|
+
if gender == 'Male'
|
117
|
+
report['All'][gender][indicator.to_sym] << patient['patient_id']
|
118
|
+
return
|
119
|
+
end
|
120
|
+
|
121
|
+
maternal_status = patient['maternal_status']
|
122
|
+
case maternal_status
|
123
|
+
when 'FP'
|
124
|
+
@report['All']['FP'][indicator.to_sym] << patient['patient_id']
|
125
|
+
when 'FBf'
|
126
|
+
@report['All']['FBf'][indicator.to_sym] << patient['patient_id']
|
127
|
+
else
|
128
|
+
@report['All']['FNP'][indicator.to_sym] << patient['patient_id']
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def process_data
|
133
|
+
patients = ActiveRecord::Base.connection.select_all <<~SQL
|
134
|
+
SELECT tesd.patient_id,
|
135
|
+
CASE tesd.gender
|
136
|
+
WHEN 'M' THEN 'Male'
|
137
|
+
WHEN 'F' THEN 'Female'
|
138
|
+
ELSE 'Unknown'
|
139
|
+
END gender,
|
140
|
+
c.maternal_status,
|
141
|
+
disaggregated_age_group(tesd.birthdate, '#{end_date}') age_group,
|
142
|
+
TIMESTAMPDIFF(DAY, tcm.start_date, tcm.auto_expire_date) prescribed_days
|
143
|
+
FROM cdr_temp_cohort_members #{current_partition} tesd
|
144
|
+
INNER JOIN cdr_temp_patient_outcomes #{current_partition} tpo ON tpo.patient_id = tesd.patient_id AND tpo.cum_outcome = 'On antiretrovirals'
|
145
|
+
INNER JOIN cdr_temp_min_auto_expire_date #{current_partition} tcm ON tcm.patient_id = tesd.patient_id
|
146
|
+
LEFT JOIN cdr_temp_maternal_status #{current_partition} c ON c.patient_id = tesd.patient_id
|
147
|
+
WHERE tesd.date_enrolled <= '#{end_date}' AND tesd.gender IN ('M', 'F')
|
148
|
+
SQL
|
149
|
+
|
150
|
+
return report if patients.blank?
|
113
151
|
|
114
|
-
|
152
|
+
process_indicators(patients)
|
115
153
|
end
|
116
154
|
end
|
117
155
|
end
|