emr_ohsp_interface 2.2.3 → 2.2.4

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: 6ca9634e36555a67204142daadaef5e7c15c390654d5481ee41c753c8b040e33
4
- data.tar.gz: f12fa09bf6867abff6f52e31902989b6d16cb5938644fc2095417186c48074d3
3
+ metadata.gz: cd0223562697c86dc3dc5e2e0090f447b27d3d6375dd1d1ff7cdb7fb706a7f84
4
+ data.tar.gz: b9102f891cf79cbc20d89ad6edf65662dd97fd3f9fe0cf2505b3fdb1c728386e
5
5
  SHA512:
6
- metadata.gz: bb7b7599d5c501e5784b5ee039df5eb04f4c8b417aaf9049648436e2d67d1b435d6b9cfd4c63e4b007c6db410f1f712e5387e4731a512daed54f820b1f5a3d83
7
- data.tar.gz: 076bee885a2a2c8634ac7a81676be77dd32f2b7d8acf459b10163e3de435ada2de4885492d00f2c43cb9de8bde517021a26b22f57105b4fcd5202d9982666cd7
6
+ metadata.gz: 79cc7e22960e8c66ba9b062d7913950be036a1385c56f67ff391f041b1c2fe35d1bda9699f75dd1919a03f2bfff34748ce6b1d47dd4bc30791c77890330eb901
7
+ data.tar.gz: 13a729509212714349e6cfa6969e80bae9025716481e1182b236a8d788dbc0307e45faf89c753435ebd9dee6181786282ba256c64b427e5c627371927c942b56
@@ -5,7 +5,15 @@ class EmrOhspInterface::EmrOhspInterfaceController < ::ApplicationController
5
5
 
6
6
  def months_generator
7
7
  render json: service.months_generator();
8
- end
8
+ end
9
+
10
+ def quarters_generator
11
+ render json: service.quarters_generator
12
+ end
13
+
14
+ def generate_quarterly_idsr_report
15
+ render json: service.generate_quarterly_idsr_report(params[:request],params[:start_date],params[:end_date]);
16
+ end
9
17
 
10
18
  def generate_weekly_idsr_report
11
19
  render json: service.generate_weekly_idsr_report(params[:request],params[:start_date],params[:end_date]);
@@ -6,6 +6,8 @@ module EmrOhspInterface
6
6
  require 'csv'
7
7
  require 'rest-client'
8
8
  require 'json'
9
+ include EmrOhspInterface::Utils
10
+
9
11
  def settings
10
12
  file = File.read(Rails.root.join("db","idsr_metadata","idsr_ohsp_settings.json"))
11
13
  config = JSON.parse(file)
@@ -102,6 +104,107 @@ module EmrOhspInterface
102
104
  return collection
103
105
  end
104
106
 
107
+ def generate_quarterly_idsr_report(request=nil,start_date=nil,end_date=nil)
108
+ epi_month = quarters_generator.first.first.strip
109
+ start_date = quarters_generator.first.last[1].split("to").first.strip if start_date.nil?
110
+ end_date = quarters_generator.first.last[1].split("to").last.strip if end_date.nil?
111
+ indicators = [
112
+ 'Diabetes Mellitus',
113
+ 'Cervical Cancer',
114
+ 'Hypertension',
115
+ 'Onchocerciasis',
116
+ 'Trachoma',
117
+ 'Lymphatic Filariasis',
118
+ 'Tuberculosis',
119
+ 'Trypanosomiasis',
120
+ 'Epilepsy',
121
+ 'Depression',
122
+ 'Suicide',
123
+ 'Psychosis'
124
+ ]
125
+
126
+ diagnosis_concepts = ['Primary Diagnosis','Secondary Diagnosis']
127
+ encounters = ['OUTPATIENT DIAGNOSIS','ADMISSION DIAGNOSIS']
128
+
129
+ report_struct = indicators.each_with_object({}) do |indicator, report|
130
+ report[indicator] = ['<5 yrs','>=5 yrs'].each_with_object({}) do |group, sub_report|
131
+ sub_report[group] = {
132
+ outpatient_cases: [],
133
+ inpatient_cases: [],
134
+ inpatient_cases_death: [],
135
+ tested_malaria: [],
136
+ tested_positive_malaria: []
137
+ }
138
+ end
139
+ end
140
+
141
+ admitted_patient_died = Proc.new do |patient|
142
+ visit_type = patient['visit_type']
143
+ dead = patient['dead']
144
+
145
+ visit_type == 'ADMISSION DIAGNOSIS' && dead
146
+ end
147
+
148
+
149
+ diagonised = ActiveRecord::Base.connection.select_all <<~SQL
150
+ SELECT
151
+ e.patient_id,
152
+ p.birthdate,
153
+ d.name diagnosis,
154
+ et.name visit_type
155
+ FROM
156
+ encounter e
157
+ INNER JOIN
158
+ obs ON obs.encounter_id = e.encounter_id
159
+ INNER JOIN
160
+ person p ON p.person_id = e.patient_id
161
+ INNER JOIN concept_name d ON d.concept_id = obs.value_coded
162
+ INNER JOIN
163
+ encounter_type et ON et.encounter_type_id = e.encounter_type
164
+ WHERE
165
+ e.encounter_type IN (#{EncounterType.where(name: encounters).pluck(:encounter_type_id).join(',')})
166
+ AND DATE(e.encounter_datetime) > '#{start_date}'
167
+ AND DATE(e.encounter_datetime) < '#{end_date}'
168
+ AND obs.concept_id IN (#{ConceptName.where(name: diagnosis_concepts).pluck(:concept_id).join(',')})
169
+ AND obs.value_coded IN (#{ConceptName.where(name: indicators).pluck(:concept_id).join(',')})
170
+ GROUP BY
171
+ p.person_id
172
+ SQL
173
+
174
+ malaria_tests = lab_results(test_types: ['Malaria Screening'], start_date: start_date, end_date: end_date)
175
+
176
+ tested_patient_ids = malaria_tests.map{|patient| patient['patient_id']}
177
+
178
+ tested_positive = Proc.new do |patient|
179
+ patient_id = patient['patient_id']
180
+ return false unless tested_patient_ids.include?(patient_id)
181
+
182
+ results = malaria_tests.find{|test| test['patient_id'] == patient_id}['results']
183
+ ['positive', 'parasites seen'].include?(results)
184
+ end
185
+
186
+ diagonised.each do |patient|
187
+ diagnosis = patient['diagnosis']
188
+ visit_type = patient['visit_type']
189
+ patient_id = patient['patient_id']
190
+ birthdate = patient['birthdate']
191
+
192
+ five_plus = '>=5 yrs'
193
+ less_than_5 = '<5 yrs'
194
+
195
+ age_group = birthdate > 5.years.ago ? less_than_5 : five_plus
196
+
197
+ report_struct[diagnosis][age_group][:outpatient_cases] << patient_id if visit_type == 'OUTPATIENT DIAGNOSIS'
198
+ report_struct[diagnosis][age_group][:inpatient_cases] << patient_id if visit_type == 'ADMISSION DIAGNOSIS'
199
+ report_struct[diagnosis][age_group][:tested_malaria] << patient_id if tested_patient_ids.include?(patient_id)
200
+ report_struct[diagnosis][age_group][:tested_positive_malaria] << patient_id if tested_positive.call(patient)
201
+ report_struct[diagnosis][age_group][:inpatient_cases_death] << patient_id if admitted_patient_died.call(patient)
202
+ end
203
+
204
+ report_struct
205
+
206
+ end
207
+
105
208
  #idsr monthly report
106
209
  def generate_monthly_idsr_report(request=nil,start_date=nil,end_date=nil)
107
210
  diag_map = settings["monthly_idsr_map"]
@@ -443,8 +546,13 @@ module EmrOhspInterface
443
546
  end
444
547
 
445
548
  def generate_hmis_17_report(start_date=nil,end_date=nil)
549
+
446
550
  diag_map = settings["hmis_17_map"]
551
+
552
+ #pull the data
553
+ type = EncounterType.find_by_name 'Outpatient diagnosis'
447
554
  collection = {}
555
+
448
556
  special_indicators = [
449
557
  "Referals from other institutions",
450
558
  "OPD total attendance",
@@ -452,68 +560,124 @@ module EmrOhspInterface
452
560
  "Malaria 5 years and older - new",
453
561
  "HIV/AIDS - new"
454
562
  ]
563
+
455
564
  special_under_five_indicators = [
456
565
  "Measles under five years - new",
457
566
  "Pneumonia under 5 years- new",
458
567
  "Dysentery under 5 years - new",
459
568
  "Diarrhoea non - bloody -new cases (under5)",
460
- "Malaria under 5 years - new",
461
- "Acute respiratory infections U5 - new"
569
+ "Malaria under 5 years - new"
462
570
  ]
463
571
 
464
-
465
- reg_data = registration_report(start_date,end_date)
466
-
467
- data =Observation.where(Arel.sql("obs_datetime BETWEEN '#{start_date.to_date.strftime('%Y-%m-%d 00:00:00')}' AND '#{end_date.to_date.strftime('%Y-%m-%d 23:59:59')}' AND c.voided = 0 AND obs.concept_id IN (6543, 6542) "))\
468
- .joins(Arel.sql('INNER JOIN concept_name c ON c.concept_id = obs.value_coded
469
- INNER JOIN person p ON p.person_id = obs.person_id'))\
470
- .pluck(Arel.sql("c.name, CASE WHEN (SELECT timestampdiff(year, birthdate, '#{end_date.to_date.strftime('%Y-%m-%d')}')) >= 5 THEN 'more_than_5'
471
- ELSE 'less_than_5' END AS age_group,p.person_id")).group_by(&:shift)
572
+ diag_map.each do |key,value|
573
+ options = {"ids"=>nil}
574
+ concept_ids = ConceptName.where(name: value).collect{|cn| cn.concept_id}
575
+
576
+ if !special_indicators.include?(key) && !special_under_five_indicators.include?(key)
577
+ data = Encounter.where('encounter_datetime BETWEEN ? AND ?
578
+ AND encounter_type = ? AND value_coded IN (?)
579
+ AND concept_id IN(6543, 6542)',
580
+ start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
581
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),type.id,concept_ids).\
582
+ joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
583
+ INNER JOIN person p ON p.person_id = encounter.patient_id').\
584
+ select('encounter.encounter_type, obs.value_coded, p.*')
585
+
586
+ all = data.collect{|record| record.person_id}
587
+
588
+
589
+ options["ids"] = all
590
+
591
+ collection[key] = options
592
+ else
593
+ if key.eql?("Referals from other institutions")
594
+ _type = EncounterType.find_by_name 'PATIENT REGISTRATION'
595
+ visit_type = ConceptName.find_by_name 'Type of visit'
596
+
597
+ data = Encounter.where('encounter_datetime BETWEEN ? AND ?
598
+ AND encounter_type = ? AND value_coded IS NOT NULL
599
+ AND obs.concept_id = ?', start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
600
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),_type.id, visit_type.concept_id).\
601
+ joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
602
+ INNER JOIN person p ON p.person_id = encounter.patient_id
603
+ INNER JOIN concept_name c ON c.concept_id = 6541').\
604
+ select('encounter.encounter_type, obs.value_coded, obs.obs_datetime, p.*, c.name visit_type').\
605
+ group('p.person_id, encounter.encounter_id')
472
606
 
607
+ all = data.collect{|record| record.person_id}
608
+
609
+ options["ids"] = all
610
+
611
+ collection[key] = options
612
+ end
473
613
 
474
- diag_map.each do |key, value|
475
- collection[key] = { "ids" => [] }
476
614
  if key.eql?("OPD total attendance")
477
- collection[key]["ids"] = reg_data.map { |item| item[1] }
478
- else
479
- if key.eql?("Referals from other institutions")
480
- reg_data = reg_data.rows.group_by(&:shift)
481
- collection[key]["ids"]= reg_data['Referral'] ? reg_data['Referral'].flatten : []
482
- end
615
+ programID = Program.find_by_name 'OPD Program'
616
+ data = Encounter.find_by_sql(
617
+ "SELECT patient_id, DATE_FORMAT(encounter_datetime,'%Y-%m-%d') enc_date
618
+ FROM encounter e
619
+ LEFT OUTER JOIN person p ON p.person_id = e.patient_id
620
+ WHERE e.voided = 0 AND encounter_datetime BETWEEN '" + start_date.to_date.strftime('%Y-%m-%d 00:00:00') +"'
621
+ AND '" + end_date.to_date.strftime('%Y-%m-%d 23:59:59') + "'
622
+ AND program_id ='" + programID.program_id.to_s + "'
623
+ GROUP BY enc_date"
624
+ ).map{|e| e. patient_id}
625
+
626
+ options["ids"] = data
627
+ collection[key] = options
483
628
  end
484
- data.each do |phrase, counts|
485
- next unless value.include?(phrase)
486
-
487
- counts.each do |label, count|
488
- if !key.eql?("Malaria 5 years and older - new") && !special_under_five_indicators.include?(key)
489
- collection[key]["ids"] << count
490
- else
491
- if ((special_under_five_indicators.include?(key) && label.eql?("less_than_5")) ||
492
- (key.eql?("Malaria 5 years and older - new") && label.eql?("more_than_5")))
493
- collection[key]["ids"] << count
494
- end
495
- end
496
- end
629
+
630
+ if key.eql?("Referal to other institutions")
631
+ data = Observation.where("obs_datetime BETWEEN ? AND ?
632
+ AND concept_id = ?",start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
633
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),'7414').\
634
+ joins('LEFT JOIN location l ON l.location_id = obs.value_text').\
635
+ select('obs.person_id').order('obs_datetime DESC')
636
+ all = data.collect{|record| record.person_id}
637
+ options["ids"] = all
638
+ collection[key] = options
639
+ end
640
+
641
+ if key.eql?("HIV/AIDS - new")
642
+ data = ActiveRecord::Base.connection.select_all(
643
+ "SELECT * FROM temp_earliest_start_date
644
+ WHERE date_enrolled BETWEEN '#{start_date}' AND '#{end_date}'
645
+ AND date_enrolled = earliest_start_date
646
+ GROUP BY patient_id" )
647
+ all = data.collect{|record| record["patient_id"]}
648
+ options["ids"] = all
649
+ collection[key] = options
497
650
  end
651
+
652
+ if key.eql?("Measles under five years - new")
653
+ collection[key] = disaggregate('less',concept_ids, start_date, end_date, type)
654
+ end
655
+
656
+ if key.eql?("Pneumonia under 5 years- new")
657
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
658
+ end
659
+
660
+ if key.eql?("Malaria under 5 years - new")
661
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
662
+ end
663
+
664
+ if key.eql?("Malaria 5 years and older - new")
665
+ collection[key] = disaggregate('greater',concept_ids, start_date, end_date, type)
666
+ end
667
+
668
+ if key.eql?("Dysentery under 5 years - new")
669
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
670
+ end
671
+
672
+ if key.eql?("Diarrhoea non - bloody -new cases (under5)")
673
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
674
+ end
675
+
498
676
  end
499
- collection
500
- end
677
+ end
678
+
679
+ collection
501
680
 
502
- def registration_report(start_date=nil,end_date=nil)
503
- ActiveRecord::Base.connection.select_all <<~SQL
504
- SELECT
505
- MIN(IFNULL(c.name, 'Unidentified')) AS visit_type,
506
- obs.person_id
507
- FROM `encounter`
508
- LEFT JOIN obs ON obs.encounter_id = encounter.encounter_id AND obs.voided = 0
509
- LEFT JOIN concept_name c ON c.concept_id = obs.value_coded
510
- AND c.name IN ('New patient','Revisiting','Referral') AND c.voided = 0
511
- WHERE
512
- encounter.voided = 0
513
- AND DATE(encounter_datetime) BETWEEN '#{start_date}' AND '#{end_date}'
514
- AND encounter.program_id = 14 -- OPD program
515
- GROUP BY encounter.patient_id, DATE(encounter_datetime);
516
- SQL
517
681
  end
518
682
 
519
683
  def generate_notifiable_disease_conditions_report(start_date=nil,end_date=nil)
@@ -571,6 +735,25 @@ module EmrOhspInterface
571
735
  return months.to_a
572
736
  end
573
737
 
738
+ def quarters_generator
739
+ quarters = Hash.new
740
+
741
+ to_quarter = Proc.new do |date|
742
+ ((date.month - 1) / 3) + 1
743
+ end
744
+
745
+ init_quarter = Date.today.beginning_of_year - 2.years
746
+
747
+ while init_quarter <= Date.today do
748
+ quarter = init_quarter.strftime("%Y")+" Q"+to_quarter.call(init_quarter).to_s
749
+ dates = "#{(init_quarter.beginning_of_quarter).to_s} to #{(init_quarter.end_of_quarter).to_s}"
750
+ quarters[quarter] = dates
751
+ init_quarter = init_quarter + 3.months
752
+ end
753
+
754
+ return quarters.to_a
755
+ end
756
+
574
757
  # helper menthod
575
758
  def weeks_generator
576
759
 
@@ -0,0 +1,31 @@
1
+ module EmrOhspInterface
2
+ module Utils
3
+ def lab_results(test_types:, start_date:, end_date:)
4
+ test_type_ids = ConceptName.where(name: test_types).pluck(:concept_id)
5
+
6
+ ActiveRecord::Base.connection.select_all <<~SQL
7
+ SELECT lab.patient_id,
8
+ tt.name,
9
+ COALESCE(result.value_numeric, result.value_text,
10
+ result.value_coded) AS results
11
+ FROM orders
12
+ INNER JOIN encounter lab ON lab.patient_id = orders.patient_id
13
+ AND lab.encounter_datetime >= '#{start_date}'
14
+ AND lab.encounter_datetime <= '#{end_date}'
15
+ AND lab.program_id = #{Program.find_by_name('OPD Program').program_id}
16
+ AND lab.voided = 0
17
+ AND orders.voided = 0
18
+ INNER JOIN obs test_type ON test_type.encounter_id = lab.encounter_id
19
+ AND test_type.concept_id = #{ConceptName.find_by_name('Test type').concept_id}
20
+ AND test_type.value_coded IN (#{test_type_ids.join(', ')})
21
+ INNER JOIN concept_name tt ON tt.concept_id = test_type.value_coded
22
+ INNER JOIN obs tr ON tr.order_id = orders.order_id
23
+ AND tr.voided = 0
24
+ AND tr.concept_id = #{ConceptName.find_by_name('Lab test result').concept_id}
25
+ AND tr.obs_group_id = test_type.obs_id
26
+ INNER JOIN obs result ON result.obs_group_id = tr.obs_id
27
+ GROUP BY lab.patient_id
28
+ SQL
29
+ end
30
+ end
31
+ end
data/config/routes.rb CHANGED
@@ -4,6 +4,7 @@ EmrOhspInterface::Engine.routes.draw do
4
4
  get '/get_weeks', to: 'emr_ohsp_interface#weeks_generator'
5
5
  get '/get_months', to: 'emr_ohsp_interface#months_generator'
6
6
  get '/generate_weekly_idsr_report', to: 'emr_ohsp_interface#generate_weekly_idsr_report'
7
+ get '/generate_quarterly_idsr_report', to: 'emr_ohsp_interface#generate_quarterly_idsr_report'
7
8
  get '/generate_monthly_idsr_report', to: 'emr_ohsp_interface#generate_monthly_idsr_report'
8
9
  get '/generate_hmis_15_report', to: 'emr_ohsp_interface#generate_hmis_15_report'
9
10
  get '/generate_hmis_17_report', to: 'emr_ohsp_interface#generate_hmis_17_report'
@@ -12,8 +13,10 @@ EmrOhspInterface::Engine.routes.draw do
12
13
  get 'api/v1/get_lims_user', to: 'emr_lims_interface#get_user_info'
13
14
  get 'api/v1/get_weeks', to: 'emr_ohsp_interface#weeks_generator'
14
15
  get 'api/v1/get_months', to: 'emr_ohsp_interface#months_generator'
16
+ get 'api/v1/get_quarters', to: 'emr_ohsp_interface#quarters_generator'
15
17
  get 'api/v1/generate_weekly_idsr_report', to: 'emr_ohsp_interface#generate_weekly_idsr_report'
16
18
  get 'api/v1/generate_monthly_idsr_report', to: 'emr_ohsp_interface#generate_monthly_idsr_report'
19
+ get 'api/v1/generate_quarterly_idsr_report', to: 'emr_ohsp_interface#generate_quarterly_idsr_report'
17
20
  get 'api/v1/generate_hmis_15_report', to: 'emr_ohsp_interface#generate_hmis_15_report'
18
21
  get 'api/v1/generate_hmis_17_report', to: 'emr_ohsp_interface#generate_hmis_17_report'
19
22
  end
@@ -1,3 +1,3 @@
1
1
  module EmrOhspInterface
2
- VERSION = '2.2.3'
2
+ VERSION = '2.2.4'
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: 2.2.3
4
+ version: 2.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Manda, Petros Kayange, Dominic Kasanga
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-11 00:00:00.000000000 Z
11
+ date: 2025-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -86,7 +86,7 @@ dependencies:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
88
  version: '1.3'
89
- description:
89
+ description:
90
90
  email:
91
91
  - justinmandah@gmail.com, kayangepetros@gmail.com, dominickasanga@gmail.com
92
92
  executables: []
@@ -108,6 +108,7 @@ files:
108
108
  - app/models/emr_ohsp_interface/application_record.rb
109
109
  - app/services/emr_ohsp_interface/emr_lims_interface_service.rb
110
110
  - app/services/emr_ohsp_interface/emr_ohsp_interface_service.rb
111
+ - app/services/emr_ohsp_interface/utils.rb
111
112
  - app/views/layouts/emr_ohsp_interface/application.html.erb
112
113
  - config/routes.rb
113
114
  - lib/emr_ohsp_interface.rb
@@ -119,7 +120,7 @@ licenses:
119
120
  - MIT
120
121
  metadata:
121
122
  homepage_uri: https://github.com/LUKEINTERNATIONAL/emr_OHSP_interface
122
- post_install_message:
123
+ post_install_message:
123
124
  rdoc_options: []
124
125
  require_paths:
125
126
  - lib
@@ -135,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
136
  version: '0'
136
137
  requirements: []
137
138
  rubygems_version: 3.4.1
138
- signing_key:
139
+ signing_key:
139
140
  specification_version: 4
140
141
  summary: This in a gem that facilitates interfacing of EMR, One Health Surveillance
141
142
  Platform and Lims