emr_ohsp_interface 0.1.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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