malawi_hiv_program_reports 1.0.21 → 1.0.23
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13a308e891673d2c03b82b355cbd1cb30acf9562bd4710e90b975563a7b9a5d0
|
4
|
+
data.tar.gz: 5a347a6889a9bf4cedd109e83df9146c21265b38e4aab1999ca1db3dca5f7fd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f918d797106fafc2c0ea27b5f529dbee2403583be90428e679ec27b5d2bd4bc97a541c5ee369cf7122ec9b52d63be1bb01331833e40a7c7e8ebbc950d612d319
|
7
|
+
data.tar.gz: 882a731d6f7f538e3d4cbd81fe9052ac54b15dd5b304b49d27abb097876de56daf9d4e6fcbbe5310fd69fa9003fdb3e01834071e7732afcf292ea56f895e11da
|
@@ -27,7 +27,7 @@ module MalawiHivProgramReports
|
|
27
27
|
process_thread
|
28
28
|
end_time = Time.now
|
29
29
|
time_in_minutes = ((end_time - start_time) / 60).round(2)
|
30
|
-
Rails.logger.info("Cumulative Cohort report took #{time_in_minutes} minutes to generate")
|
30
|
+
Rails.logger.info("Cumulative Cohort report took #{time_in_minutes} minutes to generate for these locations: #{locations}")
|
31
31
|
{ cohort_time: time_in_minutes }
|
32
32
|
end
|
33
33
|
|
@@ -47,7 +47,7 @@ module MalawiHivProgramReports
|
|
47
47
|
queue = Queue.new
|
48
48
|
locations.each { |loc| queue << loc }
|
49
49
|
|
50
|
-
threads = Array.new(
|
50
|
+
threads = Array.new(40) do
|
51
51
|
Thread.new do
|
52
52
|
until queue.empty?
|
53
53
|
loc = begin
|
@@ -59,6 +59,9 @@ module MalawiHivProgramReports
|
|
59
59
|
|
60
60
|
ActiveRecord::Base.connection_pool.with_connection do
|
61
61
|
process_data loc
|
62
|
+
rescue StandardError => e
|
63
|
+
Rails.logger.error("Error processing location #{loc}: #{e.message}")
|
64
|
+
save_incomplete_site(location: loc, time_taken: 0)
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
@@ -104,6 +107,13 @@ module MalawiHivProgramReports
|
|
104
107
|
SQL
|
105
108
|
end
|
106
109
|
|
110
|
+
def save_incomplete_site(location:, time_taken:)
|
111
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
112
|
+
INSERT INTO cdr_temp_cohort_status
|
113
|
+
VALUES (#{location}, DATE(#{start_date}), DATE(#{end_date}), 'incomplete', #{time_taken})
|
114
|
+
SQL
|
115
|
+
end
|
116
|
+
|
107
117
|
def create_cdr_temp_cohort_status
|
108
118
|
ActiveRecord::Base.connection.execute <<~SQL
|
109
119
|
CREATE TABLE IF NOT EXISTS cdr_temp_cohort_status (
|
@@ -24,14 +24,13 @@ module MalawiHivProgramReports
|
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
-
# The main idea here is to come up with cumulative outcomes for patients in
|
27
|
+
# The main idea here is to come up with cumulative outcomes for patients in temp_earliest_start_date
|
28
28
|
# 1. load_patients_who_died
|
29
29
|
# 2. load_patients_who_stopped_treatment
|
30
|
-
# 3.
|
31
|
-
# 4.
|
32
|
-
# 5.
|
33
|
-
# 6.
|
34
|
-
# 7. load_defaulters
|
30
|
+
# 3. load_patients_without_drug_orders
|
31
|
+
# 4. load_patients_on_treatment
|
32
|
+
# 5. load_without_clinical_contact
|
33
|
+
# 6. load_defaulters
|
35
34
|
|
36
35
|
def program_states(*names)
|
37
36
|
::ProgramWorkflowState.joins(:program_workflow)
|
@@ -47,22 +46,27 @@ module MalawiHivProgramReports
|
|
47
46
|
# ===================================
|
48
47
|
# rubocop:disable Metrics/MethodLength
|
49
48
|
def process_data
|
50
|
-
|
51
|
-
load_min_auto_expire_date
|
52
|
-
load_max_patient_state
|
53
|
-
load_max_appointment_date
|
49
|
+
denormalize
|
54
50
|
# HIC SUNT DRACONIS: The order of the operations below matters,
|
55
51
|
# do not change it unless you know what you are doing!!!
|
56
52
|
load_patients_who_died
|
57
53
|
load_patients_who_stopped_treatment
|
58
|
-
load_patients_on_pre_art
|
59
|
-
load_patients_without_state
|
60
54
|
load_patients_without_drug_orders
|
61
55
|
load_patients_on_treatment
|
62
56
|
load_without_clinical_contact
|
63
57
|
load_defaulters
|
64
58
|
end
|
65
59
|
|
60
|
+
def denormalize
|
61
|
+
load_max_drug_orders
|
62
|
+
load_patient_current_medication
|
63
|
+
update_patient_current_medication
|
64
|
+
load_min_auto_expire_date
|
65
|
+
load_max_patient_state
|
66
|
+
load_patient_current_state
|
67
|
+
update_patient_current_state
|
68
|
+
end
|
69
|
+
|
66
70
|
def load_max_drug_orders
|
67
71
|
ActiveRecord::Base.connection.execute <<~SQL
|
68
72
|
INSERT INTO cdr_temp_max_drug_orders PARTITION (p#{location})
|
@@ -80,34 +84,67 @@ module MalawiHivProgramReports
|
|
80
84
|
SQL
|
81
85
|
end
|
82
86
|
|
83
|
-
def
|
87
|
+
def load_patient_current_medication
|
84
88
|
ActiveRecord::Base.connection.execute <<~SQL
|
85
|
-
INSERT INTO
|
86
|
-
SELECT patient_id,
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
ON
|
89
|
+
INSERT INTO cdr_temp_current_medication PARTITION (p#{location})
|
90
|
+
SELECT mdo.patient_id, mdo.site_id, d.concept_id, do.drug_inventory_id drug_id,
|
91
|
+
CASE
|
92
|
+
WHEN do.equivalent_daily_dose IS NULL THEN 1
|
93
|
+
WHEN do.equivalent_daily_dose = 0 THEN 1
|
94
|
+
WHEN do.equivalent_daily_dose REGEXP '^[0-9]+(.[0-9]+)?$' THEN do.equivalent_daily_dose
|
95
|
+
ELSE 1
|
96
|
+
END daily_dose,
|
97
|
+
SUM(do.quantity) quantity,
|
98
|
+
DATE(mdo.start_date) start_date, null, null, null, null
|
99
|
+
FROM cdr_temp_max_drug_orders mdo
|
100
|
+
INNER JOIN orders o ON o.patient_id = mdo.patient_id AND o.site_id = mdo.site_id AND o.order_type_id = 1 AND DATE(o.start_date) = DATE(mdo.start_date) AND o.voided = 0
|
101
|
+
INNER JOIN drug_order do ON do.order_id = o.order_id AND do.site_id = o.site_id AND do.quantity > 0 AND do.drug_inventory_id IN (#{arv_drug})
|
102
|
+
INNER JOIN drug d ON d.drug_id = do.drug_inventory_id
|
103
|
+
WHERE mdo.site_id = #{location}
|
104
|
+
GROUP BY mdo.patient_id, do.drug_inventory_id HAVING quantity < 6000
|
105
|
+
ON DUPLICATE KEY UPDATE concept_id = VALUES(concept_id), daily_dose = VALUES(daily_dose), quantity=VALUES(quantity), start_date = VALUES(start_date), pill_count = VALUES(pill_count), expiry_date = VALUES(expiry_date), pepfar_defaulter_date = VALUES(pepfar_defaulter_date), moh_defaulter_date = VALUES(moh_defaulter_date)
|
97
106
|
SQL
|
98
107
|
end
|
99
108
|
|
100
|
-
def
|
109
|
+
def update_patient_current_medication
|
101
110
|
ActiveRecord::Base.connection.execute <<~SQL
|
102
|
-
INSERT INTO
|
103
|
-
SELECT
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
+
INSERT INTO cdr_temp_current_medication PARTITION (p#{location})
|
112
|
+
SELECT cm.patient_id, cm.site_id, cm.concept_id, cm.drug_id, cm.daily_dose, cm.quantity, cm.start_date,
|
113
|
+
COALESCE(first_ob.quantity, 0) + COALESCE(SUM(second_ob.value_numeric),0) + COALESCE(SUM(third_ob.value_numeric),0) AS pill_count,
|
114
|
+
DATE_ADD(DATE_SUB(cm.start_date, INTERVAL 1 DAY), INTERVAL (cm.quantity + COALESCE(first_ob.quantity, 0) + COALESCE(SUM(second_ob.value_numeric),0) + COALESCE(SUM(third_ob.value_numeric),0)) / cm.daily_dose DAY),
|
115
|
+
DATE_ADD(DATE_ADD(DATE_SUB(cm.start_date, INTERVAL 1 DAY), INTERVAL (cm.quantity + COALESCE(first_ob.quantity, 0) + COALESCE(SUM(second_ob.value_numeric),0) + COALESCE(SUM(third_ob.value_numeric),0)) / cm.daily_dose DAY), INTERVAL 30 DAY),
|
116
|
+
DATE_ADD(DATE_ADD(DATE_SUB(cm.start_date, INTERVAL 1 DAY), INTERVAL (cm.quantity + COALESCE(first_ob.quantity, 0) + COALESCE(SUM(second_ob.value_numeric),0) + COALESCE(SUM(third_ob.value_numeric),0)) / cm.daily_dose DAY), INTERVAL 60 DAY)
|
117
|
+
FROM cdr_temp_current_medication cm
|
118
|
+
LEFT JOIN (
|
119
|
+
SELECT ob.person_id,ob.site_id, cm.drug_id,
|
120
|
+
SUM(ob.value_numeric) + SUM(CASE
|
121
|
+
WHEN ob.value_text is null then 0
|
122
|
+
WHEN ob.value_text REGEXP '^[0-9]+(.[0-9]+)?$' then ob.value_text
|
123
|
+
ELSE 0
|
124
|
+
END) quantity
|
125
|
+
FROM obs ob
|
126
|
+
INNER JOIN cdr_temp_current_medication cm ON cm.patient_id = ob.person_id AND cm.site_id = ob.site_id AND cm.start_date = DATE(ob.obs_datetime)
|
127
|
+
INNER JOIN orders o ON o.order_id = ob.order_id AND o.site_id = ob.site_id AND o.voided = 0
|
128
|
+
INNER JOIN drug_order do ON do.order_id = o.order_id AND do.site_id = o.site_id AND do.drug_inventory_id = cm.drug_id
|
129
|
+
WHERE ob.concept_id = 2540 AND ob.voided = 0 AND ob.site_id = #{location}
|
130
|
+
GROUP BY ob.person_id, cm.drug_id
|
131
|
+
) first_ob ON first_ob.person_id = cm.patient_id AND first_ob.site_id = cm.site_id AND first_ob.drug_id = cm.drug_id
|
132
|
+
LEFT JOIN obs second_ob ON second_ob.person_id = cm.patient_id AND second_ob.site_id = cm.site_id AND second_ob.concept_id = cm.concept_id AND DATE(second_ob.obs_datetime) = cm.start_date AND second_ob.voided = 0
|
133
|
+
LEFT JOIN obs third_ob ON third_ob.person_id = cm.patient_id AND third_ob.site_id = cm.site_id AND third_ob.concept_id = 2540 AND third_ob.value_drug = cm.drug_id AND third_ob.voided = 0 AND DATE(third_ob.obs_datetime) = cm.start_date
|
134
|
+
WHERE cm.site_id = #{location}
|
135
|
+
GROUP BY cm.patient_id, cm.drug_id
|
136
|
+
ON DUPLICATE KEY UPDATE pill_count = VALUES(pill_count), expiry_date = VALUES(expiry_date), pepfar_defaulter_date = VALUES(pepfar_defaulter_date), moh_defaulter_date = VALUES(moh_defaulter_date);
|
137
|
+
SQL
|
138
|
+
end
|
139
|
+
|
140
|
+
def load_min_auto_expire_date
|
141
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
142
|
+
INSERT INTO cdr_temp_min_auto_expire_date PARTITION (p#{location})
|
143
|
+
SELECT cm.patient_id, cm.site_id, MIN(cm.start_date), MIN(cm.expiry_date), MIN(cm.pepfar_defaulter_date), MIN(cm.moh_defaulter_date)
|
144
|
+
FROM cdr_temp_current_medication cm
|
145
|
+
WHERE cm.site_id = #{location}
|
146
|
+
GROUP BY cm.patient_id
|
147
|
+
ON DUPLICATE KEY UPDATE start_date = VALUES(start_date), auto_expire_date = VALUES(auto_expire_date), pepfar_defaulter_date = VALUES(pepfar_defaulter_date), moh_defaulter_date = VALUES(moh_defaulter_date)
|
111
148
|
SQL
|
112
149
|
end
|
113
150
|
|
@@ -118,13 +155,43 @@ module MalawiHivProgramReports
|
|
118
155
|
FROM patient_state ps
|
119
156
|
INNER JOIN patient_program pp ON pp.patient_program_id = ps.patient_program_id AND pp.site_id = ps.site_id AND pp.program_id = 1 AND pp.voided = 0
|
120
157
|
WHERE ps.start_date < DATE(#{end_date}) + INTERVAL 1 DAY
|
121
|
-
AND ps.voided = 0 AND ps.site_id = #{location}
|
158
|
+
AND ps.voided = 0 AND ps.site_id = #{location} AND pp.patient_id IN (SELECT patient_id FROM temp_earliest_start_date WHERE site_id = #{location})
|
122
159
|
GROUP BY pp.patient_id, pp.site_id
|
123
160
|
HAVING start_date IS NOT NULL
|
124
161
|
ON DUPLICATE KEY UPDATE start_date = VALUES(start_date)
|
125
162
|
SQL
|
126
163
|
end
|
127
164
|
|
165
|
+
def load_patient_current_state
|
166
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
167
|
+
INSERT INTO cdr_temp_current_state PARTITION (p#{location})
|
168
|
+
SELECT mps.patient_id, mps.site_id, cn.name AS cum_outcome, ps.start_date as outcome_date, ps.state, count(DISTINCT(ps.state)) outcomes, MAX(ps.patient_state_id) patient_state_id
|
169
|
+
FROM cdr_temp_max_patient_state mps
|
170
|
+
INNER JOIN patient_program pp ON pp.patient_id = mps.patient_id AND pp.site_id = mps.site_id AND pp.program_id = 1 AND pp.voided = 0
|
171
|
+
INNER JOIN patient_state ps ON ps.patient_program_id = pp.patient_program_id AND ps.site_id = pp.site_id AND ps.start_date = mps.start_date AND ps.voided = 0
|
172
|
+
AND (ps.end_date IS NULL OR ps.end_date > DATE(#{end_date}))
|
173
|
+
INNER JOIN program_workflow_state pws ON pws.program_workflow_state_id = ps.state AND pws.retired = 0
|
174
|
+
INNER JOIN concept_name cn ON cn.concept_id = pws.concept_id AND cn.concept_name_type = 'FULLY_SPECIFIED' AND cn.voided = 0
|
175
|
+
LEFT JOIN patient_state ps2 ON ps.patient_program_id = ps2.patient_program_id AND ps2.site_id = ps.site_id AND ps.start_date = ps2.start_date AND ps.date_created < ps2.date_created AND ps2.voided = 0
|
176
|
+
WHERE ps2.patient_program_id IS NULL AND ps.voided = 0 AND mps.site_id = #{location}
|
177
|
+
GROUP BY mps.patient_id
|
178
|
+
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), state = VALUES(state), outcomes = VALUES(outcomes)
|
179
|
+
SQL
|
180
|
+
end
|
181
|
+
|
182
|
+
def update_patient_current_state
|
183
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
184
|
+
INSERT INTO cdr_temp_current_state
|
185
|
+
SELECT cs.patient_id, cs.site_id, cn.name as cum_outcome, ps.start_date as outcome_date, ps.state, 1, cs.patient_state_id
|
186
|
+
FROM patient_state ps
|
187
|
+
INNER JOIN cdr_temp_current_state cs ON cs.patient_state_id = ps.patient_state_id AND cs.site_id = ps.site_id
|
188
|
+
INNER JOIN program_workflow_state pws ON pws.program_workflow_state_id = ps.state AND pws.retired = 0
|
189
|
+
INNER JOIN concept_name cn ON cn.concept_id = pws.concept_id AND cn.concept_name_type = 'FULLY_SPECIFIED' AND cn.voided = 0
|
190
|
+
WHERE ps.voided = 0 AND cs.outcomes > 1 AND cs.site_id = #{location}
|
191
|
+
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), state = VALUES(state), outcomes = VALUES(outcomes), patient_state_id = VALUES(patient_state_id)
|
192
|
+
SQL
|
193
|
+
end
|
194
|
+
|
128
195
|
# Loads all patiens with an outcome of died as of given date
|
129
196
|
# into the temp_patient_outcomes table.
|
130
197
|
def load_patients_who_died
|
@@ -160,98 +227,20 @@ module MalawiHivProgramReports
|
|
160
227
|
ActiveRecord::Base.connection.execute <<~SQL
|
161
228
|
INSERT INTO cdr_temp_patient_outcomes PARTITION (p#{location})
|
162
229
|
SELECT patients.patient_id,
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
AND patient_program.voided = 0
|
178
|
-
INNER JOIN patient_state
|
179
|
-
ON patient_state.patient_program_id = patient_program.patient_program_id
|
180
|
-
AND patient_state.site_id = patient_program.site_id
|
181
|
-
AND patient_state.state IN (#{program_states('Patient transferred out', 'Treatment stopped').to_sql})
|
182
|
-
AND patient_state.start_date < DATE(#{end_date}) + INTERVAL 1 DAY
|
183
|
-
AND (patient_state.end_date >= #{end_date} OR patient_state.end_date IS NULL)
|
184
|
-
AND patient_state.voided = 0
|
185
|
-
INNER JOIN cdr_temp_max_patient_state AS max_patient_state
|
186
|
-
ON max_patient_state.patient_id = patient_program.patient_id
|
187
|
-
AND max_patient_state.site_id = patient_state.site_id
|
188
|
-
AND max_patient_state.start_date = patient_state.start_date
|
189
|
-
WHERE patients.date_enrolled <= #{end_date} AND patients.site_id = #{location}
|
190
|
-
AND (patients.patient_id, patients.site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step = 1)
|
191
|
-
GROUP BY patients.patient_id, patients.site_id
|
192
|
-
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), step = VALUES(step)
|
193
|
-
SQL
|
194
|
-
end
|
195
|
-
|
196
|
-
# Load all patients on Pre-ART.
|
197
|
-
def load_patients_on_pre_art
|
198
|
-
ActiveRecord::Base.connection.execute <<~SQL
|
199
|
-
INSERT INTO cdr_temp_patient_outcomes PARTITION (p#{location})
|
200
|
-
SELECT patients.patient_id,
|
201
|
-
CASE
|
202
|
-
WHEN #{current_defaulter_function('patients.patient_id', 'patients.site_id')} = 1 THEN 'Defaulted'
|
203
|
-
ELSE 'Pre-ART (Continue)'
|
204
|
-
END AS cum_outcome,
|
205
|
-
patient_state.start_date, patients.site_id, 3
|
206
|
-
FROM cdr_temp_cohort_members AS patients
|
207
|
-
INNER JOIN patient_program
|
208
|
-
ON patient_program.patient_id = patients.patient_id
|
209
|
-
AND patient_program.site_id = patients.site_id
|
210
|
-
AND patient_program.program_id = 1
|
211
|
-
AND patient_program.voided = 0
|
212
|
-
INNER JOIN patient_state
|
213
|
-
ON patient_state.patient_program_id = patient_program.patient_program_id
|
214
|
-
AND patient_state.site_id = patient_program.site_id
|
215
|
-
AND patient_state.state = (#{program_states('Pre-ART (Continue)').limit(1).to_sql})
|
216
|
-
AND patient_state.start_date < DATE(#{end_date}) + INTERVAL 1 DAY
|
217
|
-
AND (patient_state.end_date >= #{end_date} OR patient_state.end_date IS NULL)
|
218
|
-
AND patient_state.voided = 0
|
219
|
-
INNER JOIN cdr_temp_max_patient_state AS max_patient_state
|
220
|
-
ON max_patient_state.patient_id = patient_program.patient_id
|
221
|
-
AND max_patient_state.site_id = patient_state.site_id
|
222
|
-
AND max_patient_state.start_date = patient_state.start_date
|
223
|
-
WHERE patients.date_enrolled <= #{end_date} AND patients.site_id = #{location}
|
224
|
-
AND (patients.patient_id, patients.site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2))
|
225
|
-
GROUP BY patients.patient_id, patients.site_id
|
226
|
-
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), step = VALUES(step)
|
227
|
-
SQL
|
228
|
-
end
|
229
|
-
|
230
|
-
# Load all patients without a state
|
231
|
-
def load_patients_without_state
|
232
|
-
ActiveRecord::Base.connection.execute <<~SQL
|
233
|
-
INSERT INTO cdr_temp_patient_outcomes PARTITION (p#{location})
|
234
|
-
SELECT patients.patient_id,
|
235
|
-
CASE
|
236
|
-
WHEN #{current_defaulter_function('patients.patient_id', 'patients.site_id')} = 1 THEN 'Defaulted'
|
237
|
-
ELSE 'Unknown'
|
238
|
-
END AS cum_outcome,
|
239
|
-
NULL, patients.site_id, 4
|
240
|
-
FROM cdr_temp_cohort_members AS patients
|
241
|
-
INNER JOIN patient_program
|
242
|
-
ON patient_program.patient_id = patients.patient_id
|
243
|
-
AND patient_program.site_id = patients.site_id
|
244
|
-
AND patient_program.program_id = 1
|
245
|
-
AND patient_program.voided = 0
|
246
|
-
WHERE patients.date_enrolled <= #{end_date} AND patients.site_id = #{location}
|
247
|
-
AND (patient_program.patient_program_id, patient_program.site_id) NOT IN (
|
248
|
-
SELECT patient_program_id, site_id
|
249
|
-
FROM patient_state
|
250
|
-
WHERE start_date < DATE(#{end_date}) + INTERVAL 1 DAY AND voided = 0
|
251
|
-
)
|
252
|
-
AND (patients.patient_id, patients.site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3))
|
253
|
-
GROUP BY patients.patient_id, patients.site_id
|
254
|
-
HAVING cum_outcome = 'Defaulted'
|
230
|
+
patients.cum_outcome,
|
231
|
+
patients.outcome_date, patients.site_id, 2
|
232
|
+
FROM cdr_temp_current_state AS patients
|
233
|
+
WHERE (patients.patient_id) NOT IN (SELECT patient_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step = 1)
|
234
|
+
AND patients.outcomes = 1
|
235
|
+
AND patients.site_id = #{location}
|
236
|
+
AND patients.state IN (
|
237
|
+
SELECT pws.program_workflow_state_id state
|
238
|
+
FROM program_workflow pw
|
239
|
+
INNER JOIN program_workflow_state pws ON pws.program_workflow_id = pw.program_workflow_id AND pws.retired = 0
|
240
|
+
WHERE pw.program_id = 1 AND pw.retired = 0 AND pws.terminal = 1
|
241
|
+
AND pws.program_workflow_state_id IN (2, 3, 6) -- Transferred out,Patient Died, Treatment stopped
|
242
|
+
)
|
243
|
+
GROUP BY patients.patient_id
|
255
244
|
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), step = VALUES(step)
|
256
245
|
SQL
|
257
246
|
end
|
@@ -261,9 +250,7 @@ module MalawiHivProgramReports
|
|
261
250
|
def load_patients_without_drug_orders
|
262
251
|
ActiveRecord::Base.connection.execute <<~SQL
|
263
252
|
INSERT INTO cdr_temp_patient_outcomes PARTITION (p#{location})
|
264
|
-
SELECT patients.patient_id,
|
265
|
-
'Unknown',
|
266
|
-
NULL, patients.site_id, 5
|
253
|
+
SELECT patients.patient_id, 'Unknown', NULL, patients.site_id, 3
|
267
254
|
FROM cdr_temp_cohort_members AS patients
|
268
255
|
WHERE date_enrolled <= #{end_date} AND site_id = #{location}
|
269
256
|
AND (patient_id, site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3, 4))
|
@@ -276,37 +263,12 @@ module MalawiHivProgramReports
|
|
276
263
|
def load_patients_on_treatment
|
277
264
|
ActiveRecord::Base.connection.execute <<~SQL
|
278
265
|
INSERT INTO cdr_temp_patient_outcomes PARTITION (p#{location})
|
279
|
-
SELECT patients.patient_id, 'On antiretrovirals',
|
280
|
-
FROM
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
AND patient_program.voided = 0
|
286
|
-
/* Get patients' `on ARV` states that are before given date */
|
287
|
-
INNER JOIN patient_state
|
288
|
-
ON patient_state.patient_program_id = patient_program.patient_program_id
|
289
|
-
AND patient_state.site_id = patient_program.site_id
|
290
|
-
AND patient_state.state = 7 -- ON ART
|
291
|
-
AND patient_state.start_date < DATE(#{end_date}) + INTERVAL 1 DAY
|
292
|
-
AND (patient_state.end_date >= #{end_date} OR patient_state.end_date IS NULL)
|
293
|
-
AND patient_state.voided = 0
|
294
|
-
/* Select only the most recent state out of those retrieved above */
|
295
|
-
INNER JOIN cdr_temp_max_patient_state AS max_patient_state
|
296
|
-
ON max_patient_state.patient_id = patient_program.patient_id
|
297
|
-
AND max_patient_state.site_id = patient_state.site_id
|
298
|
-
AND max_patient_state.start_date = patient_state.start_date
|
299
|
-
/* HACK: Ensure that the states captured above do correspond have corresponding
|
300
|
-
ARV dispensations. In other words filter out any `on ARVs` states whose
|
301
|
-
dispensation's may have been voided or states that were created manually
|
302
|
-
without any drugs being dispensed. */
|
303
|
-
INNER JOIN cdr_temp_min_auto_expire_date AS first_order_to_expire
|
304
|
-
ON first_order_to_expire.patient_id = patient_program.patient_id
|
305
|
-
AND first_order_to_expire.site_id = patient_program.site_id
|
306
|
-
AND (first_order_to_expire.auto_expire_date >= #{end_date} OR TIMESTAMPDIFF(DAY,first_order_to_expire.auto_expire_date, #{end_date}) <= #{@definition == 'pepfar' ? 28 : 56})
|
307
|
-
WHERE patients.date_enrolled <= #{end_date} AND patients.site_id = #{location}
|
308
|
-
AND (patients.patient_id, patients.site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3, 4, 5))
|
309
|
-
GROUP BY patients.patient_id, patients.site_id
|
266
|
+
SELECT patients.patient_id, 'On antiretrovirals', COALESCE(cs.outcome_date, patients.start_date), patients.site_id, 4
|
267
|
+
FROM cdr_temp_min_auto_expire_date AS patients
|
268
|
+
LEFT JOIN cdr_temp_current_state AS cs ON cs.patient_id = patients.patient_id AND cs.site_id = patients.site_id
|
269
|
+
WHERE patients.#{@definition == 'pepfar' ? 'pepfar_defaulter_date' : 'moh_defaulter_date'} > #{end_date}
|
270
|
+
AND (patients.patient_id) NOT IN (SELECT patient_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3))
|
271
|
+
AND patients.site_id = #{location}
|
310
272
|
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), step = VALUES(step)
|
311
273
|
SQL
|
312
274
|
end
|
@@ -314,38 +276,12 @@ module MalawiHivProgramReports
|
|
314
276
|
def load_without_clinical_contact
|
315
277
|
ActiveRecord::Base.connection.execute <<~SQL
|
316
278
|
INSERT INTO cdr_temp_patient_outcomes PARTITION (p#{location})
|
317
|
-
SELECT patients.patient_id, 'Defaulted',
|
318
|
-
FROM
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
AND patient_program.voided = 0
|
324
|
-
/* Get patients' `on ARV` states that are before given date */
|
325
|
-
INNER JOIN patient_state
|
326
|
-
ON patient_state.patient_program_id = patient_program.patient_program_id
|
327
|
-
AND patient_state.site_id = patient_program.site_id
|
328
|
-
AND patient_state.state = 7 -- On ART
|
329
|
-
AND patient_state.start_date < DATE(#{end_date}) + INTERVAL 1 DAY
|
330
|
-
AND (patient_state.end_date >= #{end_date} OR patient_state.end_date IS NULL)
|
331
|
-
AND patient_state.voided = 0
|
332
|
-
/* Select only the most recent state out of those retrieved above */
|
333
|
-
INNER JOIN cdr_temp_max_patient_state AS max_patient_state
|
334
|
-
ON max_patient_state.patient_id = patient_program.patient_id
|
335
|
-
AND max_patient_state.site_id = patient_state.site_id
|
336
|
-
AND max_patient_state.start_date = patient_state.start_date
|
337
|
-
INNER JOIN cdr_temp_max_patient_appointment app ON app.patient_id = patients.patient_id
|
338
|
-
AND app.site_id = patients.site_id AND app.appointment_date < #{end_date}
|
339
|
-
INNER JOIN cdr_temp_min_auto_expire_date AS first_order_to_expire
|
340
|
-
ON first_order_to_expire.patient_id = patient_program.patient_id
|
341
|
-
AND first_order_to_expire.site_id = patient_program.site_id
|
342
|
-
AND TIMESTAMPDIFF(DAY,app.appointment_date, first_order_to_expire.auto_expire_date) >= 0
|
343
|
-
AND TIMESTAMPDIFF(DAY,app.appointment_date, first_order_to_expire.auto_expire_date) <= 5
|
344
|
-
AND first_order_to_expire.auto_expire_date < #{end_date}
|
345
|
-
AND TIMESTAMPDIFF(DAY,first_order_to_expire.auto_expire_date, #{end_date}) >= 365
|
346
|
-
WHERE patients.date_enrolled <= #{end_date} AND patients.site_id = #{location}
|
347
|
-
AND (patients.patient_id, patients.site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3, 4, 5, 6))
|
348
|
-
GROUP BY patients.patient_id, patients.site_id
|
279
|
+
SELECT patients.patient_id, 'Defaulted', patients.#{@definition == 'pepfar' ? 'pepfar_defaulter_date' : 'moh_defaulter_date'}, patients.site_id, 5
|
280
|
+
FROM cdr_temp_current_medication AS patients
|
281
|
+
LEFT JOIN cdr_temp_current_state AS cs ON cs.patient_id = patients.patient_id AND cs.site_id = patients.site_id#{' '}
|
282
|
+
WHERE patients.#{@definition == 'pepfar' ? 'pepfar_defaulter_date' : 'moh_defaulter_date'} <= #{end_date}
|
283
|
+
AND (patients.patient_id) NOT IN (SELECT patient_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3, 4))
|
284
|
+
AND patients.site_id = #{location}
|
349
285
|
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), step = VALUES(step)
|
350
286
|
SQL
|
351
287
|
end
|
@@ -354,10 +290,10 @@ module MalawiHivProgramReports
|
|
354
290
|
def load_defaulters
|
355
291
|
ActiveRecord::Base.connection.execute <<~SQL
|
356
292
|
INSERT INTO cdr_temp_patient_outcomes PARTITION (p#{location})
|
357
|
-
SELECT patient_id, #{patient_outcome_function('patient_id', 'site_id')}, NULL, site_id,
|
293
|
+
SELECT patient_id, #{patient_outcome_function('patient_id', 'site_id')}, NULL, site_id, 6
|
358
294
|
FROM cdr_temp_cohort_members
|
359
295
|
WHERE date_enrolled <= #{end_date} AND site_id = #{location}
|
360
|
-
AND (patient_id, site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3, 4, 5
|
296
|
+
AND (patient_id, site_id) NOT IN (SELECT patient_id, site_id FROM cdr_temp_patient_outcomes PARTITION (p#{location}) WHERE step IN (1, 2, 3, 4, 5))
|
361
297
|
ON DUPLICATE KEY UPDATE cum_outcome = VALUES(cum_outcome), outcome_date = VALUES(outcome_date), step = VALUES(step)
|
362
298
|
SQL
|
363
299
|
end
|
@@ -367,15 +303,6 @@ module MalawiHivProgramReports
|
|
367
303
|
# ===================================
|
368
304
|
# Function Management Region
|
369
305
|
# ===================================
|
370
|
-
|
371
|
-
def current_defaulter_function(sql_column, site_id)
|
372
|
-
case definition
|
373
|
-
when 'moh' then "current_defaulter(#{sql_column}, #{end_date}, #{site_id})"
|
374
|
-
when 'pepfar' then "current_pepfar_defaulter(#{sql_column}, #{end_date}, #{site_id})"
|
375
|
-
else raise "Invalid outcomes definition: #{definition}" # Should never happen but you never know!
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
306
|
def patient_outcome_function(sql_column, site_id)
|
380
307
|
case definition
|
381
308
|
when 'moh' then "patient_outcome(#{sql_column}, #{end_date}, #{site_id})"
|
@@ -391,8 +318,11 @@ module MalawiHivProgramReports
|
|
391
318
|
create_outcome_table unless check_if_table_exists('cdr_temp_patient_outcomes')
|
392
319
|
create_tmp_max_drug_orders_table unless check_if_table_exists('cdr_temp_max_drug_orders')
|
393
320
|
create_tmp_min_auto_expire_date unless check_if_table_exists('cdr_temp_min_auto_expire_date')
|
321
|
+
drop_tmp_min_auto_expirte_date unless count_table_columns('cdr_temp_min_auto_expire_date') == 6
|
394
322
|
create_cdr_temp_max_patient_state unless check_if_table_exists('cdr_temp_max_patient_state')
|
395
|
-
|
323
|
+
create_temp_current_state unless check_if_table_exists('cdr_temp_current_state')
|
324
|
+
drop_temp_current_state unless count_table_columns('cdr_temp_current_state') == 7
|
325
|
+
create_temp_current_medication unless check_if_table_exists('cdr_temp_current_medication')
|
396
326
|
end
|
397
327
|
|
398
328
|
def check_if_table_exists(table_name)
|
@@ -405,6 +335,16 @@ module MalawiHivProgramReports
|
|
405
335
|
result['count'].to_i.positive?
|
406
336
|
end
|
407
337
|
|
338
|
+
def count_table_columns(table_name)
|
339
|
+
result = ActiveRecord::Base.connection.select_one <<~SQL
|
340
|
+
SELECT COUNT(*) AS count
|
341
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
342
|
+
WHERE table_schema = DATABASE()
|
343
|
+
AND table_name = '#{table_name}'
|
344
|
+
SQL
|
345
|
+
result['count'].to_i
|
346
|
+
end
|
347
|
+
|
408
348
|
def create_outcome_table
|
409
349
|
ActiveRecord::Base.connection.execute <<~SQL
|
410
350
|
CREATE TABLE IF NOT EXISTS cdr_temp_patient_outcomes (
|
@@ -456,7 +396,10 @@ module MalawiHivProgramReports
|
|
456
396
|
CREATE TABLE IF NOT EXISTS cdr_temp_min_auto_expire_date (
|
457
397
|
patient_id INT NOT NULL,
|
458
398
|
site_id INT NOT NULL,
|
399
|
+
start_date DATE DEFAULT NULL,
|
459
400
|
auto_expire_date DATE DEFAULT NULL,
|
401
|
+
pepfar_defaulter_date DATE DEFAULT NULL,
|
402
|
+
moh_defaulter_date DATE DEFAULT NULL,
|
460
403
|
PRIMARY KEY (patient_id, site_id)
|
461
404
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
462
405
|
PARTITION BY LIST(site_id) (#{partition_by_site})
|
@@ -466,7 +409,13 @@ module MalawiHivProgramReports
|
|
466
409
|
|
467
410
|
def create_min_auto_expire_date_indexes
|
468
411
|
ActiveRecord::Base.connection.execute <<~SQL
|
469
|
-
CREATE INDEX idx_min_auto_expire_date ON
|
412
|
+
CREATE INDEX idx_min_auto_expire_date ON temp_min_auto_expire_date (auto_expire_date)
|
413
|
+
SQL
|
414
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
415
|
+
CREATE INDEX idx_min_pepfar ON temp_min_auto_expire_date (pepfar_defaulter_date)
|
416
|
+
SQL
|
417
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
418
|
+
CREATE INDEX idx_min_moh ON temp_min_auto_expire_date (moh_defaulter_date)
|
470
419
|
SQL
|
471
420
|
end
|
472
421
|
|
@@ -489,25 +438,84 @@ module MalawiHivProgramReports
|
|
489
438
|
SQL
|
490
439
|
end
|
491
440
|
|
492
|
-
def
|
441
|
+
def create_temp_current_state
|
493
442
|
ActiveRecord::Base.connection.execute <<~SQL
|
494
|
-
CREATE TABLE IF NOT EXISTS
|
443
|
+
CREATE TABLE IF NOT EXISTS cdr_temp_current_state(
|
495
444
|
patient_id INT NOT NULL,
|
496
445
|
site_id INT NOT NULL,
|
497
|
-
|
498
|
-
|
446
|
+
cum_outcome VARCHAR(120) NOT NULL,
|
447
|
+
outcome_date DATE DEFAULT NULL,
|
448
|
+
state INT NOT NULL,
|
449
|
+
outcomes INT NOT NULL,
|
450
|
+
patient_state_id INT NOT NULL,
|
451
|
+
PRIMARY KEY(patient_id, site_id)
|
452
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
453
|
+
PARTITION BY LIST(site_id) (#{partition_by_site})
|
454
|
+
SQL
|
455
|
+
create_current_state_index
|
456
|
+
end
|
457
|
+
|
458
|
+
def create_current_state_index
|
459
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
460
|
+
CREATE INDEX idx_state_name ON cdr_temp_current_state (cum_outcome)
|
461
|
+
SQL
|
462
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
463
|
+
CREATE INDEX idx_state_id ON cdr_temp_current_state (state)
|
464
|
+
SQL
|
465
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
466
|
+
CREATE INDEX idx_state_count ON cdr_temp_current_state (outcomes)
|
467
|
+
SQL
|
468
|
+
end
|
469
|
+
|
470
|
+
def create_temp_current_medication
|
471
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
472
|
+
CREATE TABLE IF NOT EXISTS cdr_temp_current_medication(
|
473
|
+
patient_id INT NOT NULL,
|
474
|
+
site_id INT NOT NULL,
|
475
|
+
concept_id INT NOT NULL,
|
476
|
+
drug_id INT NOT NULL,
|
477
|
+
daily_dose DECIMAL(32,2) NOT NULL,
|
478
|
+
quantity DECIMAL(32,2) NOT NULL,
|
479
|
+
start_date DATE NOT NULL,
|
480
|
+
pill_count DECIMAL(32,2) NULL,
|
481
|
+
expiry_date DATE NULL,
|
482
|
+
pepfar_defaulter_date DATE NULL,
|
483
|
+
moh_defaulter_date DATE NULL,
|
484
|
+
PRIMARY KEY(patient_id, site_id, drug_id)
|
499
485
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
500
486
|
PARTITION BY LIST(site_id) (#{partition_by_site})
|
501
487
|
SQL
|
502
|
-
|
488
|
+
craete_tmp_current_med_index
|
503
489
|
end
|
504
490
|
|
505
|
-
def
|
491
|
+
def craete_tmp_current_med_index
|
492
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
493
|
+
CREATE INDEX idx_cm_concept ON cdr_temp_current_medication (concept_id)
|
494
|
+
SQL
|
495
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
496
|
+
CREATE INDEX idx_cm_drug ON cdr_temp_current_medication (drug_id)
|
497
|
+
SQL
|
498
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
499
|
+
CREATE INDEX idx_cm_date ON cdr_temp_current_medication (start_date)
|
500
|
+
SQL
|
501
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
502
|
+
CREATE INDEX idx_cm_pepfar ON cdr_temp_current_medication (pepfar_defaulter_date)
|
503
|
+
SQL
|
506
504
|
ActiveRecord::Base.connection.execute <<~SQL
|
507
|
-
CREATE INDEX
|
505
|
+
CREATE INDEX idx_cm_moh ON cdr_temp_current_medication (moh_defaulter_date)
|
508
506
|
SQL
|
509
507
|
end
|
510
508
|
|
509
|
+
def drop_tmp_min_auto_expirte_date
|
510
|
+
ActiveRecord::Base.connection.execute 'DROP TABLE cdr_temp_min_auto_expire_date'
|
511
|
+
create_tmp_min_auto_expire_date
|
512
|
+
end
|
513
|
+
|
514
|
+
def drop_temp_current_state
|
515
|
+
ActiveRecord::Base.connection.execute 'DROP TABLE cdr_temp_current_state'
|
516
|
+
create_temp_current_state
|
517
|
+
end
|
518
|
+
|
511
519
|
def update_steps
|
512
520
|
ActiveRecord::Base.connection.execute <<~SQL
|
513
521
|
UPDATE cdr_temp_patient_outcomes SET step = 0 WHERE step > 0 AND site_id = #{location}
|
@@ -525,15 +533,15 @@ module MalawiHivProgramReports
|
|
525
533
|
ActiveRecord::Base.connection.execute('TRUNCATE cdr_temp_max_drug_orders')
|
526
534
|
ActiveRecord::Base.connection.execute('TRUNCATE cdr_temp_min_auto_expire_date')
|
527
535
|
ActiveRecord::Base.connection.execute('TRUNCATE cdr_temp_max_patient_state')
|
528
|
-
ActiveRecord::Base.connection.execute('TRUNCATE
|
529
|
-
ActiveRecord::Base.connection.execute('TRUNCATE
|
536
|
+
ActiveRecord::Base.connection.execute('TRUNCATE cdr_temp_current_state')
|
537
|
+
ActiveRecord::Base.connection.execute('TRUNCATE cdr_temp_current_medication')
|
530
538
|
else
|
531
539
|
ActiveRecord::Base.connection.execute("DELETE FROM cdr_temp_patient_outcomes WHERE site_id = #{location}")
|
532
540
|
ActiveRecord::Base.connection.execute("DELETE FROM cdr_temp_max_drug_orders WHERE site_id = #{location}")
|
533
541
|
ActiveRecord::Base.connection.execute("DELETE FROM cdr_temp_min_auto_expire_date WHERE site_id = #{location}")
|
534
542
|
ActiveRecord::Base.connection.execute("DELETE FROM cdr_temp_max_patient_state WHERE site_id = #{location}")
|
535
|
-
ActiveRecord::Base.connection.execute("DELETE FROM
|
536
|
-
ActiveRecord::Base.connection.execute("DELETE FROM
|
543
|
+
ActiveRecord::Base.connection.execute("DELETE FROM cdr_temp_current_state WHERE site_id = #{location}")
|
544
|
+
ActiveRecord::Base.connection.execute("DELETE FROM cdr_temp_current_medication WHERE site_id = #{location}")
|
537
545
|
end
|
538
546
|
end
|
539
547
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: malawi_hiv_program_reports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.23
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roy Chanunkha
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05
|
11
|
+
date: 2024-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -174,7 +174,7 @@ licenses:
|
|
174
174
|
metadata:
|
175
175
|
source_code_uri: https://github.com/EGPAFMalawiHIS/malawi_hiv_program_reports
|
176
176
|
rubygems_mfa_required: 'true'
|
177
|
-
post_install_message:
|
177
|
+
post_install_message:
|
178
178
|
rdoc_options: []
|
179
179
|
require_paths:
|
180
180
|
- lib
|
@@ -189,8 +189,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
189
|
- !ruby/object:Gem::Version
|
190
190
|
version: '0'
|
191
191
|
requirements: []
|
192
|
-
rubygems_version: 3.
|
193
|
-
signing_key:
|
192
|
+
rubygems_version: 3.5.6
|
193
|
+
signing_key:
|
194
194
|
specification_version: 4
|
195
195
|
summary: Malawi HIV PROGRAM Reports for Ruby on Rails
|
196
196
|
test_files: []
|