malawi_hiv_program_reports 1.0.1 → 1.0.2
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/README.md +16 -0
- data/app/services/malawi_hiv_program_reports/adapters/moh/custom.rb +199 -0
- data/app/services/malawi_hiv_program_reports/archiving_candidates.rb +130 -0
- data/app/services/malawi_hiv_program_reports/arv_refill_periods.rb +311 -0
- data/app/services/malawi_hiv_program_reports/clinic/README.md +5 -0
- data/app/services/malawi_hiv_program_reports/clinic/appointments_report.rb +317 -0
- data/app/services/malawi_hiv_program_reports/clinic/discrepancy_report.rb +42 -0
- data/app/services/malawi_hiv_program_reports/clinic/docs/hypertension_report.md +31 -0
- data/app/services/malawi_hiv_program_reports/clinic/drug_dispensations.rb +48 -0
- data/app/services/malawi_hiv_program_reports/clinic/external_consultation_clients.rb +69 -0
- data/app/services/malawi_hiv_program_reports/clinic/hypertension_report.rb +223 -0
- data/app/services/malawi_hiv_program_reports/clinic/ipt_coverage.rb +112 -0
- data/app/services/malawi_hiv_program_reports/clinic/ipt_report.rb +69 -0
- data/app/services/malawi_hiv_program_reports/clinic/lims_results.rb +55 -0
- data/app/services/malawi_hiv_program_reports/clinic/outcome_list.rb +127 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_alive_and_on_treatment.rb +57 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_due_for_viral_load.rb +39 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_on_antiretrovirals.rb +44 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_on_dtg.rb +36 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_on_treatment.rb +42 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_with_outdated_demographics.rb +173 -0
- data/app/services/malawi_hiv_program_reports/clinic/pregnant_patients.rb +91 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimen_dispensation_data.rb +282 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimen_switch.rb +456 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimens_and_formulations.rb +182 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimens_by_weight_and_gender.rb +108 -0
- data/app/services/malawi_hiv_program_reports/clinic/retention.rb +246 -0
- data/app/services/malawi_hiv_program_reports/clinic/stock_card_report.rb +65 -0
- data/app/services/malawi_hiv_program_reports/clinic/tpt_outcome.rb +494 -0
- data/app/services/malawi_hiv_program_reports/clinic/tx_rtt.rb +169 -0
- data/app/services/malawi_hiv_program_reports/clinic/viral_load.rb +292 -0
- data/app/services/malawi_hiv_program_reports/clinic/viral_load_disaggregated.rb +97 -0
- data/app/services/malawi_hiv_program_reports/clinic/viral_load_results.rb +175 -0
- data/app/services/malawi_hiv_program_reports/clinic/visits_report.rb +113 -0
- data/app/services/malawi_hiv_program_reports/clinic/vl_collection.rb +48 -0
- data/app/services/malawi_hiv_program_reports/cohort/outcomes.rb +338 -0
- data/app/services/malawi_hiv_program_reports/cohort/regimens.rb +69 -0
- data/app/services/malawi_hiv_program_reports/cohort/side_effects.rb +141 -0
- data/app/services/malawi_hiv_program_reports/cohort/tpt.rb +172 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort.rb +278 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_builder.rb +2340 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated.rb +608 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated_additions.rb +208 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated_builder.rb +526 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_struct.rb +219 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_survival_analysis.rb +203 -0
- data/app/services/malawi_hiv_program_reports/moh/moh_tpt.rb +223 -0
- data/app/services/malawi_hiv_program_reports/moh/tpt_newly_initiated.rb +235 -0
- data/app/services/malawi_hiv_program_reports/pepfar/defaulter_list.rb +25 -0
- data/app/services/malawi_hiv_program_reports/pepfar/maternal_status.rb +29 -0
- data/app/services/malawi_hiv_program_reports/pepfar/patient_start_vl.rb +45 -0
- data/app/services/malawi_hiv_program_reports/pepfar/regimen_switch.rb +479 -0
- data/app/services/malawi_hiv_program_reports/pepfar/sc_arvdisp.rb +174 -0
- data/app/services/malawi_hiv_program_reports/pepfar/sc_curr.rb +98 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tb_prev.rb +163 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tb_prev2.rb +222 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tb_prev3.rb +421 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tpt_status.rb +181 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_ml.rb +181 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_new.rb +202 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_rtt.rb +288 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_tb.rb +283 -0
- data/app/services/malawi_hiv_program_reports/pepfar/utils.rb +141 -0
- data/app/services/malawi_hiv_program_reports/pepfar/viral_load_coverage.rb +414 -0
- data/app/services/malawi_hiv_program_reports/pepfar/viral_load_coverage2.rb +433 -0
- data/app/services/malawi_hiv_program_reports/report_map.rb +56 -0
- data/app/services/malawi_hiv_program_reports/utils/README.md +8 -0
- data/app/services/malawi_hiv_program_reports/utils/common_sql_query_utils.rb +60 -0
- data/app/services/malawi_hiv_program_reports/utils/concurrency_utils.rb +53 -0
- data/app/services/malawi_hiv_program_reports/utils/docs/common_sql_query_utils.md +53 -0
- data/app/services/malawi_hiv_program_reports/utils/model_utils.rb +66 -0
- data/app/services/malawi_hiv_program_reports/utils/parameter_utils.rb +32 -0
- data/app/services/malawi_hiv_program_reports/utils/time_utils.rb +52 -0
- data/lib/malawi_hiv_program_reports/version.rb +1 -1
- metadata +74 -1
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MalawiHivProgramReports
|
|
4
|
+
module Moh
|
|
5
|
+
# This class is used to add additional cohort disaggregated data
|
|
6
|
+
# rubocop:disable Metrics/ClassLength
|
|
7
|
+
class CohortDisaggregated
|
|
8
|
+
include MalawiHivProgramReports::Utils::ModelUtils
|
|
9
|
+
include MalawiHivProgramReports::Adapters::Moh::Custom
|
|
10
|
+
|
|
11
|
+
def initialize(name:, type:, start_date:, end_date:, rebuild:, **kwargs)
|
|
12
|
+
@name = name
|
|
13
|
+
@type = type
|
|
14
|
+
@start_date = start_date
|
|
15
|
+
@end_date = end_date
|
|
16
|
+
@rebuild = rebuild
|
|
17
|
+
@occupation = kwargs[:occupation]
|
|
18
|
+
@location = kwargs[:location]
|
|
19
|
+
@adapter = ActiveRecord::Base.connection.adapter_name.downcase
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def find_report
|
|
23
|
+
build_report
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def build_report
|
|
27
|
+
builder = CohortDisaggregatedBuilder.new(outcomes_definition: 'moh', location: @location,
|
|
28
|
+
occupation: @occupation)
|
|
29
|
+
builder.build(nil, @start_date, @end_date)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initialize_disaggregated
|
|
33
|
+
ActiveRecord::Base.connection.execute('DROP TABLE IF EXISTS temp_disaggregated')
|
|
34
|
+
|
|
35
|
+
ActiveRecord::Base.connection.execute(
|
|
36
|
+
'CREATE TABLE IF NOT EXISTS temp_disaggregated (
|
|
37
|
+
patient_id INTEGER NOT NULL,
|
|
38
|
+
age_group VARCHAR(20),
|
|
39
|
+
initial_maternal_status VARCHAR(10),
|
|
40
|
+
maternal_status VARCHAR(10),
|
|
41
|
+
given_ipt INT(1),
|
|
42
|
+
screened_for_tb INT(1),
|
|
43
|
+
site_id INT NOT NULL DEFAULT 1,
|
|
44
|
+
PRIMARY KEY(patient_id, site_id)
|
|
45
|
+
);'
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
{ temp_disaggregated: 'created' }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def disaggregated(quarter, age_group)
|
|
52
|
+
if quarter == 'pepfar'
|
|
53
|
+
start_date = @start_date
|
|
54
|
+
end_date = @end_date
|
|
55
|
+
|
|
56
|
+
begin
|
|
57
|
+
records = ActiveRecord::Base.connection.select_one("SELECT count(*) rec_count FROM temp_patient_outcomes #{site_manager(
|
|
58
|
+
operator: 'AND', column: 'site_id', location: @location
|
|
59
|
+
)}")
|
|
60
|
+
@rebuild = true if records['rec_count'].to_i < 1
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
Rails.logger.error "Error: #{e.message}"
|
|
63
|
+
initialize_disaggregated
|
|
64
|
+
rebuild_outcomes 'pepfar'
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if @rebuild
|
|
68
|
+
initialize_disaggregated
|
|
69
|
+
rebuild_outcomes 'pepfar'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
else
|
|
73
|
+
start_date, end_date = generate_start_date_and_end_date(quarter)
|
|
74
|
+
|
|
75
|
+
if @rebuild
|
|
76
|
+
initialize_disaggregated
|
|
77
|
+
art_service = CohortBuilder.new
|
|
78
|
+
art_service.init_temporary_tables(@start_date, @end_date, @occupation)
|
|
79
|
+
art_service.update_tb_status(end_date)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
tmp = get_age_groups(age_group, start_date, end_date)
|
|
84
|
+
|
|
85
|
+
# A hack to get female that were pregnant / breastfeeding at the beginning of the reporting period + those are currently the same state
|
|
86
|
+
if age_group == 'Pregnant'
|
|
87
|
+
tmp_arr = []
|
|
88
|
+
(tmp || []).each do |data|
|
|
89
|
+
begin
|
|
90
|
+
date_enrolled = data['date_enrolled'].to_date
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
Rails.logger.error "Error: #{e.message}"
|
|
93
|
+
raise data.inspect
|
|
94
|
+
end
|
|
95
|
+
earliest_start_date = begin
|
|
96
|
+
data['earliest_start_date']
|
|
97
|
+
rescue StandardError
|
|
98
|
+
date_enrolled
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
imstaus = data['initial_maternal_status']
|
|
102
|
+
mstatus = data['mstatus']
|
|
103
|
+
|
|
104
|
+
if (date_enrolled >= start_date && date_enrolled <= end_date) && imstaus == 'FP' && (date_enrolled == earliest_start_date)
|
|
105
|
+
tmp_arr << data
|
|
106
|
+
elsif mstatus == 'FP'
|
|
107
|
+
tmp_arr << data
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
tmp = tmp_arr
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
if age_group == 'Breastfeeding'
|
|
115
|
+
tmp_arr = []
|
|
116
|
+
(tmp || []).each do |data|
|
|
117
|
+
begin
|
|
118
|
+
date_enrolled = data['date_enrolled'].to_date
|
|
119
|
+
rescue StandardError
|
|
120
|
+
raise data.inspect
|
|
121
|
+
end
|
|
122
|
+
earliest_start_date = begin
|
|
123
|
+
data['earliest_start_date']
|
|
124
|
+
rescue StandardError
|
|
125
|
+
date_enrolled
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
imstaus = data['initial_maternal_status']
|
|
129
|
+
mstatus = data['mstatus']
|
|
130
|
+
|
|
131
|
+
if (date_enrolled >= start_date && date_enrolled <= end_date) && imstaus == 'FBf' && (date_enrolled == earliest_start_date)
|
|
132
|
+
tmp_arr << data
|
|
133
|
+
elsif mstatus == 'FBf'
|
|
134
|
+
tmp_arr << data
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
tmp = tmp_arr
|
|
139
|
+
end
|
|
140
|
+
# ........................... Hack ends .......... Will clean up later
|
|
141
|
+
|
|
142
|
+
on_art = []
|
|
143
|
+
all_clients = []
|
|
144
|
+
all_clients_outcomes = {}
|
|
145
|
+
|
|
146
|
+
(tmp || []).each do |pat|
|
|
147
|
+
patient_id = pat['patient_id'].to_i
|
|
148
|
+
outcome = pat['outcome']
|
|
149
|
+
|
|
150
|
+
on_art << patient_id if outcome == 'On antiretrovirals'
|
|
151
|
+
all_clients << patient_id
|
|
152
|
+
all_clients_outcomes[patient_id] = outcome
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
list = {}
|
|
156
|
+
|
|
157
|
+
if all_clients.blank? && %w[Breastfeeding Pregnant].include?(age_group)
|
|
158
|
+
list[age_group] = {}
|
|
159
|
+
list[age_group]['F'] = {
|
|
160
|
+
tx_new: [], tx_curr: [],
|
|
161
|
+
tx_screened_for_tb: [],
|
|
162
|
+
tx_given_ipt: []
|
|
163
|
+
}
|
|
164
|
+
return list
|
|
165
|
+
elsif all_clients.blank?
|
|
166
|
+
return {}
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
big_insert tmp, age_group if /year|month/i.match?(age_group)
|
|
170
|
+
|
|
171
|
+
(tmp || []).each do |r|
|
|
172
|
+
gender = r['gender']&.first || 'Unknown'
|
|
173
|
+
patient_id = r['patient_id'].to_i
|
|
174
|
+
tx_new, tx_curr, tx_given_ipt, tx_screened_for_tb = get_numbers(r, age_group, start_date, end_date,
|
|
175
|
+
all_clients_outcomes)
|
|
176
|
+
|
|
177
|
+
list[age_group] = {} if list[age_group].blank?
|
|
178
|
+
|
|
179
|
+
if list[age_group][gender].blank?
|
|
180
|
+
list[age_group][gender] = {
|
|
181
|
+
tx_new: [], tx_curr: [],
|
|
182
|
+
tx_screened_for_tb: [],
|
|
183
|
+
tx_given_ipt: []
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
list[age_group][gender][:tx_new] << r['patient_id'] if tx_new
|
|
188
|
+
list[age_group][gender][:tx_curr] << r['patient_id'] if tx_curr
|
|
189
|
+
list[age_group][gender][:tx_given_ipt] << r['patient_id'] if tx_given_ipt
|
|
190
|
+
list[age_group][gender][:tx_screened_for_tb] << r['patient_id'] if tx_screened_for_tb
|
|
191
|
+
|
|
192
|
+
date_enrolled = r['date_enrolled'].to_date
|
|
193
|
+
|
|
194
|
+
if gender == 'F' && all_clients_outcomes[patient_id] == 'On antiretrovirals'
|
|
195
|
+
insert_female_maternal_status(patient_id, age_group, end_date)
|
|
196
|
+
elsif gender == 'F' && (date_enrolled >= start_date && date_enrolled <= end_date)
|
|
197
|
+
insert_female_maternal_status(patient_id, age_group, end_date)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
list
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def generate_start_date_and_end_date(quarter)
|
|
205
|
+
return [@start_date, @end_date] if quarter == 'Custom'
|
|
206
|
+
|
|
207
|
+
quarter, quarter_year = quarter.humanize.split
|
|
208
|
+
|
|
209
|
+
quarter_start_dates = [
|
|
210
|
+
"#{quarter_year}-01-01".to_date,
|
|
211
|
+
"#{quarter_year}-04-01".to_date,
|
|
212
|
+
"#{quarter_year}-07-01".to_date,
|
|
213
|
+
"#{quarter_year}-10-01".to_date
|
|
214
|
+
]
|
|
215
|
+
|
|
216
|
+
quarter_end_dates = [
|
|
217
|
+
"#{quarter_year}-03-31".to_date,
|
|
218
|
+
"#{quarter_year}-06-30".to_date,
|
|
219
|
+
"#{quarter_year}-09-30".to_date,
|
|
220
|
+
"#{quarter_year}-12-31".to_date
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
current_quarter = (quarter.match(/\d+/).to_s.to_i - 1)
|
|
224
|
+
quarter_beginning = quarter_start_dates[current_quarter]
|
|
225
|
+
quarter_ending = quarter_end_dates[current_quarter]
|
|
226
|
+
|
|
227
|
+
[quarter_beginning, quarter_ending]
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def screened_for_tb(my_patient_id, age_group, start_date, end_date)
|
|
231
|
+
data = ActiveRecord::Base.connection.select_one <<~SQL
|
|
232
|
+
SELECT patient_screened_for_tb(#{my_patient_id},
|
|
233
|
+
'#{start_date.to_date}', '#{end_date.to_date}', #{@location}) AS screened;
|
|
234
|
+
SQL
|
|
235
|
+
|
|
236
|
+
screened = data['screened'].to_i
|
|
237
|
+
|
|
238
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
239
|
+
UPDATE temp_disaggregated SET screened_for_tb = #{screened},
|
|
240
|
+
age_group = '#{age_group}'
|
|
241
|
+
WHERE patient_id = #{my_patient_id} AND site_id = #{@location};
|
|
242
|
+
SQL
|
|
243
|
+
|
|
244
|
+
screened
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def given_ipt(my_patient_id, age_group, start_date, end_date)
|
|
248
|
+
data = ActiveRecord::Base.connection.select_one <<~SQL
|
|
249
|
+
SELECT patient_given_ipt(#{my_patient_id},
|
|
250
|
+
'#{start_date.to_date}', '#{end_date.to_date}', #{@location}) AS given;
|
|
251
|
+
SQL
|
|
252
|
+
|
|
253
|
+
given = data['given'].to_i
|
|
254
|
+
|
|
255
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
256
|
+
UPDATE temp_disaggregated SET given_ipt = #{given} ,
|
|
257
|
+
age_group = '#{age_group}'
|
|
258
|
+
WHERE patient_id = #{my_patient_id} AND site_id = #{@location};
|
|
259
|
+
SQL
|
|
260
|
+
|
|
261
|
+
given
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def get_numbers(data, age_group, start_date, end_date, outcomes)
|
|
265
|
+
patient_id = data['patient_id'].to_i
|
|
266
|
+
tx_new = false
|
|
267
|
+
tx_curr = false
|
|
268
|
+
tx_screened_for_tb = false
|
|
269
|
+
tx_given_ipt = false
|
|
270
|
+
outcome = outcomes[patient_id]
|
|
271
|
+
|
|
272
|
+
begin
|
|
273
|
+
date_enrolled = data['date_enrolled'].to_date
|
|
274
|
+
rescue StandardError
|
|
275
|
+
raise data.inspect
|
|
276
|
+
end
|
|
277
|
+
earliest_start_date = begin
|
|
278
|
+
data['earliest_start_date'].to_date
|
|
279
|
+
rescue StandardError
|
|
280
|
+
nil
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
if date_enrolled >= start_date && date_enrolled <= end_date
|
|
284
|
+
tx_new = true if !earliest_start_date.blank? && (date_enrolled == earliest_start_date)
|
|
285
|
+
|
|
286
|
+
tx_curr = true if outcome == 'On antiretrovirals'
|
|
287
|
+
elsif outcome == 'On antiretrovirals'
|
|
288
|
+
tx_curr = true
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
if age_group == 'Pregnant'
|
|
292
|
+
tx_new = false if data['initial_maternal_status'] != 'FP' && tx_new
|
|
293
|
+
|
|
294
|
+
tx_curr = false if data['mstatus'] != 'FP'
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
if age_group == 'Breastfeeding'
|
|
298
|
+
tx_new = false if data['initial_maternal_status'] != 'FBf' && tx_new
|
|
299
|
+
|
|
300
|
+
tx_curr = false if data['mstatus'] != 'FBf'
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
[tx_new, tx_curr, tx_given_ipt, tx_screened_for_tb]
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def get_age_groups(age_group, _start_date, _end_date)
|
|
307
|
+
if age_group != 'Pregnant' && age_group != 'FNP' && age_group != 'Not pregnant' && age_group != 'Breastfeeding'
|
|
308
|
+
|
|
309
|
+
age_group_patients = ActiveRecord::Base.connection.select_all <<~SQL
|
|
310
|
+
SELECT
|
|
311
|
+
patient_id, `disaggregated_age_group`(date(birthdate), date('#{@end_date}')) AS age_group
|
|
312
|
+
FROM temp_earliest_start_date e #{site_manager(operator: 'WHERE', column: 'e.site_id', location: @location)}
|
|
313
|
+
GROUP BY e.patient_id
|
|
314
|
+
HAVING #{@adapter == 'mysql2' ? 'age_group' : "`disaggregated_age_group`(date(birthdate), date('#{@end_date}'))"} = '#{age_group}';
|
|
315
|
+
SQL
|
|
316
|
+
age_group_patient_ids = [0]
|
|
317
|
+
(age_group_patients || []).each do |patient|
|
|
318
|
+
age_group_patient_ids << patient['patient_id'].to_i
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
results = ActiveRecord::Base.connection.select_all <<~SQL
|
|
322
|
+
SELECT o.cum_outcome AS outcome, e.*
|
|
323
|
+
FROM temp_earliest_start_date e
|
|
324
|
+
LEFT JOIN temp_patient_outcomes o ON o.patient_id = e.patient_id #{site_manager(operator: 'AND', column: 'o.site_id', location: @location)}
|
|
325
|
+
WHERE date_enrolled <= '#{@end_date}' #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
|
|
326
|
+
AND e.patient_id IN(#{age_group_patient_ids.join(',')})
|
|
327
|
+
GROUP BY #{@adapter == 'mysql2' ? 'e.patient_id' : 'o.cum_outcome, e.*'};
|
|
328
|
+
SQL
|
|
329
|
+
elsif age_group == 'Pregnant'
|
|
330
|
+
create_mysql_female_maternal_status
|
|
331
|
+
results = ActiveRecord::Base.connection.select_all <<~SQL
|
|
332
|
+
SELECT
|
|
333
|
+
e.*, maternal_status AS mstatus,
|
|
334
|
+
t2.initial_maternal_status,
|
|
335
|
+
t3.cum_outcome AS outcome
|
|
336
|
+
FROM temp_earliest_start_date e
|
|
337
|
+
INNER JOIN temp_disaggregated t2 ON t2.patient_id = e.patient_id #{site_manager(operator: 'AND', column: 't2.site_id', location: @location)}
|
|
338
|
+
INNER JOIN temp_patient_outcomes t3 ON t3.patient_id = e.patient_id #{site_manager(operator: 'AND', column: 't3.site_id', location: @location)}
|
|
339
|
+
WHERE maternal_status = 'FP' OR initial_maternal_status = 'FP' #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
|
|
340
|
+
GROUP BY #{@adapter == 'mysql2' ? 'e.patient_id' : 't3.cum_outcome, maternal_status, t2.initial_maternal_status, e.*'};
|
|
341
|
+
SQL
|
|
342
|
+
|
|
343
|
+
elsif age_group == 'Breastfeeding'
|
|
344
|
+
create_mysql_female_maternal_status
|
|
345
|
+
results = ActiveRecord::Base.connection.select_all <<~SQL
|
|
346
|
+
SELECT
|
|
347
|
+
e.*, maternal_status AS mstatus,
|
|
348
|
+
initial_maternal_status,
|
|
349
|
+
t3.cum_outcome AS outcome
|
|
350
|
+
FROM temp_earliest_start_date e
|
|
351
|
+
INNER JOIN temp_disaggregated t2 ON t2.patient_id = e.patient_id #{site_manager(operator: 'AND', column: 't2.site_id', location: @location)}
|
|
352
|
+
INNER JOIN temp_patient_outcomes t3 ON t3.patient_id = e.patient_id #{site_manager(operator: 'AND', column: 't3.site_id', location: @location)}
|
|
353
|
+
WHERE maternal_status = 'FBf' OR initial_maternal_status = 'FBf' #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
|
|
354
|
+
GROUP BY #{@adapter == 'mysql2' ? 'e.patient_id' : 't3.cum_outcome, maternal_status, initial_maternal_status, e.*'};
|
|
355
|
+
SQL
|
|
356
|
+
|
|
357
|
+
elsif age_group == 'FNP'
|
|
358
|
+
create_mysql_female_maternal_status
|
|
359
|
+
results = ActiveRecord::Base.connection.select_all <<~SQL
|
|
360
|
+
SELECT
|
|
361
|
+
e.*, maternal_status AS mstatus,
|
|
362
|
+
initial_maternal_status,
|
|
363
|
+
t3.cum_outcome AS outcome
|
|
364
|
+
FROM temp_earliest_start_date e
|
|
365
|
+
INNER JOIN temp_disaggregated t2 ON t2.patient_id = e.patient_id #{site_manager(operator: 'AND', column: 't2.site_id', location: @location)}
|
|
366
|
+
INNER JOIN temp_patient_outcomes t3 ON t3.patient_id = e.patient_id #{site_manager(operator: 'AND', column: 't3.site_id', location: @location)}
|
|
367
|
+
WHERE maternal_status = 'FNP' #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
|
|
368
|
+
GROUP BY #{@adapter == 'mysql2' ? 'e.patient_id' : 't3.cum_outcome, maternal_status, initial_maternal_status, e.*'};
|
|
369
|
+
SQL
|
|
370
|
+
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
results
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def create_mysql_female_maternal_status
|
|
377
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
378
|
+
DROP FUNCTION IF EXISTS female_maternal_status;
|
|
379
|
+
SQL
|
|
380
|
+
|
|
381
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
382
|
+
CREATE FUNCTION female_maternal_status(my_patient_id int, end_datetime datetime, my_site_id int) RETURNS VARCHAR(20)
|
|
383
|
+
DETERMINISTIC
|
|
384
|
+
BEGIN
|
|
385
|
+
|
|
386
|
+
DECLARE breastfeeding_date DATETIME;
|
|
387
|
+
DECLARE pregnant_date DATETIME;
|
|
388
|
+
DECLARE maternal_status VARCHAR(20);
|
|
389
|
+
DECLARE obs_value_coded INT(11);
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
SET @reason_for_starting = (SELECT concept_id FROM concept_name WHERE LOWER(name) = LOWER('Reason for ART eligibility') LIMIT 1);
|
|
393
|
+
|
|
394
|
+
SET @pregnant_concepts := (SELECT GROUP_CONCAT(concept_id) FROM concept_name WHERE LOWER(name) IN (LOWER('Is patient pregnant?'), LOWER('Patient pregnant')));
|
|
395
|
+
SET @breastfeeding_concept := (SELECT GROUP_CONCAT(concept_id) FROM concept_name WHERE LOWER(name) = 'Breastfeeding');
|
|
396
|
+
|
|
397
|
+
SET pregnant_date = (SELECT MAX(obs_datetime) FROM obs WHERE concept_id IN (@pregnant_concepts) AND voided = 0 AND person_id = my_patient_id AND obs_datetime <= end_datetime AND site_id = my_site_id);
|
|
398
|
+
SET breastfeeding_date = (SELECT MAX(obs_datetime) FROM obs WHERE concept_id IN (@breastfeeding_concept) AND voided = 0 AND person_id = my_patient_id AND obs_datetime <= end_datetime AND site_id = my_site_id);
|
|
399
|
+
|
|
400
|
+
IF pregnant_date IS NULL THEN
|
|
401
|
+
SET pregnant_date = (SELECT MAX(obs_datetime) FROM obs WHERE concept_id = @reason_for_starting AND voided = 0 AND person_id = my_patient_id AND obs_datetime <= end_datetime AND value_coded IN(1755) AND site_id = my_site_id);
|
|
402
|
+
END IF;
|
|
403
|
+
|
|
404
|
+
IF breastfeeding_date IS NULL THEN
|
|
405
|
+
SET breastfeeding_date = (SELECT MAX(obs_datetime) FROM obs WHERE concept_id = @reason_for_starting AND voided = 0 AND person_id = my_patient_id AND obs_datetime <= end_datetime AND value_coded IN(834,5632) AND site_id = my_site_id);
|
|
406
|
+
END IF;
|
|
407
|
+
|
|
408
|
+
IF pregnant_date IS NULL AND breastfeeding_date IS NULL THEN SET maternal_status = "FNP";
|
|
409
|
+
ELSEIF pregnant_date IS NOT NULL AND breastfeeding_date IS NOT NULL THEN SET maternal_status = "Unknown";
|
|
410
|
+
ELSEIF pregnant_date IS NULL AND breastfeeding_date IS NOT NULL THEN SET maternal_status = "Check BF";
|
|
411
|
+
ELSEIF pregnant_date IS NOT NULL AND breastfeeding_date IS NULL THEN SET maternal_status = "Check FP";
|
|
412
|
+
END IF;
|
|
413
|
+
|
|
414
|
+
IF maternal_status = 'Unknown' THEN
|
|
415
|
+
|
|
416
|
+
IF breastfeeding_date <= pregnant_date THEN
|
|
417
|
+
SET obs_value_coded = (SELECT value_coded FROM obs WHERE concept_id IN(@pregnant_concepts) AND voided = 0 AND person_id = my_patient_id AND obs_datetime = pregnant_date AND site_id = my_site_id LIMIT 1);
|
|
418
|
+
IF obs_value_coded = 1065 THEN SET maternal_status = 'FP';
|
|
419
|
+
ELSEIF obs_value_coded = 1066 THEN SET maternal_status = 'FNP';
|
|
420
|
+
END IF;
|
|
421
|
+
END IF;
|
|
422
|
+
|
|
423
|
+
IF breastfeeding_date > pregnant_date THEN
|
|
424
|
+
SET obs_value_coded = (SELECT value_coded FROM obs WHERE concept_id IN(@breastfeeding_concept) AND voided = 0 AND person_id = my_patient_id AND obs_datetime = breastfeeding_date AND site_id = my_site_id LIMIT 1);
|
|
425
|
+
IF obs_value_coded = 1065 THEN SET maternal_status = 'FBf';
|
|
426
|
+
ELSEIF obs_value_coded = 1066 THEN SET maternal_status = 'FNP';
|
|
427
|
+
END IF;
|
|
428
|
+
END IF;
|
|
429
|
+
|
|
430
|
+
IF DATE(breastfeeding_date) = DATE(pregnant_date) AND maternal_status = 'FNP' THEN
|
|
431
|
+
SET obs_value_coded = (SELECT value_coded FROM obs WHERE concept_id IN(@breastfeeding_concept) AND voided = 0 AND person_id = my_patient_id AND obs_datetime = breastfeeding_date AND site_id = my_site_id LIMIT 1);
|
|
432
|
+
IF obs_value_coded = 1065 THEN SET maternal_status = 'FBf';
|
|
433
|
+
ELSEIF obs_value_coded = 1066 THEN SET maternal_status = 'FNP';
|
|
434
|
+
END IF;
|
|
435
|
+
END IF;
|
|
436
|
+
END IF;
|
|
437
|
+
|
|
438
|
+
IF maternal_status = 'Check FP' THEN
|
|
439
|
+
|
|
440
|
+
SET obs_value_coded = (SELECT value_coded FROM obs WHERE concept_id IN(@pregnant_concepts) AND voided = 0 AND person_id = my_patient_id AND obs_datetime = pregnant_date AND site_id = my_site_id LIMIT 1);
|
|
441
|
+
IF obs_value_coded = 1065 THEN SET maternal_status = 'FP';
|
|
442
|
+
ELSEIF obs_value_coded = 1066 THEN SET maternal_status = 'FNP';
|
|
443
|
+
END IF;
|
|
444
|
+
|
|
445
|
+
IF obs_value_coded IS NULL THEN
|
|
446
|
+
SET obs_value_coded = (SELECT GROUP_CONCAT(value_coded) FROM obs WHERE concept_id IN(7563) AND voided = 0 AND person_id = my_patient_id AND obs_datetime = pregnant_date AND site_id = my_site_id);
|
|
447
|
+
IF obs_value_coded IN(1755) THEN SET maternal_status = 'FP';
|
|
448
|
+
END IF;
|
|
449
|
+
END IF;
|
|
450
|
+
|
|
451
|
+
IF maternal_status = 'Check FP' THEN SET maternal_status = 'FNP';
|
|
452
|
+
END IF;
|
|
453
|
+
END IF;
|
|
454
|
+
|
|
455
|
+
IF maternal_status = 'Check BF' THEN
|
|
456
|
+
|
|
457
|
+
SET obs_value_coded = (SELECT value_coded FROM obs WHERE concept_id IN(@breastfeeding_concept) AND voided = 0 AND person_id = my_patient_id AND obs_datetime = breastfeeding_date AND site_id = my_site_id LIMIT 1);
|
|
458
|
+
IF obs_value_coded = 1065 THEN SET maternal_status = 'FBf';
|
|
459
|
+
ELSEIF obs_value_coded = 1066 THEN SET maternal_status = 'FNP';
|
|
460
|
+
END IF;
|
|
461
|
+
|
|
462
|
+
IF obs_value_coded IS NULL THEN
|
|
463
|
+
SET obs_value_coded = (SELECT GROUP_CONCAT(value_coded) FROM obs WHERE concept_id IN(7563) AND voided = 0 AND person_id = my_patient_id AND obs_datetime = breastfeeding_date AND site_id = my_site_id);
|
|
464
|
+
IF obs_value_coded IN(834,5632) THEN SET maternal_status = 'FBf';
|
|
465
|
+
END IF;
|
|
466
|
+
END IF;
|
|
467
|
+
|
|
468
|
+
IF maternal_status = 'Check BF' THEN SET maternal_status = 'FNP';
|
|
469
|
+
END IF;
|
|
470
|
+
END IF;
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
RETURN maternal_status;
|
|
475
|
+
END;
|
|
476
|
+
SQL
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def rebuild_outcomes(report_type)
|
|
480
|
+
MalawiHivProgramReports::Moh::CohortBuilder.new(outcomes_definition: report_type, location: @location).init_temporary_tables(@start_date,
|
|
481
|
+
@end_date, @occupation)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def insert_female_maternal_status(patient_id, age_group, end_date)
|
|
485
|
+
encounter_types = []
|
|
486
|
+
encounter_types << encounter_type('HIV CLINIC CONSULTATION').encounter_type_id
|
|
487
|
+
encounter_types << encounter_type('HIV STAGING').encounter_type_id
|
|
488
|
+
|
|
489
|
+
pregnant_concepts = []
|
|
490
|
+
pregnant_concepts << concept_name('Is patient pregnant?').concept_id
|
|
491
|
+
pregnant_concepts << concept_name('patient pregnant').concept_id
|
|
492
|
+
|
|
493
|
+
results = ActiveRecord::Base.connection.select_all <<~SQL
|
|
494
|
+
SELECT person_id, obs.value_coded value_coded
|
|
495
|
+
FROM obs obs
|
|
496
|
+
INNER JOIN encounter enc ON enc.encounter_id = obs.encounter_id AND enc.encounter_type IN(#{encounter_types.join(',')}) AND enc.voided = 0 AND enc.program_id = 1 #{site_manager(operator: 'AND', column: 'enc.site_id', location: @location)}
|
|
497
|
+
WHERE obs.person_id = #{patient_id}
|
|
498
|
+
AND obs.obs_datetime <= '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}'
|
|
499
|
+
AND obs.concept_id IN(#{pregnant_concepts.join(',')})
|
|
500
|
+
AND obs.voided = 0 #{site_manager(operator: 'AND', column: 'obs.site_id', location: @location)}
|
|
501
|
+
AND DATE(obs.obs_datetime) = (SELECT MAX(DATE(o.obs_datetime)) FROM obs o
|
|
502
|
+
INNER JOIN encounter e ON e.encounter_id = o.encounter_id
|
|
503
|
+
AND e.program_id = 1 AND e.voided = 0 #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
|
|
504
|
+
WHERE o.concept_id IN(#{pregnant_concepts.join(',')})
|
|
505
|
+
AND o.voided = 0 AND o.person_id = obs.person_id #{site_manager(operator: 'AND', column: 'o.site_id', location: @location)}
|
|
506
|
+
AND o.obs_datetime <= '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}')
|
|
507
|
+
GROUP BY #{@adapter == 'mysql2' ? 'obs.person_id' : 'obs.person_id, obs.value_coded'}
|
|
508
|
+
HAVING #{@adapter == 'mysql2' ? 'value_coded' : 'obs.value_coded'} = 1065
|
|
509
|
+
ORDER BY MAX(obs.obs_datetime) DESC
|
|
510
|
+
SQL
|
|
511
|
+
|
|
512
|
+
female_maternal_status = results.blank? ? 'FNP' : 'FP'
|
|
513
|
+
|
|
514
|
+
if female_maternal_status == 'FNP'
|
|
515
|
+
|
|
516
|
+
breastfeeding_concepts = []
|
|
517
|
+
breastfeeding_concepts << concept_name('Breast feeding?').concept_id
|
|
518
|
+
breastfeeding_concepts << concept_name('Breast feeding').concept_id
|
|
519
|
+
breastfeeding_concepts << concept_name('Breastfeeding').concept_id
|
|
520
|
+
|
|
521
|
+
results2 = ActiveRecord::Base.connection.select_all <<~SQL
|
|
522
|
+
SELECT person_id, obs.value_coded value_coded
|
|
523
|
+
FROM obs obs
|
|
524
|
+
INNER JOIN encounter enc ON enc.encounter_id = obs.encounter_id AND enc.encounter_type IN(#{encounter_types.join(',')}) AND enc.voided = 0 AND enc.program_id = 1 #{site_manager(operator: 'AND', column: 'enc.site_id', location: @location)}
|
|
525
|
+
WHERE obs.person_id =#{patient_id}
|
|
526
|
+
AND obs.obs_datetime <= '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}'
|
|
527
|
+
AND obs.concept_id IN(#{breastfeeding_concepts.join(',')})
|
|
528
|
+
AND obs.voided = 0 #{site_manager(operator: 'AND', column: 'obs.site_id', location: @location)}
|
|
529
|
+
AND DATE(obs.obs_datetime) = (SELECT MAX(DATE(o.obs_datetime)) FROM obs o
|
|
530
|
+
INNER JOIN encounter e ON e.encounter_id = o.encounter_id
|
|
531
|
+
AND e.program_id = 1 AND e.voided = 0 #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
|
|
532
|
+
WHERE o.concept_id IN(#{breastfeeding_concepts.join(',')}) AND o.voided = 0
|
|
533
|
+
AND o.person_id = obs.person_id #{site_manager(operator: 'AND', column: 'o.site_id', location: @location)}
|
|
534
|
+
AND o.obs_datetime <='#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}')
|
|
535
|
+
GROUP BY #{@adapter == 'mysql2' ? 'obs.person_id' : 'obs.person_id, obs.value_coded'}
|
|
536
|
+
HAVING #{@adapter == 'mysql2' ? 'value_coded' : 'obs.value_coded'} = 1065
|
|
537
|
+
ORDER BY MAX(obs.obs_datetime) DESC
|
|
538
|
+
SQL
|
|
539
|
+
|
|
540
|
+
female_maternal_status = results2.blank? ? 'FNP' : 'FBf'
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
results = ActiveRecord::Base.connection.select_all <<~SQL
|
|
544
|
+
SELECT person_id, obs.value_coded value_coded
|
|
545
|
+
FROM obs obs
|
|
546
|
+
INNER JOIN encounter enc ON enc.encounter_id = obs.encounter_id AND enc.encounter_type IN(#{encounter_types.join(',')}) AND enc.voided = 0 AND enc.program_id = 1 #{site_manager(operator: 'AND', column: 'enc.site_id', location: @location)}
|
|
547
|
+
WHERE obs.person_id = #{patient_id}
|
|
548
|
+
AND obs.obs_datetime <= '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}'
|
|
549
|
+
AND obs.concept_id IN(#{pregnant_concepts.join(',')})
|
|
550
|
+
AND obs.voided = 0 #{site_manager(operator: 'AND', column: 'obs.site_id', location: @location)}
|
|
551
|
+
AND DATE(obs.obs_datetime) = (SELECT DATE(es.earliest_start_date) FROM temp_earliest_start_date es
|
|
552
|
+
WHERE es.patient_id = obs.person_id #{site_manager(operator: 'AND', column: 'es.site_id', location: @location)})
|
|
553
|
+
GROUP BY #{@adapter == 'mysql2' ? 'obs.person_id' : 'obs.person_id, obs.value_coded'}
|
|
554
|
+
HAVING #{@adapter == 'mysql2' ? 'value_coded' : 'obs.value_coded'} = 1065
|
|
555
|
+
ORDER BY MAX(obs.obs_datetime) DESC
|
|
556
|
+
SQL
|
|
557
|
+
|
|
558
|
+
initial_female_maternal_status = results.blank? ? 'FNP' : 'FP'
|
|
559
|
+
|
|
560
|
+
if initial_female_maternal_status == 'FNP'
|
|
561
|
+
|
|
562
|
+
breastfeeding_concepts = []
|
|
563
|
+
breastfeeding_concepts << concept_name('Breast feeding?').concept_id
|
|
564
|
+
breastfeeding_concepts << concept_name('Breast feeding').concept_id
|
|
565
|
+
breastfeeding_concepts << concept_name('Breastfeeding').concept_id
|
|
566
|
+
|
|
567
|
+
results2 = ActiveRecord::Base.connection.select_all <<~SQL
|
|
568
|
+
SELECT person_id, obs.value_coded value_coded
|
|
569
|
+
FROM obs obs
|
|
570
|
+
INNER JOIN encounter enc ON enc.encounter_id = obs.encounter_id AND enc.encounter_type IN(#{encounter_types.join(',')}) AND enc.voided = 0 AND enc.program_id = 1 #{site_manager(operator: 'AND', column: 'enc.site_id', location: @location)}
|
|
571
|
+
WHERE obs.person_id =#{patient_id}
|
|
572
|
+
AND obs.obs_datetime <= '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}'
|
|
573
|
+
AND obs.concept_id IN(#{breastfeeding_concepts.join(',')})
|
|
574
|
+
AND obs.voided = 0 #{site_manager(operator: 'AND', column: 'obs.site_id', location: @location)}
|
|
575
|
+
AND DATE(obs.obs_datetime) = (SELECT DATE(es.earliest_start_date) FROM temp_earliest_start_date es
|
|
576
|
+
WHERE es.patient_id = obs.person_id #{site_manager(operator: 'AND', column: 'es.site_id', location: @location)})
|
|
577
|
+
GROUP BY #{@adapter == 'mysql2' ? 'obs.person_id' : 'obs.person_id, obs.value_coded'}
|
|
578
|
+
HAVING #{@adapter == 'mysql2' ? 'value_coded' : 'obs.value_coded'} = 1065
|
|
579
|
+
ORDER BY MAX(obs.obs_datetime) DESC
|
|
580
|
+
SQL
|
|
581
|
+
|
|
582
|
+
initial_female_maternal_status = results2.blank? ? 'FNP' : 'FBf'
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
586
|
+
UPDATE temp_disaggregated SET maternal_status = '#{female_maternal_status}',
|
|
587
|
+
initial_maternal_status = '#{initial_female_maternal_status}',
|
|
588
|
+
age_group = '#{age_group}' WHERE patient_id = #{patient_id} AND site_id = #{@location};
|
|
589
|
+
SQL
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
def big_insert(data, age_group)
|
|
593
|
+
insert_array = []
|
|
594
|
+
(data || []).each do |r|
|
|
595
|
+
insert_array << "(#{r['patient_id']}, '#{age_group}', #{r['site_id']})"
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
return if insert_array.blank?
|
|
599
|
+
|
|
600
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
601
|
+
INSERT INTO temp_disaggregated (patient_id, age_group, site_id)
|
|
602
|
+
VALUES #{insert_array.join(',')};
|
|
603
|
+
SQL
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
# rubocop:enable Metrics/ClassLength
|
|
607
|
+
end
|
|
608
|
+
end
|