emr_ohsp_interface 0.1.0 → 0.5.0

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: 6fcec054826eeae6514b895fa86875cabf197b38518c30f85ceba1db894bbced
4
- data.tar.gz: 1ad95664c8d0f5d5a87069e42f6fa9bfbd8095f70473f5d842e75d2c916fa240
3
+ metadata.gz: 474cd01fab975e0d16f3c70e36e86f5723f8e7ab41497537c9e301d8d1dcdef4
4
+ data.tar.gz: d949f4630492570b5a5dee8426492e23846498a629ab24cdaa77eb100ce95321
5
5
  SHA512:
6
- metadata.gz: 240a306c8c35d3b2ce53f348afd7f135e8f08fe0c126697cb60fa895632af43335d90112917b16db2a9997eefe5ce421aef61d3bc7690e1a7b15daed07bbdd8e
7
- data.tar.gz: 37334da676a6c066644e78613b7296ef2c8fc4c0f7cf9c9af6ac9aa9d81bfc6cf7ffd1f8fc3bce642346d0bf1a1441e66d1cdce637ac46190a1d97503ca5c90a
6
+ metadata.gz: b146539a2f7b8a50c6301f457d8d8f48fb3371da299ba4ea7f2e3cf327d473633d6f8cb414aa80e5f346f42d54936c2a6aa5d84664d07afe8d3c8658e286579c
7
+ data.tar.gz: a5a2eb25f4c916feb96bea06bbf2160b0a86ad4d08d14169d58c8f64f89bb2011a486ac6fb64d89b9e89b6f71cfe2aec701882c1a820e482d7a2a2a4a22ed12e
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ class EmrOhspInterface::EmrLimsInterfaceController < ::ApplicationController
4
+ def create
5
+ # lab_details = params.require %i[lab_details]
6
+ # render json: "#{lab_details[0]['firstname']}"
7
+ # render json:
8
+ order_params_list, clinician_id = params.require %i[lab_details clinician_id]
9
+
10
+ render json: service.create_lab_order(order_params_list, clinician_id)
11
+ end
12
+
13
+ def index
14
+ render json: service.get_lims_test_results(params[:id],params[:patient_id])
15
+ end
16
+
17
+ def get_user_info()
18
+ render json: service.get_user_details(params[:id])
19
+ end
20
+
21
+ def service
22
+ EmrOhspInterface::EmrLimsInterfaceService
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ class EmrOhspInterface::EmrOhspInterfaceController < ::ApplicationController
2
+ def weeks_generator
3
+ render json: service.weeks_generator();
4
+ end
5
+
6
+ def months_generator
7
+ render json: service.months_generator();
8
+ end
9
+
10
+ def generate_weekly_idsr_report
11
+ render json: service.generate_weekly_idsr_report(params[:request],params[:start_date],params[:end_date]);
12
+ end
13
+
14
+ def generate_monthly_idsr_report
15
+ render json: service.generate_monthly_idsr_report(params[:request],params[:start_date],params[:end_date]);
16
+ end
17
+
18
+ def service
19
+ EmrOhspInterface::EmrOhspInterfaceService
20
+ end
21
+ end
@@ -0,0 +1,410 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'emr_ohsp_interface/version'
4
+ module EmrOhspInterface
5
+ module EmrLimsInterfaceService
6
+ class << self
7
+ require 'csv'
8
+ require 'rest-client'
9
+
10
+ def initialize
11
+ @mysql_connection_pool = {}
12
+ end
13
+ ######################################### start creation of lab test in lims #####################################################
14
+ def settings
15
+ file = File.read(Rails.root.join('db', 'lims_metadata', 'lims_map.json'))
16
+ JSON.parse(file)
17
+ end
18
+
19
+ def get_patient_number
20
+ get_patient_id = query "SELECT id FROM iblis.patients order by id desc limit 1;"
21
+
22
+ get_patient_id.each do |x|
23
+ return patient_number = x['id']
24
+ end
25
+
26
+
27
+
28
+ end
29
+
30
+ def check_patient_number(patient_id)
31
+ get_patient_id = query "SELECT patient_number FROM patients WHERE `external_patient_number` ='#{patient_id}'; "
32
+
33
+ get_patient_id.each do |x|
34
+ return patient_number = x['patient_number']
35
+ end
36
+
37
+ end
38
+
39
+ def filterpatient_number(data)
40
+ patient_number = 0
41
+ data.each do |x|
42
+ patient_number = x['patient_identify']
43
+ end
44
+ patient_number
45
+ end
46
+
47
+ def get_patient_dentifier(patient_id)
48
+ patient_dentifier =PatientIdentifier.where('patient_id= ? AND identifier_type = ?', patient_id,3)[0]
49
+ patient_dentifier[:identifier]
50
+ end
51
+ def create_lab_order(lab_details, clinician_id)
52
+ external_patient_number = get_patient_dentifier(lab_details[0][:patient_id])
53
+ patient_number = check_patient_number(external_patient_number)
54
+ time = Time.new
55
+ date = time.strftime('%Y-%m-%d %H:%M:%S')
56
+ lab_details.map do |order_params|
57
+ if patient_number.blank?
58
+ patient_number = get_patient_number() + 1
59
+
60
+ person_data = Person.where('person_id= ?', order_params[:patient_id])[0]
61
+ address_data = PersonAddress.where('person_id= ?', order_params[:patient_id])[0]
62
+ name_data = PersonName.where('person_id= ?', order_params[:patient_id])[0]
63
+
64
+ gender = person_data[:gender].match(/f/i) ? 1 : (person_data[:gender].match(/m/i) ? 0 : 2)
65
+ create_patient(
66
+ name_data[:given_name],
67
+ name_data[:family_name],
68
+ clinician_id[0][:requesting_clinician_id],
69
+ address_data[:address1],
70
+ gender,
71
+ person_data[:birthdate],
72
+ person_data[:birthdate_estimated],
73
+ external_patient_number,
74
+ patient_number,
75
+ date
76
+ )
77
+ end
78
+ create_visit(patient_number, date)
79
+ create_specimens(
80
+ clinician_id[0][:requesting_clinician_id],
81
+ order_params[:specimen][:name],
82
+ order_params[:accession_number]
83
+ )
84
+ specimen_id = get_specimen_id
85
+ create_unsync_orders(date, specimen_id)
86
+
87
+ create_test(specimen_id, order_params[:requesting_clinician], order_params[:tests][0][:name])
88
+ end
89
+ end
90
+
91
+ def create_patient(
92
+ firstname, surname,
93
+ user_id, address,
94
+ gender, dob,
95
+ dob_estimated, external_patient_number,
96
+ patient_number, date
97
+ )
98
+ query(
99
+ "INSERT INTO `patients` (`name`, `first_name_code`, `last_name_code`, `created_by`, `address`, `gender`, `patient_number`, `dob`, `dob_estimated`, `external_patient_number`, `created_at`, `updated_at`)
100
+ VALUES ('#{firstname} #{surname}', SOUNDEX('#{firstname}'), SOUNDEX('#{surname}'), #{user_id}, '#{address}',#{gender},'#{patient_number}', '#{dob}', '#{dob_estimated}', '#{external_patient_number}', '#{date}', '#{date}')"
101
+ )
102
+ end
103
+
104
+ def create_visit(patient_number, date)
105
+ query "INSERT INTO `visits` (`patient_id`, `visit_type`, `ward_or_location`, `created_at`, `updated_at`)
106
+ VALUES ('#{patient_number}', 'Out Patient', 'EM OPD', '#{date}', '#{date}')"
107
+ end
108
+
109
+ def create_specimens(user_id, specimen_type, tracking_number)
110
+ specimen_type_id = settings['lims_specimen_map'][specimen_type.to_s]
111
+ accession_number = new_accession_number
112
+ # prepare_next_tracking_number()
113
+ # tracking_number = create_local_tracking_number()
114
+ query(" INSERT INTO `specimens` (`specimen_type_id`, `accepted_by`, `priority`, `accession_number`, `tracking_number`)
115
+ VALUES ('#{specimen_type_id}', '#{user_id}', 'Stat', '#{accession_number}', '#{tracking_number}')")
116
+ end
117
+
118
+ def create_unsync_orders(date, specimen_id)
119
+ query(" INSERT INTO `unsync_orders` (`specimen_id`, `data_not_synced`, `data_level`, `sync_status`, `updated_by_name`, `updated_by_id`, `created_at`, `updated_at`)
120
+ VALUES ('#{specimen_id}', 'new order', 'specimen', 'not-synced', 'kBLIS Administrator', '1', '#{date}', '#{date}')")
121
+ end
122
+
123
+ def create_test(specimen_id, requested_by, test_type)
124
+ visit_id = get_visit_id
125
+ test_type_id = settings['lims_test_type_map'][test_type.to_s]
126
+ query("INSERT INTO `tests` (`visit_id`, `test_type_id`, `specimen_id`, `test_status_id`, `not_done_reasons`, `person_talked_to_for_not_done`, `created_by`, `requested_by`)
127
+ VALUES ('#{visit_id}', '#{test_type_id}', '#{specimen_id}', '2', '0', '0', 1, '#{requested_by}')")
128
+ end
129
+
130
+ def new_accession_number
131
+ # Generate the next accession number for specimen registration
132
+ @mutex = Mutex.new if @mutex.blank?
133
+ @mutex.lock
134
+ max_acc_num = 0
135
+ return_value = nil
136
+ sentinel = 99_999_999
137
+
138
+ settings = YAML.load_file("#{Rails.root}/config/application.yml")[Rails.env]
139
+ code = settings['facility_code']
140
+ year = Date.today.year.to_s[2..3]
141
+
142
+ record = get_last_accession_number
143
+
144
+ unless record.blank?
145
+ max_acc_num = record[5..20].match(/\d+/)[0].to_i # first 5 chars are for facility code and 2 digit year
146
+ end
147
+
148
+ if max_acc_num < sentinel
149
+ max_acc_num += 1
150
+ else
151
+ max_acc_num = 1
152
+ end
153
+
154
+ max_acc_num = max_acc_num.to_s.rjust(8, '0')
155
+ return_value = "#{code}#{year}#{max_acc_num}"
156
+ @mutex.unlock
157
+
158
+ return_value
159
+ end
160
+
161
+ def get_last_accession_number
162
+ data = query('SELECT * FROM specimens WHERE accession_number IS NOT NULL ORDER BY id DESC LIMIT 1')
163
+ data.each do |x|
164
+ return last_accession_number = x['accession_number']
165
+ end
166
+ end
167
+
168
+ def get_specimen_id
169
+ data = query('SELECT * FROM specimens WHERE accession_number IS NOT NULL ORDER BY id DESC LIMIT 1')
170
+ data.each do |x|
171
+ return specimen_id = x['id']
172
+ end
173
+ end
174
+
175
+ def get_visit_id
176
+ data = query('SELECT * FROM visits WHERE id IS NOT NULL ORDER BY id DESC LIMIT 1')
177
+ data.each do |x|
178
+ return specimen_id = x['id']
179
+ end
180
+ end
181
+
182
+ def prepare_next_tracking_number
183
+ file = JSON.parse(File.read("#{Rails.root}/public/tracker.json"))
184
+ todate = Time.now.strftime('%Y%m%d')
185
+
186
+ counter = file[todate]
187
+ counter = counter.to_i + 1
188
+ fi = {}
189
+ fi[todate] = counter
190
+ File.open("#{Rails.root}/public/tracker.json", 'w') do |f|
191
+ f.write(fi.to_json)
192
+ end
193
+ end
194
+
195
+ ###### lims tracking number ###############
196
+ def create_local_tracking_number
197
+ configs = YAML.load_file "#{Rails.root}/config/application.yml"
198
+ site_code = configs['facility_code']
199
+ file = JSON.parse(File.read("#{Rails.root}/public/tracker.json"))
200
+ todate = Time.now.strftime('%Y%m%d')
201
+ year = Time.now.strftime('%Y%m%d').to_s.slice(2..3)
202
+ month = Time.now.strftime('%m')
203
+ day = Time.now.strftime('%d')
204
+
205
+ key = file.keys
206
+
207
+ if todate > key[0]
208
+
209
+ fi = {}
210
+ fi[todate] = 1
211
+ File.open("#{Rails.root}/public/tracker.json", 'w') do |f|
212
+ f.write(fi.to_json)
213
+ end
214
+
215
+ value = '001'
216
+ tracking_number = "X#{site_code}#{year}#{get_month(month)}#{get_day(day)}#{value}"
217
+
218
+ else
219
+ counter = file[todate]
220
+
221
+ value = if counter.to_s.length == 1
222
+ '00' + counter.to_s
223
+ elsif counter.to_s.length == 2
224
+ '0' + counter.to_s
225
+ else
226
+ begin
227
+ counter.to_s
228
+ rescue StandardError
229
+ '001'
230
+ end
231
+ end
232
+
233
+ tracking_number = "X#{site_code}#{year}#{get_month(month)}#{get_day(day)}#{value}"
234
+
235
+ end
236
+ tracking_number
237
+ end
238
+
239
+ def get_month(month)
240
+ case month
241
+
242
+ when '01'
243
+ '1'
244
+ when '02'
245
+ '2'
246
+ when '03'
247
+ '3'
248
+ when '04'
249
+ '4'
250
+ when '05'
251
+ '5'
252
+ when '06'
253
+ '6'
254
+ when '07'
255
+ '7'
256
+ when '08'
257
+ '8'
258
+ when '09'
259
+ '9'
260
+ when '10'
261
+ 'A'
262
+ when '11'
263
+ 'B'
264
+ when '12'
265
+ 'C'
266
+ end
267
+ end
268
+
269
+ def get_day(day)
270
+ case day
271
+
272
+ when '01'
273
+ '1'
274
+ when '02'
275
+ '2'
276
+ when '03'
277
+ '3'
278
+ when '04'
279
+ '4'
280
+ when '05'
281
+ '5'
282
+ when '06'
283
+ '6'
284
+ when '07'
285
+ '7'
286
+ when '08'
287
+ '8'
288
+ when '09'
289
+ '9'
290
+ when '10'
291
+ 'A'
292
+ when '11'
293
+ 'B'
294
+ when '12'
295
+ 'C'
296
+ when '13'
297
+ 'E'
298
+ when '14'
299
+ 'F'
300
+ when '15'
301
+ 'G'
302
+ when '16'
303
+ 'H'
304
+ when '17'
305
+ 'Y'
306
+ when '18'
307
+ 'J'
308
+ when '19'
309
+ 'K'
310
+ when '20'
311
+ 'Z'
312
+ when '21'
313
+ 'M'
314
+ when '22'
315
+ 'N'
316
+ when '23'
317
+ 'O'
318
+ when '24'
319
+ 'P'
320
+ when '25'
321
+ 'Q'
322
+ when '26'
323
+ 'R'
324
+ when '27'
325
+ 'S'
326
+ when '28'
327
+ 'T'
328
+ when '29'
329
+ 'V'
330
+ when '30'
331
+ 'W'
332
+ when '31'
333
+ 'X'
334
+ end
335
+ end
336
+ ############################################# end creation of lab test in lims #####################################################
337
+
338
+ ############## get results from lims ###############
339
+
340
+ def get_lims_test_results(tracking_number,patient_id)
341
+ external_patient_number = get_patient_dentifier(patient_id)
342
+ data = query("
343
+ SELECT
344
+ visits.ward_or_location, specimens.accession_number,
345
+ tests.created_by, tests.verified_by,
346
+ tests.time_completed,tests.requested_by,tests.interpretation,
347
+ tests.time_created as tests_time_created,
348
+ test_types.name as test_types_name,
349
+ test_categories.name as test_categories_name,
350
+ tests.time_verified as tests_time_verified,
351
+ users.name as users_name,
352
+ specimen_types.name as specimen_types_name,
353
+ specimen_statuses.name as specimen_statuses_name,
354
+ test_results.result as test_results_result,
355
+ test_results.device_name as test_results_device_name,
356
+ measures.name as measures_name,
357
+ measures.unit as measures_unit,
358
+ measure_ranges.range_lower as measure_ranges_range_lower,
359
+ measure_ranges.range_upper as measure_ranges_range_upper
360
+ FROM iblis.patients
361
+ inner join iblis.visits on `visits`.`patient_id` = `patients`.`patient_number`
362
+ inner join iblis.tests on `tests`.`visit_id` = `visits`.`id`
363
+ inner join iblis.test_types on `test_types`.`id` = `tests`.`test_type_id`
364
+ inner join iblis.test_categories on `test_categories`.`id` = `test_types`.`test_category_id`
365
+ inner join iblis.users on `users`.`id` = `tests`.`tested_by`
366
+ inner join iblis.specimens on `specimens`.`id` = `tests`.`specimen_id`
367
+ inner join iblis.specimen_types on `specimen_types`.`id` = `specimens`.`specimen_type_id`
368
+ inner join iblis.specimen_statuses on `specimen_statuses`.`id` = `specimens`.`specimen_status_id`
369
+ right join iblis.test_results on `test_results`.`test_id` = `tests`.`id`
370
+ right join iblis.measures on `measures`.`id` = `test_results`.`measure_id`
371
+ right join iblis.measure_ranges on `measure_ranges`.`measure_id` = `measures`.`id`
372
+ where `patients`.`deleted_at` is null and `specimens`.`tracking_number` = '#{tracking_number}' and `patients`.`external_patient_number` = '#{external_patient_number}' and `measure_ranges`.`deleted_at`
373
+ is null group by(`measure_ranges`.`measure_id`) order by time_completed asc ;
374
+ ")
375
+ data
376
+ end
377
+ def get_user_details(user_id)
378
+ data = query("SELECT * FROM iblis.users where id = #{user_id};")
379
+ data
380
+ end
381
+ ############################################# start connection to lims database ######################################################
382
+ def query(sql)
383
+ Rails.logger.debug(sql.to_s)
384
+ result = mysql.query(sql)
385
+ end
386
+
387
+ def mysql
388
+ # self.initialize
389
+ return mysql_connection if mysql_connection
390
+
391
+ connection = Mysql2::Client.new(host: settings['headers']['host'],
392
+ username: settings['headers']['username'],
393
+ password: settings['headers']['password'],
394
+ port: settings['headers']['port'],
395
+ database: settings['headers']['database'],
396
+ reconnect: true)
397
+ self.mysql_connection = connection
398
+ end
399
+
400
+ def mysql_connection=(connection)
401
+ @mysql_connection_pool = connection
402
+ end
403
+
404
+ def mysql_connection
405
+ @mysql_connection_pool
406
+ end
407
+ ############################################# end connection to lims database ######################################################
408
+ end
409
+ end
410
+ end
@@ -0,0 +1,312 @@
1
+ require "emr_ohsp_interface/version"
2
+
3
+ module EmrOhspInterface
4
+ module EmrOhspInterfaceService
5
+ class << self
6
+ require 'csv'
7
+ require 'rest-client'
8
+ def settings
9
+ file = File.read(Rails.root.join("db","idsr_metadata","idsr_ohsp_settings.json"))
10
+ config = JSON.parse(file)
11
+ end
12
+
13
+ def get_ohsp_facility_id
14
+ file = File.open(Rails.root.join("db","idsr_metadata","emr_ohsp_facility_map.csv"))
15
+ data = CSV.parse(file,headers: true)
16
+ emr_facility_id = Location.current_health_center.id
17
+ facility = data.select{|row| row["EMR_Facility_ID"].to_i == emr_facility_id}
18
+ ohsp_id = facility[0]["OrgUnit ID"]
19
+ end
20
+
21
+ def get_ohsp_de_ids(de,type)
22
+ #this method returns an array ohsp report line ids
23
+ result = []
24
+ #["waoQ016uOz1", "r1AT49VBKqg", "FPN4D0s6K3m", "zE8k2BtValu"]
25
+ # ds, de_id , <5yrs , >=5yrs
26
+ puts de
27
+ if type == "weekly"
28
+ file = File.open(Rails.root.join("db","idsr_metadata","idsr_weekly_ohsp_ids.csv"))
29
+ else
30
+ file = File.open(Rails.root.join("db","idsr_metadata","idsr_monthly_ohsp_ids.csv"))
31
+ end
32
+ data = CSV.parse(file,headers: true)
33
+ row = data.select{|row| row["Data Element Name"].strip.downcase.eql?(de.downcase.strip)}
34
+ ohsp_ds_id = row[0]["Data Set ID"]
35
+ result << ohsp_ds_id
36
+ ohsp_de_id = row[0]["UID"]
37
+ result << ohsp_de_id
38
+ option1 = row[0]["<5Yrs"]
39
+ result << option1
40
+ option2 = row[0][">=5Yrs"]
41
+ result << option2
42
+
43
+ return result
44
+ end
45
+
46
+ def get_data_set_id(type)
47
+ if type == "weekly"
48
+ file = File.open(Rails.root.join("db","idsr_metadata","idsr_weekly_ohsp_ids.csv"))
49
+ else
50
+ file = File.open(Rails.root.join("db","idsr_metadata","idsr_monthly_ohsp_ids.csv"))
51
+ end
52
+ data = CSV.parse(file,headers: true)
53
+ data_set_id = data.first["Data Set ID"]
54
+ end
55
+
56
+ def generate_weekly_idsr_report(request=nil,start_date=nil,end_date=nil)
57
+
58
+ diag_map = settings["weekly_idsr_map"]
59
+
60
+ epi_week = weeks_generator.last.first.strip
61
+ start_date = weeks_generator.last.last.split("to")[0].strip if start_date.nil?
62
+ end_date = weeks_generator.last.last.split("to")[1].strip if end_date.nil?
63
+
64
+ #pull the data
65
+ type = EncounterType.find_by_name 'Outpatient diagnosis'
66
+ collection = {}
67
+
68
+ diag_map.each do |key,value|
69
+ options = {"<5yrs"=>nil,">=5yrs"=>nil}
70
+ concept_ids = ConceptName.where(name: value).collect{|cn| cn.concept_id}
71
+
72
+ data = Encounter.where('encounter_datetime BETWEEN ? AND ?
73
+ AND encounter_type = ? AND value_coded IN (?)
74
+ AND concept_id IN(6543, 6542)',
75
+ start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
76
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),type.id,concept_ids).\
77
+ joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
78
+ INNER JOIN person p ON p.person_id = encounter.patient_id').\
79
+ select('encounter.encounter_type, obs.value_coded, p.*')
80
+
81
+ #under_five
82
+ under_five = data.select{|record| calculate_age(record["birthdate"]) < 5}.\
83
+ collect{|record| record.person_id}
84
+ options["<5yrs"] = under_five
85
+ #above 5 years
86
+ over_five = data.select{|record| calculate_age(record["birthdate"]) >=5 }.\
87
+ collect{|record| record.person_id}
88
+
89
+ options[">=5yrs"] = over_five
90
+
91
+ collection[key] = options
92
+ end
93
+ if request == nil
94
+ response = send_data(collection,"weekly")
95
+ end
96
+ return collection
97
+ end
98
+ #idsr monthly report
99
+
100
+ def generate_monthly_idsr_report(request=nil,start_date=nil,end_date=nil)
101
+ diag_map = settings["monthly_idsr_map"]
102
+ epi_month = months_generator.first.first.strip
103
+ start_date = months_generator.first.last[1].split("to").first.strip if start_date.nil?
104
+ end_date = months_generator.first.last[1].split("to").last.strip if end_date.nil?
105
+ type = EncounterType.find_by_name 'Outpatient diagnosis'
106
+ collection = {}
107
+
108
+ special_indicators = ["Malaria in Pregnancy","HIV New Initiated on ART"]
109
+
110
+ diag_map.each do |key,value|
111
+ options = {"<5yrs"=>nil,">=5yrs"=>nil}
112
+ concept_ids = ConceptName.where(name: value).collect{|cn| cn.concept_id}
113
+ if !special_indicators.include?(key)
114
+ data = Encounter.where('encounter_datetime BETWEEN ? AND ?
115
+ AND encounter_type = ? AND value_coded IN (?)
116
+ AND concept_id IN(6543, 6542)',
117
+ start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
118
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),type.id,concept_ids).\
119
+ joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
120
+ INNER JOIN person p ON p.person_id = encounter.patient_id').\
121
+ select('encounter.encounter_type, obs.value_coded, p.*')
122
+
123
+ #under_five
124
+ under_five = data.select{|record| calculate_age(record["birthdate"]) < 5}.\
125
+ collect{|record| record.person_id}
126
+ options["<5yrs"] = under_five
127
+ #above 5 years
128
+ over_five = data.select{|record| calculate_age(record["birthdate"]) >=5 }.\
129
+ collect{|record| record.person_id}
130
+
131
+ options[">=5yrs"] = over_five
132
+
133
+ collection[key] = options
134
+ else
135
+ if key.eql?("Malaria in Pregnancy")
136
+ mal_patient_id = Encounter.where('encounter_datetime BETWEEN ? AND ?
137
+ AND encounter_type = ? AND value_coded IN (?)
138
+ AND concept_id IN(6543, 6542)',
139
+ start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
140
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),type.id,concept_ids).\
141
+ joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
142
+ INNER JOIN person p ON p.person_id = encounter.patient_id').\
143
+ select('encounter.encounter_type, obs.value_coded, p.*')
144
+
145
+ mal_patient_id= mal_patient_id.collect{|record| record.person_id}
146
+ #find those that are pregnant
147
+ preg = Observation.where(["concept_id = 6131 AND obs_datetime
148
+ BETWEEN ? AND ? AND person_id IN(?)
149
+ AND value_coded =1065",
150
+ start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
151
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),mal_patient_id ])
152
+
153
+ options[">=5yrs"] = preg.collect{|record| record.person_id} rescue 0
154
+ collection[key] = options
155
+ end
156
+
157
+ if key.eql?("HIV New Initiated on ART")
158
+ data = ActiveRecord::Base.connection.select_all(
159
+ "SELECT * FROM temp_earliest_start_date
160
+ WHERE date_enrolled BETWEEN '#{start_date}' AND '#{end_date}'
161
+ AND date_enrolled = earliest_start_date
162
+ GROUP BY patient_id" ).to_hash
163
+
164
+ under_five = data.select{|record| calculate_age(record["birthdate"]) < 5 }.\
165
+ collect{|record| record["patient_id"]}
166
+
167
+ over_five = data.select{|record| calculate_age(record["birthdate"]) >=5 }.\
168
+ collect{|record| record["patient_id"]}
169
+
170
+ options["<5yrs"] = under_five
171
+ options[">=5yrs"] = over_five
172
+
173
+ collection[key] = options
174
+ end
175
+ end
176
+ end
177
+ if request == nil
178
+ response = send_data(collection,"monthly")
179
+ end
180
+ return collection
181
+ end
182
+
183
+ # helper menthod
184
+ def months_generator
185
+ months = Hash.new
186
+ count = 1
187
+ curr_date = Date.today
188
+ while count < 13 do
189
+ curr_date = curr_date - 1.month
190
+ months[curr_date.strftime("%Y%m")] = [curr_date.strftime("%B-%Y"),\
191
+ (curr_date.beginning_of_month.to_s+" to " + curr_date.end_of_month.to_s)]
192
+ count += 1
193
+ end
194
+ return months.to_a
195
+ end
196
+
197
+ # helper menthod
198
+ def weeks_generator
199
+
200
+ weeks = Hash.new
201
+ first_day = ((Date.today.year.to_s)+"-01-01").to_date
202
+ wk_of_first_day = first_day.cweek
203
+
204
+ if wk_of_first_day > 1
205
+ wk = first_day.prev_year.year.to_s+"W"+wk_of_first_day.to_s
206
+ dates = "#{(first_day-first_day.wday+1).to_s} to #{((first_day-first_day.wday+1)+6).to_s}"
207
+ weeks[wk] = dates
208
+ end
209
+
210
+ #get the firt monday of the year
211
+ while !first_day.monday? do
212
+ first_day = first_day+1
213
+ end
214
+ first_monday = first_day
215
+ #generate week numbers and date ranges
216
+
217
+ while first_monday <= Date.today do
218
+ wk = (first_monday.year).to_s+"W"+(first_monday.cweek).to_s
219
+ dates = "#{first_monday.to_s} to #{(first_monday+6).to_s}"
220
+ #add to the hash
221
+ weeks[wk] = dates
222
+ #step by week
223
+ first_monday += 7
224
+ end
225
+ #remove the last week
226
+ this_wk = (Date.today.year).to_s+"W"+(Date.today.cweek).to_s
227
+ weeks = weeks.delete_if{|key,value| key==this_wk}
228
+
229
+ return weeks.to_a
230
+ end
231
+
232
+ #Age calculator
233
+ def calculate_age(dob)
234
+ age = ((Date.today-dob.to_date).to_i)/365 rescue 0
235
+ end
236
+
237
+ def send_data(data,type)
238
+ # method used to post data to the server
239
+ #prepare payload here
240
+ conn = settings["headers"]
241
+ payload = {
242
+ "dataSet" =>get_data_set_id(type),
243
+ "period"=>(type.eql?("weekly") ? weeks_generator.last[0] : months_generator.first[0]),
244
+ "orgUnit"=> get_ohsp_facility_id,
245
+ "dataValues"=> []
246
+ }
247
+ special = ["Severe Pneumonia in under 5 cases","Malaria in Pregnancy",
248
+ "Underweight Newborns < 2500g in Under 5 Cases","Diarrhoea In Under 5"]
249
+
250
+ data.each do |key,value|
251
+ if !special.include?(key)
252
+ option1 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
253
+ "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[2],
254
+ "value"=>value["<5yrs"].size }
255
+
256
+ option2 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
257
+ "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[3],
258
+ "value"=>value[">=5yrs"].size}
259
+
260
+ #fill data values array
261
+ payload["dataValues"] << option1
262
+ payload["dataValues"] << option2
263
+ else
264
+ case key
265
+ when special[0]
266
+ option1 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
267
+ "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[2],
268
+ "value"=>value["<5yrs"].size }
269
+
270
+ payload["dataValues"] << option1
271
+ when special[1]
272
+ option2 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
273
+ "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[3],
274
+ "value"=>value[">=5yrs"].size }
275
+
276
+ payload["dataValues"] << option2
277
+ when special[2]
278
+ option1 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
279
+ "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[2],
280
+ "value"=>value["<5yrs"].size }
281
+
282
+ payload["dataValues"] << option1
283
+ when special[3]
284
+ option1 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
285
+ "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[2],
286
+ "value"=>value["<5yrs"].size}
287
+
288
+ payload["dataValues"] << option1
289
+ end
290
+ end
291
+ end
292
+
293
+ puts "now sending these values: #{payload.to_json}"
294
+ url = "#{conn["url"]}/api/dataValueSets"
295
+ puts url
296
+ puts "pushing #{type} IDSR Reports"
297
+ send = RestClient::Request.execute(method: :post,
298
+ url: url,
299
+ headers:{'Content-Type'=> 'application/json'},
300
+ payload: payload.to_json,
301
+ #headers: {accept: :json},
302
+ user: conn["user"],
303
+ password: conn["pass"])
304
+
305
+ puts send
306
+ end
307
+
308
+ end
309
+ end
310
+
311
+
312
+ end
data/config/routes.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  EmrOhspInterface::Engine.routes.draw do
2
- resources :radiology, path: 'api/v1/emr_ohsp_interface'
2
+ resources :emr_lims_interface, path: 'api/v1/emr_lims_interface'
3
+ get '/get_lims_user', to: 'emr_lims_interface#get_user_info'
3
4
  get '/get_weeks', to: 'emr_ohsp_interface#weeks_generator'
4
5
  get '/get_months', to: 'emr_ohsp_interface#months_generator'
6
+ get '/generate_weekly_idsr_report', to: 'emr_ohsp_interface#generate_weekly_idsr_report'
7
+ get '/generate_monthly_idsr_report', to: 'emr_ohsp_interface#generate_monthly_idsr_report'
5
8
  end
@@ -1,3 +1,3 @@
1
1
  module EmrOhspInterface
2
- VERSION = '0.1.0'
2
+ VERSION = '0.5.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emr_ohsp_interface
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
- - Justin Manda
7
+ - Justin Manda and Petros Kayange
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-14 00:00:00.000000000 Z
11
+ date: 2021-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -74,7 +74,7 @@ dependencies:
74
74
  version: '0'
75
75
  description:
76
76
  email:
77
- - justinmandah@gmail.com
77
+ - justinmandah@gmail.com, kayangepetros@gmail.com
78
78
  executables: []
79
79
  extensions: []
80
80
  extra_rdoc_files: []
@@ -86,12 +86,14 @@ files:
86
86
  - app/assets/javascripts/emr_ohsp_interface/application.js
87
87
  - app/assets/stylesheets/emr_ohsp_interface/application.css
88
88
  - app/controllers/emr_ohsp_interface/application_controller.rb
89
- - app/controllers/emr_ohsp_interface/emr_OHSP_interface_controller.rb
89
+ - app/controllers/emr_ohsp_interface/emr_lims_interface_controller.rb
90
+ - app/controllers/emr_ohsp_interface/emr_ohsp_interface_controller.rb
90
91
  - app/helpers/emr_ohsp_interface/application_helper.rb
91
92
  - app/jobs/emr_ohsp_interface/application_job.rb
92
93
  - app/mailers/emr_ohsp_interface/application_mailer.rb
93
94
  - app/models/emr_ohsp_interface/application_record.rb
94
- - app/services/emr_ohsp_interface/emr_OHSP_interface_service.rb
95
+ - app/services/emr_ohsp_interface/emr_lims_interface_service.rb
96
+ - app/services/emr_ohsp_interface/emr_ohsp_interface_service.rb
95
97
  - app/views/layouts/emr_ohsp_interface/application.html.erb
96
98
  - config/routes.rb
97
99
  - lib/emr_ohsp_interface.rb
@@ -118,9 +120,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
120
  - !ruby/object:Gem::Version
119
121
  version: '0'
120
122
  requirements: []
121
- rubygems_version: 3.0.8
123
+ rubygems_version: 3.2.32
122
124
  signing_key:
123
125
  specification_version: 4
124
- summary: This in a gem that facilitates interfacing of EMR and One Health Surveillance
125
- Platform
126
+ summary: This in a gem that facilitates interfacing of EMR, One Health Surveillance
127
+ Platform and Lims
126
128
  test_files: []
@@ -1,12 +0,0 @@
1
- class EmrOHSPInterface::EmrOHSPInterfaceController < ::ApplicationController
2
- def weeks_generator
3
- render json: service.weeks_generator();
4
- end
5
- def months_generator
6
- render json: service.months_generator();
7
- end
8
-
9
- def service
10
- EmrOHSPInterface::EmrOHSPInterfaceService
11
- end
12
- end
@@ -1,196 +0,0 @@
1
- require "emr_OHSP_interface/version"
2
-
3
- module EmrOHSPInterface
4
- module EmrOHSPInterfaceService
5
- class << self
6
- require 'csv'
7
- require 'rest-client'
8
- def settings
9
- file = File.read(Rails.root.join("db","idsr_metadata","idsr_ohsp_settings.json"))
10
- config = JSON.parse(file)
11
- end
12
-
13
- def get_ohsp_facility_id
14
- file = File.open(Rails.root.join("db","idsr_metadata","emr_ohsp_facility_map.csv"))
15
- data = CSV.parse(file,headers: true)
16
- emr_facility_id = Location.current_health_center.id
17
- facility = data.select{|row| row["EMR_Facility_ID"].to_i == emr_facility_id}
18
- ohsp_id = facility[0]["OrgUnit ID"]
19
- end
20
-
21
- def get_ohsp_de_ids(de,type)
22
- #this method returns an array ohsp report line ids
23
- result = []
24
- #["waoQ016uOz1", "r1AT49VBKqg", "FPN4D0s6K3m", "zE8k2BtValu"]
25
- # ds, de_id , <5yrs , >=5yrs
26
- if type == "weekly"
27
- file = File.open(Rails.root.join("db","idsr_metadata","idsr_weekly_ohsp_ids.csv"))
28
- else
29
- file = File.open(Rails.root.join("db","idsr_metadata","idsr_monthly_ohsp_ids.csv"))
30
- end
31
- data = CSV.parse(file,headers: true)
32
- row = data.select{|row| row["Data Element Name"].strip.downcase.eql?(de.downcase)}
33
- ohsp_ds_id = row[0]["Data Set ID"]
34
- result << ohsp_ds_id
35
- ohsp_de_id = row[0]["UID"]
36
- result << ohsp_de_id
37
- option1 = row[0]["<5Yrs"]
38
- result << option1
39
- option2 = row[0][">=5Yrs"]
40
- result << option2
41
-
42
- return result
43
- end
44
-
45
- def get_data_set_id(type)
46
- if type == "weekly"
47
- file = File.open(Rails.root.join("db","idsr_metadata","idsr_weekly_ohsp_ids.csv"))
48
- else
49
- file = File.open(Rails.root.join("db","idsr_metadata","idsr_monthly_ohsp_ids.csv"))
50
- end
51
- data = CSV.parse(file,headers: true)
52
- data_set_id = data.first["Data Set ID"]
53
- end
54
-
55
- def generate_weekly_idsr_report()
56
-
57
- diag_map = settings["weekly_idsr_map"]
58
-
59
- epi_week = weeks_generator.last.first.strip
60
- start_date = weeks_generator.last.last.split("to")[0].strip
61
- end_date = weeks_generator.last.last.split("to")[1].strip
62
-
63
- #pull the data
64
- type = EncounterType.find_by_name 'Outpatient diagnosis'
65
- collection = {}
66
-
67
- diag_map.each do |key,value|
68
- options = {"<5yrs"=>nil,">=5yrs"=>nil}
69
- concept_ids = ConceptName.where(name: value).collect{|cn| cn.concept_id}
70
-
71
- data = Encounter.where('encounter_datetime BETWEEN ? AND ?
72
- AND encounter_type = ? AND value_coded IN (?)
73
- AND concept_id IN(6543, 6542)',
74
- start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
75
- end_date.to_date.strftime('%Y-%m-%d 23:59:59'),type.id,concept_ids).\
76
- joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
77
- INNER JOIN person p ON p.person_id = encounter.patient_id').\
78
- select('encounter.encounter_type, obs.value_coded, p.*')
79
-
80
- #under_five
81
- under_five = data.select{|record| calculate_age(record["birthdate"]) < 5}.\
82
- collect{|record| record.person_id}
83
- options["<5yrs"] = under_five
84
- #above 5 years
85
- over_five = data.select{|record| calculate_age(record["birthdate"]) >=5 }.\
86
- collect{|record| record.person_id}
87
-
88
- options[">=5yrs"] = over_five
89
-
90
- collection[key] = options
91
- end
92
-
93
- response = send_data(collection,"weekly")
94
- end
95
-
96
- def generate_monthly_idsr_report()
97
- end
98
-
99
- # helper menthod
100
- def months_generator
101
- months = Hash.new
102
- count = 1
103
- curr_date = Date.today
104
- while count < 13 do
105
- curr_date = curr_date - 1.month
106
- months[curr_date.strftime("%Y%m")] = [curr_date.strftime("%B-%Y"),\
107
- (curr_date.beginning_of_month.to_s+" to " + curr_date.end_of_month.to_s)]
108
- count += 1
109
- end
110
- return months.to_a
111
- end
112
-
113
- # helper menthod
114
- def weeks_generator
115
-
116
- weeks = Hash.new
117
- first_day = ((Date.today.year.to_s)+"-01-01").to_date
118
- wk_of_first_day = first_day.cweek
119
-
120
- if wk_of_first_day > 1
121
- wk = first_day.prev_year.year.to_s+"W"+wk_of_first_day.to_s
122
- dates = "#{(first_day-first_day.wday+1).to_s} to #{((first_day-first_day.wday+1)+6).to_s}"
123
- weeks[wk] = dates
124
- end
125
-
126
- #get the firt monday of the year
127
- while !first_day.monday? do
128
- first_day = first_day+1
129
- end
130
- first_monday = first_day
131
- #generate week numbers and date ranges
132
-
133
- while first_monday <= Date.today do
134
- wk = (first_monday.year).to_s+"W"+(first_monday.cweek).to_s
135
- dates = "#{first_monday.to_s} to #{(first_monday+6).to_s}"
136
- #add to the hash
137
- weeks[wk] = dates
138
- #step by week
139
- first_monday += 7
140
- end
141
- #remove the last week
142
- this_wk = (Date.today.year).to_s+"W"+(Date.today.cweek).to_s
143
- weeks = weeks.delete_if{|key,value| key==this_wk}
144
-
145
- return weeks.to_a
146
- end
147
-
148
- #Age calculator
149
- def calculate_age(dob)
150
- age = ((Date.today-dob.to_date).to_i)/365 rescue 0
151
- end
152
-
153
- def send_data(data,type)
154
- # method used to post data to the server
155
- #prepare payload here
156
- conn = settings["headers"]
157
- payload = {
158
- "dataSet" =>get_data_set_id(type),
159
- "period"=>(type.eql?("weekly") ? weeks_generator.last[0] : months_generator.first[0]),
160
- "orgUnit"=> get_ohsp_facility_id,
161
- "dataValues"=> []
162
- }
163
-
164
- data.each do |key,value|
165
- option1 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
166
- "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[2],
167
- "value"=>value["<5yrs"].size }
168
-
169
- option2 = {"dataElement"=>get_ohsp_de_ids(key,type)[1],
170
- "categoryOptionCombo"=> get_ohsp_de_ids(key,type)[3],
171
- "value"=>value[">=5yrs"].size}
172
-
173
- #fill data values array
174
- payload["dataValues"] << option1
175
- payload["dataValues"] << option2
176
- end
177
-
178
- puts "now sending these values: #{payload.to_s}"
179
- url = "#{conn["url"]}/api/dataValueSets"
180
- puts url
181
- send = RestClient::Request.execute(method: :post,
182
- url: url,
183
- headers:{'Content-Type'=> 'application/json'},
184
- payload: payload.to_json,
185
- #headers: {accept: :json},
186
- user: conn["user"],
187
- password: conn["pass"])
188
-
189
- puts send
190
- end
191
-
192
- end
193
- end
194
-
195
-
196
- end