malawi_hiv_program_reports 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/services/malawi_hiv_program_reports/README.md +16 -0
- data/app/services/malawi_hiv_program_reports/adapters/moh/custom.rb +199 -0
- data/app/services/malawi_hiv_program_reports/archiving_candidates.rb +130 -0
- data/app/services/malawi_hiv_program_reports/arv_refill_periods.rb +311 -0
- data/app/services/malawi_hiv_program_reports/clinic/README.md +5 -0
- data/app/services/malawi_hiv_program_reports/clinic/appointments_report.rb +317 -0
- data/app/services/malawi_hiv_program_reports/clinic/discrepancy_report.rb +42 -0
- data/app/services/malawi_hiv_program_reports/clinic/docs/hypertension_report.md +31 -0
- data/app/services/malawi_hiv_program_reports/clinic/drug_dispensations.rb +48 -0
- data/app/services/malawi_hiv_program_reports/clinic/external_consultation_clients.rb +69 -0
- data/app/services/malawi_hiv_program_reports/clinic/hypertension_report.rb +223 -0
- data/app/services/malawi_hiv_program_reports/clinic/ipt_coverage.rb +112 -0
- data/app/services/malawi_hiv_program_reports/clinic/ipt_report.rb +69 -0
- data/app/services/malawi_hiv_program_reports/clinic/lims_results.rb +55 -0
- data/app/services/malawi_hiv_program_reports/clinic/outcome_list.rb +127 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_alive_and_on_treatment.rb +57 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_due_for_viral_load.rb +39 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_on_antiretrovirals.rb +44 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_on_dtg.rb +36 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_on_treatment.rb +42 -0
- data/app/services/malawi_hiv_program_reports/clinic/patients_with_outdated_demographics.rb +173 -0
- data/app/services/malawi_hiv_program_reports/clinic/pregnant_patients.rb +91 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimen_dispensation_data.rb +282 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimen_switch.rb +456 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimens_and_formulations.rb +182 -0
- data/app/services/malawi_hiv_program_reports/clinic/regimens_by_weight_and_gender.rb +108 -0
- data/app/services/malawi_hiv_program_reports/clinic/retention.rb +246 -0
- data/app/services/malawi_hiv_program_reports/clinic/stock_card_report.rb +65 -0
- data/app/services/malawi_hiv_program_reports/clinic/tpt_outcome.rb +494 -0
- data/app/services/malawi_hiv_program_reports/clinic/tx_rtt.rb +169 -0
- data/app/services/malawi_hiv_program_reports/clinic/viral_load.rb +292 -0
- data/app/services/malawi_hiv_program_reports/clinic/viral_load_disaggregated.rb +97 -0
- data/app/services/malawi_hiv_program_reports/clinic/viral_load_results.rb +175 -0
- data/app/services/malawi_hiv_program_reports/clinic/visits_report.rb +113 -0
- data/app/services/malawi_hiv_program_reports/clinic/vl_collection.rb +48 -0
- data/app/services/malawi_hiv_program_reports/cohort/outcomes.rb +338 -0
- data/app/services/malawi_hiv_program_reports/cohort/regimens.rb +69 -0
- data/app/services/malawi_hiv_program_reports/cohort/side_effects.rb +141 -0
- data/app/services/malawi_hiv_program_reports/cohort/tpt.rb +172 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort.rb +278 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_builder.rb +2340 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated.rb +608 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated_additions.rb +208 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_disaggregated_builder.rb +526 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_struct.rb +219 -0
- data/app/services/malawi_hiv_program_reports/moh/cohort_survival_analysis.rb +203 -0
- data/app/services/malawi_hiv_program_reports/moh/moh_tpt.rb +223 -0
- data/app/services/malawi_hiv_program_reports/moh/tpt_newly_initiated.rb +235 -0
- data/app/services/malawi_hiv_program_reports/pepfar/defaulter_list.rb +25 -0
- data/app/services/malawi_hiv_program_reports/pepfar/maternal_status.rb +29 -0
- data/app/services/malawi_hiv_program_reports/pepfar/patient_start_vl.rb +45 -0
- data/app/services/malawi_hiv_program_reports/pepfar/regimen_switch.rb +479 -0
- data/app/services/malawi_hiv_program_reports/pepfar/sc_arvdisp.rb +174 -0
- data/app/services/malawi_hiv_program_reports/pepfar/sc_curr.rb +98 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tb_prev.rb +163 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tb_prev2.rb +222 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tb_prev3.rb +421 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tpt_status.rb +181 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_ml.rb +181 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_new.rb +202 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_rtt.rb +288 -0
- data/app/services/malawi_hiv_program_reports/pepfar/tx_tb.rb +283 -0
- data/app/services/malawi_hiv_program_reports/pepfar/utils.rb +141 -0
- data/app/services/malawi_hiv_program_reports/pepfar/viral_load_coverage.rb +414 -0
- data/app/services/malawi_hiv_program_reports/pepfar/viral_load_coverage2.rb +433 -0
- data/app/services/malawi_hiv_program_reports/report_map.rb +56 -0
- data/app/services/malawi_hiv_program_reports/utils/README.md +8 -0
- data/app/services/malawi_hiv_program_reports/utils/common_sql_query_utils.rb +60 -0
- data/app/services/malawi_hiv_program_reports/utils/concurrency_utils.rb +53 -0
- data/app/services/malawi_hiv_program_reports/utils/docs/common_sql_query_utils.md +53 -0
- data/app/services/malawi_hiv_program_reports/utils/model_utils.rb +66 -0
- data/app/services/malawi_hiv_program_reports/utils/parameter_utils.rb +32 -0
- data/app/services/malawi_hiv_program_reports/utils/time_utils.rb +52 -0
- data/lib/malawi_hiv_program_reports/version.rb +1 -1
- metadata +74 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Report for Showing all HIV Viral Load Tests Done Or Sample Collected per the specified period
|
|
4
|
+
module MalawiHivProgramReports
|
|
5
|
+
module Clinic
|
|
6
|
+
class VlCollection
|
|
7
|
+
include MalawiHivProgramReports::Utils::CommonSqlQueryUtils
|
|
8
|
+
def initialize(start_date:, end_date:, **kwargs)
|
|
9
|
+
@start_date = start_date.to_date.beginning_of_day
|
|
10
|
+
@end_date = end_date.to_date.end_of_day
|
|
11
|
+
@occupation = kwargs[:occupation]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def find_report
|
|
15
|
+
data
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def data
|
|
21
|
+
ActiveRecord::Base.connection.select_all <<~SQL
|
|
22
|
+
SELECT
|
|
23
|
+
o.person_id AS patient_id,
|
|
24
|
+
pn.given_name,
|
|
25
|
+
pn.family_name,
|
|
26
|
+
p.gender,
|
|
27
|
+
p.birthdate,
|
|
28
|
+
i.identifier AS identifier,
|
|
29
|
+
DATE(ord.start_date) AS order_date
|
|
30
|
+
FROM obs o
|
|
31
|
+
INNER JOIN orders ord ON ord.order_id = o.order_id AND ord.voided = 0
|
|
32
|
+
INNER JOIN person p ON p.person_id = o.person_id AND p.voided = 0
|
|
33
|
+
INNER JOIN person_name pn ON pn.person_id = p.person_id AND pn.voided = 0
|
|
34
|
+
LEFT JOIN patient_identifier i ON i.patient_id = p.person_id AND i.voided = 0 AND i.identifier_type = #{indetifier_type}
|
|
35
|
+
LEFT JOIN (#{current_occupation_query}) AS a ON a.person_id = p.person_id
|
|
36
|
+
WHERE o.concept_id = 9737 -- Test Type
|
|
37
|
+
AND o.value_coded = 856 -- Viral Load
|
|
38
|
+
AND o.obs_datetime BETWEEN '#{@start_date}' AND '#{@end_date}'
|
|
39
|
+
AND o.voided = 0 #{%w[Military Civilian].include?(@occupation) ? 'AND' : ''} #{occupation_filter(occupation: @occupation, field_name: 'value', table_name: 'a', include_clause: false)}
|
|
40
|
+
SQL
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def indetifier_type
|
|
44
|
+
@indetifier_type ||= ::PatientIdentifierType.find_by_name!(::GlobalPropertyService.use_filing_numbers? ? 'Filing Number' : 'ARV Number').id
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MalawiHivProgramReports
|
|
4
|
+
module Cohort
|
|
5
|
+
class Outcomes
|
|
6
|
+
include MalawiHivProgramReports::Adapters::Moh::Custom
|
|
7
|
+
include MalawiHivProgramReports::Utils::ModelUtils
|
|
8
|
+
attr_reader :end_date
|
|
9
|
+
|
|
10
|
+
def initialize(end_date:, definition: 'moh', location: nil)
|
|
11
|
+
definition = definition.downcase
|
|
12
|
+
raise ::ArgumentError, "Invalid outcomes definition: #{definition}" unless %w[moh pepfar].include?(definition)
|
|
13
|
+
|
|
14
|
+
@adapter = ActiveRecord::Base.connection.adapter_name.downcase
|
|
15
|
+
@end_date = end_date.to_date
|
|
16
|
+
@definition = definition
|
|
17
|
+
@location = location
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def update_cummulative_outcomes
|
|
21
|
+
initialize_table
|
|
22
|
+
|
|
23
|
+
# HIC SUNT DRACONIS: The order of the operations below matters,
|
|
24
|
+
# do not change it unless you know what you are doing!!!
|
|
25
|
+
load_patients_who_died
|
|
26
|
+
load_patients_who_stopped_treatment
|
|
27
|
+
load_patients_on_pre_art
|
|
28
|
+
load_patients_without_state
|
|
29
|
+
load_patients_without_drug_orders
|
|
30
|
+
load_patients_on_treatment
|
|
31
|
+
load_defaulters
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def arv_drugs_concept_set
|
|
37
|
+
@arv_drugs_concept_set ||= ::ConceptSet.where(set: concept_name('Antiretroviral drugs').concept)
|
|
38
|
+
.select(:concept_id)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def drug_order_type
|
|
42
|
+
@drug_order_type ||= order_type('Drug order')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def program_states(*names)
|
|
46
|
+
::ProgramWorkflowState.joins(:program_workflow)
|
|
47
|
+
.joins(:concept)
|
|
48
|
+
.merge(::ProgramWorkflow.where(program: hiv_program))
|
|
49
|
+
.merge(::Concept.joins(:concept_names)
|
|
50
|
+
.merge(::ConceptName.where(name: names)))
|
|
51
|
+
.select(:program_workflow_state_id)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def hiv_program
|
|
55
|
+
@hiv_program ||= program('HIV Program')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def initialize_table
|
|
59
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
60
|
+
DROP TABLE IF EXISTS temp_patient_outcomes
|
|
61
|
+
SQL
|
|
62
|
+
|
|
63
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
64
|
+
CREATE TABLE temp_patient_outcomes (
|
|
65
|
+
patient_id INT NOT NULL,
|
|
66
|
+
cum_outcome VARCHAR(120) NOT NULL,
|
|
67
|
+
outcome_date DATE DEFAULT NULL,
|
|
68
|
+
site_id INT NOT NULL,
|
|
69
|
+
PRIMARY KEY (patient_id, site_id)
|
|
70
|
+
)
|
|
71
|
+
SQL
|
|
72
|
+
|
|
73
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
74
|
+
CREATE INDEX tpo_outcomes ON temp_patient_outcomes (patient_id, cum_outcome, outcome_date, site_id)
|
|
75
|
+
SQL
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Loads all patiens with an outcome of died as of given date
|
|
79
|
+
# into the temp_patient_outcomes table.
|
|
80
|
+
def load_patients_who_died
|
|
81
|
+
date = ActiveRecord::Base.connection.quote(end_date)
|
|
82
|
+
|
|
83
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
84
|
+
INSERT INTO temp_patient_outcomes
|
|
85
|
+
SELECT patients.patient_id, 'Patient died', MIN(patient_state.start_date), #{@location}
|
|
86
|
+
FROM temp_earliest_start_date AS patients
|
|
87
|
+
INNER JOIN patient_program
|
|
88
|
+
ON patient_program.patient_id = patients.patient_id
|
|
89
|
+
AND patient_program.program_id = #{hiv_program.program_id}
|
|
90
|
+
AND patient_program.voided = 0 #{site_manager(operator: 'AND', column: 'patient_program.site_id', location: @location)}
|
|
91
|
+
INNER JOIN patient_state
|
|
92
|
+
ON patient_state.patient_program_id = patient_program.patient_program_id
|
|
93
|
+
AND patient_state.state = (#{program_states('Patient died').limit(1).to_sql})
|
|
94
|
+
AND patient_state.start_date < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
95
|
+
AND patient_state.voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
96
|
+
WHERE patients.date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'patients.site_id', location: @location)}
|
|
97
|
+
GROUP BY patients.patient_id
|
|
98
|
+
SQL
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Loads all patients with an outcome of transferred out or
|
|
102
|
+
# treatment stopped into temp_patient_outcomes table.
|
|
103
|
+
def load_patients_who_stopped_treatment
|
|
104
|
+
date = ActiveRecord::Base.connection.quote(end_date)
|
|
105
|
+
|
|
106
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
107
|
+
INSERT INTO temp_patient_outcomes
|
|
108
|
+
SELECT patients.patient_id,
|
|
109
|
+
(
|
|
110
|
+
SELECT name FROM concept_name
|
|
111
|
+
WHERE concept_id = (
|
|
112
|
+
SELECT concept_id FROM program_workflow_state
|
|
113
|
+
WHERE program_workflow_state_id = patient_state.state
|
|
114
|
+
LIMIT 1
|
|
115
|
+
)
|
|
116
|
+
) AS cum_outcome,
|
|
117
|
+
patient_state.start_date, #{@location}
|
|
118
|
+
FROM temp_earliest_start_date AS patients
|
|
119
|
+
INNER JOIN patient_program
|
|
120
|
+
ON patient_program.patient_id = patients.patient_id
|
|
121
|
+
AND patient_program.program_id = #{hiv_program.program_id}
|
|
122
|
+
AND patient_program.voided = 0 #{site_manager(operator: 'AND', column: 'patient_program.site_id', location: @location)}
|
|
123
|
+
INNER JOIN patient_state
|
|
124
|
+
ON patient_state.patient_program_id = patient_program.patient_program_id
|
|
125
|
+
AND patient_state.state IN (#{program_states('Patient transferred out', 'Treatment stopped').to_sql})
|
|
126
|
+
AND patient_state.start_date < #{interval_manager(date: end_date, value: 1, interval: 'DAY', operator: '+')}
|
|
127
|
+
AND (patient_state.end_date >= #{date} OR patient_state.end_date IS NULL)
|
|
128
|
+
AND patient_state.voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
129
|
+
INNER JOIN (
|
|
130
|
+
SELECT patient_program_id, MAX(start_date) AS start_date
|
|
131
|
+
FROM patient_state
|
|
132
|
+
WHERE patient_state.start_date < #{interval_manager(date: end_date, value: 1, interval: 'DAY', operator: '+')}
|
|
133
|
+
AND patient_state.voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
134
|
+
GROUP BY patient_program_id
|
|
135
|
+
) AS max_patient_state
|
|
136
|
+
ON max_patient_state.patient_program_id = patient_state.patient_program_id
|
|
137
|
+
AND max_patient_state.start_date = patient_state.start_date #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
138
|
+
WHERE patients.date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'patients.site_id', location: @location)}
|
|
139
|
+
AND patients.patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)} )
|
|
140
|
+
GROUP BY patients.patient_id #{@adapter == 'mysql2' ? '' : ',patient_state.state, patient_state.start_date'}
|
|
141
|
+
SQL
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Load all patients on Pre-ART.
|
|
145
|
+
def load_patients_on_pre_art
|
|
146
|
+
date = ActiveRecord::Base.connection.quote(end_date)
|
|
147
|
+
|
|
148
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
149
|
+
INSERT INTO temp_patient_outcomes
|
|
150
|
+
SELECT patients.patient_id,
|
|
151
|
+
CASE
|
|
152
|
+
WHEN #{current_defaulter_function('patients.patient_id')} = 1 THEN 'Defaulted'
|
|
153
|
+
ELSE 'Pre-ART (Continue)'
|
|
154
|
+
END AS cum_outcome,
|
|
155
|
+
patient_state.start_date, #{@location}
|
|
156
|
+
FROM temp_earliest_start_date AS patients
|
|
157
|
+
INNER JOIN patient_program
|
|
158
|
+
ON patient_program.patient_id = patients.patient_id
|
|
159
|
+
AND patient_program.program_id = #{hiv_program.program_id}
|
|
160
|
+
AND patient_program.voided = 0 #{site_manager(operator: 'AND', column: 'patient_program.site_id', location: @location)}
|
|
161
|
+
INNER JOIN patient_state
|
|
162
|
+
ON patient_state.patient_program_id = patient_program.patient_program_id
|
|
163
|
+
AND patient_state.state = (#{program_states('Pre-ART (Continue)').limit(1).to_sql})
|
|
164
|
+
AND patient_state.start_date < #{interval_manager(date: end_date, value: 1, interval: 'DAY', operator: '+')}
|
|
165
|
+
AND (patient_state.end_date >= #{date} OR patient_state.end_date IS NULL)
|
|
166
|
+
AND patient_state.voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
167
|
+
INNER JOIN (
|
|
168
|
+
SELECT patient_program_id, MAX(start_date) AS start_date
|
|
169
|
+
FROM patient_state
|
|
170
|
+
WHERE patient_state.start_date < #{interval_manager(date: end_date, value: 1, interval: 'DAY', operator: '+')}
|
|
171
|
+
AND patient_state.voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
172
|
+
GROUP BY patient_program_id
|
|
173
|
+
) AS max_patient_state
|
|
174
|
+
ON max_patient_state.patient_program_id = patient_state.patient_program_id
|
|
175
|
+
AND max_patient_state.start_date = patient_state.start_date #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
176
|
+
WHERE patients.date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'patients.site_id', location: @location)}
|
|
177
|
+
AND patients.patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)} )
|
|
178
|
+
GROUP BY patients.patient_id #{@adapter == 'mysql2' ? '' : ',patient_state.start_date'}
|
|
179
|
+
SQL
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Load all patients without a state
|
|
183
|
+
def load_patients_without_state
|
|
184
|
+
date = ActiveRecord::Base.connection.quote(end_date)
|
|
185
|
+
|
|
186
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
187
|
+
INSERT INTO temp_patient_outcomes
|
|
188
|
+
SELECT patients.patient_id,
|
|
189
|
+
CASE
|
|
190
|
+
WHEN #{current_defaulter_function('patients.patient_id')} = 1 THEN 'Defaulted'
|
|
191
|
+
ELSE 'Unknown'
|
|
192
|
+
END AS cum_outcome,
|
|
193
|
+
NULL, #{@location} as site_id
|
|
194
|
+
FROM temp_earliest_start_date AS patients
|
|
195
|
+
INNER JOIN patient_program
|
|
196
|
+
ON patient_program.patient_id = patients.patient_id
|
|
197
|
+
AND patient_program.program_id = #{hiv_program.program_id}
|
|
198
|
+
AND patient_program.voided = 0 #{site_manager(operator: 'AND', column: 'patient_program.site_id', location: @location)}
|
|
199
|
+
WHERE patients.date_enrolled <= #{date}
|
|
200
|
+
AND patient_program.patient_program_id NOT IN (
|
|
201
|
+
SELECT patient_program_id
|
|
202
|
+
FROM patient_state
|
|
203
|
+
WHERE start_date < #{interval_manager(date: end_date, value: 1, interval: 'DAY', operator: '+')}
|
|
204
|
+
AND voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
205
|
+
)
|
|
206
|
+
AND patients.patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'patient_program.site_id', location: @location)} )
|
|
207
|
+
GROUP BY patients.patient_id
|
|
208
|
+
SQL
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Load all patients without drug orders or have drug orders
|
|
212
|
+
# without a quantity.
|
|
213
|
+
def load_patients_without_drug_orders
|
|
214
|
+
date = ActiveRecord::Base.connection.quote(end_date)
|
|
215
|
+
|
|
216
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
217
|
+
INSERT INTO temp_patient_outcomes
|
|
218
|
+
SELECT patients.patient_id,
|
|
219
|
+
'Unknown',
|
|
220
|
+
NULL, #{@location}
|
|
221
|
+
FROM temp_earliest_start_date AS patients
|
|
222
|
+
WHERE date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'patients.site_id', location: @location)}
|
|
223
|
+
AND patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)} )
|
|
224
|
+
AND patient_id NOT IN (
|
|
225
|
+
SELECT patient_id
|
|
226
|
+
FROM orders
|
|
227
|
+
LEFT JOIN drug_order ON orders.order_id = drug_order.order_id #{site_manager(operator: 'AND', column: 'drug_order.site_id', location: @location)}
|
|
228
|
+
WHERE start_date < #{interval_manager(date: end_date, value: 1, interval: 'DAY', operator: '+')}
|
|
229
|
+
AND quantity > 0 #{site_manager(operator: 'AND', column: 'orders.site_id', location: @location)}
|
|
230
|
+
AND order_type_id = #{drug_order_type.order_type_id}
|
|
231
|
+
AND concept_id IN (#{arv_drugs_concept_set.to_sql})
|
|
232
|
+
)
|
|
233
|
+
SQL
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Loads all patients who are on treatment
|
|
237
|
+
def load_patients_on_treatment
|
|
238
|
+
date = ActiveRecord::Base.connection.quote(end_date)
|
|
239
|
+
|
|
240
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
241
|
+
INSERT INTO temp_patient_outcomes
|
|
242
|
+
SELECT patients.patient_id, 'On antiretrovirals', patient_state.start_date, #{@location}
|
|
243
|
+
FROM temp_earliest_start_date AS patients
|
|
244
|
+
INNER JOIN patient_program
|
|
245
|
+
ON patient_program.patient_id = patients.patient_id
|
|
246
|
+
AND patient_program.program_id = #{hiv_program.program_id}
|
|
247
|
+
AND patient_program.voided = 0 #{site_manager(operator: 'AND', column: 'patient_program.site_id', location: @location)}
|
|
248
|
+
/* Get patients' `on ARV` states that are before given date */
|
|
249
|
+
INNER JOIN patient_state
|
|
250
|
+
ON patient_state.patient_program_id = patient_program.patient_program_id
|
|
251
|
+
AND patient_state.state = (#{program_states('On antiretrovirals').limit(1).to_sql})
|
|
252
|
+
AND patient_state.start_date < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
253
|
+
AND (patient_state.end_date >= #{date} OR patient_state.end_date IS NULL)
|
|
254
|
+
AND patient_state.voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
255
|
+
/* Select only the most recent state out of those retrieved above */
|
|
256
|
+
INNER JOIN (
|
|
257
|
+
SELECT patient_program_id, MAX(start_date) AS start_date
|
|
258
|
+
FROM patient_state
|
|
259
|
+
WHERE patient_state.start_date < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
260
|
+
AND patient_state.voided = 0 #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
261
|
+
GROUP BY patient_program_id
|
|
262
|
+
) AS max_patient_state
|
|
263
|
+
ON max_patient_state.patient_program_id = patient_state.patient_program_id
|
|
264
|
+
AND max_patient_state.start_date = patient_state.start_date #{site_manager(operator: 'AND', column: 'patient_state.site_id', location: @location)}
|
|
265
|
+
/* HACK: Ensure that the states captured above do correspond have corresponding
|
|
266
|
+
ARV dispensations. In other words filter out any `on ARVs` states whose
|
|
267
|
+
dispensation's may have been voided or states that were created manually
|
|
268
|
+
without any drugs being dispensed. */
|
|
269
|
+
INNER JOIN (
|
|
270
|
+
SELECT orders.patient_id, MIN(orders.auto_expire_date) AS auto_expire_date
|
|
271
|
+
FROM orders
|
|
272
|
+
INNER JOIN drug_order ON orders.order_id = drug_order.order_id #{site_manager(operator: 'AND', column: 'drug_order.site_id', location: @location)}
|
|
273
|
+
INNER JOIN (
|
|
274
|
+
SELECT patient_id, MAX(start_date) AS start_date
|
|
275
|
+
FROM orders
|
|
276
|
+
INNER JOIN drug_order ON orders.order_id = drug_order.order_id #{site_manager(operator: 'AND', column: 'drug_order.site_id', location: @location)} AND drug_order.quantity > 0
|
|
277
|
+
WHERE order_type_id = #{drug_order_type.order_type_id}
|
|
278
|
+
AND concept_id IN (#{arv_drugs_concept_set.to_sql})
|
|
279
|
+
AND orders.start_date < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
280
|
+
AND voided = 0 #{site_manager(operator: 'AND', column: 'orders.site_id', location: @location)}
|
|
281
|
+
AND patient_id IN (SELECT patient_id FROM temp_earliest_start_date #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)} )
|
|
282
|
+
AND patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)} )
|
|
283
|
+
GROUP BY patient_id
|
|
284
|
+
) AS max_drug_orders
|
|
285
|
+
ON max_drug_orders.patient_id = orders.patient_id
|
|
286
|
+
AND max_drug_orders.start_date = orders.start_date #{site_manager(operator: 'AND', column: 'orders.site_id', location: @location)}
|
|
287
|
+
WHERE order_type_id = #{drug_order_type.order_type_id}
|
|
288
|
+
AND concept_id IN (#{arv_drugs_concept_set.to_sql})
|
|
289
|
+
AND orders.start_date < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
290
|
+
AND quantity > 0
|
|
291
|
+
AND voided = 0 #{site_manager(operator: 'AND', column: 'orders.site_id', location: @location)}
|
|
292
|
+
AND orders.patient_id IN (SELECT patient_id FROM temp_earliest_start_date #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)})
|
|
293
|
+
AND orders.patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)})
|
|
294
|
+
GROUP BY orders.patient_id
|
|
295
|
+
) AS first_order_to_expire
|
|
296
|
+
ON (first_order_to_expire.auto_expire_date >= #{date} OR #{timestampdiff_manager(date1: 'DATE(first_order_to_expire.auto_expire_date)', date2: date, interval: 'DAY')} <= #{@definition == 'pepfar' ? 28 : 56})
|
|
297
|
+
AND first_order_to_expire.patient_id = patient_program.patient_id #{site_manager(operator: 'AND', column: 'patient_program.site_id', location: @location)}
|
|
298
|
+
WHERE patients.date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'patients.site_id', location: @location)}
|
|
299
|
+
AND patients.patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)} )
|
|
300
|
+
GROUP BY patients.patient_id #{@adapter == 'mysql2' ? '' : ',patient_state.start_date'}
|
|
301
|
+
SQL
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Load defaulters
|
|
305
|
+
def load_defaulters
|
|
306
|
+
date = ActiveRecord::Base.connection.quote(end_date)
|
|
307
|
+
|
|
308
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
309
|
+
INSERT INTO temp_patient_outcomes
|
|
310
|
+
SELECT patient_id, #{patient_outcome_function('patient_id')}, NULL, #{@location}
|
|
311
|
+
FROM temp_earliest_start_date
|
|
312
|
+
WHERE date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
|
|
313
|
+
AND patient_id NOT IN (SELECT patient_id FROM temp_patient_outcomes #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)} )
|
|
314
|
+
SQL
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def current_defaulter_function(sql_column)
|
|
318
|
+
defaulter_function = @definition == 'moh' ? 'current_defaulter' : 'current_pepfar_defaulter'
|
|
319
|
+
quoted_end_date = ActiveRecord::Base.connection.quote(end_date)
|
|
320
|
+
parameters = "#{sql_column}, #{quoted_end_date}, #{@location}"
|
|
321
|
+
function_manager(function: defaulter_function, location: @location, args: parameters)
|
|
322
|
+
rescue StandardError => e
|
|
323
|
+
Rails.logger.error "Error: #{e.message}"
|
|
324
|
+
raise "Invalid outcomes definition: #{@definition}"
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def patient_outcome_function(sql_column)
|
|
328
|
+
outcome_function = @definition == 'moh' ? 'patient_outcome' : 'pepfar_patient_outcome'
|
|
329
|
+
quoted_end_date = ActiveRecord::Base.connection.quote(end_date)
|
|
330
|
+
parameters = "#{sql_column}, #{quoted_end_date}, #{@location}"
|
|
331
|
+
function_manager(function: outcome_function, location: @location, args: parameters)
|
|
332
|
+
rescue StandardError => e
|
|
333
|
+
Rails.logger.error "Error: #{e.message}"
|
|
334
|
+
raise "Invalid outcomes definition: #{@definition}"
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MalawiHivProgramReports
|
|
4
|
+
module Cohort
|
|
5
|
+
class Regimens
|
|
6
|
+
include MalawiHivProgramReports::Utils::ModelUtils
|
|
7
|
+
include MalawiHivProgramReports::Adapters::Moh::Custom
|
|
8
|
+
|
|
9
|
+
def patient_regimens(date, location)
|
|
10
|
+
@location = location
|
|
11
|
+
@adapter = ActiveRecord::Base.connection.adapter_name.downcase
|
|
12
|
+
date = ActiveRecord::Base.connection.quote(date)
|
|
13
|
+
|
|
14
|
+
ActiveRecord::Base.connection.select_all <<~SQL
|
|
15
|
+
SELECT prescriptions.patient_id,
|
|
16
|
+
regimens.name AS regimen_category,
|
|
17
|
+
prescriptions.drugs,
|
|
18
|
+
prescriptions.prescription_date
|
|
19
|
+
FROM (
|
|
20
|
+
SELECT orders.patient_id,
|
|
21
|
+
#{@adapter == 'mysql2' ? 'GROUP_CONCAT(DISTINCT drug_order.drug_inventory_id ORDER BY drug_order.drug_inventory_id ASC) AS drugs,' : "(SELECT STRING_AGG(drug_inventory_id::VARCHAR, ',') FROM (SELECT DISTINCT drug_order.drug_inventory_id FROM drug_order ORDER BY drug_order.drug_inventory_id ASC) AS subquery) AS drugs,"}
|
|
22
|
+
recent_prescription.prescription_date
|
|
23
|
+
FROM temp_patient_outcomes AS outcomes
|
|
24
|
+
INNER JOIN orders
|
|
25
|
+
ON orders.patient_id = outcomes.patient_id
|
|
26
|
+
AND orders.concept_id IN (#{arv_drugs_concept_set.to_sql})
|
|
27
|
+
AND orders.voided = 0 #{site_manager(operator: 'AND', column: 'orders.site_id', location: @location)}
|
|
28
|
+
INNER JOIN drug_order
|
|
29
|
+
ON drug_order.order_id = orders.order_id AND drug_order.quantity > 0 #{site_manager(operator: 'AND', column: 'drug_order.site_id', location: @location)}
|
|
30
|
+
/* Only select drugs prescribed on the last prescription day */
|
|
31
|
+
INNER JOIN (
|
|
32
|
+
SELECT patient_id, DATE(MAX(start_date)) AS prescription_date
|
|
33
|
+
FROM orders
|
|
34
|
+
INNER JOIN drug_order
|
|
35
|
+
ON drug_order.order_id = orders.order_id
|
|
36
|
+
AND drug_order.quantity > 0 #{site_manager(operator: 'AND', column: 'drug_order.site_id', location: @location)}
|
|
37
|
+
WHERE orders.voided = 0 #{site_manager(operator: 'AND', column: 'orders.site_id', location: @location)}
|
|
38
|
+
AND orders.concept_id IN (#{arv_drugs_concept_set.to_sql})
|
|
39
|
+
AND orders.start_date < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
40
|
+
AND orders.patient_id IN (
|
|
41
|
+
SELECT patient_id FROM temp_patient_outcomes WHERE cum_outcome = 'On antiretrovirals' #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
|
|
42
|
+
)
|
|
43
|
+
GROUP BY orders.patient_id
|
|
44
|
+
) AS recent_prescription
|
|
45
|
+
ON recent_prescription.patient_id = orders.patient_id
|
|
46
|
+
AND orders.start_date
|
|
47
|
+
BETWEEN recent_prescription.prescription_date
|
|
48
|
+
AND #{interval_manager(date: 'recent_prescription.prescription_date', value: 1, interval: 'DAY', operator: '+')}
|
|
49
|
+
GROUP BY orders.patient_id #{@adapter == 'mysql2' ? '' : ', recent_prescription.prescription_date'}
|
|
50
|
+
) AS prescriptions
|
|
51
|
+
LEFT JOIN (
|
|
52
|
+
SELECT #{@adapter == 'mysql2' ? 'GROUP_CONCAT(drug.drug_id ORDER BY drug.drug_id ASC) AS drugs,' : "(SELECT STRING_AGG(drug_id::VARCHAR, ',') FROM (SELECT drug.drug_id FROM drug ORDER BY drug.drug_id ASC) AS subquery) AS drugs,"}
|
|
53
|
+
regimen_name.name AS name
|
|
54
|
+
FROM moh_regimen_combination AS combo
|
|
55
|
+
INNER JOIN moh_regimen_combination_drug AS drug USING (regimen_combination_id)
|
|
56
|
+
INNER JOIN moh_regimen_name AS regimen_name USING (regimen_name_id)
|
|
57
|
+
GROUP BY combo.regimen_combination_id, regimen_name.name#{' '}
|
|
58
|
+
) AS regimens
|
|
59
|
+
ON regimens.drugs = prescriptions.drugs
|
|
60
|
+
SQL
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def arv_drugs_concept_set
|
|
64
|
+
@arv_drugs_concept_set ||= ::ConceptSet.where(set: concept_name('Antiretroviral drugs'))
|
|
65
|
+
.select(:concept_id)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MalawiHivProgramReports
|
|
4
|
+
module Cohort
|
|
5
|
+
class SideEffects
|
|
6
|
+
include MalawiHivProgramReports::Utils::ModelUtils
|
|
7
|
+
include MalawiHivProgramReports::Adapters::Moh::Custom
|
|
8
|
+
|
|
9
|
+
def update_side_effects(date, location)
|
|
10
|
+
@location = location
|
|
11
|
+
@adapter = ActiveRecord::Base.connection.adapter_name.downcase
|
|
12
|
+
initialize_table
|
|
13
|
+
|
|
14
|
+
load_patients_with_side_effects(date)
|
|
15
|
+
load_patients_without_side_effects(date)
|
|
16
|
+
load_patients_missing_side_effects(date)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def initialize_table
|
|
20
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
21
|
+
DROP TABLE IF EXISTS temp_patient_side_effects
|
|
22
|
+
SQL
|
|
23
|
+
|
|
24
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
25
|
+
CREATE TABLE temp_patient_side_effects (
|
|
26
|
+
patient_id INT PRIMARY KEY,
|
|
27
|
+
has_se VARCHAR(120) NOT NULL,
|
|
28
|
+
site_id INT DEFAULT NULL
|
|
29
|
+
)
|
|
30
|
+
SQL
|
|
31
|
+
ActiveRecord::Base.connection.execute 'CREATE INDEX tpse_site_id ON temp_patient_side_effects(site_id)'
|
|
32
|
+
ActiveRecord::Base.connection.execute 'CREATE INDEX idx_se ON temp_patient_side_effects(has_se)'
|
|
33
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
34
|
+
CREATE INDEX idx_side_effects ON temp_patient_side_effects (patient_id, has_se, site_id)
|
|
35
|
+
SQL
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def load_patients_with_side_effects(date)
|
|
39
|
+
date = ActiveRecord::Base.connection.quote(date)
|
|
40
|
+
|
|
41
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
42
|
+
INSERT INTO temp_patient_side_effects(patient_id, has_se, site_id)
|
|
43
|
+
SELECT patients.patient_id, 'Yes', #{@location}
|
|
44
|
+
FROM temp_earliest_start_date AS patients
|
|
45
|
+
INNER JOIN temp_patient_outcomes
|
|
46
|
+
ON temp_patient_outcomes.patient_id = patients.patient_id
|
|
47
|
+
AND LOWER(temp_patient_outcomes.cum_outcome) = LOWER('On antiretrovirals') #{site_manager(operator: 'AND', column: 'temp_patient_outcomes.site_id', location: @location)}
|
|
48
|
+
INNER JOIN obs AS side_effects_group
|
|
49
|
+
ON side_effects_group.person_id = patients.patient_id
|
|
50
|
+
AND side_effects_group.concept_id = #{art_side_effects.concept_id}
|
|
51
|
+
AND side_effects_group.voided = 0 #{site_manager(operator: 'AND', column: 'side_effects_group.site_id', location: @location)}
|
|
52
|
+
/* Limit check to last visit before #{date} */
|
|
53
|
+
INNER JOIN (
|
|
54
|
+
SELECT person_id, MAX(obs_datetime) AS obs_datetime FROM obs
|
|
55
|
+
WHERE concept_id = #{art_side_effects.concept_id}
|
|
56
|
+
/* Side effects on initial visit are treated as contra-indications */
|
|
57
|
+
AND obs_datetime < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
58
|
+
AND voided = 0 #{site_manager(operator: 'AND', column: 'obs.site_id', location: @location)}
|
|
59
|
+
AND person_id IN (SELECT patient_id FROM temp_patient_outcomes WHERE LOWER(cum_outcome) = LOWER('On antiretrovirals') #{site_manager(operator: 'AND', column: 'site_id', location: @location)})
|
|
60
|
+
GROUP BY person_id
|
|
61
|
+
) AS last_visit
|
|
62
|
+
ON last_visit.person_id = side_effects_group.person_id
|
|
63
|
+
AND last_visit.obs_datetime = side_effects_group.obs_datetime
|
|
64
|
+
AND last_visit.obs_datetime >= #{interval_manager(date: 'patients.date_enrolled', value: 1, interval: 'DAY', operator: '+')}
|
|
65
|
+
INNER JOIN obs AS side_effects
|
|
66
|
+
ON side_effects.person_id = patients.patient_id
|
|
67
|
+
AND side_effects_group.obs_id = side_effects.obs_group_id
|
|
68
|
+
AND side_effects.value_coded = #{yes.concept_id}
|
|
69
|
+
AND side_effects.voided = 0 #{site_manager(operator: 'AND', column: 'side_effects.site_id', location: @location)}
|
|
70
|
+
WHERE patients.date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'patients.site_id', location: @location)}
|
|
71
|
+
GROUP BY patients.patient_id
|
|
72
|
+
SQL
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def load_patients_without_side_effects(date)
|
|
76
|
+
date = ActiveRecord::Base.connection.quote(date)
|
|
77
|
+
|
|
78
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
79
|
+
INSERT INTO temp_patient_side_effects
|
|
80
|
+
SELECT patients.patient_id, 'No', #{@location}
|
|
81
|
+
FROM temp_earliest_start_date AS patients
|
|
82
|
+
INNER JOIN temp_patient_outcomes
|
|
83
|
+
ON temp_patient_outcomes.patient_id = patients.patient_id
|
|
84
|
+
AND LOWER(temp_patient_outcomes.cum_outcome) = LOWER('On antiretrovirals') #{site_manager(operator: 'AND', column: 'temp_patient_outcomes.site_id', location: @location)}
|
|
85
|
+
INNER JOIN obs AS side_effects_group
|
|
86
|
+
ON side_effects_group.person_id = patients.patient_id
|
|
87
|
+
AND side_effects_group.concept_id = #{art_side_effects.concept_id}
|
|
88
|
+
AND side_effects_group.voided = 0 #{site_manager(operator: 'AND', column: 'side_effects_group.site_id', location: @location)}
|
|
89
|
+
/* Limit check to last visit before #{date} */
|
|
90
|
+
INNER JOIN (
|
|
91
|
+
SELECT person_id, MAX(obs_datetime) AS obs_datetime FROM obs
|
|
92
|
+
WHERE concept_id = #{art_side_effects.concept_id}
|
|
93
|
+
/* Side effects on initial visit are treated as contra-indications */
|
|
94
|
+
AND obs_datetime < #{interval_manager(date:, value: 1, interval: 'DAY', operator: '+')}
|
|
95
|
+
AND voided = 0 #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
|
|
96
|
+
AND person_id IN (
|
|
97
|
+
SELECT patient_id FROM temp_patient_outcomes WHERE LOWER(cum_outcome) = LOWER('On antiretrovirals') #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
|
|
98
|
+
)
|
|
99
|
+
GROUP BY person_id
|
|
100
|
+
) AS last_visit
|
|
101
|
+
ON last_visit.person_id = side_effects_group.person_id
|
|
102
|
+
AND last_visit.obs_datetime = side_effects_group.obs_datetime
|
|
103
|
+
AND last_visit.obs_datetime >= #{interval_manager(date: 'patients.date_enrolled', value: 1, interval: 'DAY', operator: '+')}
|
|
104
|
+
INNER JOIN obs AS side_effects
|
|
105
|
+
ON side_effects.person_id = patients.patient_id
|
|
106
|
+
AND side_effects_group.obs_id = side_effects.obs_group_id
|
|
107
|
+
AND side_effects.value_coded = #{no.concept_id}
|
|
108
|
+
AND side_effects.voided = 0 #{site_manager(operator: 'AND', column: 'side_effects.site_id', location: @location)}
|
|
109
|
+
WHERE patients.date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'patients.site_id', location: @location)}
|
|
110
|
+
AND patients.patient_id NOT IN (
|
|
111
|
+
SELECT patient_id FROM temp_patient_side_effects WHERE has_se = 'Yes' #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
|
|
112
|
+
)
|
|
113
|
+
GROUP BY patients.patient_id
|
|
114
|
+
SQL
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def load_patients_missing_side_effects(date)
|
|
118
|
+
date = ActiveRecord::Base.connection.quote(date)
|
|
119
|
+
|
|
120
|
+
ActiveRecord::Base.connection.execute <<~SQL
|
|
121
|
+
INSERT INTO temp_patient_side_effects
|
|
122
|
+
SELECT patient_id, 'Unknown', #{@location} FROM temp_earliest_start_date
|
|
123
|
+
WHERE date_enrolled <= #{date} #{site_manager(operator: 'AND', column: 'site_id', location: @location)}
|
|
124
|
+
AND patient_id NOT IN (SELECT patient_id FROM temp_patient_side_effects #{site_manager(operator: 'WHERE', column: 'site_id', location: @location)})
|
|
125
|
+
SQL
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def yes
|
|
129
|
+
@yes ||= concept_name('Yes')
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def no
|
|
133
|
+
@no ||= concept_name('No')
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def art_side_effects
|
|
137
|
+
@art_side_effects ||= concept_name('Malawi ART Side Effects')
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|