his_emr_api_lab 2.1.0 → 2.1.2
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 +4 -4
- data/app/controllers/lab/labels_controller.rb +2 -1
- data/app/controllers/lab/orders_controller.rb +14 -25
- data/app/controllers/lab/results_controller.rb +2 -1
- data/app/controllers/lab/specimen_types_controller.rb +0 -1
- data/app/controllers/lab/test_methods_controller.rb +9 -0
- data/app/controllers/lab/test_types_controller.rb +1 -1
- data/app/controllers/lab/tests_controller.rb +1 -3
- data/app/controllers/lab/users_controller.rb +2 -1
- data/app/jobs/lab/process_lab_result_job.rb +13 -0
- data/app/models/lab/lab_order.rb +4 -1
- data/app/models/lab/lab_result.rb +4 -0
- data/app/models/lab/lab_test.rb +1 -1
- data/app/models/lab/order_extension.rb +14 -0
- data/app/serializers/lab/lab_order_serializer.rb +27 -4
- data/app/serializers/lab/result_serializer.rb +10 -2
- data/app/serializers/lab/test_serializer.rb +24 -1
- data/app/services/lab/accession_number_service.rb +2 -2
- data/app/services/lab/acknowledgement_service.rb +4 -1
- data/app/services/lab/concepts_service.rb +77 -22
- data/app/services/lab/lims/acknowledgement_worker.rb +1 -1
- data/app/services/lab/lims/api/rest_api.rb +543 -78
- data/app/services/lab/lims/config.rb +7 -2
- data/app/services/lab/lims/exceptions.rb +7 -6
- data/app/services/lab/lims/migrator.rb +3 -3
- data/app/services/lab/lims/order_dto.rb +1 -1
- data/app/services/lab/lims/order_serializer.rb +28 -7
- data/app/services/lab/lims/pull_worker.rb +6 -6
- data/app/services/lab/lims/push_worker.rb +3 -3
- data/app/services/lab/lims/utils.rb +3 -4
- data/app/services/lab/lims/worker.rb +2 -2
- data/app/services/lab/metadata.rb +4 -0
- data/app/services/lab/notification_service.rb +72 -0
- data/app/services/lab/orders_search_service.rb +11 -5
- data/app/services/lab/orders_service.rb +82 -36
- data/app/services/lab/results_service.rb +32 -17
- data/app/services/lab/tests_service.rb +15 -3
- data/config/routes.rb +1 -0
- data/db/migrate/20260119104240_add_fulfiller_fields_to_orders.rb +11 -0
- data/db/migrate/20260119104241_create_comment_to_fulfiller_concept.rb +50 -0
- data/lib/lab/version.rb +1 -1
- data/lib/mahis_emr_api_lab.rb +6 -0
- metadata +12 -5
- /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
|
|
|
@@ -32,23 +34,30 @@ module Lab
|
|
|
32
34
|
|
|
33
35
|
serializer = Lab::ResultSerializer.serialize(results_obs)
|
|
34
36
|
end
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
|
|
38
|
+
ProcessLabResultJob.perform_later(results_obs.id, serializer, result_enter_by)
|
|
39
|
+
|
|
37
40
|
Rails.logger.info("Lab::ResultsService: Result created for test #{test_id} #{serializer}")
|
|
38
41
|
serializer
|
|
39
42
|
end
|
|
40
43
|
|
|
44
|
+
def process_result_completion(results_obs, serializer, result_enter_by)
|
|
45
|
+
process_acknowledgement(results_obs, result_enter_by)
|
|
46
|
+
precess_notification_message(results_obs, serializer, result_enter_by)
|
|
47
|
+
end
|
|
48
|
+
|
|
41
49
|
private
|
|
42
50
|
|
|
43
51
|
def precess_notification_message(result, values, result_enter_by)
|
|
44
52
|
order = Order.find(result.order_id)
|
|
45
53
|
data = { Type: result_enter_by,
|
|
54
|
+
Specimen: ConceptName.find_by(concept_id: order.concept_id)&.name,
|
|
46
55
|
'Test type': ConceptName.find_by(concept_id: result.test.value_coded)&.name,
|
|
47
56
|
'Accession number': order&.accession_number,
|
|
48
|
-
'Orde date': order
|
|
57
|
+
'Orde date': Order.columns.include?('start_date') ? order.start_date : order.date_created,
|
|
49
58
|
'ARV-Number': find_arv_number(result.person_id),
|
|
50
59
|
PatientID: result.person_id,
|
|
51
|
-
'Ordered By': order&.provider&.person&.name,
|
|
60
|
+
'Ordered By': Order.columns.include?('provider_id') ? order&.provider&.person&.name : Person.find(order.creator)&.name,
|
|
52
61
|
Result: values }.as_json
|
|
53
62
|
NotificationService.new.create_notification(result_enter_by, data)
|
|
54
63
|
end
|
|
@@ -66,22 +75,26 @@ module Lab
|
|
|
66
75
|
.first&.identifier
|
|
67
76
|
end
|
|
68
77
|
|
|
69
|
-
def find_encounter(test, encounter_id: nil, date: nil, provider_id: nil)
|
|
78
|
+
def find_encounter(test, encounter_id: nil, encounter_uuid: nil, date: nil, provider_id: nil)
|
|
70
79
|
return Encounter.find(encounter_id) if encounter_id
|
|
80
|
+
return Encounter.find_by_uuid(encounter_uuid) if encounter_uuid
|
|
71
81
|
|
|
72
|
-
Encounter.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
82
|
+
encounter = Encounter.new
|
|
83
|
+
encounter.patient_id = test.person_id
|
|
84
|
+
encounter.program_id = test.encounter.program_id if Encounter.column_names.include?('program_id')
|
|
85
|
+
encounter.visit_id = test.encounter.visit_id if Encounter.column_names.include?('visit_id')
|
|
86
|
+
encounter.encounter_type = EncounterType.find_by_name!(Lab::Metadata::ENCOUNTER_TYPE_NAME)
|
|
87
|
+
encounter.encounter_datetime = date || Date.today
|
|
88
|
+
encounter.provider_id = provider_id || User.current.user_id if Encounter.column_names.include?('provider_id')
|
|
89
|
+
|
|
90
|
+
encounter.save!
|
|
91
|
+
|
|
92
|
+
encounter
|
|
79
93
|
end
|
|
80
94
|
|
|
81
95
|
# Creates the parent observation for results to which the different measures are attached
|
|
82
96
|
def create_results_obs(encounter, test, date, comments = nil)
|
|
83
97
|
void_existing_results_obs(encounter, test)
|
|
84
|
-
|
|
85
98
|
Lab::LabResult.create!(
|
|
86
99
|
person_id: encounter.patient_id,
|
|
87
100
|
encounter_id: encounter.encounter_id,
|
|
@@ -111,11 +124,13 @@ module Lab
|
|
|
111
124
|
def add_measure_to_results(results_obs, params, date)
|
|
112
125
|
validate_measure_params(params)
|
|
113
126
|
|
|
127
|
+
concept_id = params[:indicator][:concept_id] || Concept.find_concept_by_uuid(params.dig(:indicator, :concept))&.id
|
|
128
|
+
|
|
114
129
|
Observation.create!(
|
|
115
130
|
person_id: results_obs.person_id,
|
|
116
131
|
encounter_id: results_obs.encounter_id,
|
|
117
132
|
order_id: results_obs.order_id,
|
|
118
|
-
concept_id:
|
|
133
|
+
concept_id: concept_id,
|
|
119
134
|
obs_group_id: results_obs.obs_id,
|
|
120
135
|
obs_datetime: date&.to_datetime || DateTime.now,
|
|
121
136
|
**make_measure_value(params)
|
|
@@ -125,8 +140,8 @@ module Lab
|
|
|
125
140
|
def validate_measure_params(params)
|
|
126
141
|
raise InvalidParameterError, 'measures.value is required' if params[:value].blank?
|
|
127
142
|
|
|
128
|
-
if params[:indicator]&.[](:concept_id).blank?
|
|
129
|
-
raise InvalidParameterError, 'measures.indicator.concept_id is required'
|
|
143
|
+
if params[:indicator]&.[](:concept_id).blank? && params[:indicator]&.[](:concept).blank?
|
|
144
|
+
raise InvalidParameterError, 'measures.indicator.concept_id or concept is required'
|
|
130
145
|
end
|
|
131
146
|
|
|
132
147
|
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:
|
|
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
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
|
+
version: 2.1.2
|
|
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-
|
|
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,11 +238,13 @@ 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
|
|
244
245
|
- app/controllers/lab/users_controller.rb
|
|
245
246
|
- app/jobs/lab/application_job.rb
|
|
247
|
+
- app/jobs/lab/process_lab_result_job.rb
|
|
246
248
|
- app/jobs/lab/push_order_job.rb
|
|
247
249
|
- app/jobs/lab/update_patient_orders_job.rb
|
|
248
250
|
- app/jobs/lab/void_order_job.rb
|
|
@@ -256,6 +258,7 @@ files:
|
|
|
256
258
|
- app/models/lab/lab_test.rb
|
|
257
259
|
- app/models/lab/lims_failed_import.rb
|
|
258
260
|
- app/models/lab/lims_order_mapping.rb
|
|
261
|
+
- app/models/lab/order_extension.rb
|
|
259
262
|
- app/serializers/lab/lab_order_serializer.rb
|
|
260
263
|
- app/serializers/lab/result_serializer.rb
|
|
261
264
|
- app/serializers/lab/test_serializer.rb
|
|
@@ -267,7 +270,7 @@ files:
|
|
|
267
270
|
- app/services/lab/lims/acknowledgement_serializer.rb
|
|
268
271
|
- app/services/lab/lims/acknowledgement_worker.rb
|
|
269
272
|
- app/services/lab/lims/api/blackhole_api.rb
|
|
270
|
-
- app/services/lab/lims/api/
|
|
273
|
+
- app/services/lab/lims/api/couch_db_api.rb
|
|
271
274
|
- app/services/lab/lims/api/mysql_api.rb
|
|
272
275
|
- app/services/lab/lims/api/rest_api.rb
|
|
273
276
|
- app/services/lab/lims/api/ws_api.rb
|
|
@@ -282,6 +285,7 @@ files:
|
|
|
282
285
|
- app/services/lab/lims/utils.rb
|
|
283
286
|
- app/services/lab/lims/worker.rb
|
|
284
287
|
- app/services/lab/metadata.rb
|
|
288
|
+
- app/services/lab/notification_service.rb
|
|
285
289
|
- app/services/lab/orders_search_service.rb
|
|
286
290
|
- app/services/lab/orders_service.rb
|
|
287
291
|
- app/services/lab/results_service.rb
|
|
@@ -295,6 +299,8 @@ files:
|
|
|
295
299
|
- db/migrate/20210407071728_create_lab_lims_failed_imports.rb
|
|
296
300
|
- db/migrate/20210610095024_fix_numeric_results_value_type.rb
|
|
297
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
|
|
298
304
|
- lib/auto12epl.rb
|
|
299
305
|
- lib/couch_bum/couch_bum.rb
|
|
300
306
|
- lib/generators/lab/install/USAGE
|
|
@@ -306,6 +312,7 @@ files:
|
|
|
306
312
|
- lib/lab/engine.rb
|
|
307
313
|
- lib/lab/version.rb
|
|
308
314
|
- lib/logger_multiplexor.rb
|
|
315
|
+
- lib/mahis_emr_api_lab.rb
|
|
309
316
|
- lib/tasks/lab_tasks.rake
|
|
310
317
|
- lib/tasks/loaders/data/reasons-for-test.csv
|
|
311
318
|
- lib/tasks/loaders/data/test-measures.csv
|
|
File without changes
|