emr_ohsp_interface 2.2.3 → 2.2.5

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: c1e2f8f301b8057aed4f7ddb6e62eefd3c8108171cd949d5c329134ccae53c66
4
+ data.tar.gz: aa4515b396f441535ba766eb68ea0c71ea481f42f285dd457b7f1520fecb9bc8
5
5
  SHA512:
6
- metadata.gz: bb7b7599d5c501e5784b5ee039df5eb04f4c8b417aaf9049648436e2d67d1b435d6b9cfd4c63e4b007c6db410f1f712e5387e4731a512daed54f820b1f5a3d83
7
- data.tar.gz: 076bee885a2a2c8634ac7a81676be77dd32f2b7d8acf459b10163e3de435ada2de4885492d00f2c43cb9de8bde517021a26b22f57105b4fcd5202d9982666cd7
6
+ metadata.gz: a5e32307d05ce57d5badf73902fe312b1944ac66be0caa055da6dc05123c9219e63e6c9288fe85edd03069ace7c4c750557454a1cee16542a407e87ee00185c8
7
+ data.tar.gz: 9faf563358135620f679014461235bcfb05df09e7337e343746da1117bdaf3ea475133ae05b1282359d3f6f03fd791919af4b74fa713ba513fec113f26450482
@@ -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,106 @@ 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.downcase] = ['<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
+ diagonised = ActiveRecord::Base.connection.select_all <<~SQL
142
+ SELECT
143
+ e.patient_id,
144
+ p.birthdate,
145
+ d.name diagnosis,
146
+ et.name visit_type
147
+ FROM
148
+ encounter e
149
+ INNER JOIN
150
+ obs ON obs.encounter_id = e.encounter_id
151
+ INNER JOIN
152
+ person p ON p.person_id = e.patient_id
153
+ INNER JOIN concept_name d ON d.concept_id = obs.value_coded
154
+ INNER JOIN
155
+ encounter_type et ON et.encounter_type_id = e.encounter_type
156
+ WHERE
157
+ e.encounter_type IN (#{EncounterType.where(name: encounters).pluck(:encounter_type_id).join(',')})
158
+ AND DATE(e.encounter_datetime) > '#{start_date}'
159
+ AND DATE(e.encounter_datetime) < '#{end_date}'
160
+ AND obs.concept_id IN (#{ConceptName.where(name: diagnosis_concepts).pluck(:concept_id).join(',')})
161
+ AND obs.value_coded IN (#{ConceptName.where(name: indicators).pluck(:concept_id).join(',')})
162
+ GROUP BY
163
+ p.person_id, obs.concept_id
164
+ SQL
165
+
166
+ malaria_tests = lab_results(test_types: ['Malaria Screening'], start_date: start_date, end_date: end_date)
167
+
168
+ tested_patient_ids = malaria_tests.map{|patient| patient['patient_id']}
169
+
170
+ diagonised.each do |patient|
171
+ diagnosis = patient['diagnosis']&.downcase
172
+ visit_type = patient['visit_type']
173
+ patient_id = patient['patient_id']
174
+ birthdate = patient['birthdate']
175
+
176
+ five_plus = '>=5 yrs'
177
+ less_than_5 = '<5 yrs'
178
+
179
+ age_group = birthdate > 5.years.ago ? less_than_5 : five_plus
180
+
181
+ report_struct[diagnosis][age_group][:outpatient_cases] << patient_id if visit_type == 'OUTPATIENT DIAGNOSIS'
182
+ report_struct[diagnosis][age_group][:inpatient_cases] << patient_id if visit_type == 'ADMISSION DIAGNOSIS'
183
+ report_struct[diagnosis][age_group][:tested_malaria] << patient_id if tested_patient_ids.include?(patient_id)
184
+ report_struct[diagnosis][age_group][:tested_positive_malaria] << patient_id if tested_positive(tested_patient_ids, patient)
185
+ report_struct[diagnosis][age_group][:inpatient_cases_death] << patient_id if admitted_patient_died(patient)
186
+ end
187
+
188
+ report_struct
189
+
190
+ end
191
+
192
+ def tested_positive(ids, patient)
193
+ patient_id = patient['patient_id']
194
+ return false unless ids.include?(patient_id)
195
+
196
+ results = malaria_tests.find{|test| test['patient_id'] == patient_id}['results']
197
+ ['positive', 'parasites seen'].include?(results)
198
+ end
199
+
200
+ def admitted_patient_died(patient)
201
+ visit_type = patient['visit_type']
202
+ dead = patient['dead']
203
+
204
+ visit_type == 'ADMISSION DIAGNOSIS' && dead
205
+ end
206
+
105
207
  #idsr monthly report
106
208
  def generate_monthly_idsr_report(request=nil,start_date=nil,end_date=nil)
107
209
  diag_map = settings["monthly_idsr_map"]
@@ -443,8 +545,13 @@ module EmrOhspInterface
443
545
  end
444
546
 
445
547
  def generate_hmis_17_report(start_date=nil,end_date=nil)
548
+
446
549
  diag_map = settings["hmis_17_map"]
550
+
551
+ #pull the data
552
+ type = EncounterType.find_by_name 'Outpatient diagnosis'
447
553
  collection = {}
554
+
448
555
  special_indicators = [
449
556
  "Referals from other institutions",
450
557
  "OPD total attendance",
@@ -452,68 +559,124 @@ module EmrOhspInterface
452
559
  "Malaria 5 years and older - new",
453
560
  "HIV/AIDS - new"
454
561
  ]
562
+
455
563
  special_under_five_indicators = [
456
564
  "Measles under five years - new",
457
565
  "Pneumonia under 5 years- new",
458
566
  "Dysentery under 5 years - new",
459
567
  "Diarrhoea non - bloody -new cases (under5)",
460
- "Malaria under 5 years - new",
461
- "Acute respiratory infections U5 - new"
568
+ "Malaria under 5 years - new"
462
569
  ]
463
570
 
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)
571
+ diag_map.each do |key,value|
572
+ options = {"ids"=>nil}
573
+ concept_ids = ConceptName.where(name: value).collect{|cn| cn.concept_id}
574
+
575
+ if !special_indicators.include?(key) && !special_under_five_indicators.include?(key)
576
+ data = Encounter.where('encounter_datetime BETWEEN ? AND ?
577
+ AND encounter_type = ? AND value_coded IN (?)
578
+ AND concept_id IN(6543, 6542)',
579
+ start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
580
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),type.id,concept_ids).\
581
+ joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
582
+ INNER JOIN person p ON p.person_id = encounter.patient_id').\
583
+ select('encounter.encounter_type, obs.value_coded, p.*')
584
+
585
+ all = data.collect{|record| record.person_id}
586
+
587
+
588
+ options["ids"] = all
589
+
590
+ collection[key] = options
591
+ else
592
+ if key.eql?("Referals from other institutions")
593
+ _type = EncounterType.find_by_name 'PATIENT REGISTRATION'
594
+ visit_type = ConceptName.find_by_name 'Type of visit'
595
+
596
+ data = Encounter.where('encounter_datetime BETWEEN ? AND ?
597
+ AND encounter_type = ? AND value_coded IS NOT NULL
598
+ AND obs.concept_id = ?', start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
599
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),_type.id, visit_type.concept_id).\
600
+ joins('INNER JOIN obs ON obs.encounter_id = encounter.encounter_id
601
+ INNER JOIN person p ON p.person_id = encounter.patient_id
602
+ INNER JOIN concept_name c ON c.concept_id = 6541').\
603
+ select('encounter.encounter_type, obs.value_coded, obs.obs_datetime, p.*, c.name visit_type').\
604
+ group('p.person_id, encounter.encounter_id')
472
605
 
606
+ all = data.collect{|record| record.person_id}
607
+
608
+ options["ids"] = all
609
+
610
+ collection[key] = options
611
+ end
473
612
 
474
- diag_map.each do |key, value|
475
- collection[key] = { "ids" => [] }
476
613
  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
614
+ programID = Program.find_by_name 'OPD Program'
615
+ data = Encounter.find_by_sql(
616
+ "SELECT patient_id, DATE_FORMAT(encounter_datetime,'%Y-%m-%d') enc_date
617
+ FROM encounter e
618
+ LEFT OUTER JOIN person p ON p.person_id = e.patient_id
619
+ WHERE e.voided = 0 AND encounter_datetime BETWEEN '" + start_date.to_date.strftime('%Y-%m-%d 00:00:00') +"'
620
+ AND '" + end_date.to_date.strftime('%Y-%m-%d 23:59:59') + "'
621
+ AND program_id ='" + programID.program_id.to_s + "'
622
+ GROUP BY enc_date"
623
+ ).map{|e| e. patient_id}
624
+
625
+ options["ids"] = data
626
+ collection[key] = options
483
627
  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
628
+
629
+ if key.eql?("Referal to other institutions")
630
+ data = Observation.where("obs_datetime BETWEEN ? AND ?
631
+ AND concept_id = ?",start_date.to_date.strftime('%Y-%m-%d 00:00:00'),
632
+ end_date.to_date.strftime('%Y-%m-%d 23:59:59'),'7414').\
633
+ joins('LEFT JOIN location l ON l.location_id = obs.value_text').\
634
+ select('obs.person_id').order('obs_datetime DESC')
635
+ all = data.collect{|record| record.person_id}
636
+ options["ids"] = all
637
+ collection[key] = options
638
+ end
639
+
640
+ if key.eql?("HIV/AIDS - new")
641
+ data = ActiveRecord::Base.connection.select_all(
642
+ "SELECT * FROM temp_earliest_start_date
643
+ WHERE date_enrolled BETWEEN '#{start_date}' AND '#{end_date}'
644
+ AND date_enrolled = earliest_start_date
645
+ GROUP BY patient_id" )
646
+ all = data.collect{|record| record["patient_id"]}
647
+ options["ids"] = all
648
+ collection[key] = options
649
+ end
650
+
651
+ if key.eql?("Measles under five years - new")
652
+ collection[key] = disaggregate('less',concept_ids, start_date, end_date, type)
653
+ end
654
+
655
+ if key.eql?("Pneumonia under 5 years- new")
656
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
657
+ end
658
+
659
+ if key.eql?("Malaria under 5 years - new")
660
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
661
+ end
662
+
663
+ if key.eql?("Malaria 5 years and older - new")
664
+ collection[key] = disaggregate('greater',concept_ids, start_date, end_date, type)
665
+ end
666
+
667
+ if key.eql?("Dysentery under 5 years - new")
668
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
669
+ end
670
+
671
+ if key.eql?("Diarrhoea non - bloody -new cases (under5)")
672
+ collection[key] = disaggregate('less', concept_ids, start_date, end_date, type)
497
673
  end
674
+
498
675
  end
499
- collection
500
- end
676
+ end
677
+
678
+ collection
501
679
 
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
680
  end
518
681
 
519
682
  def generate_notifiable_disease_conditions_report(start_date=nil,end_date=nil)
@@ -571,6 +734,25 @@ module EmrOhspInterface
571
734
  return months.to_a
572
735
  end
573
736
 
737
+ def quarters_generator
738
+ quarters = Hash.new
739
+
740
+ to_quarter = Proc.new do |date|
741
+ ((date.month - 1) / 3) + 1
742
+ end
743
+
744
+ init_quarter = Date.today.beginning_of_year - 2.years
745
+
746
+ while init_quarter <= Date.today do
747
+ quarter = init_quarter.strftime("%Y")+" Q"+to_quarter.call(init_quarter).to_s
748
+ dates = "#{(init_quarter.beginning_of_quarter).to_s} to #{(init_quarter.end_of_quarter).to_s}"
749
+ quarters[quarter] = dates
750
+ init_quarter = init_quarter + 3.months
751
+ end
752
+
753
+ return quarters.to_a
754
+ end
755
+
574
756
  # helper menthod
575
757
  def weeks_generator
576
758
 
@@ -719,4 +901,4 @@ module EmrOhspInterface
719
901
  end
720
902
  end
721
903
 
722
- end
904
+ end
@@ -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.5'
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.5
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