his_emr_api_lab 2.1.7.pre.beta.0 → 2.1.7.pre.gamma
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 -1
- data/app/services/lab/acknowledgement_service.rb +8 -4
- data/app/services/lab/lims/acknowledgement_worker.rb +5 -3
- data/app/services/lab/lims/api/rest_api.rb +15 -11
- data/app/services/lab/lims/pull_worker.rb +4 -3
- data/app/services/lab/lims/push_worker.rb +15 -8
- data/app/services/lab/lims/worker.rb +13 -13
- data/app/services/lab/orders_service.rb +20 -29
- data/lib/lab/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 593219b282a6f5cbe26cdd80a8324412650f3242d6ab48d622d1572699033c82
|
|
4
|
+
data.tar.gz: fb5bf82bc4569423c1e8b3ac5ff5d076e7734c565736e51ab0d453a61269d027
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1a941f7c1be9866e55bdbc035e23566b9e185f6131ab52f5fb17b3dd362cbfeb2d2b630929aea6904121232247edcb69ff451a1bc5a3d4528a1373e8db79f907
|
|
7
|
+
data.tar.gz: 60e00f01de37eb379b7f1a816baa793452f0b4b05cdda4596c495f5049a2431d69946aa33c3cae26c23847a69e1a99a9903b25a6dcf48b73c4cd237896653671
|
|
@@ -7,7 +7,7 @@ module Lab
|
|
|
7
7
|
queue_as :default
|
|
8
8
|
def perform(results_obs_id, serializer, result_enter_by)
|
|
9
9
|
Rails.logger.info("Lab::ProcessLabResultJob: Processing result completion for #{serializer}")
|
|
10
|
-
results_obs = Lab::LabResult.find(results_obs_id)
|
|
10
|
+
results_obs = Lab::LabResult.unscoped.find(results_obs_id)
|
|
11
11
|
Lab::ResultsService.process_result_completion(results_obs, serializer, result_enter_by)
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -14,9 +14,12 @@ module Lab
|
|
|
14
14
|
date_received: params[:date_received])
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def acknowledgements_pending_sync(batch_size)
|
|
18
|
-
Lab::LabAcknowledgement.where(pushed: false)
|
|
19
|
-
|
|
17
|
+
def acknowledgements_pending_sync(batch_size, start_date: nil)
|
|
18
|
+
query = Lab::LabAcknowledgement.joins(:order).where(pushed: false)
|
|
19
|
+
|
|
20
|
+
query = query.where('orders.date_created >= ?', start_date) if start_date
|
|
21
|
+
|
|
22
|
+
query.limit(batch_size)
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
def push_acknowledgement(acknowledgement, lims_api)
|
|
@@ -30,7 +33,8 @@ module Lab
|
|
|
30
33
|
Rails.logger.info("Updating acknowledgement ##{acknowledgement_dto[:tracking_number]} in LIMS")
|
|
31
34
|
response = lims_api.acknowledge(acknowledgement_dto)
|
|
32
35
|
Rails.logger.info("Info #{response}")
|
|
33
|
-
if ['results already delivered for test name given', 'test result acknowledged successfully',
|
|
36
|
+
if ['results already delivered for test name given', 'test result acknowledged successfully',
|
|
37
|
+
'test result already acknowledged electronically at facility'].include?(response['message'])
|
|
34
38
|
acknowledgement.pushed = true
|
|
35
39
|
acknowledgement.date_pushed = Time.now
|
|
36
40
|
acknowledgement.save!
|
|
@@ -4,20 +4,22 @@ module Lab
|
|
|
4
4
|
module Lims
|
|
5
5
|
# This class is responsible for handling the acknowledgement of lab orders
|
|
6
6
|
class AcknowledgementWorker
|
|
7
|
-
attr_reader :lims_api
|
|
7
|
+
attr_reader :lims_api, :start_date
|
|
8
8
|
|
|
9
9
|
include Utils # for logger
|
|
10
10
|
|
|
11
11
|
SECONDS_TO_WAIT_FOR_ORDERS = 30
|
|
12
12
|
|
|
13
|
-
def initialize(lims_api)
|
|
13
|
+
def initialize(lims_api, start_date: nil)
|
|
14
14
|
@lims_api = lims_api
|
|
15
|
+
@start_date = start_date
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def push_acknowledgement(batch_size: 1000, wait: false)
|
|
18
19
|
loop do
|
|
19
20
|
logger.info('Looking for new acknowledgements to push to LIMS...')
|
|
20
|
-
acknowledgements = Lab::AcknowledgementService.acknowledgements_pending_sync(batch_size
|
|
21
|
+
acknowledgements = Lab::AcknowledgementService.acknowledgements_pending_sync(batch_size,
|
|
22
|
+
start_date: start_date).all
|
|
21
23
|
|
|
22
24
|
logger.debug("Found #{acknowledgements.size} acknowledgements...")
|
|
23
25
|
acknowledgements.each do |acknowledgement|
|
|
@@ -74,8 +74,8 @@ module Lab
|
|
|
74
74
|
{ tracking_number: order_dto[:tracking_number] }
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
def consume_orders(*_args, patient_id: nil, **_kwargs)
|
|
78
|
-
orders_pending_updates(patient_id).each do |order|
|
|
77
|
+
def consume_orders(*_args, patient_id: nil, start_date: nil, **_kwargs)
|
|
78
|
+
orders_pending_updates(patient_id, start_date: start_date).each do |order|
|
|
79
79
|
order_dto = Lab::Lims::OrderSerializer.serialize_order(order)
|
|
80
80
|
if order_dto['priority'].nil? || order_dto['sample_type'].casecmp?('not_specified')
|
|
81
81
|
patch_order_dto_with_lims_order!(order_dto, find_lims_order(order.accession_number))
|
|
@@ -510,43 +510,47 @@ module Lab
|
|
|
510
510
|
}
|
|
511
511
|
end
|
|
512
512
|
|
|
513
|
-
def orders_pending_updates(patient_id = nil)
|
|
513
|
+
def orders_pending_updates(patient_id = nil, start_date: nil)
|
|
514
514
|
Rails.logger.info('Looking for orders that need to be updated...')
|
|
515
515
|
orders = {}
|
|
516
516
|
|
|
517
|
-
orders_without_specimen(patient_id).each { |order| orders[order.order_id] = order }
|
|
518
|
-
orders_without_results(patient_id).each { |order| orders[order.order_id] = order }
|
|
519
|
-
orders_without_reason(patient_id).each { |order| orders[order.order_id] = order }
|
|
517
|
+
orders_without_specimen(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
|
|
518
|
+
orders_without_results(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
|
|
519
|
+
orders_without_reason(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
|
|
520
520
|
|
|
521
521
|
orders.values
|
|
522
522
|
end
|
|
523
523
|
|
|
524
|
-
def orders_without_specimen(patient_id = nil)
|
|
524
|
+
def orders_without_specimen(patient_id = nil, start_date: nil)
|
|
525
525
|
Rails.logger.debug('Looking for orders without a specimen')
|
|
526
526
|
unknown_specimen = ConceptName.where(name: Lab::Metadata::UNKNOWN_SPECIMEN)
|
|
527
527
|
.select(:concept_id)
|
|
528
528
|
orders = Lab::LabOrder.where(concept_id: unknown_specimen)
|
|
529
529
|
.where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
|
|
530
530
|
orders = orders.where(patient_id:) if patient_id
|
|
531
|
+
orders = orders.where('orders.date_created >= ?', start_date) if start_date
|
|
531
532
|
|
|
532
533
|
orders
|
|
533
534
|
end
|
|
534
535
|
|
|
535
|
-
def orders_without_results(patient_id = nil)
|
|
536
|
+
def orders_without_results(patient_id = nil, start_date: nil)
|
|
536
537
|
Rails.logger.debug('Looking for orders without a result')
|
|
537
538
|
# Lab::OrdersSearchService.find_orders_without_results(patient_id: patient_id)
|
|
538
539
|
# .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id).where("pulled_at IS NULL"))
|
|
539
|
-
Lab::OrdersSearchService.find_orders_without_results(patient_id:)
|
|
540
|
-
|
|
540
|
+
orders = Lab::OrdersSearchService.find_orders_without_results(patient_id:)
|
|
541
|
+
.where(order_id: Lab::LimsOrderMapping.select(:order_id))
|
|
542
|
+
orders = orders.where('orders.date_created >= ?', start_date) if start_date
|
|
543
|
+
orders
|
|
541
544
|
end
|
|
542
545
|
|
|
543
|
-
def orders_without_reason(patient_id = nil)
|
|
546
|
+
def orders_without_reason(patient_id = nil, start_date: nil)
|
|
544
547
|
Rails.logger.debug('Looking for orders without a reason for test')
|
|
545
548
|
orders = Lab::LabOrder.joins(:reason_for_test)
|
|
546
549
|
.merge(Observation.where(value_coded: nil, value_text: nil))
|
|
547
550
|
.limit(1000)
|
|
548
551
|
.where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
|
|
549
552
|
orders = orders.where(patient_id:) if patient_id
|
|
553
|
+
orders = orders.where('orders.date_created >= ?', start_date) if start_date
|
|
550
554
|
|
|
551
555
|
orders
|
|
552
556
|
end
|
|
@@ -5,14 +5,15 @@ module Lab
|
|
|
5
5
|
##
|
|
6
6
|
# Pulls orders from a Lims API object and saves them to the local database.
|
|
7
7
|
class PullWorker
|
|
8
|
-
attr_reader :lims_api
|
|
8
|
+
attr_reader :lims_api, :start_date
|
|
9
9
|
|
|
10
10
|
include Utils # for logger
|
|
11
11
|
|
|
12
12
|
LIMS_LOG_PATH = Rails.root.join('log', 'lims')
|
|
13
13
|
|
|
14
|
-
def initialize(lims_api)
|
|
14
|
+
def initialize(lims_api, start_date: nil)
|
|
15
15
|
@lims_api = lims_api
|
|
16
|
+
@start_date = start_date
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
##
|
|
@@ -20,7 +21,7 @@ module Lab
|
|
|
20
21
|
def pull_orders(batch_size: 10_000, **)
|
|
21
22
|
logger.info("Retrieving LIMS orders starting from #{last_seq}")
|
|
22
23
|
|
|
23
|
-
lims_api.consume_orders(from: last_seq, limit: batch_size, **) do |order_dto, context|
|
|
24
|
+
lims_api.consume_orders(from: last_seq, limit: batch_size, start_date: start_date, **) do |order_dto, context|
|
|
24
25
|
logger.debug("Retrieved order ##{order_dto[:tracking_number]}: #{order_dto}")
|
|
25
26
|
|
|
26
27
|
patient = find_patient_by_nhid(order_dto[:patient][:id], order_dto[:tracking_number])
|
|
@@ -5,15 +5,16 @@ module Lab
|
|
|
5
5
|
##
|
|
6
6
|
# Pushes all local orders to a LIMS Api object.
|
|
7
7
|
class PushWorker
|
|
8
|
-
attr_reader :lims_api
|
|
8
|
+
attr_reader :lims_api, :start_date
|
|
9
9
|
|
|
10
10
|
include Utils # for logger
|
|
11
11
|
|
|
12
12
|
SECONDS_TO_WAIT_FOR_ORDERS = 30
|
|
13
13
|
START_DATE = Time.parse('2024-09-03').freeze
|
|
14
14
|
|
|
15
|
-
def initialize(lims_api)
|
|
15
|
+
def initialize(lims_api, start_date: nil)
|
|
16
16
|
@lims_api = lims_api
|
|
17
|
+
@start_date = start_date
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def push_orders(batch_size: 1000, wait: false)
|
|
@@ -81,8 +82,8 @@ module Lab
|
|
|
81
82
|
|
|
82
83
|
def void_order_in_lims(order_id)
|
|
83
84
|
order = Lab::LabOrder.joins(order_type: { name: 'Lab' })
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
.unscoped
|
|
86
|
+
.find(order_id)
|
|
86
87
|
order_dto = Lab::Lims::OrderSerializer.serialize_order(order)
|
|
87
88
|
Rails.logger.info("Deleting order ##{order_dto[:accession_number]} from LIMS")
|
|
88
89
|
lims_api.delete_order('', order_dto)
|
|
@@ -100,10 +101,16 @@ module Lab
|
|
|
100
101
|
|
|
101
102
|
def new_orders
|
|
102
103
|
Rails.logger.debug('Looking for new orders that need to be created in LIMS...')
|
|
103
|
-
Lab::LabOrder.where.not(order_id: Lab::LimsOrderMapping.all.select(:order_id))
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
query = Lab::LabOrder.where.not(order_id: Lab::LimsOrderMapping.all.select(:order_id))
|
|
105
|
+
.where("accession_number IS NOT NULL AND accession_number !=''")
|
|
106
|
+
|
|
107
|
+
query = if start_date
|
|
108
|
+
query.where('orders.date_created >= ?', start_date)
|
|
109
|
+
else
|
|
110
|
+
query.where('orders.date_created >= ? AND orders.date_created <= ?', START_DATE, Date.today + 1.day)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
query.order(date_created: :desc)
|
|
107
114
|
end
|
|
108
115
|
|
|
109
116
|
def updated_orders
|
|
@@ -9,43 +9,43 @@ module Lab
|
|
|
9
9
|
##
|
|
10
10
|
# Pull/Push orders from/to the LIMS queue (Oops meant CouchDB).
|
|
11
11
|
module Worker
|
|
12
|
-
def self.start
|
|
12
|
+
def self.start(start_date: nil)
|
|
13
13
|
User.current = Utils.lab_user
|
|
14
14
|
|
|
15
|
-
fork(
|
|
16
|
-
fork(
|
|
17
|
-
fork(
|
|
18
|
-
fork(
|
|
15
|
+
fork { start_push_worker(start_date: start_date) }
|
|
16
|
+
fork { start_pull_worker(start_date: start_date) }
|
|
17
|
+
fork { start_acknowledgement_worker(start_date: start_date) }
|
|
18
|
+
fork { start_realtime_pull_worker(start_date: start_date) } if realtime_updates_enabled?
|
|
19
19
|
|
|
20
20
|
Process.waitall
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def self.start_push_worker
|
|
23
|
+
def self.start_push_worker(start_date: nil)
|
|
24
24
|
start_worker('push_worker') do
|
|
25
|
-
worker = PushWorker.new(lims_api)
|
|
25
|
+
worker = PushWorker.new(lims_api, start_date: start_date)
|
|
26
26
|
|
|
27
27
|
worker.push_orders # (wait: true)
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def self.start_acknowledgement_worker
|
|
31
|
+
def self.start_acknowledgement_worker(start_date: nil)
|
|
32
32
|
start_worker('acknowledgement_worker') do
|
|
33
|
-
worker = AcknowledgementWorker.new(lims_api)
|
|
33
|
+
worker = AcknowledgementWorker.new(lims_api, start_date: start_date)
|
|
34
34
|
worker.push_acknowledgement
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def self.start_pull_worker
|
|
38
|
+
def self.start_pull_worker(start_date: nil)
|
|
39
39
|
start_worker('pull_worker') do
|
|
40
|
-
worker = PullWorker.new(lims_api)
|
|
40
|
+
worker = PullWorker.new(lims_api, start_date: start_date)
|
|
41
41
|
|
|
42
42
|
worker.pull_orders
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def self.start_realtime_pull_worker
|
|
46
|
+
def self.start_realtime_pull_worker(start_date: nil)
|
|
47
47
|
start_worker('realtime_pull_worker') do
|
|
48
|
-
worker = PullWorker.new(Lims::Api::WsApi.new(Lab::Lims::Config.updates_socket))
|
|
48
|
+
worker = PullWorker.new(Lims::Api::WsApi.new(Lab::Lims::Config.updates_socket), start_date: start_date)
|
|
49
49
|
|
|
50
50
|
worker.pull_orders
|
|
51
51
|
end
|
|
@@ -102,16 +102,14 @@ module Lab
|
|
|
102
102
|
|
|
103
103
|
if reason_for_test
|
|
104
104
|
Rails.logger.debug("Updating reason for test on order ##{order.order_id}")
|
|
105
|
-
update_reason_for_test(order, Concept.find(reason_for_test)&.id,
|
|
106
|
-
force_update: params.fetch('force_update', false))
|
|
105
|
+
update_reason_for_test(order, Concept.find(reason_for_test)&.id, force_update: params.fetch('force_update', false))
|
|
107
106
|
end
|
|
108
107
|
|
|
109
108
|
Lab::LabOrderSerializer.serialize_order(order)
|
|
110
109
|
end
|
|
111
110
|
|
|
112
111
|
def void_order(order_id, reason)
|
|
113
|
-
order = Lab::LabOrder.includes(%i[requesting_clinician reason_for_test target_lab comment_to_fulfiller],
|
|
114
|
-
tests: [:result])
|
|
112
|
+
order = Lab::LabOrder.includes(%i[requesting_clinician reason_for_test target_lab comment_to_fulfiller], tests: [:result])
|
|
115
113
|
.find(order_id)
|
|
116
114
|
|
|
117
115
|
order.requesting_clinician&.void(reason)
|
|
@@ -162,15 +160,13 @@ module Lab
|
|
|
162
160
|
last_order_date: Lab::LabOrder.last&.start_date&.to_date,
|
|
163
161
|
lab_orders: []
|
|
164
162
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
end
|
|
173
|
-
end
|
|
163
|
+
data[:lab_orders] = orders.map do |order|
|
|
164
|
+
Lab::LabOrderSerializer.serialize_order(
|
|
165
|
+
order, requesting_clinician: order.requesting_clinician,
|
|
166
|
+
reason_for_test: order.reason_for_test,
|
|
167
|
+
target_lab: order.target_lab
|
|
168
|
+
)
|
|
169
|
+
end if include_data
|
|
174
170
|
data
|
|
175
171
|
end
|
|
176
172
|
|
|
@@ -178,14 +174,14 @@ module Lab
|
|
|
178
174
|
|
|
179
175
|
def create_rejection_notification(order_params)
|
|
180
176
|
order = find_order order_params['tracking_number']
|
|
181
|
-
data = { type: 'LIMS',
|
|
182
|
-
specimen: ConceptName.find_by(concept_id: order.concept_id)&.name,
|
|
183
|
-
accession_number: order&.accession_number,
|
|
184
|
-
order_date: order&.start_date,
|
|
185
|
-
arv_number: find_arv_number(order.patient_id),
|
|
186
|
-
patient_id: result.person_id,
|
|
187
|
-
ordered_by: order&.provider&.person&.name,
|
|
188
|
-
rejection_reason: order_params['comments'] }.as_json
|
|
177
|
+
data = { 'type': 'LIMS',
|
|
178
|
+
'specimen': ConceptName.find_by(concept_id: order.concept_id)&.name,
|
|
179
|
+
'accession_number': order&.accession_number,
|
|
180
|
+
'order_date': order&.start_date,
|
|
181
|
+
'arv_number': find_arv_number(order.patient_id),
|
|
182
|
+
'patient_id': result.person_id,
|
|
183
|
+
'ordered_by': order&.provider&.person&.name,
|
|
184
|
+
'rejection_reason': order_params['comments'] }.as_json
|
|
189
185
|
NotificationService.new.create_notification('LIMS', data)
|
|
190
186
|
end
|
|
191
187
|
|
|
@@ -239,9 +235,7 @@ module Lab
|
|
|
239
235
|
encounter.encounter_datetime = order_params[:date] || Date.today
|
|
240
236
|
encounter.visit = Visit.find_by_uuid(visit) if Encounter.column_names.include?('visit_id')
|
|
241
237
|
encounter.provider_id = User.current&.person&.id if Encounter.column_names.include?('provider_id')
|
|
242
|
-
if Encounter.column_names.include?('program_id') && order_params[:program_id].present?
|
|
243
|
-
encounter.program_id = order_params[:program_id]
|
|
244
|
-
end
|
|
238
|
+
encounter.program_id = order_params[:program_id] if Encounter.column_names.include?('program_id') && order_params[:program_id].present?
|
|
245
239
|
encounter.save!
|
|
246
240
|
encounter.reload
|
|
247
241
|
end
|
|
@@ -265,7 +259,7 @@ module Lab
|
|
|
265
259
|
order.date_created = params[:date]&.to_date || Date.today if order.respond_to?(:date_created)
|
|
266
260
|
order.start_date = params[:date]&.to_date || Date.today if order.respond_to?(:start_date)
|
|
267
261
|
order.auto_expire_date = params[:end_date]
|
|
268
|
-
#
|
|
262
|
+
# Note: comment_to_fulfiller is a has_one association, not a field
|
|
269
263
|
# It will be created via add_comment_to_fulfiller method
|
|
270
264
|
order.accession_number = access_number
|
|
271
265
|
order.orderer = User.current&.user_id
|
|
@@ -362,10 +356,7 @@ module Lab
|
|
|
362
356
|
|
|
363
357
|
return if order.reason_for_test&.value_coded == concept_id
|
|
364
358
|
|
|
365
|
-
if order.reason_for_test&.value_coded && !force_update
|
|
366
|
-
raise InvalidParameterError,
|
|
367
|
-
"Can't change reason for test once set"
|
|
368
|
-
end
|
|
359
|
+
raise InvalidParameterError, "Can't change reason for test once set" if order.reason_for_test&.value_coded && !force_update
|
|
369
360
|
|
|
370
361
|
order.reason_for_test&.delete
|
|
371
362
|
date = order.start_date if order.respond_to?(:start_date)
|
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.7.pre.
|
|
4
|
+
version: 2.1.7.pre.gamma
|
|
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-02-
|
|
11
|
+
date: 2026-02-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: couchrest
|