his_emr_api_lab 2.1.4.pre.beta → 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 +4 -4
- data/app/jobs/lab/process_lab_result_job.rb +1 -0
- data/app/serializers/lab/result_serializer.rb +12 -6
- data/app/services/lab/concepts_service.rb +1 -1
- data/app/services/lab/json_web_token_service.rb +1 -1
- data/app/services/lab/lims/api/rest_api.rb +1 -1
- data/app/services/lab/lims/pull_worker.rb +1 -1
- data/app/services/lab/lims/utils.rb +6 -2
- data/app/services/lab/results_service.rb +27 -13
- data/lib/lab/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4aeefd371ffd0e3a4c9d460b7d7bd280b3d65868438b0760f992cf66dced202b
|
|
4
|
+
data.tar.gz: 48ca67bb59e2daebe7776f62fdafa6bc158d18351bbb161690a9a598a442b905
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
@@ -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
|
-
|
|
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:
|
|
23
|
-
name: concept_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(:
|
|
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.
|
|
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...")
|
|
@@ -78,8 +78,12 @@ module Lab
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def self.find_concept_by_name(name)
|
|
81
|
-
|
|
82
|
-
|
|
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
|
|
@@ -20,7 +20,11 @@ module Lab
|
|
|
20
20
|
serializer = {}
|
|
21
21
|
results_obs = {}
|
|
22
22
|
ActiveRecord::Base.transaction do
|
|
23
|
-
test =
|
|
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
|
-
#
|
|
42
|
-
ProcessLabResultJob.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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,
|
|
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
|
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.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-
|
|
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:
|
|
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:
|
|
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
|