his_emr_api_lab 2.1.4 → 2.1.5.streaming

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: 2086e2372ae3182efa9a1eb56d5dfe0845f770800f25891dec98af02530d7953
4
- data.tar.gz: cebae46dd81f29f128b6904ccaa7dbefc780b0dfcc57d9f2e1f3087f86cfc830
3
+ metadata.gz: 4aeefd371ffd0e3a4c9d460b7d7bd280b3d65868438b0760f992cf66dced202b
4
+ data.tar.gz: 48ca67bb59e2daebe7776f62fdafa6bc158d18351bbb161690a9a598a442b905
5
5
  SHA512:
6
- metadata.gz: 6381879cefbb24c3226d2a68f458e26cea19bcf3db7f4b50fb97a14afc7b94958f2e76178d8f1fa0f4abd6ff976ddaa0ca5ce3f26fb309414117f0b82c872389
7
- data.tar.gz: b6bede3239bb94db739c4ea1f7cf817a4eb217b9c5ba77bb9b3678dcb1b3edba44f41f71c8e0db00d9f1d333458a49376d8bb57a631473ed35ef4d3641293399
6
+ metadata.gz: fabfe624347d8724f40a063266d04619057111f92f512be9e847587c53d1d435caaf46dda9055cf8adde7af5d791091bc5898c54a1a4857b5a4536e11e5f723e
7
+ data.tar.gz: b24da9322346b8efdf05b3e671e550d3d6b6b59c8cd02b52415747acdd2b968e9f30eba0ef7b4df63e6cf9e25b4811189114f074139eac7fdaf967954569dc3c
@@ -6,6 +6,7 @@ module Lab
6
6
  class ProcessLabResultJob < ApplicationJob
7
7
  queue_as :default
8
8
  def perform(results_obs_id, serializer, result_enter_by)
9
+ Rails.logger.info("Lab::ProcessLabResultJob: Processing result completion for #{serializer}")
9
10
  results_obs = Lab::LabResult.find(results_obs_id)
10
11
  Lab::ResultsService.process_result_completion(results_obs, serializer, result_enter_by)
11
12
  end
@@ -21,7 +21,7 @@ module Lab
21
21
  order_date: order.date_created,
22
22
  location_id: encounter.location_id,
23
23
  program_id: encounter.program_id,
24
- program_name: program.name,
24
+ program_name: program&.name,
25
25
  # order_date: order.start_date,
26
26
  patient_id: order.patient_id,
27
27
  accession_number: order.accession_number,
@@ -7,11 +7,11 @@ module Lab
7
7
  def self.serialize(result)
8
8
  result.children.map do |measure|
9
9
  value, value_type = read_value(measure)
10
- concept_name = ConceptName.find_by_concept_id(measure.concept_id)
11
-
12
- program_id = ""
10
+ # Get the test catalog name instead of any random concept name
11
+ concept_name = get_test_catalog_concept_name(measure.concept_id)
12
+ program_id = ''
13
13
  if measure.obs_id.present?
14
- obs = Observation.find(measure.obs_id)
14
+ obs = Observation.unscope(where: :obs_group_id).find(measure.obs_id)
15
15
  encounter = Encounter.find(obs.encounter_id)
16
16
  program_id = encounter.program_id
17
17
  end
@@ -19,8 +19,8 @@ module Lab
19
19
  {
20
20
  id: measure.obs_id,
21
21
  indicator: {
22
- concept_id: concept_name&.concept_id,
23
- name: concept_name&.name
22
+ concept_id: measure.concept_id,
23
+ name: concept_name
24
24
  },
25
25
  date: measure.obs_datetime,
26
26
  value:,
@@ -31,6 +31,12 @@ module Lab
31
31
  end
32
32
  end
33
33
 
34
+ def self.get_test_catalog_concept_name(concept_id)
35
+ return nil unless concept_id
36
+
37
+ ::ConceptAttribute.find_by(concept_id:, attribute_type: ConceptAttributeType.test_catalogue_name)&.value_reference
38
+ end
39
+
34
40
  def self.read_value(measure)
35
41
  %w[value_numeric value_coded value_boolean value_text].each do |field|
36
42
  value = measure.send(field) if measure.respond_to?(field)
@@ -61,7 +61,7 @@ module Lab
61
61
  INNER JOIN concept_attribute ca2 ON ca.concept_id = ca2.concept_id
62
62
  AND ca2.attribute_type_id = #{ConceptAttributeType.nlims_code.concept_attribute_type_id}
63
63
  WHERE ca.attribute_type_id = #{ConceptAttributeType.test_catalogue_name.concept_attribute_type_id}
64
- AND ca.concept_id IN (#{concept_set.select(:concept_id).to_sql})
64
+ AND ca.concept_id IN (#{concept_set.select(:concept_set).to_sql})
65
65
  GROUP BY ca.concept_id
66
66
  SQL
67
67
  end
@@ -4,7 +4,7 @@ module Lab
4
4
  # This class is used to encode and decode the JWT token
5
5
  module JsonWebTokenService
6
6
  class << self
7
- SECRET_KEY = Rails.application.secrets.secret_key_base.to_s
7
+ SECRET_KEY = Rails.application.credentials[:secret_key_base].to_s
8
8
 
9
9
  def encode(payload, request_ip, exp = 18.hours.from_now)
10
10
  payload[:exp] = exp.to_i
@@ -341,7 +341,7 @@ module Lab
341
341
  def nlims_order_exists?(tracking_number)
342
342
  response = in_authenticated_session do |headers|
343
343
  Rails.logger.info("Verifying order ##{tracking_number}")
344
- RestClient.get(expand_uri("orders/#{tracking_number}", api_version: 'v2'), headers)
344
+ RestClient.get(expand_uri("orders/#{tracking_number}/exists", api_version: 'v2'), headers)
345
345
  end
346
346
 
347
347
  Rails.logger.info("Order ##{tracking_number} verified... Parsing...")
@@ -29,7 +29,7 @@ require 'lab/lab_test'
29
29
  require 'lab/lims_order_mapping'
30
30
  require 'lab/lims_failed_import'
31
31
 
32
- require_relative 'api/couch_db_api'
32
+ require_relative 'api/couchdb_api'
33
33
  require_relative 'config'
34
34
  require_relative 'pull_worker'
35
35
  require_relative 'utils'
@@ -144,7 +144,7 @@ module Lab
144
144
  end
145
145
 
146
146
  def format_test_status_trail(order)
147
- tests = order.voided.zero? ? order.tests : Lab::LabOrderSerializer.voided_tests(order)
147
+ tests = [0, false].include?(order.voided) ? order.tests : Lab::LabOrderSerializer.voided_tests(order)
148
148
  tests.each_with_object({}) do |test, trail|
149
149
  test_name = format_test_name(::Concept.find(test.value_coded).test_catalogue_name)
150
150
 
@@ -155,7 +155,7 @@ module Lab
155
155
  updated_by: find_user(test.creator)
156
156
  }
157
157
 
158
- unless test.voided.zero?
158
+ unless [0, false].include?(test.voided)
159
159
  current_test_trail[test.date_voided.strftime('%Y%m%d%H%M%S')] = {
160
160
  status: 'Voided',
161
161
  updated_by: find_user(test.voided_by)
@@ -216,7 +216,7 @@ module Lab
216
216
  end
217
217
 
218
218
  next if test.result || test_results['results'].blank?
219
-
219
+
220
220
  result_date = Time.now
221
221
  measures = test_results['results'].map do |indicator, value|
222
222
  measure = find_measure(order, indicator, value)
@@ -51,7 +51,7 @@ module Lab
51
51
  mapping = Lab::LimsOrderMapping.find_by(order_id: order.order_id)
52
52
 
53
53
  ActiveRecord::Base.transaction do
54
- if mapping && !order.voided.zero?
54
+ if mapping && ![0, false].include?(order.voided)
55
55
  Rails.logger.info("Deleting order ##{order_dto['accession_number']} from LIMS")
56
56
  lims_api.delete_order(mapping.lims_id, order_dto)
57
57
  mapping.destroy
@@ -78,8 +78,12 @@ module Lab
78
78
  end
79
79
 
80
80
  def self.find_concept_by_name(name)
81
- ConceptName.joins("INNER JOIN concept_attribute ON concept_attribute.concept_id = concept_name.concept_id")
82
- .where("concept_attribute.value_reference = ?", CGI.unescapeHTML(name))
81
+ unescaped_name = CGI.unescapeHTML(name)
82
+ attribute_type_id = ConceptAttributeType.test_catalogue_name.concept_attribute_type_id
83
+
84
+ ConceptName.joins('INNER JOIN concept_attribute ON concept_attribute.concept_id = concept_name.concept_id')
85
+ .where('concept_attribute.attribute_type_id = ? AND concept_attribute.value_reference = ? AND concept_name.name = ?',
86
+ attribute_type_id, unescaped_name, unescaped_name)
83
87
  .first
84
88
  end
85
89
  end
@@ -234,7 +234,7 @@ module Lab
234
234
  encounter.encounter_type = EncounterType.find_by_name!(Lab::Metadata::ENCOUNTER_TYPE_NAME)
235
235
  encounter.encounter_datetime = order_params[:date] || Date.today
236
236
  encounter.visit = Visit.find_by_uuid(visit) if Encounter.column_names.include?('visit_id')
237
- encounter.provider_id = User.current&.person.id if Encounter.column_names.include?('provider_id')
237
+ encounter.provider_id = User.current&.person&.id if Encounter.column_names.include?('provider_id')
238
238
  encounter.program_id = order_params[:program_id] if Encounter.column_names.include?('program_id') && order_params[:program_id].present?
239
239
  encounter.save!
240
240
  encounter.reload
@@ -20,7 +20,11 @@ module Lab
20
20
  serializer = {}
21
21
  results_obs = {}
22
22
  ActiveRecord::Base.transaction do
23
- test = Lab::LabTest.find(test_id) rescue nil
23
+ test = begin
24
+ Lab::LabTest.find(test_id)
25
+ rescue StandardError
26
+ nil
27
+ end
24
28
  test = Lab::LabTest.find_by_uuid(test_id) if test.blank?
25
29
  encounter = find_encounter(test, encounter_id: params[:encounter_id],
26
30
  encounter_uuid: params[:encounter],
@@ -37,9 +41,9 @@ module Lab
37
41
 
38
42
  # force commit all transactions
39
43
  ActiveRecord::Base.connection.commit_db_transaction
40
-
41
- # delay job by a second
42
- ProcessLabResultJob.set(wait: 1.second).perform_later(results_obs.id, serializer, result_enter_by)
44
+
45
+ # Execute job synchronously
46
+ ProcessLabResultJob.perform_now(results_obs.id, serializer, result_enter_by)
43
47
 
44
48
  Rails.logger.info("Lab::ResultsService: Result created for test #{test_id} #{serializer}")
45
49
  serializer
@@ -55,10 +59,10 @@ module Lab
55
59
  def precess_notification_message(result, values, result_enter_by)
56
60
  order = Order.find(result.order_id)
57
61
  data = { Type: result_enter_by,
58
- Specimen: ConceptName.find_by(concept_id: order.concept_id)&.name,
59
- 'Test type': ConceptName.find_by(concept_id: result.test.value_coded)&.name,
62
+ Specimen: get_test_catalog_name(order.concept_id) || ConceptName.find_by(concept_id: order.concept_id)&.name,
63
+ 'Test type': get_test_catalog_name(result.test.value_coded) || ConceptName.find_by(concept_id: result.test.value_coded)&.name,
60
64
  'Accession number': order&.accession_number,
61
- 'Orde date': Order.columns.include?('start_date') ? order.start_date : order.date_created,
65
+ order_date: Order.columns.include?('start_date') ? order.start_date : order.date_created,
62
66
  'ARV-Number': find_arv_number(result.person_id),
63
67
  PatientID: result.person_id,
64
68
  'Ordered By': Order.columns.include?('provider_id') ? order&.provider&.person&.name : Person.find(order.creator)&.name,
@@ -82,19 +86,21 @@ module Lab
82
86
  def find_encounter(test, encounter_id: nil, encounter_uuid: nil, date: nil, provider_id: nil)
83
87
  return Encounter.find(encounter_id) if encounter_id
84
88
  return Encounter.find_by_uuid(encounter_uuid) if encounter_uuid
85
- encounter_type = EncounterType.find_by_name!(Lab::Metadata::ENCOUNTER_TYPE_NAME)
89
+
90
+ lab_encounter_type = EncounterType.find_by_name!(Lab::Metadata::ENCOUNTER_TYPE_NAME)
86
91
 
87
92
  encounter = Encounter.new
88
93
  encounter.patient_id = test.person_id
89
94
  encounter.program_id = test.encounter.program_id if Encounter.column_names.include?('program_id')
90
95
  encounter.visit_id = test.encounter.visit_id if Encounter.column_names.include?('visit_id')
91
- encounter.type = encounter_type
92
- encounter.encounter_type = encounter_type if (encounter&.encounter_type.nil? || encounter&.type.nil?)
96
+ # Use bracket notation to set the encounter_type column directly (bypasses association)
97
+ # This handles both Integer and EncounterType object
98
+ encounter_type_value = lab_encounter_type.is_a?(Integer) ? lab_encounter_type : lab_encounter_type.encounter_type_id
99
+ encounter[:encounter_type] = encounter_type_value
93
100
  encounter.encounter_datetime = date || Date.today
94
101
  encounter.provider_id = provider_id || User.current.user_id if Encounter.column_names.include?('provider_id')
95
-
96
102
  encounter.save!
97
-
103
+ encounter.reload
98
104
  encounter
99
105
  end
100
106
 
@@ -130,7 +136,8 @@ module Lab
130
136
  def add_measure_to_results(results_obs, params, date)
131
137
  validate_measure_params(params)
132
138
 
133
- concept_id = params[:indicator][:concept_id] || Concept.find_concept_by_uuid(params.dig(:indicator, :concept))&.id
139
+ concept_id = params[:indicator][:concept_id] || Concept.find_concept_by_uuid(params.dig(:indicator,
140
+ :concept))&.id
134
141
 
135
142
  Observation.create!(
136
143
  person_id: results_obs.person_id,
@@ -174,6 +181,13 @@ module Lab
174
181
  else raise InvalidParameterError, "Invalid boolean value: #{string}"
175
182
  end
176
183
  end
184
+
185
+ def get_test_catalog_name(concept_id)
186
+ return nil unless concept_id
187
+
188
+ ::ConceptAttribute.find_by(concept_id:,
189
+ attribute_type: ConceptAttributeType.test_catalogue_name)&.value_reference
190
+ end
177
191
  end
178
192
  end
179
193
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This migration adds the program_id column to the encounter table if it doesn't already exist.
4
+ # The program_id column is used to associate encounters with specific programs (e.g., HIV Program, TB Program).
5
+ class AddProgramIdToEncounter < ActiveRecord::Migration[5.2]
6
+ def change
7
+ return if column_exists?(:encounter, :program_id)
8
+
9
+ add_column :encounter, :program_id, :integer, after: :encounter_type
10
+ add_index :encounter, :program_id
11
+ add_foreign_key :encounter, :program, column: :program_id, primary_key: :program_id
12
+ end
13
+ end
data/lib/lab/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lab
4
- VERSION = '2.1.4'
4
+ VERSION = '2.1.5.streaming'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: his_emr_api_lab
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.4
4
+ version: 2.1.5.streaming
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elizabeth Glaser Pediatric Foundation Malawi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-01-22 00:00:00.000000000 Z
11
+ date: 2026-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: couchrest
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 7.0.6
47
+ version: 8.0.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 7.0.6
54
+ version: 8.0.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: socket.io-client-simple
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -270,7 +270,7 @@ files:
270
270
  - app/services/lab/lims/acknowledgement_serializer.rb
271
271
  - app/services/lab/lims/acknowledgement_worker.rb
272
272
  - app/services/lab/lims/api/blackhole_api.rb
273
- - app/services/lab/lims/api/couch_db_api.rb
273
+ - app/services/lab/lims/api/couchdb_api.rb
274
274
  - app/services/lab/lims/api/mysql_api.rb
275
275
  - app/services/lab/lims/api/rest_api.rb
276
276
  - app/services/lab/lims/api/ws_api.rb
@@ -301,6 +301,7 @@ files:
301
301
  - db/migrate/20210807111531_add_default_to_lims_order_mapping.rb
302
302
  - db/migrate/20260119104240_add_fulfiller_fields_to_orders.rb
303
303
  - db/migrate/20260119104241_create_comment_to_fulfiller_concept.rb
304
+ - db/migrate/20260128111557_add_program_id_to_encounter.rb
304
305
  - lib/auto12epl.rb
305
306
  - lib/couch_bum/couch_bum.rb
306
307
  - lib/generators/lab/install/USAGE
@@ -339,9 +340,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
339
340
  version: '0'
340
341
  required_rubygems_version: !ruby/object:Gem::Requirement
341
342
  requirements:
342
- - - ">="
343
+ - - ">"
343
344
  - !ruby/object:Gem::Version
344
- version: '0'
345
+ version: 1.3.1
345
346
  requirements: []
346
347
  rubygems_version: 3.4.1
347
348
  signing_key: