malawi_hiv_program_reports 1.0.21 → 1.0.23
Sign up to get free protection for your applications and to get access to all the features.
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: []
|