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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/app/services/malawi_hiv_program_reports/README.md +16 -0
  3. data/app/services/malawi_hiv_program_reports/adapters/moh/custom.rb +199 -0
  4. data/app/services/malawi_hiv_program_reports/archiving_candidates.rb +130 -0
  5. data/app/services/malawi_hiv_program_reports/arv_refill_periods.rb +311 -0
  6. data/app/services/malawi_hiv_program_reports/clinic/README.md +5 -0
  7. data/app/services/malawi_hiv_program_reports/clinic/appointments_report.rb +317 -0
  8. data/app/services/malawi_hiv_program_reports/clinic/discrepancy_report.rb +42 -0
  9. data/app/services/malawi_hiv_program_reports/clinic/docs/hypertension_report.md +31 -0
  10. data/app/services/malawi_hiv_program_reports/clinic/drug_dispensations.rb +48 -0
  11. data/app/services/malawi_hiv_program_reports/clinic/external_consultation_clients.rb +69 -0
  12. data/app/services/malawi_hiv_program_reports/clinic/hypertension_report.rb +223 -0
  13. data/app/services/malawi_hiv_program_reports/clinic/ipt_coverage.rb +112 -0
  14. data/app/services/malawi_hiv_program_reports/clinic/ipt_report.rb +69 -0
  15. data/app/services/malawi_hiv_program_reports/clinic/lims_results.rb +55 -0
  16. data/app/services/malawi_hiv_program_reports/clinic/outcome_list.rb +127 -0
  17. data/app/services/malawi_hiv_program_reports/clinic/patients_alive_and_on_treatment.rb +57 -0
  18. data/app/services/malawi_hiv_program_reports/clinic/patients_due_for_viral_load.rb +39 -0
  19. data/app/services/malawi_hiv_program_reports/clinic/patients_on_antiretrovirals.rb +44 -0
  20. data/app/services/malawi_hiv_program_reports/clinic/patients_on_dtg.rb +36 -0
  21. data/app/services/malawi_hiv_program_reports/clinic/patients_on_treatment.rb +42 -0
  22. data/app/services/malawi_hiv_program_reports/clinic/patients_with_outdated_demographics.rb +173 -0
  23. data/app/services/malawi_hiv_program_reports/clinic/pregnant_patients.rb +91 -0
  24. data/app/services/malawi_hiv_program_reports/clinic/regimen_dispensation_data.rb +282 -0
  25. data/app/services/malawi_hiv_program_reports/clinic/regimen_switch.rb +456 -0
  26. data/app/services/malawi_hiv_program_reports/clinic/regimens_and_formulations.rb +182 -0
  27. data/app/services/malawi_hiv_program_reports/clinic/regimens_by_weight_and_gender.rb +108 -0
  28. data/app/services/malawi_hiv_program_reports/clinic/retention.rb +246 -0
  29. data/app/services/malawi_hiv_program_reports/clinic/stock_card_report.rb +65 -0
  30. data/app/services/malawi_hiv_program_reports/clinic/tpt_outcome.rb +494 -0
  31. data/app/services/malawi_hiv_program_reports/clinic/tx_rtt.rb +169 -0
  32. data/app/services/malawi_hiv_program_reports/clinic/viral_load.rb +292 -0
  33. data/app/services/malawi_hiv_program_reports/clinic/viral_load_disaggregated.rb +97 -0
  34. data/app/services/malawi_hiv_program_reports/clinic/viral_load_results.rb +175 -0
  35. data/app/services/malawi_hiv_program_reports/clinic/visits_report.rb +113 -0
  36. data/app/services/malawi_hiv_program_reports/clinic/vl_collection.rb +48 -0
  37. data/app/services/malawi_hiv_program_reports/cohort/outcomes.rb +338 -0
  38. data/app/services/malawi_hiv_program_reports/cohort/regimens.rb +69 -0
  39. data/app/services/malawi_hiv_program_reports/cohort/side_effects.rb +141 -0
  40. data/app/services/malawi_hiv_program_reports/cohort/tpt.rb +172 -0
  41. data/app/services/malawi_hiv_program_reports/moh/cohort.rb +278 -0
  42. data/app/services/malawi_hiv_program_reports/moh/cohort_builder.rb +2340 -0
  43. data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated.rb +608 -0
  44. data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated_additions.rb +208 -0
  45. data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated_builder.rb +526 -0
  46. data/app/services/malawi_hiv_program_reports/moh/cohort_struct.rb +219 -0
  47. data/app/services/malawi_hiv_program_reports/moh/cohort_survival_analysis.rb +203 -0
  48. data/app/services/malawi_hiv_program_reports/moh/moh_tpt.rb +223 -0
  49. data/app/services/malawi_hiv_program_reports/moh/tpt_newly_initiated.rb +235 -0
  50. data/app/services/malawi_hiv_program_reports/pepfar/defaulter_list.rb +25 -0
  51. data/app/services/malawi_hiv_program_reports/pepfar/maternal_status.rb +29 -0
  52. data/app/services/malawi_hiv_program_reports/pepfar/patient_start_vl.rb +45 -0
  53. data/app/services/malawi_hiv_program_reports/pepfar/regimen_switch.rb +479 -0
  54. data/app/services/malawi_hiv_program_reports/pepfar/sc_arvdisp.rb +174 -0
  55. data/app/services/malawi_hiv_program_reports/pepfar/sc_curr.rb +98 -0
  56. data/app/services/malawi_hiv_program_reports/pepfar/tb_prev.rb +163 -0
  57. data/app/services/malawi_hiv_program_reports/pepfar/tb_prev2.rb +222 -0
  58. data/app/services/malawi_hiv_program_reports/pepfar/tb_prev3.rb +421 -0
  59. data/app/services/malawi_hiv_program_reports/pepfar/tpt_status.rb +181 -0
  60. data/app/services/malawi_hiv_program_reports/pepfar/tx_ml.rb +181 -0
  61. data/app/services/malawi_hiv_program_reports/pepfar/tx_new.rb +202 -0
  62. data/app/services/malawi_hiv_program_reports/pepfar/tx_rtt.rb +288 -0
  63. data/app/services/malawi_hiv_program_reports/pepfar/tx_tb.rb +283 -0
  64. data/app/services/malawi_hiv_program_reports/pepfar/utils.rb +141 -0
  65. data/app/services/malawi_hiv_program_reports/pepfar/viral_load_coverage.rb +414 -0
  66. data/app/services/malawi_hiv_program_reports/pepfar/viral_load_coverage2.rb +433 -0
  67. data/app/services/malawi_hiv_program_reports/report_map.rb +56 -0
  68. data/app/services/malawi_hiv_program_reports/utils/README.md +8 -0
  69. data/app/services/malawi_hiv_program_reports/utils/common_sql_query_utils.rb +60 -0
  70. data/app/services/malawi_hiv_program_reports/utils/concurrency_utils.rb +53 -0
  71. data/app/services/malawi_hiv_program_reports/utils/docs/common_sql_query_utils.md +53 -0
  72. data/app/services/malawi_hiv_program_reports/utils/model_utils.rb +66 -0
  73. data/app/services/malawi_hiv_program_reports/utils/parameter_utils.rb +32 -0
  74. data/app/services/malawi_hiv_program_reports/utils/time_utils.rb +52 -0
  75. data/lib/malawi_hiv_program_reports/version.rb +1 -1
  76. metadata +74 -1
@@ -0,0 +1,526 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MalawiHivProgramReports
4
+ module Moh
5
+ # This class is used to add additional cohort disaggregated data
6
+ class CohortDisaggregatedBuilder < CohortBuilder
7
+ def initialize(outcomes_definition: 'moh', **kwargs)
8
+ unless %w[moh pepfar].include?(outcomes_definition.downcase)
9
+ raise ::ArgumentError, "Invalid outcomes_definition `#{outcomes_definition}` expected moh or pepfar"
10
+ end
11
+
12
+ @location = kwargs[:location]
13
+ @adapter = ActiveRecord::Base.connection.adapter_name.downcase
14
+ @outcomes_definition = outcomes_definition
15
+ end
16
+
17
+ def build(_cohort_struct, start_date, end_date)
18
+ build_disaggregated_report(cohort(nil, start_date, end_date), start_date, end_date)
19
+ rescue StandardError => e
20
+ Rails.logger.error "Error Message #{e.message}"
21
+ raise e
22
+ end
23
+
24
+ def cohort(_cohort_struct, start_date, end_date)
25
+ time_started = Time.now.strftime('%Y-%m-%d %H:%M:%S')
26
+
27
+ @cohort_struct = cohort_struct = CohortStruct.new
28
+
29
+ #=end
30
+ # Get earliest date enrolled
31
+ @cohort_cum_start_date = cum_start_date = get_cum_start_date
32
+
33
+ # Total registered
34
+ cohort_struct.total_registered = total_registered(start_date, end_date)
35
+ cohort_struct.cum_total_registered = total_registered(cum_start_date, end_date)
36
+
37
+ # Patients initiated on ART first time
38
+ cohort_struct.initiated_on_art_first_time = initiated_on_art_first_time(start_date, end_date)
39
+ cohort_struct.cum_initiated_on_art_first_time = initiated_on_art_first_time(cum_start_date, end_date)
40
+
41
+ # Patients re-initiated on ART
42
+ cohort_struct.re_initiated_on_art = re_initiated_on_art(start_date, end_date)
43
+ cohort_struct.cum_re_initiated_on_art = re_initiated_on_art(cum_start_date, end_date)
44
+
45
+ # Patients transferred in on ART
46
+ cohort_struct.transfer_in = transfer_in(start_date, end_date, cohort_struct.re_initiated_on_art)
47
+ cohort_struct.cum_transfer_in = transfer_in(cum_start_date, end_date, cohort_struct.cum_re_initiated_on_art)
48
+
49
+ # All males
50
+ cohort_struct.all_males = males(start_date, end_date)
51
+ cohort_struct.cum_all_males = males(cum_start_date, end_date)
52
+
53
+ # Unknown age
54
+ cohort_struct.unknown_age = unknown_age(start_date, end_date)
55
+ cohort_struct.cum_unknown_age = unknown_age(cum_start_date, end_date)
56
+
57
+ # No TB
58
+ # total_registered - (current_episode - tb_within_the_last_two_years)
59
+ cohort_struct.no_tb = no_tb(cohort_struct.total_registered, cohort_struct.tb_within_the_last_two_years,
60
+ cohort_struct.current_episode_of_tb)
61
+ cohort_struct.cum_no_tb = cum_no_tb(cohort_struct.cum_total_registered,
62
+ cohort_struct.cum_tb_within_the_last_two_years, cohort_struct.cum_current_episode_of_tb)
63
+
64
+ # Total Alive and On ART
65
+ # Unique PatientProgram entries at the current location for those patients with at least one state
66
+ # ON ARVs and earliest start date of the 'ON ARVs' state less than or equal to end date of quarter
67
+ # and latest state is ON ARVs (Excluding defaulters)
68
+ cohort_struct.total_alive_and_on_art = get_outcome('On antiretrovirals')
69
+
70
+ # Pregnant women
71
+ #
72
+ # Unique PatientProgram entries at the current location for those patients with at least one state ON ARVs
73
+ # and earliest start date of the 'ON ARVs' state within the quarter
74
+ # and having a REASON FOR ELIGIBILITY observation with an answer as PATIENT PREGNANT
75
+ cohort_struct.total_pregnant_women = total_pregnant_women(cohort_struct.total_alive_and_on_art, cum_start_date,
76
+ end_date)
77
+
78
+ # Breastfeeding mothers
79
+ #
80
+ # Unique PatientProgram entries at the current location for those patients with at least one state
81
+ # ON ARVs and earliest start date of the 'ON ARVs' state within the quarter
82
+ # and having a REASON FOR ELIGIBILITY observation with an answer as BREASTFEEDING
83
+ cohort_struct.total_breastfeeding_women = total_breastfeeding_women(cohort_struct.total_alive_and_on_art, cohort_struct.total_pregnant_women,
84
+ cum_start_date, end_date)
85
+
86
+ # Non-pregnant females (all ages)
87
+
88
+ # Unique PatientProgram entries at the current location for those patients with at least one state ON ARVs
89
+ # and earliest start date of the 'ON ARVs' state within the quarter and having gender of
90
+ # related PERSON entry as F for female and no entries of 'IS PATIENT PREGNANT?' observation answered 'YES'
91
+ # in related HIV CLINIC CONSULTATION encounters not within 28 days from earliest registration date
92
+ pregnant_females = []
93
+ (cohort_struct.total_pregnant_women || []).each do |patient|
94
+ pregnant_females << patient['person_id'].to_i
95
+ end
96
+ cohort_struct.non_pregnant_females = non_pregnant_females(start_date, end_date, pregnant_females)
97
+ cohort_struct.cum_non_pregnant_females = non_pregnant_females(cum_start_date, end_date, pregnant_females)
98
+ end_time = Time.now.strftime('%Y-%m-%d %H:%M:%S')
99
+
100
+ puts "Started at: #{time_started}. Finished at: #{end_time}. Total time in minutes: #{((end_time.to_time - time_started.to_time) / 60).round(2)} minutes."
101
+ Rails.logger.info "Started at: #{time_started}. Finished at: #{end_time}. Total time in minutes: #{((end_time.to_time - time_started.to_time) / 60).round(2)} minutes."
102
+ cohort_struct
103
+ rescue StandardError => e
104
+ Rails.logger.error "Error Message #{e}"
105
+ raise e
106
+ end
107
+
108
+ def build_disaggregated_report(cohort, start_date, end_date)
109
+ @age_groups = ['0-5 months', '6-11 months', '12-23 months', '2-4 years',
110
+ '5-9 years', '10-14 years', '15-17 years', '18-19 years',
111
+ '20-24 years', '25-29 years', '30-34 years', '35-39 years',
112
+ '40-44 years', '45-49 years', '50+ years', 'All']
113
+
114
+ report = {}
115
+ counter = 1
116
+
117
+ %w[Male Female].each do |gender|
118
+ @age_groups.each do |ag|
119
+ next if /all/i.match?(ag)
120
+
121
+ report[counter] = {} if report[counter].blank?
122
+ report[counter][gender] = {} if report[counter][gender].blank?
123
+ report[counter][gender][ag] = get_data(cohort, start_date, end_date, gender, ag)
124
+ counter += 1
125
+ end
126
+ end
127
+
128
+ %w[M FP FNP FBf].each do |gender|
129
+ @age_groups.each do |ag|
130
+ next unless /all/i.match?(ag)
131
+
132
+ report[counter] = {} if report[counter].blank?
133
+ report[counter][gender] = {} if report[counter][gender].blank?
134
+ report[counter][gender][ag] = get_data(cohort, start_date, end_date, gender, ag)
135
+ counter += 1
136
+ end
137
+ end
138
+
139
+ report
140
+ rescue StandardError => e
141
+ Rails.logger.error "Error Message #{e}"
142
+ raise e
143
+ end
144
+
145
+ def get_data(cohort, start_date, end_date, gender, age_group)
146
+ @cohort = cohort
147
+
148
+ if %w[Male Female].include?(gender)
149
+ case age_group
150
+ when '50+ years'
151
+ yrs_months = 'year'
152
+ age_to = 1000
153
+ age_from = 50
154
+ when /years/i
155
+ age_from, age_to = age_group.sub(' years', '').split('-')
156
+ yrs_months = 'year'
157
+ when /months/i
158
+ age_from, age_to = age_group.sub(' months', '').split('-')
159
+ yrs_months = 'month'
160
+ end
161
+
162
+ g = gender.first
163
+
164
+ started_on_art = get_started_on_art(yrs_months, age_from, age_to, g, start_date, end_date)
165
+ alive_on_art = get_alive_on_art(yrs_months, age_from, age_to, g, @cohort_cum_start_date, end_date)
166
+ started_on_ipt = get_started_on_ipt(yrs_months, age_from, age_to, g, @cohort_cum_start_date, end_date)
167
+ screened_for_tb = get_screened_for_tb(yrs_months, age_from, age_to, g, @cohort_cum_start_date, end_date)
168
+
169
+ return [started_on_art&.length || 0,
170
+ alive_on_art&.length || 0,
171
+ started_on_ipt&.length || 0,
172
+ screened_for_tb&.length || 0]
173
+ end
174
+
175
+ if gender == 'M'
176
+ age_from = 0
177
+ age_to = 1000
178
+ yrs_months = 'year'
179
+ started_on_art = get_started_on_art(yrs_months, age_from, age_to, gender, start_date, end_date)
180
+ alive_on_art = get_alive_on_art(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date)
181
+ started_on_ipt = get_started_on_ipt(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date)
182
+ screened_for_tb = get_screened_for_tb(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date)
183
+
184
+ return [started_on_art&.length || 0,
185
+ alive_on_art&.length || 0,
186
+ started_on_ipt&.length || 0,
187
+ screened_for_tb&.length || 0]
188
+ end
189
+
190
+ if gender == 'FP'
191
+ a, b, c, d = get_fp(start_date, end_date)
192
+ return [a.length, b.length, c.length, d.length]
193
+ end
194
+
195
+ if gender == 'FNP'
196
+ fnp_a, fnp_b, fnp_c, fnp_d = get_fnp(start_date, end_date)
197
+ return [fnp_a.length, fnp_b.length, fnp_c.length, fnp_d.length]
198
+ end
199
+
200
+ if gender == 'FBf'
201
+ a, b, c, d = get_fbf(start_date, end_date)
202
+ return [a.length, b.length, c.length, d.length]
203
+ end
204
+
205
+ [0, 0, 0, 0]
206
+ end
207
+
208
+ def get_fnp(start_date, end_date)
209
+ age_from = 0
210
+ age_to = 1000
211
+ yrs_months = 'year'
212
+ gender = 'F'
213
+
214
+ females_pregnant = []
215
+ cum_females_pregnant = []
216
+ breast_feeding_women = []
217
+ cum_breast_feeding_women = []
218
+
219
+ started_on_art = []
220
+ alive_on_art = []
221
+ started_on_ipt = []
222
+ screened_for_tb = []
223
+
224
+ ###############################################################
225
+ (@cohort.total_breastfeeding_women || []).each do |p|
226
+ date_enrolled_str = ActiveRecord::Base.connection.select_one(
227
+ "SELECT date_enrolled FROM temp_earliest_start_date e
228
+ WHERE patient_id = #{p['person_id']} #{site_manager(operator: 'AND', column: 'e.site_id',
229
+ location: @location)}"
230
+ )
231
+
232
+ date_enrolled = date_enrolled_str['date_enrolled'].to_date
233
+ if (date_enrolled >= start_date.to_date) && (end_date.to_date <= end_date.to_date)
234
+ breast_feeding_women << p['person_id'].to_i
235
+ breast_feeding_women = breast_feeding_women.uniq
236
+ else
237
+ cum_breast_feeding_women << p['person_id'].to_i
238
+ cum_breast_feeding_women = cum_breast_feeding_women.uniq
239
+ end
240
+ end
241
+
242
+ cum_pregnant_women = @cohort.total_pregnant_women
243
+ (cum_pregnant_women || []).each do |p|
244
+ next if breast_feeding_women.include?(p['person_id'].to_i)
245
+
246
+ date_enrolled_str = ActiveRecord::Base.connection.select_one(
247
+ "SELECT date_enrolled FROM temp_earliest_start_date e
248
+ WHERE patient_id = #{p['person_id'].to_i} #{site_manager(operator: 'AND', column: 'e.site_id',
249
+ location: @location)}"
250
+ )
251
+
252
+ date_enrolled = date_enrolled_str['date_enrolled'].to_date
253
+ if (date_enrolled >= start_date.to_date) && (end_date.to_date <= end_date.to_date)
254
+ females_pregnant << p['person_id'].to_i
255
+ females_pregnant = females_pregnant.uniq
256
+ else
257
+ cum_females_pregnant << p['person_id'].to_i
258
+ cum_females_pregnant = cum_females_pregnant.uniq
259
+ end
260
+ end
261
+
262
+ cum_females_pregnant = (cum_females_pregnant + females_pregnant)&.uniq || []
263
+ cum_breast_feeding_women += breast_feeding_women
264
+ #####################################################################
265
+
266
+ (get_started_on_art(yrs_months, age_from, age_to, gender, start_date, end_date) || []).each do |fnp|
267
+ next if females_pregnant.include?(fnp['patient_id'].to_i)
268
+ next if breast_feeding_women.include?(fnp['patient_id'].to_i)
269
+
270
+ started_on_art << { patient_id: fnp['patient_id'].to_i, date_enrolled: fnp['date_enrolled'].to_date }
271
+ end
272
+
273
+ (get_alive_on_art(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date) || []).each do |fnp|
274
+ next if cum_females_pregnant.include?(fnp['patient_id'].to_i)
275
+ next if cum_breast_feeding_women.include?(fnp['patient_id'].to_i)
276
+
277
+ alive_on_art << { patient_id: fnp['patient_id'].to_i }
278
+ end
279
+
280
+ (get_started_on_ipt(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date) || []).each do |fnp|
281
+ next if cum_females_pregnant.include?(fnp['patient_id'].to_i)
282
+ next if cum_breast_feeding_women.include?(fnp['patient_id'].to_i)
283
+
284
+ started_on_ipt << { patient_id: fnp['patient_id'].to_i }
285
+ end
286
+
287
+ (get_screened_for_tb(yrs_months, age_from, age_to, gender, @cohort_cum_start_date,
288
+ end_date) || []).each do |fnp|
289
+ next if cum_females_pregnant.include?(fnp['patient_id'].to_i)
290
+ next if cum_breast_feeding_women.include?(fnp['patient_id'].to_i)
291
+
292
+ screened_for_tb << { patient_id: fnp['patient_id'].to_i }
293
+ end
294
+
295
+ [started_on_art, alive_on_art, started_on_ipt, screened_for_tb]
296
+ end
297
+
298
+ def get_screened_for_tb(yrs_months, age_from, age_to, gender, start_date, end_date)
299
+ alive_on_art_patient_ids = []
300
+ start_date = @cohort_cum_start_date
301
+
302
+ (@cohort.total_alive_and_on_art || []).each do |data|
303
+ alive_on_art_patient_ids << data['patient_id'].to_i
304
+ end
305
+
306
+ return [] if alive_on_art_patient_ids.blank?
307
+
308
+ tb_treatment = concept_name('TB treatment').concept_id
309
+ tb_status_id = concept_name('TB status').concept_id
310
+ clinical_consultation = encounter_type('HIV CLINIC CONSULTATION').id
311
+
312
+ ActiveRecord::Base.connection.select_all <<~SQL
313
+ SELECT t1.patient_id
314
+ FROM obs t3
315
+ INNER JOIN temp_earliest_start_date t1 ON t1.patient_id = t3.person_id #{site_manager(operator: 'AND', column: 't1.site_id', location: @location)} AND t1.patient_id IN(#{alive_on_art_patient_ids.join(',')})
316
+ WHERE t3.concept_id IN(#{tb_treatment},#{tb_status_id}) AND t3.voided = 0
317
+ AND t3.obs_datetime BETWEEN '#{start_date.to_date.strftime('%Y-%m-%d 00:00:00')}' AND '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}'
318
+ AND gender = '#{gender.first}' AND t1.date_enrolled BETWEEN '#{start_date.to_date}' AND '#{end_date.to_date}' #{site_manager(operator: 'AND', column: 't3.site_id', location: @location)}
319
+ AND #{timestampdiff_manager(date1: 'birthdate', date2: "DATE('#{end_date.to_date}')", interval: yrs_months)} BETWEEN #{age_from} AND #{age_to}
320
+ AND t3.obs_datetime = (
321
+ SELECT MAX(obs_datetime)
322
+ FROM obs t4
323
+ INNER JOIN encounter e ON e.encounter_id = t4.encounter_id AND e.encounter_type = #{clinical_consultation} AND e.voided = 0 #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
324
+ WHERE t3.person_id = t4.person_id
325
+ AND t4.voided = 0 #{site_manager(operator: 'AND', column: 't4.site_id', location: @location)}
326
+ AND t4.obs_datetime BETWEEN '#{start_date.to_date.strftime('%Y-%m-%d 00:00:00')}' AND '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}'
327
+ )
328
+ GROUP BY t3.person_id
329
+ SQL
330
+ end
331
+
332
+ def get_started_on_ipt(yrs_months, age_from, age_to, gender, _start_date, end_date)
333
+ data = ActiveRecord::Base.connection.select_all <<~SQL
334
+ SELECT patient_id
335
+ FROM temp_earliest_start_date
336
+ WHERE gender = '#{gender}' AND earliest_start_date <= '#{end_date.to_date}'
337
+ AND #{timestampdiff_manager(date1: 'birthdate', date2: "DATE('#{end_date.to_date}')", interval: yrs_months)}
338
+ BETWEEN #{age_from} AND #{age_to} #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
339
+ SQL
340
+
341
+ return [] if data.blank?
342
+
343
+ patient_ids = []
344
+
345
+ data.each do |d|
346
+ patient_ids << d['patient_id'].to_i
347
+ end
348
+
349
+ amount_dispensed = concept_name('Amount dispensed').concept_id
350
+ ipt_drug_ids = ::Drug.where(concept_id: concept_name('Isoniazid').concept_id).map(&:drug_id)
351
+
352
+ ActiveRecord::Base.connection.select_all <<~SQL
353
+ SELECT obs.person_id patient_id
354
+ FROM obs
355
+ WHERE concept_id = #{amount_dispensed} AND obs.voided = 0 #{site_manager(operator: 'AND', column: 'obs.site_id', location: @location)}
356
+ AND obs.obs_datetime <= '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}'
357
+ AND value_drug IN(#{ipt_drug_ids.join(',')}) AND obs.person_id IN(#{patient_ids.join(',')})
358
+ SQL
359
+ end
360
+
361
+ def get_alive_on_art(yrs_months, age_from, age_to, gender, _start_date, end_date)
362
+ alive_on_art_patient_ids = []
363
+
364
+ (@cohort.total_alive_and_on_art || []).each do |data|
365
+ alive_on_art_patient_ids << data['patient_id'].to_i
366
+ end
367
+
368
+ return [] if alive_on_art_patient_ids.blank?
369
+
370
+ ActiveRecord::Base.connection.select_all <<~SQL
371
+ SELECT patient_id
372
+ FROM temp_earliest_start_date
373
+ WHERE gender = '#{gender}' AND date_enrolled <= '#{end_date.to_date}' AND
374
+ patient_id IN(#{alive_on_art_patient_ids.join(',')})
375
+ AND #{timestampdiff_manager(date1: 'birthdate', date2: "DATE('#{end_date.to_date}')", interval: yrs_months)}
376
+ BETWEEN #{age_from} AND #{age_to} #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
377
+ SQL
378
+ end
379
+
380
+ def get_started_on_art(yrs_months, age_from, age_to, gender, start_date, end_date)
381
+ ActiveRecord::Base.connection.select_all <<~SQL
382
+ SELECT patient_id, date_enrolled
383
+ FROM temp_earliest_start_date
384
+ WHERE gender = '#{gender}' AND date_enrolled BETWEEN
385
+ '#{start_date.to_date}' AND '#{end_date.to_date}' AND
386
+ (DATE(date_enrolled) = DATE(earliest_start_date))
387
+ AND #{timestampdiff_manager(date1: 'birthdate', date2: 'DATE(earliest_start_date)', interval: yrs_months)}
388
+ BETWEEN #{age_from} AND #{age_to} #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
389
+ SQL
390
+ end
391
+
392
+ def get_fp(start_date, end_date)
393
+ age_from = 0
394
+ age_to = 1000
395
+ yrs_months = 'year'
396
+ gender = 'F'
397
+ cum_pregnant_women = @cohort.total_pregnant_women
398
+
399
+ return [[], [], [], []] if cum_pregnant_women.blank?
400
+
401
+ pregnant_women_patient_ids = []
402
+
403
+ cum_pregnant_women.each do |p|
404
+ date_enrolled_str = ActiveRecord::Base.connection.select_one <<~SQL
405
+ SELECT date_enrolled FROM temp_earliest_start_date e
406
+ WHERE patient_id = #{p['person_id'].to_i} #{site_manager(operator: 'AND', column: 'e.site_id', location: @location)}
407
+ SQL
408
+
409
+ date_enrolled = date_enrolled_str['date_enrolled'].to_date
410
+ if (date_enrolled >= @cohort_cum_start_date.to_date) && (end_date.to_date <= end_date.to_date)
411
+ pregnant_women_patient_ids << p['person_id'].to_i
412
+ end
413
+ end
414
+
415
+ started_on_art = []
416
+ alive_on_art = []
417
+ started_on_ipt = []
418
+ screened_for_tb = []
419
+
420
+ (get_started_on_art(yrs_months, age_from, age_to, gender, start_date, end_date) || []).each do |p|
421
+ next unless pregnant_women_patient_ids.include?(p['patient_id'].to_i)
422
+
423
+ started_on_art << p
424
+ end
425
+
426
+ (get_alive_on_art(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date) || []).each do |p|
427
+ next unless pregnant_women_patient_ids.include?(p['patient_id'].to_i)
428
+
429
+ alive_on_art << { patient_id: p['patient_id'].to_i }
430
+ end
431
+
432
+ (get_started_on_ipt(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date) || []).each do |p|
433
+ next unless pregnant_women_patient_ids.include?(p['patient_id'].to_i)
434
+
435
+ started_on_ipt << { patient_id: p['patient_id'].to_i }
436
+ end
437
+
438
+ (get_screened_for_tb(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date) || []).each do |p|
439
+ next unless pregnant_women_patient_ids.include?(p['patient_id'].to_i)
440
+
441
+ screened_for_tb << { patient_id: p['patient_id'].to_i }
442
+ end
443
+
444
+ [started_on_art, alive_on_art,
445
+ started_on_ipt, screened_for_tb]
446
+ end
447
+
448
+ def get_fbf(start_date, end_date)
449
+ age_from = 0
450
+ age_to = 1000
451
+ yrs_months = 'year'
452
+ gender = 'F'
453
+ cum_breastfeeding_mothers = @cohort.total_breastfeeding_women
454
+
455
+ return [[], [], [], []] if cum_breastfeeding_mothers.blank?
456
+
457
+ fbf_women_patient_ids = []
458
+
459
+ started_on_art = []
460
+ alive_on_art = []
461
+ started_on_ipt = []
462
+ screened_for_tb = []
463
+
464
+ #########################################################################
465
+ cum_pregnant_women = @cohort.total_pregnant_women
466
+ pregnant_women_patient_ids = []
467
+
468
+ cum_pregnant_women.each do |p|
469
+ date_enrolled_str = ActiveRecord::Base.connection.select_one(
470
+ "SELECT date_enrolled FROM temp_earliest_start_date e
471
+ WHERE patient_id = #{p['person_id'].to_i} #{site_manager(operator: 'AND', column: 'e.site_id',
472
+ location: @location)}"
473
+ )
474
+
475
+ date_enrolled = date_enrolled_str['date_enrolled'].to_date
476
+ if (date_enrolled >= @cohort_cum_start_date.to_date) && (end_date.to_date <= end_date.to_date)
477
+ pregnant_women_patient_ids << p['person_id'].to_i
478
+ end
479
+ end
480
+ #########################################################################
481
+
482
+ cum_breastfeeding_mothers.each do |w|
483
+ next if pregnant_women_patient_ids.include?(w['person_id'].to_i)
484
+
485
+ date_enrolled_str = ActiveRecord::Base.connection.select_one(
486
+ "SELECT date_enrolled FROM temp_earliest_start_date e
487
+ WHERE patient_id = #{w['person_id'].to_i} #{site_manager(operator: 'AND', column: 'e.site_id',
488
+ location: @location)}"
489
+ )
490
+
491
+ date_enrolled = date_enrolled_str['date_enrolled'].to_date
492
+ if (date_enrolled >= @cohort_cum_start_date.to_date) && (end_date.to_date <= end_date.to_date)
493
+ fbf_women_patient_ids << w['person_id'].to_i
494
+ end
495
+ end
496
+
497
+ (get_started_on_art(yrs_months, age_from, age_to, gender, start_date, end_date) || []).each do |fbf|
498
+ next unless fbf_women_patient_ids.include?(fbf['patient_id'].to_i)
499
+
500
+ started_on_art << { patient_id: fbf['patient_id'].to_i, date_enrolled: fbf['date_enrolled'].to_date }
501
+ end
502
+
503
+ (get_alive_on_art(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date) || []).each do |fbf|
504
+ next unless fbf_women_patient_ids.include?(fbf['patient_id'].to_i)
505
+
506
+ alive_on_art << { patient_id: fbf['patient_id'].to_i }
507
+ end
508
+
509
+ (get_started_on_ipt(yrs_months, age_from, age_to, gender, @cohort_cum_start_date, end_date) || []).each do |fbf|
510
+ next unless fbf_women_patient_ids.include?(fbf['patient_id'].to_i)
511
+
512
+ started_on_ipt << { patient_id: fbf['patient_id'].to_i }
513
+ end
514
+
515
+ (get_screened_for_tb(yrs_months, age_from, age_to, gender, @cohort_cum_start_date,
516
+ end_date) || []).each do |fbf|
517
+ next unless fbf_women_patient_ids.include?(fbf['patient_id'].to_i)
518
+
519
+ screened_for_tb << { patient_id: fbf['patient_id'].to_i }
520
+ end
521
+
522
+ [started_on_art, alive_on_art, started_on_ipt, screened_for_tb]
523
+ end
524
+ end
525
+ end
526
+ end