his_emr_api_lab 2.1.1 → 2.1.3

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/lab/labels_controller.rb +2 -1
  3. data/app/controllers/lab/orders_controller.rb +14 -25
  4. data/app/controllers/lab/results_controller.rb +2 -1
  5. data/app/controllers/lab/specimen_types_controller.rb +0 -1
  6. data/app/controllers/lab/test_methods_controller.rb +9 -0
  7. data/app/controllers/lab/test_types_controller.rb +1 -1
  8. data/app/controllers/lab/tests_controller.rb +1 -3
  9. data/app/controllers/lab/users_controller.rb +2 -1
  10. data/app/models/lab/lab_result.rb +4 -0
  11. data/app/models/lab/lab_test.rb +1 -1
  12. data/app/models/lab/order_extension.rb +14 -0
  13. data/app/serializers/lab/lab_order_serializer.rb +20 -4
  14. data/app/serializers/lab/result_serializer.rb +1 -1
  15. data/app/serializers/lab/test_serializer.rb +24 -1
  16. data/app/services/lab/acknowledgement_service.rb +4 -1
  17. data/app/services/lab/concepts_service.rb +77 -22
  18. data/app/services/lab/lims/acknowledgement_worker.rb +1 -1
  19. data/app/services/lab/lims/api/rest_api.rb +543 -78
  20. data/app/services/lab/lims/config.rb +7 -2
  21. data/app/services/lab/lims/exceptions.rb +18 -6
  22. data/app/services/lab/lims/migrator.rb +3 -3
  23. data/app/services/lab/lims/order_dto.rb +1 -1
  24. data/app/services/lab/lims/order_serializer.rb +28 -7
  25. data/app/services/lab/lims/push_worker.rb +3 -3
  26. data/app/services/lab/lims/utils.rb +5 -7
  27. data/app/services/lab/lims/worker.rb +1 -1
  28. data/app/services/lab/metadata.rb +3 -0
  29. data/app/services/lab/notification_service.rb +72 -0
  30. data/app/services/lab/orders_search_service.rb +11 -5
  31. data/app/services/lab/orders_service.rb +79 -38
  32. data/app/services/lab/results_service.rb +30 -16
  33. data/app/services/lab/tests_service.rb +15 -3
  34. data/config/routes.rb +1 -0
  35. data/db/migrate/20260119104240_add_fulfiller_fields_to_orders.rb +11 -0
  36. data/db/migrate/20260119104241_create_comment_to_fulfiller_concept.rb +50 -0
  37. data/lib/lab/version.rb +1 -1
  38. data/lib/mahis_emr_api_lab.rb +6 -0
  39. metadata +11 -5
  40. /data/app/services/lab/lims/api/{couchdb_api.rb → couch_db_api.rb} +0 -0
@@ -20,8 +20,10 @@ module Lab
20
20
  serializer = {}
21
21
  results_obs = {}
22
22
  ActiveRecord::Base.transaction do
23
- test = Lab::LabTest.find(test_id)
23
+ test = Lab::LabTest.find(test_id) rescue nil
24
+ test = Lab::LabTest.find_by_uuid(test_id) if test.blank?
24
25
  encounter = find_encounter(test, encounter_id: params[:encounter_id],
26
+ encounter_uuid: params[:encounter],
25
27
  date: params[:date]&.to_date,
26
28
  provider_id: params[:provider_id])
27
29
 
@@ -33,7 +35,11 @@ module Lab
33
35
  serializer = Lab::ResultSerializer.serialize(results_obs)
34
36
  end
35
37
 
36
- ProcessLabResultJob.perform_later(results_obs.id, serializer, result_enter_by)
38
+ # force commit all transactions
39
+ 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)
37
43
 
38
44
  Rails.logger.info("Lab::ResultsService: Result created for test #{test_id} #{serializer}")
39
45
  serializer
@@ -52,10 +58,10 @@ module Lab
52
58
  Specimen: ConceptName.find_by(concept_id: order.concept_id)&.name,
53
59
  'Test type': ConceptName.find_by(concept_id: result.test.value_coded)&.name,
54
60
  'Accession number': order&.accession_number,
55
- 'Orde date': order&.start_date,
61
+ 'Orde date': Order.columns.include?('start_date') ? order.start_date : order.date_created,
56
62
  'ARV-Number': find_arv_number(result.person_id),
57
63
  PatientID: result.person_id,
58
- 'Ordered By': order&.provider&.person&.name,
64
+ 'Ordered By': Order.columns.include?('provider_id') ? order&.provider&.person&.name : Person.find(order.creator)&.name,
59
65
  Result: values }.as_json
60
66
  NotificationService.new.create_notification(result_enter_by, data)
61
67
  end
@@ -73,22 +79,28 @@ module Lab
73
79
  .first&.identifier
74
80
  end
75
81
 
76
- def find_encounter(test, encounter_id: nil, date: nil, provider_id: nil)
82
+ def find_encounter(test, encounter_id: nil, encounter_uuid: nil, date: nil, provider_id: nil)
77
83
  return Encounter.find(encounter_id) if encounter_id
84
+ return Encounter.find_by_uuid(encounter_uuid) if encounter_uuid
85
+ encounter_type = EncounterType.find_by_name!(Lab::Metadata::ENCOUNTER_TYPE_NAME)
78
86
 
79
- Encounter.create!(
80
- patient_id: test.person_id,
81
- program_id: test.encounter.program_id,
82
- type: EncounterType.find_by_name!(Lab::Metadata::ENCOUNTER_TYPE_NAME),
83
- encounter_datetime: date || Date.today,
84
- provider_id: provider_id || User.current.user_id
85
- )
87
+ encounter = Encounter.new
88
+ encounter.patient_id = test.person_id
89
+ encounter.program_id = test.encounter.program_id if Encounter.column_names.include?('program_id')
90
+ 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?)
93
+ encounter.encounter_datetime = date || Date.today
94
+ encounter.provider_id = provider_id || User.current.user_id if Encounter.column_names.include?('provider_id')
95
+
96
+ encounter.save!
97
+
98
+ encounter
86
99
  end
87
100
 
88
101
  # Creates the parent observation for results to which the different measures are attached
89
102
  def create_results_obs(encounter, test, date, comments = nil)
90
103
  void_existing_results_obs(encounter, test)
91
-
92
104
  Lab::LabResult.create!(
93
105
  person_id: encounter.patient_id,
94
106
  encounter_id: encounter.encounter_id,
@@ -118,11 +130,13 @@ module Lab
118
130
  def add_measure_to_results(results_obs, params, date)
119
131
  validate_measure_params(params)
120
132
 
133
+ concept_id = params[:indicator][:concept_id] || Concept.find_concept_by_uuid(params.dig(:indicator, :concept))&.id
134
+
121
135
  Observation.create!(
122
136
  person_id: results_obs.person_id,
123
137
  encounter_id: results_obs.encounter_id,
124
138
  order_id: results_obs.order_id,
125
- concept_id: params[:indicator][:concept_id],
139
+ concept_id: concept_id,
126
140
  obs_group_id: results_obs.obs_id,
127
141
  obs_datetime: date&.to_datetime || DateTime.now,
128
142
  **make_measure_value(params)
@@ -132,8 +146,8 @@ module Lab
132
146
  def validate_measure_params(params)
133
147
  raise InvalidParameterError, 'measures.value is required' if params[:value].blank?
134
148
 
135
- if params[:indicator]&.[](:concept_id).blank?
136
- raise InvalidParameterError, 'measures.indicator.concept_id is required'
149
+ if params[:indicator]&.[](:concept_id).blank? && params[:indicator]&.[](:concept).blank?
150
+ raise InvalidParameterError, 'measures.indicator.concept_id or concept is required'
137
151
  end
138
152
 
139
153
  params
@@ -7,9 +7,15 @@ module Lab
7
7
  class << self
8
8
  def find_tests(filters)
9
9
  tests = Lab::LabTest.all
10
+ patient_id = filters.delete(:patient_id)
11
+ patient_id ||= ::Patient.find(filters.delete(:patient))&.id if filters[:patient]
12
+
13
+ Lab::UpdatePatientOrdersJob.perform_later(patient_id) if patient_id
10
14
 
11
15
  tests = filter_tests(tests, test_type_id: filters.delete(:test_type_id),
12
- patient_id: filters.delete(:patient_id))
16
+ patient_id: filters.delete(:patient_id),
17
+ patient: filters.delete(:patient)
18
+ )
13
19
 
14
20
  tests = filter_tests_by_results(tests) if %w[1 true].include?(filters[:pending_results]&.downcase)
15
21
 
@@ -23,8 +29,12 @@ module Lab
23
29
  def create_tests(order, date, tests_params)
24
30
  raise InvalidParameterError, 'tests are required' if tests_params.nil? || tests_params.empty?
25
31
 
32
+
26
33
  Lab::LabTest.transaction do
27
34
  tests_params.map do |params|
35
+ concept_id = params[:concept_id]
36
+ concept_id = Concept.find_concept_by_uuid(params[:concept]).id if concept_id.nil?
37
+
28
38
  test = Lab::LabTest.create!(
29
39
  concept_id: ConceptName.find_by_name!(Lab::Metadata::TEST_TYPE_CONCEPT_NAME)
30
40
  .concept_id,
@@ -32,7 +42,7 @@ module Lab
32
42
  order_id: order.order_id,
33
43
  person_id: order.patient_id,
34
44
  obs_datetime: date&.to_time || Time.now,
35
- value_coded: params[:concept_id]
45
+ value_coded: concept_id
36
46
  )
37
47
 
38
48
  Lab::TestSerializer.serialize(test, order:)
@@ -44,9 +54,11 @@ module Lab
44
54
 
45
55
  ##
46
56
  # Filter a LabTests Relation.
47
- def filter_tests(tests, test_type_id: nil, patient_id: nil)
57
+ def filter_tests(tests, test_type_id: nil, patient_id: nil, patient: nil)
48
58
  tests = tests.where(value_coded: test_type_id) if test_type_id
49
59
  tests = tests.where(person_id: patient_id) if patient_id
60
+ person = ::Person.find_by_uuid(patient) if patient
61
+ tests = tests.where(person_id: person&.patient&.id) if patient
50
62
 
51
63
  tests
52
64
  end
data/config/routes.rb CHANGED
@@ -14,6 +14,7 @@ Lab::Engine.routes.draw do
14
14
 
15
15
  get 'api/v1/lab/labels/order', to: 'labels#print_order_label'
16
16
  get 'api/v1/lab/accession_number', to: 'orders#verify_tracking_number'
17
+ get 'api/v1/lab/test_methods', to: 'test_methods#index'
17
18
 
18
19
  # Metadata
19
20
  # TODO: Move the following to namespace /concepts
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This migration adds fields to the orders table to support the comment to fulfiller feature.
4
+ class AddFulfillerFieldsToOrders < ActiveRecord::Migration[5.2]
5
+ def change
6
+ add_column :orders, :comment_to_fulfiller, :string, limit: 1024 unless column_exists?(:orders,
7
+ :comment_to_fulfiller)
8
+ add_column :orders, :fulfiller_comment, :string, limit: 1024 unless column_exists?(:orders, :fulfiller_comment)
9
+ add_column :orders, :fulfiller_status, :string, limit: 50 unless column_exists?(:orders, :fulfiller_status)
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This migration creates the concept for the comment to fulfiller feature.
4
+ class CreateCommentToFulfillerConcept < ActiveRecord::Migration[5.2]
5
+ def up
6
+ # Return if the concept already exists
7
+ return if ConceptName.exists?(name: 'Comment to fulfiller')
8
+
9
+ ActiveRecord::Base.transaction do
10
+ # Find or create the concept class for Misc
11
+ concept_class = ConceptClass.find_by(name: 'Finding')
12
+
13
+ # Find or create the concept datatype for Text
14
+ concept_datatype = ConceptDatatype.find_by(name: 'Text')
15
+
16
+ # Create the concept
17
+ concept = Concept.create!(
18
+ class_id: concept_class.id,
19
+ datatype_id: concept_datatype.id,
20
+ short_name: 'Comment to fulfiller',
21
+ retired: 0,
22
+ is_set: 0,
23
+ creator: 1,
24
+ date_created: Time.current,
25
+ uuid: SecureRandom.uuid
26
+ )
27
+
28
+ # Create the concept name
29
+ ConceptName.create!(
30
+ concept: concept,
31
+ name: 'Comment to fulfiller',
32
+ locale: 'en',
33
+ locale_preferred: 1,
34
+ concept_name_type: 'FULLY_SPECIFIED',
35
+ creator: 1,
36
+ date_created: Time.current,
37
+ uuid: SecureRandom.uuid
38
+ )
39
+ puts "Created 'Comment to fulfiller' concept with ID: #{concept.concept_id}"
40
+ end
41
+ end
42
+
43
+ def down
44
+ concept = ConceptName.find_by(name: 'Comment to fulfiller')&.concept
45
+ return unless concept
46
+
47
+ ConceptName.where(concept: concept).destroy_all
48
+ concept.destroy
49
+ end
50
+ 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.1'
4
+ VERSION = '2.1.3'
5
5
  end
@@ -0,0 +1,6 @@
1
+ require 'lab/engine'
2
+ require 'lab/version'
3
+
4
+ module Lab
5
+ # Your code goes here...
6
+ 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.1
4
+ version: 2.1.3
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-12 00:00:00.000000000 Z
11
+ date: 2026-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: couchrest
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 7.0.6
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
54
  version: 7.0.6
55
55
  - !ruby/object:Gem::Dependency
@@ -238,6 +238,7 @@ files:
238
238
  - app/controllers/lab/reasons_for_test_controller.rb
239
239
  - app/controllers/lab/results_controller.rb
240
240
  - app/controllers/lab/specimen_types_controller.rb
241
+ - app/controllers/lab/test_methods_controller.rb
241
242
  - app/controllers/lab/test_result_indicators_controller.rb
242
243
  - app/controllers/lab/test_types_controller.rb
243
244
  - app/controllers/lab/tests_controller.rb
@@ -257,6 +258,7 @@ files:
257
258
  - app/models/lab/lab_test.rb
258
259
  - app/models/lab/lims_failed_import.rb
259
260
  - app/models/lab/lims_order_mapping.rb
261
+ - app/models/lab/order_extension.rb
260
262
  - app/serializers/lab/lab_order_serializer.rb
261
263
  - app/serializers/lab/result_serializer.rb
262
264
  - app/serializers/lab/test_serializer.rb
@@ -268,7 +270,7 @@ files:
268
270
  - app/services/lab/lims/acknowledgement_serializer.rb
269
271
  - app/services/lab/lims/acknowledgement_worker.rb
270
272
  - app/services/lab/lims/api/blackhole_api.rb
271
- - app/services/lab/lims/api/couchdb_api.rb
273
+ - app/services/lab/lims/api/couch_db_api.rb
272
274
  - app/services/lab/lims/api/mysql_api.rb
273
275
  - app/services/lab/lims/api/rest_api.rb
274
276
  - app/services/lab/lims/api/ws_api.rb
@@ -283,6 +285,7 @@ files:
283
285
  - app/services/lab/lims/utils.rb
284
286
  - app/services/lab/lims/worker.rb
285
287
  - app/services/lab/metadata.rb
288
+ - app/services/lab/notification_service.rb
286
289
  - app/services/lab/orders_search_service.rb
287
290
  - app/services/lab/orders_service.rb
288
291
  - app/services/lab/results_service.rb
@@ -296,6 +299,8 @@ files:
296
299
  - db/migrate/20210407071728_create_lab_lims_failed_imports.rb
297
300
  - db/migrate/20210610095024_fix_numeric_results_value_type.rb
298
301
  - db/migrate/20210807111531_add_default_to_lims_order_mapping.rb
302
+ - db/migrate/20260119104240_add_fulfiller_fields_to_orders.rb
303
+ - db/migrate/20260119104241_create_comment_to_fulfiller_concept.rb
299
304
  - lib/auto12epl.rb
300
305
  - lib/couch_bum/couch_bum.rb
301
306
  - lib/generators/lab/install/USAGE
@@ -307,6 +312,7 @@ files:
307
312
  - lib/lab/engine.rb
308
313
  - lib/lab/version.rb
309
314
  - lib/logger_multiplexor.rb
315
+ - lib/mahis_emr_api_lab.rb
310
316
  - lib/tasks/lab_tasks.rake
311
317
  - lib/tasks/loaders/data/reasons-for-test.csv
312
318
  - lib/tasks/loaders/data/test-measures.csv