malawi_hiv_program_reports 1.0.25 → 1.0.26

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@
3
3
  module MalawiHivProgramReports
4
4
  module Pepfar
5
5
  class TxMl
6
- attr_reader :start_date, :end_date, :location
6
+ attr_reader :start_date, :end_date, :location, :rebuild
7
7
 
8
8
  include Utils
9
9
  include MalawiHivProgramReports::Utils::CommonSqlQueryUtils
@@ -12,69 +12,30 @@ module MalawiHivProgramReports
12
12
  def initialize(start_date:, end_date:, **kwargs)
13
13
  @start_date = start_date.to_date.strftime('%Y-%m-%d 00:00:00')
14
14
  @end_date = end_date.to_date.strftime('%Y-%m-%d 23:59:59')
15
- @occupation = kwargs[:occupation]
16
15
  @location = kwargs[:location]
17
- @adapter = ActiveRecord::Base.connection.adapter_name.downcase
16
+ @rebuild = kwargs[:rebuild]&.casecmp?('true')
18
17
  end
19
18
 
20
19
  def find_report
21
- tx_ml
20
+ if rebuild
21
+ cohort = MalawiHivProgramReports::Moh::CumulativeCohort.new(start_date:, end_date:, definition: 'pepfar', locations: location.to_s, rebuild: true)
22
+ cohort.find_report
23
+ end
24
+ process_data
22
25
  end
23
26
 
24
27
  private
25
28
 
26
- def tx_ml
29
+ def process_data
27
30
  data = {}
28
- tx_curr = potential_tx_ml_clients
29
- tx_new = new_potential_tx_ml_clients
30
- patient_ids = []
31
- earliest_start_dates = {}
32
-
33
- (tx_curr || []).each do |pat|
34
- patient_id = pat['patient_id'].to_i
35
- patient_ids << patient_id
36
- earliest_start_dates[patient_id] = begin
37
- pat['earliest_start_date'].to_date
38
- rescue StandardError
39
- pat['date_enrolled'].to_date
40
- end
41
- end
42
-
43
- (tx_new || []).each do |pat|
31
+ (process_tx_ml_clients || []).each do |pat|
44
32
  patient_id = pat['patient_id'].to_i
45
- patient_ids << patient_id
46
- patient_ids = patient_ids.uniq
47
- earliest_start_dates[patient_id] = begin
48
- pat['earliest_start_date'].to_date
49
- rescue StandardError
50
- pat['date_enrolled'].to_date
51
- end
52
- patient_ids << pat['patient_id']
53
- patient_ids = patient_ids.uniq
54
- end
55
-
56
- return [] if patient_ids.blank?
57
-
58
- filtered_patients = ActiveRecord::Base.connection.select_all <<~SQL
59
- SELECT
60
- p.person_id patient_id, birthdate, gender,
61
- #{function_manager(function: 'pepfar_patient_outcome', location: @location, args: "p.person_id::int, '#{end_date.to_date}'::date, #{@location}::int")} outcome,
62
- #{function_manager(function: 'disaggregated_age_group', location: @location, args: "p.birthdate::date, '#{end_date.to_date}::date'")} age_group
63
- FROM person #{current_partition} p
64
- WHERE #{in_manager(column: 'p.person_id', values: patient_ids)}
65
- GROUP BY p.person_id #{group_by_columns('p.birthdate, p.gender')}
66
- SQL
67
-
68
- (filtered_patients || []).each do |pat|
69
33
  outcome = pat['outcome']
70
- next if outcome == 'On antiretrovirals'
71
-
72
- patient_id = pat['patient_id'].to_i
73
34
  gender = begin
74
- pat['gender'].first.upcase
75
- rescue StandardError
76
- 'Unknown'
77
- end
35
+ pat['gender'].first.upcase
36
+ rescue StandardError
37
+ 'Unknown'
38
+ end
78
39
  age_group = pat['age_group']
79
40
 
80
41
  if data[age_group].blank?
@@ -86,7 +47,7 @@ module MalawiHivProgramReports
86
47
 
87
48
  case outcome
88
49
  when 'Defaulted'
89
- def_months = defaulter_period(patient_id, earliest_start_dates[patient_id])
50
+ def_months = pat['months'].to_i
90
51
  if def_months < 3
91
52
  data[age_group][gender][1] << patient_id
92
53
  elsif def_months <= 5
@@ -104,70 +65,54 @@ module MalawiHivProgramReports
104
65
  rescue StandardError => e
105
66
  Rails.logger.error(e.message)
106
67
  end
107
-
108
68
  data
109
69
  end
110
70
 
111
- def potential_tx_ml_clients
112
- ActiveRecord::Base.connection.select_all <<~SQL
113
- SELECT
114
- p.patient_id AS patient_id,
115
- pe.birthdate,
116
- pe.gender,
117
- #{function_manager(function: 'patient_date_enrolled', location: @location, args: "p.patient_id::int, #{@location}::int")} AS date_enrolled,
118
- #{function_manager(function: 'date_antiretrovirals_started', location: @location, args: "p.patient_id::int, MIN(s.start_date)::date, #{@location}::int")} AS earliest_start_date
119
- FROM patient_program #{current_partition} p
120
- INNER JOIN person #{current_partition} pe ON pe.person_id = p.patient_id AND pe.voided = 0
121
- INNER JOIN patient_state #{current_partition} s ON p.patient_program_id = s.patient_program_id AND s.voided = 0 AND s.state = 7
122
- LEFT JOIN (#{current_occupation_query}) a ON a.person_id = p.patient_id
123
- WHERE p.program_id = 1 #{%w[Military Civilian].include?(@occupation) ? 'AND' : ''} #{occupation_filter(occupation: @occupation, field_name: 'value', table_name: 'a', include_clause: false)}
124
- AND DATE(s.start_date) < '#{start_date.to_date}'
125
- AND #{function_manager(function: 'pepfar_patient_outcome', location: @location, args: "p.patient_id::int, '#{start_date.to_date}'::date, #{@location}::int")} = 'On antiretrovirals'
126
- AND pe.person_id NOT IN (#{drug_refills_and_external_consultation_list})
127
- GROUP BY p.patient_id
128
- HAVING date_enrolled IS NOT NULL AND DATE(date_enrolled) < '#{start_date.to_date}';
129
- SQL
71
+ def tx_ml_clients
72
+ <<~SQL
73
+ SELECT
74
+ e.patient_id,
75
+ e.birthdate,
76
+ e.gender,
77
+ e.date_enrolled,
78
+ e.earliest_start_date,
79
+ o.outcome_date,
80
+ TIMESTAMPDIFF(MONTH, DATE(e.earliest_start_date), DATE(o.outcome_date)) months,
81
+ disaggregated_age_group(e.birthdate, DATE('#{end_date}')) age_group,
82
+ o.cum_outcome outcome
83
+ FROM cdr_temp_cohort_members #{current_partition} e
84
+ INNER JOIN cdr_temp_patient_outcomes #{current_partition} o ON e.patient_id = o.patient_id AND o.cum_outcome IN ('Defaulted', 'Patient died', 'Treatment stopped', 'Patient transferred out')
85
+ WHERE e.patient_id IN (SELECT patient_id FROM cdr_temp_patient_outcomes_start #{current_partition} WHERE cum_outcome = 'On antiretrovirals')
86
+ AND DATE(e.date_enrolled) < '#{start_date.to_date}'
87
+ GROUP BY e.patient_id
88
+ SQL
130
89
  end
131
90
 
132
- def new_potential_tx_ml_clients
133
- ActiveRecord::Base.connection.select_all <<~SQL
134
- SELECT
135
- p.patient_id AS patient_id,
136
- pe.birthdate,
137
- pe.gender,
138
- #{function_manager(function: 'patient_date_enrolled', location: @location, args: "p.patient_id::int, #{@location}::int")} AS date_enrolled,
139
- #{function_manager(function: 'date_antiretrovirals_started', location: @location, args: "p.patient_id::int, MIN(s.start_date)::date, #{@location}::int")} AS earliest_start_date
140
- FROM patient_program #{current_partition} p
141
- INNER JOIN person #{current_partition} pe ON pe.person_id = p.patient_id AND pe.voided = 0
142
- INNER JOIN patient_state #{current_partition} s ON p.patient_program_id = s.patient_program_id AND s.voided = 0 AND s.state = 7
143
- LEFT JOIN (#{current_occupation_query}) a ON a.person_id = p.patient_id
144
- WHERE p.program_id = 1 #{%w[Military Civilian].include?(@occupation) ? 'AND' : ''} #{occupation_filter(occupation: @occupation, field_name: 'value', table_name: 'a', include_clause: false)}
145
- AND DATE(s.start_date) BETWEEN DATE('#{start_date}') AND DATE('#{end_date}')
146
- AND pe.person_id NOT IN (#{drug_refills_and_external_consultation_list})
147
- GROUP BY p.patient_id
148
- HAVING date_enrolled IS NOT NULL AND date_enrolled BETWEEN DATE('#{start_date}') AND DATE('#{end_date}');
149
- SQL
91
+ def tx_ml_clients_new
92
+ <<~SQL
93
+ SELECT
94
+ e.patient_id,
95
+ e.birthdate,
96
+ e.gender,
97
+ e.date_enrolled,
98
+ e.earliest_start_date,
99
+ o.outcome_date,
100
+ TIMESTAMPDIFF(MONTH, DATE(e.earliest_start_date), DATE(o.outcome_date)) months,
101
+ disaggregated_age_group(e.birthdate, DATE('#{end_date}')) age_group,
102
+ o.cum_outcome outcome
103
+ FROM cdr_temp_cohort_members #{current_partition} e
104
+ INNER JOIN cdr_temp_patient_outcomes #{current_partition} o ON e.patient_id = o.patient_id AND o.cum_outcome IN ('Defaulted', 'Patient died', 'Treatment stopped', 'Patient transferred out')
105
+ WHERE e.date_enrolled BETWEEN DATE('#{start_date}') AND DATE('#{end_date}')
106
+ GROUP BY e.patient_id
107
+ SQL
150
108
  end
151
109
 
152
- def defaulter_period(patient_id, earliest_start_date)
153
- defaulter_date = ActiveRecord::Base.connection.select_one <<~SQL
154
- SELECT #{function_manager(function: 'current_pepfar_defaulter_date', location: @location, args: "#{patient_id}::int, '#{end_date}'::date, #{@location}::int")} def_date;
155
- SQL
156
-
157
- defaulter_date = begin
158
- defaulter_date['def_date'].to_date
159
- rescue StandardError
160
- end_date.to_date
161
- end
162
-
163
- raise 'Defaulted outside the reporting period' if defaulter_date > end_date.to_date
164
- raise 'Defaulted outside the reporting period' if defaulter_date < start_date.to_date
165
-
166
- days_gone = ActiveRecord::Base.connection.select_one <<~SQL
167
- SELECT TIMESTAMPDIFF(MONTH, DATE('#{earliest_start_date}'), DATE('#{defaulter_date}')) months;
168
- SQL
169
-
170
- days_gone['months'].to_i
110
+ def process_tx_ml_clients
111
+ ActiveRecord::Base.connection.select_all <<~SQL
112
+ (#{tx_ml_clients})
113
+ UNION
114
+ (#{tx_ml_clients_new})
115
+ SQL
171
116
  end
172
117
  end
173
118
  end
@@ -14,8 +14,7 @@ module MalawiHivProgramReports
14
14
  def initialize(start_date:, end_date:, **kwargs)
15
15
  @start_date = start_date.to_date.beginning_of_day.strftime('%Y-%m-%d %H:%M:%S')
16
16
  @end_date = end_date.to_date.end_of_day.strftime('%Y-%m-%d %H:%M:%S')
17
- rebuild_string = kwargs[:rebuild]
18
- @rebuild = rebuild_string.present? ? rebuild_string&.downcase == 'true' : false
17
+ @rebuild = kwargs[:rebuild]&.casecmp?('true')
19
18
  @location = kwargs[:location]
20
19
  end
21
20
 
@@ -23,8 +22,8 @@ module MalawiHivProgramReports
23
22
  report = init_report
24
23
  addittional_groups report
25
24
  if rebuild
26
- MalawiHivProgramReports::Moh::CohortBuilder.new(location: @location).init_temporary_tables(start_date,
27
- end_date, '')
25
+ cohort = MalawiHivProgramReports::Moh::CumulativeCohort.new(start_date:, end_date:, definition: 'pepfar', locations: location.to_s, rebuild: true)
26
+ cohort.find_report
28
27
  end
29
28
  process_data report
30
29
  flatten_the_report report
@@ -64,8 +63,12 @@ module MalawiHivProgramReports
64
63
  end
65
64
  end
66
65
 
66
+ # rubocop:disable Metrics/AbcSize
67
+ # rubocop:disable Metrics/MethodLength
68
+ # rubocop:disable Metrics/PerceivedComplexity
69
+ # rubocop:disable Metrics/CyclomaticComplexity
67
70
  def process_data(report)
68
- data.each do |row|
71
+ fetch_data.each do |row|
69
72
  age_group = row['age_group']
70
73
  gender = row['gender']
71
74
  date_enrolled = row['date_enrolled']
@@ -106,6 +109,8 @@ module MalawiHivProgramReports
106
109
  report['All']['FNP'][indicator.to_sym] << kwargs[:patient_id]
107
110
  end
108
111
  end
112
+ # rubocop:enable Metrics/PerceivedComplexity
113
+ # rubocop:enable Metrics/CyclomaticComplexity
109
114
 
110
115
  def process_age_group_report(age_group, gender, age_group_report)
111
116
  {
@@ -115,12 +120,14 @@ module MalawiHivProgramReports
115
120
  else
116
121
  (gender == 'M' ? 'Male' : gender)
117
122
  end,
118
- cd4_less_than_200: age_group_report[:cd4_less_than_200],
119
- cd4_greater_than_equal_to_200: age_group_report[:cd4_greater_than_equal_to_200],
120
- cd4_unknown_or_not_done: age_group_report[:cd4_unknown_or_not_done],
121
- transfer_in: age_group_report[:transfer_in]
123
+ cd4_less_than_200: age_group_report['cd4_less_than_200'.to_sym],
124
+ cd4_greater_than_equal_to_200: age_group_report['cd4_greater_than_equal_to_200'.to_sym],
125
+ cd4_unknown_or_not_done: age_group_report['cd4_unknown_or_not_done'.to_sym],
126
+ transfer_in: age_group_report['transfer_in'.to_sym]
122
127
  }
123
128
  end
129
+ # rubocop:enable Metrics/AbcSize
130
+ # rubocop:enable Metrics/MethodLength
124
131
 
125
132
  def flatten_the_report(report)
126
133
  result = []
@@ -142,58 +149,50 @@ module MalawiHivProgramReports
142
149
  result_scores.reject { |item| item[:age_group].match?(/unknown/i) }
143
150
  end
144
151
 
145
- def data
152
+ def fetch_data
146
153
  ActiveRecord::Base.connection.select_all <<~SQL
147
- SELECT
148
- pp.patient_id,
149
- MIN(pp.gender) gender,
150
- disaggregated_age_group(pp.birthdate, DATE('#{end_date}')) age_group,
151
- CASE
152
- WHEN o.value_numeric < 200 THEN 'cd4_less_than_200'
153
- WHEN o.value_numeric = 200 AND o.value_modifier = '=' THEN 'cd4_greater_than_equal_to_200'
154
- WHEN o.value_numeric = 200 AND o.value_modifier = '<' THEN 'cd4_less_than_200'
155
- WHEN o.value_numeric = 200 AND o.value_modifier = '>' THEN 'cd4_greater_than_equal_to_200'
156
- WHEN o.value_numeric > 200 THEN 'cd4_greater_than_equal_to_200'
157
- ELSE 'cd4_unknown_or_not_done'
158
- END cd4_count_group,
159
- CASE
160
- WHEN transfer_in.value_coded IS NOT NULL THEN 0
161
- ELSE 1
162
- END new_patient,
163
- pp.date_enrolled,
164
- pp.earliest_start_date,
165
- preg_or_breast.name AS maternal_status,
166
- DATE(MIN(pregnant_or_breastfeeding.obs_datetime)) AS maternal_status_date
167
- FROM cdr_temp_cohort_members pp
168
- INNER JOIN person #{current_partition} pe ON pe.person_id = pp.patient_id AND pe.voided = 0
169
- #{site_manager(operator: 'AND', column: 'pp.site_id', location: @location)}
170
- LEFT JOIN (
171
- SELECT max(o.obs_datetime) AS obs_datetime, o.person_id
172
- FROM obs #{current_partition} o
173
- INNER JOIN concept_name cn ON cn.concept_id = o.concept_id AND cn.name = 'CD4 count' AND cn.voided = 0
174
- INNER JOIN patient_program #{current_partition} pp ON pp.patient_id = o.person_id
175
- AND pp.program_id = #{program('HIV PROGRAM').id}
176
- AND pp.voided = 0
177
- INNER JOIN patient_state #{current_partition} ps ON ps.patient_program_id = pp.patient_program_id AND ps.voided = 0 AND ps.state = 7 AND ps.start_date <= DATE('#{end_date}')
178
- WHERE o.concept_id = #{concept_name('CD4 count').concept_id} AND o.voided = 0
179
- AND o.obs_datetime <= '#{end_date}' AND o.obs_datetime >= '#{start_date}'
180
- GROUP BY o.person_id
181
- ) current_cd4 ON current_cd4.person_id = pp.patient_id
182
- LEFT JOIN obs #{current_partition} o ON o.person_id = pp.patient_id AND o.concept_id = #{concept_name('CD4 count').concept_id} AND o.voided = 0 AND o.obs_datetime = current_cd4.obs_datetime
183
- LEFT JOIN obs #{current_partition} transfer_in ON transfer_in.person_id = pp.patient_id
184
- AND transfer_in.concept_id = #{concept_name('Ever registered at ART clinic').concept_id}
185
- AND transfer_in.voided = 0
186
- AND transfer_in.value_coded = #{concept_name('Yes').concept_id}
187
- AND transfer_in.obs_datetime <= '#{end_date}'
188
- AND transfer_in.obs_datetime >= '#{start_date}'
189
- LEFT JOIN obs #{current_partition} pregnant_or_breastfeeding ON pregnant_or_breastfeeding.person_id = pp.patient_id
190
- AND pregnant_or_breastfeeding.concept_id IN (SELECT concept_id FROM concept_name WHERE name IN ('Breast feeding?', 'Breast feeding', 'Breastfeeding', 'Is patient pregnant?', 'patient pregnant') AND voided = 0)
191
- AND pregnant_or_breastfeeding.voided = 0
192
- AND pregnant_or_breastfeeding.value_coded = #{concept_name('Yes').concept_id}
154
+ SELECT
155
+ e.patient_id,
156
+ e.gender,
157
+ disaggregated_age_group(e.birthdate, DATE('#{end_date}')) age_group,
158
+ CASE
159
+ WHEN o.value_numeric < 200 THEN 'cd4_less_than_200'
160
+ WHEN o.value_numeric = 200 AND o.value_modifier = '=' THEN 'cd4_greater_than_equal_to_200'
161
+ WHEN o.value_numeric = 200 AND o.value_modifier = '<' THEN 'cd4_less_than_200'
162
+ WHEN o.value_numeric = 200 AND o.value_modifier = '>' THEN 'cd4_greater_than_equal_to_200'
163
+ WHEN o.value_numeric > 200 THEN 'cd4_greater_than_equal_to_200'
164
+ ELSE 'cd4_unknown_or_not_done'
165
+ END cd4_count_group,
166
+ CASE
167
+ WHEN e.recorded_start_date IS NULL THEN 1
168
+ ELSE 0
169
+ END new_patient,
170
+ e.date_enrolled,
171
+ e.earliest_start_date,
172
+ preg_or_breast.name AS maternal_status,
173
+ DATE(MIN(pregnant_or_breastfeeding.obs_datetime)) AS maternal_status_date
174
+ FROM cdr_temp_cohort_members #{current_partition} e
175
+ LEFT JOIN (
176
+ SELECT max(o.obs_datetime) AS obs_datetime, o.person_id
177
+ FROM obs #{current_partition} o
178
+ INNER JOIN concept_name cn ON cn.concept_id = o.concept_id AND cn.name = 'CD4 count' AND cn.voided = 0
179
+ INNER JOIN patient_program #{current_partition} pp ON pp.patient_id = o.person_id
180
+ AND pp.program_id = #{program('HIV PROGRAM').id}
181
+ AND pp.voided = 0
182
+ INNER JOIN patient_state #{current_partition} ps ON ps.patient_program_id = pp.patient_program_id AND ps.voided = 0 AND ps.state = 7 AND ps.start_date <= DATE('#{end_date}')
183
+ WHERE o.concept_id = #{concept_name('CD4 count').concept_id} AND o.voided = 0
184
+ AND o.obs_datetime <= '#{end_date}' AND o.obs_datetime >= '#{start_date}'
185
+ GROUP BY o.person_id
186
+ ) current_cd4 ON current_cd4.person_id = e.patient_id
187
+ LEFT JOIN obs #{current_partition} o ON o.person_id = e.patient_id AND o.concept_id = #{concept_name('CD4 count').concept_id} AND o.voided = 0 AND o.obs_datetime = current_cd4.obs_datetime
188
+ LEFT JOIN obs #{current_partition} pregnant_or_breastfeeding ON pregnant_or_breastfeeding.person_id = e.patient_id
189
+ AND pregnant_or_breastfeeding.concept_id IN (SELECT concept_id FROM concept_name WHERE name IN ('Breast feeding?', 'Breast feeding', 'Breastfeeding', 'Is patient pregnant?', 'patient pregnant') AND voided = 0)
190
+ AND pregnant_or_breastfeeding.voided = 0
191
+ AND pregnant_or_breastfeeding.value_coded = #{concept_name('Yes').concept_id}
193
192
  LEFT JOIN concept_name preg_or_breast ON preg_or_breast.concept_id = pregnant_or_breastfeeding.concept_id AND preg_or_breast.voided = 0
194
- WHERE pp.date_enrolled <= '#{end_date}' AND pp.date_enrolled >= '#{start_date}'
195
- GROUP BY pp.patient_id
196
- SQL
193
+ WHERE e.date_enrolled <= '#{end_date}' AND e.date_enrolled >= '#{start_date}'
194
+ GROUP BY e.patient_id
195
+ SQL
197
196
  end
198
197
  end
199
198
  # rubocop:enable Metrics/ClassLength
@@ -7,20 +7,28 @@ module MalawiHivProgramReports
7
7
  include MalawiHivProgramReports::Utils::CommonSqlQueryUtils
8
8
  include MalawiHivProgramReports::Adapters::Moh::Custom
9
9
  include MalawiHivProgramReports::Utils::ModelUtils
10
- attr_reader :start_date, :end_date, :location
10
+ attr_reader :start_date, :end_date, :location, :rebuild
11
11
 
12
12
  def initialize(start_date:, end_date:, **kwargs)
13
13
  @start_date = ActiveRecord::Base.connection.quote(start_date.to_date.beginning_of_day.strftime('%Y-%m-%d %H:%M:%S'))
14
14
  @end_date = ActiveRecord::Base.connection.quote(end_date.to_date.end_of_day.strftime('%Y-%m-%d %H:%M:%S'))
15
- @occupation = kwargs[:occupation]
15
+ @rebuild = kwargs[:rebuild]&.casecmp?(true)
16
16
  @location = kwargs[:location]
17
17
  end
18
18
 
19
19
  def find_report
20
+ if rebuild
21
+ cohort = MalawiHivProgramReports::Moh::CumulativeCohort.new(start_date:, end_date:, definition: 'pepfar', locations: location.to_s, rebuild: true)
22
+ cohort.find_report
23
+ end
20
24
  process_report
21
25
  end
22
26
 
23
27
  def data
28
+ if rebuild
29
+ cohort = MalawiHivProgramReports::Moh::CumulativeCohort.new(start_date:, end_date:, definition: 'pepfar', locations: location.to_s, rebuild: true)
30
+ cohort.find_report
31
+ end
24
32
  process_report
25
33
  rescue StandardError => e
26
34
  Rails.logger.error "Error running TX_RTT Report: #{e}"
@@ -47,7 +55,7 @@ module MalawiHivProgramReports
47
55
  end
48
56
 
49
57
  def process_data(report)
50
- tx_rtt.each do |row|
58
+ fetch_data.each do |row|
51
59
  age_group = row['age_group']
52
60
  gender = row['gender']
53
61
  months = row['months']
@@ -64,14 +72,17 @@ module MalawiHivProgramReports
64
72
  end
65
73
 
66
74
  def process_months(report, months, patient_id)
67
- report[:returned_less_than_3_months] << patient_id if months.blank?
68
- report[:returned_less_than_3_months] << patient_id if months < 3
69
- report[:returned_greater_than_3_months_and_less_than_6_months] << patient_id if months >= 3 && months < 6
75
+ return report[:returned_less_than_3_months] << patient_id if months.blank?
76
+ return report[:returned_less_than_3_months] << patient_id if months < 3
77
+ if months >= 3 && months < 6
78
+ return report[:returned_greater_than_3_months_and_less_than_6_months] << patient_id
79
+ end
80
+
70
81
  report[:returned_greater_than_or_equal_to_6_months] << patient_id if months >= 6
71
82
  end
72
83
 
73
84
  def process_cd4(report, months, patient_id, cd4_cat)
74
- if cd4_cat == 'unknown_cd4_count' && months <= 2
85
+ if cd4_cat == 'unknown_cd4_count' && (months.blank? || months <= 2)
75
86
  report[:not_eligible_for_cd4] << patient_id
76
87
  return
77
88
  end
@@ -120,160 +131,31 @@ module MalawiHivProgramReports
120
131
  sorted_results.sort_by { |h| [h[:gender] == 'F' ? 0 : 1] }
121
132
  end
122
133
 
123
- def tx_rtt
134
+ def fetch_data
124
135
  ActiveRecord::Base.connection.select_all <<~SQL
125
- SELECT patient_program.patient_id,
126
- #{function_manager(function: 'disaggregated_age_group', location: @location, args: "person.birthdate::date, #{@end_date}::date")} AS age_group,
127
- person.gender,
128
- IF(
129
- patient_state_at_start_of_quarter.state = 6, 'Treatment stopped',
130
- IF(
131
- patient_state_at_start_of_quarter.state = 12, 'Defaulted',
132
- #{function_manager(function: 'pepfar_patient_outcome', location: @location, args: "patient_program.patient_id, (DATE(#{@start_date}) - INTERVAL 1 DAY), #{@location}")}
133
- )
134
- ) AS initial_outcome,
135
- IF(
136
- patient_state_at_start_of_quarter.state = 6,
137
- patient_state_at_start_of_quarter.start_date,
138
- IF(
139
- patient_state_at_start_of_quarter.state = 12,
140
- patient_state_at_start_of_quarter.start_date,
141
- #{function_manager(function: 'current_pepfar_defaulter_date', location: @location, args: "patient_program.patient_id, (DATE(#{@start_date}) - INTERVAL 1 DAY), #{@location}")}
142
- )) AS initial_outcome_date,
143
- IF(
144
- patients_with_orders_at_end_of_quarter.patient_id IS NOT NULL, 'On antiretrovirals',
145
- IF(
146
- #{function_manager(function: 'current_pepfar_defaulter', location: @location, args: "patient_program.patient_id, #{@end_date}, #{@location}")} = 0,
147
- 'On antiretrovirals','Defaulted'
148
- )
149
- ) AS final_outcome,
150
- TIMESTAMPDIFF(MONTH, IF(
151
- patient_state_at_start_of_quarter.state = 6,
152
- patient_state_at_start_of_quarter.start_date,
153
- IF(
154
- patient_state_at_start_of_quarter.state = 12,
155
- patient_state_at_start_of_quarter.start_date,
156
- #{function_manager(function: 'current_pepfar_defaulter_date', location: @location, args: "patient_program.patient_id, (DATE(#{@start_date}) - INTERVAL 1 DAY), #{@location}")})
157
- ), patients_who_received_art_in_quarter.start_date) AS months,
158
- CASE
159
- WHEN cd4_result.value_numeric < 200 THEN 'cd4_less_than_200'
160
- WHEN cd4_result.value_numeric = 200 AND cd4_result.value_modifier = '=' THEN 'cd4_greater_than_or_equal_to_200'
161
- WHEN cd4_result.value_numeric = 200 AND cd4_result.value_modifier = '<' THEN 'cd4_less_than_200'
162
- WHEN cd4_result.value_numeric = 200 AND cd4_result.value_modifier = '>' THEN 'cd4_greater_than_or_equal_to_200'
163
- WHEN cd4_result.value_numeric > 200 THEN 'cd4_greater_than_or_equal_to_200'
164
- ELSE 'unknown_cd4_count'
165
- END cd4_count_group
166
- FROM patient_program #{current_partition}
167
- INNER JOIN person #{current_partition} ON person.person_id = patient_program.patient_id
168
- /* Select patients that were on treatment before start of reporting period */
169
- INNER JOIN patient_state #{current_partition} AS patient_ever_on_treatment
170
- ON patient_ever_on_treatment.patient_program_id = patient_program.patient_program_id
171
- AND patient_ever_on_treatment.state = 7
172
- AND patient_ever_on_treatment.start_date < DATE(#{start_date})
173
- AND patient_ever_on_treatment.voided = 0
174
- /* Get patient's state at the start of the quarter. */
175
- INNER JOIN (
176
- SELECT patient_program_id, MAX(patient_state.date_created) AS date_created
177
- FROM patient_state #{current_partition}
178
- INNER JOIN patient_program #{current_partition} USING (patient_program_id)
179
- WHERE patient_state.voided = 0
180
- AND patient_program.voided = 0
181
- AND patient_program.program_id = 1
182
- AND patient_state.start_date < DATE(#{start_date}) + INTERVAL 1 DAY
183
- GROUP BY patient_program_id
184
- ) AS date_of_last_patient_state_before_quarter
185
- ON date_of_last_patient_state_before_quarter.patient_program_id = patient_program.patient_program_id
186
- LEFT JOIN patient_state #{current_partition} AS patient_state_at_start_of_quarter
187
- ON patient_state_at_start_of_quarter.patient_program_id = date_of_last_patient_state_before_quarter.patient_program_id
188
- AND patient_state_at_start_of_quarter.date_created = date_of_last_patient_state_before_quarter.date_created
189
- AND patient_state_at_start_of_quarter.state IN (6, 12) /* 2: TO, 6: Tx Stopped, 12: Defaulted */
190
- /* Select patients who received ART within the reporting period. */
191
- INNER JOIN (
192
- SELECT DISTINCT encounter.patient_id, orders.start_date
193
- FROM encounter #{current_partition}
194
- INNER JOIN orders #{current_partition}
195
- ON orders.encounter_id = encounter.encounter_id
196
- AND DATE(orders.start_date) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
197
- AND orders.voided = 0
198
- INNER JOIN drug_order #{current_partition}
199
- ON drug_order.order_id = orders.order_id
200
- AND drug_order.quantity > 0
201
- AND drug_order.drug_inventory_id IN (SELECT DISTINCT drug_id FROM arv_drug)
202
- WHERE encounter.voided = 0
203
- AND encounter.program_id = 1
204
- AND DATE(encounter.encounter_datetime) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
205
- ) AS patients_who_received_art_in_quarter
206
- ON patients_who_received_art_in_quarter.patient_id = patient_program.patient_id
207
- /* Ensure that patients are on ART at the end of the quarter */
208
- INNER JOIN (
209
- SELECT patient_program_id, MAX(patient_state.date_created) AS date_created
210
- FROM patient_state #{current_partition}
211
- INNER JOIN patient_program #{current_partition} USING (patient_program_id)
212
- WHERE patient_state.voided = 0
213
- AND patient_program.voided = 0
214
- AND patient_program.program_id = 1
215
- AND patient_state.start_date < DATE(#{end_date}) + INTERVAL 1 DAY
216
- GROUP BY patient_program_id
217
- ) AS date_of_last_patient_state_in_quarter
218
- ON date_of_last_patient_state_in_quarter.patient_program_id = patient_program.patient_program_id
219
-
220
- /*Not sure why Walter had this section in but I believe its not neccessary*/
221
- /*INNER JOIN patient_state AS patient_state_at_end_of_quarter
222
- ON patient_state_at_end_of_quarter.patient_program_id = patient_program.patient_program_id
223
- AND patient_state_at_end_of_quarter.date_created = date_of_last_patient_state_before_quarter.date_created
224
- AND patient_state_at_end_of_quarter.state = 7*/
225
-
226
- /* Select patient who had orders in the last 30 days of the reporting period.
227
- This is to be used as a quick filter for patients who are definitely
228
- 'On ART' by the end of the reporting period. The rest will be filtered by
229
- the current_defaulter function. */
230
- LEFT JOIN (
231
- SELECT DISTINCT encounter.patient_id
232
- FROM encounter #{current_partition}
233
- INNER JOIN orders #{current_partition}
234
- ON orders.encounter_id = encounter.encounter_id
235
- AND orders.voided = 0
236
- AND DATE(orders.start_date) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
237
- AND DATE(orders.auto_expire_date) >= (DATE(#{end_date}) - INTERVAL 30 DAY)
238
- INNER JOIN drug_order #{current_partition}
239
- ON drug_order.order_id = orders.order_id
240
- AND drug_order.quantity > 0
241
- AND drug_order.drug_inventory_id IN (SELECT DISTINCT drug_id FROM arv_drug)
242
- WHERE encounter.program_id = 1
243
- AND DATE(encounter.encounter_datetime) BETWEEN DATE(#{start_date}) AND DATE(#{end_date})
244
- AND encounter.voided = 0
245
- ) AS patients_with_orders_at_end_of_quarter
246
- ON patients_with_orders_at_end_of_quarter.patient_id = patient_program.patient_id
247
- LEFT JOIN (
248
- SELECT max(o.obs_datetime) AS obs_datetime, o.person_id
249
- FROM obs #{current_partition} o
250
- INNER JOIN concept_name cn ON cn.concept_id = o.concept_id AND cn.name = 'CD4 count'
251
- WHERE o.concept_id = #{concept_name('CD4 count').concept_id} AND o.voided = 0
252
- AND o.obs_datetime <= #{end_date} AND o.obs_datetime >= #{start_date}
253
- GROUP BY o.person_id
254
- ) current_cd4 ON current_cd4.person_id = patient_program.patient_id
255
- LEFT JOIN obs #{current_partition} cd4_result ON cd4_result.person_id = patient_program.patient_id AND cd4_result.concept_id = #{concept_name('CD4 count').concept_id} AND cd4_result.voided = 0
256
- # Not sure why we are matching the two dates but the result was excluding cd4 results for patients.
257
- # AND cd4_result.obs_datetime = current_cd4.obs_datetime
258
- LEFT JOIN (#{current_occupation_query}) a ON a.person_id = patient_program.patient_id
259
- WHERE patient_program.program_id = 1 #{%w[Military Civilian].include?(@occupation) ? 'AND' : ''} #{occupation_filter(occupation: @occupation, field_name: 'value', table_name: 'a', include_clause: false)}
260
- /* Ensure that the patients retrieved, did not receive ART within 28 days
261
- before the start of the reporting period */
262
- AND patient_program.patient_id NOT IN (
263
- SELECT DISTINCT orders.patient_id
264
- FROM orders #{current_partition}
265
- INNER JOIN drug_order #{current_partition} USING (order_id)
266
- INNER JOIN arv_drug ON arv_drug.drug_id = drug_inventory_id
267
- INNER JOIN patient_program #{current_partition}
268
- ON patient_program.patient_id = orders.patient_id
269
- AND patient_program.program_id = 1
270
- WHERE ((DATE(orders.start_date )BETWEEN (DATE(#{start_date}) - INTERVAL 30 DAY) AND DATE(#{start_date}))
271
- OR (DATE(orders.auto_expire_date) BETWEEN (DATE(#{start_date}) - INTERVAL 30 DAY) AND DATE(#{start_date})))
272
- AND orders.voided = 0
273
- )
274
- GROUP BY patient_program.patient_id
275
- HAVING initial_outcome IN ('Defaulted', 'Treatment stopped')
276
- AND final_outcome = 'On antiretrovirals';
136
+ SELECT
137
+ e.patient_id,
138
+ disaggregated_age_group(e.birthdate, #{end_date}) AS age_group,
139
+ e.gender,
140
+ s.cum_outcome initial_outcome,
141
+ o.cum_outcome final_outcome,
142
+ TIMESTAMPDIFF(MONTH, COALESCE(s.outcome_date, c.outcome_date), ord.min_order_date) months,
143
+ CASE
144
+ WHEN cd4_result.value_numeric < 200 THEN 'cd4_less_than_200'
145
+ WHEN cd4_result.value_numeric = 200 AND cd4_result.value_modifier = '=' THEN 'cd4_greater_than_or_equal_to_200'
146
+ WHEN cd4_result.value_numeric = 200 AND cd4_result.value_modifier = '<' THEN 'cd4_less_than_200'
147
+ WHEN cd4_result.value_numeric = 200 AND cd4_result.value_modifier = '>' THEN 'cd4_greater_than_or_equal_to_200'
148
+ WHEN cd4_result.value_numeric > 200 THEN 'cd4_greater_than_or_equal_to_200'
149
+ ELSE 'unknown_cd4_count'
150
+ END cd4_count_group
151
+ FROM cdr_temp_cohort_members #{current_partition} e
152
+ INNER JOIN cdr_temp_patient_outcomes #{current_partition} o ON o.patient_id = e.patient_id AND o.cum_outcome = 'On antiretrovirals'
153
+ INNER JOIN cdr_temp_patient_outcomes_start #{current_partition} s ON s.patient_id = e.patient_id AND s.cum_outcome IN ('Defaulted', 'Treatment stopped')
154
+ INNER JOIN cdr_temp_current_state_start #{current_partition} c ON c.patient_id = e.patient_id
155
+ INNER JOIN cdr_temp_max_drug_orders #{current_partition} ord ON ord.patient_id = e.patient_id
156
+ LEFT JOIN obs #{current_partition} cd4_result ON cd4_result.person_id = e.patient_id AND cd4_result.concept_id = #{concept_name('CD4 count').concept_id} AND cd4_result.voided = 0
157
+ WHERE e.date_enrolled < #{start_date}
158
+ GROUP BY e.patient_id
277
159
  SQL
278
160
  end
279
161
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MalawiHivProgramReports
4
- VERSION = '1.0.25'
4
+ VERSION = '1.0.26'
5
5
  end