his_emr_api_lab 2.4.5 → 2.4.6
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/services/lab/acknowledgement_service.rb +4 -2
- data/app/services/lab/lims/acknowledgement_worker.rb +6 -2
- data/app/services/lab/lims/api/rest_api.rb +12 -14
- data/app/services/lab/lims/pull_worker.rb +7 -5
- data/app/services/lab/lims/push_worker.rb +11 -5
- data/app/services/lab/lims/worker.rb +28 -18
- data/app/services/lab/orders_service.rb +2 -2
- data/app/services/lab/tests_service.rb +1 -1
- 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: 2ac3fb7e82f896ac9c5f0545aa1c7e97290e7aaf11cc149fd6e8f385938397dc
|
|
4
|
+
data.tar.gz: 707411853618c5b391c99ecdc043bdbc71ef5df5a1b801567869d279b068c6d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0ae79db2d3cb66121a3daf92c1fb0e141a09309dc148f604da49cb167203fe22c77e50c843a9a10e6531fe505cb8241c5212668a643bff38ef5f851d8232a72
|
|
7
|
+
data.tar.gz: 32ec983d0e45aa6af8b280ae1850544ad42bb250465cdfa45a597818e589c3ff9238d7ebea7ba7cdc7c613ae4f2368fc05c2c854809fa2f1d2d8b76ed82c1bcf
|
|
@@ -14,11 +14,13 @@ module Lab
|
|
|
14
14
|
date_received: params[:date_received])
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def acknowledgements_pending_sync(batch_size, start_date: nil, last_order_id: 0)
|
|
17
|
+
def acknowledgements_pending_sync(batch_size, start_date: nil, last_order_id: 0, accession_numbers: [], patient_id: nil)
|
|
18
18
|
query = Lab::LabAcknowledgement.joins(:order).where(pushed: false)
|
|
19
19
|
.where('lims_acknowledgement_statuses.order_id > ?', last_order_id)
|
|
20
20
|
query = query.where('orders.date_created >= ?', start_date) if start_date
|
|
21
|
-
query.
|
|
21
|
+
query = query.where(orders: {accession_number: accession_numbers}) if accession_numbers.any?
|
|
22
|
+
query = query.where(orders: {patient_id: patient_id}) if patient_id
|
|
23
|
+
query.order('lims_acknowledgement_statuses.order_id DESC').limit(batch_size)
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def push_acknowledgement(acknowledgement, lims_api)
|
|
@@ -4,15 +4,17 @@ 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, :start_date
|
|
7
|
+
attr_reader :lims_api, :start_date, :accession_numbers, :patient_id
|
|
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, start_date: nil)
|
|
13
|
+
def initialize(lims_api, start_date: nil, accession_numbers: [], patient_id: nil)
|
|
14
14
|
@lims_api = lims_api
|
|
15
15
|
@start_date = start_date
|
|
16
|
+
@accession_numbers = accession_numbers
|
|
17
|
+
@patient_id = patient_id
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def push_acknowledgement(batch_size: 1000, wait: false)
|
|
@@ -21,6 +23,8 @@ module Lab
|
|
|
21
23
|
logger.info('Looking for new acknowledgements to push to LIMS...')
|
|
22
24
|
acknowledgements = Lab::AcknowledgementService.acknowledgements_pending_sync(batch_size,
|
|
23
25
|
start_date: start_date,
|
|
26
|
+
accession_numbers: accession_numbers,
|
|
27
|
+
patient_id: patient_id,
|
|
24
28
|
last_order_id: last_order_id).all
|
|
25
29
|
|
|
26
30
|
logger.debug("Found #{acknowledgements.size} acknowledgements...")
|
|
@@ -75,8 +75,8 @@ module Lab
|
|
|
75
75
|
{ tracking_number: order_dto[:tracking_number] }
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
def consume_orders(*_args, patient_id: nil, start_date: nil, **_kwargs)
|
|
79
|
-
orders_pending_updates(patient_id, start_date: start_date).each do |order|
|
|
78
|
+
def consume_orders(*_args, patient_id: nil, start_date: nil, accession_numbers: [], **_kwargs)
|
|
79
|
+
orders_pending_updates(patient_id, start_date: start_date, accession_numbers: accession_numbers).each do |order|
|
|
80
80
|
order_dto = Lab::Lims::OrderSerializer.serialize_order(order)
|
|
81
81
|
|
|
82
82
|
# Always fetch the full order from NLIMS to get status trails
|
|
@@ -84,11 +84,6 @@ module Lab
|
|
|
84
84
|
lims_order = find_lims_order(order.accession_number)
|
|
85
85
|
patch_order_dto_with_lims_order!(order_dto, lims_order)
|
|
86
86
|
|
|
87
|
-
Rails.logger.debug("NLIMS order structure for #{order.accession_number}:")
|
|
88
|
-
Rails.logger.debug(" Has 'order' key: #{lims_order.key?('order')}")
|
|
89
|
-
Rails.logger.debug(" Has 'data' key: #{lims_order.key?('data')}")
|
|
90
|
-
Rails.logger.debug(" Top level keys: #{lims_order.keys.inspect}")
|
|
91
|
-
|
|
92
87
|
# Also extract status trails from the NLIMS order
|
|
93
88
|
# Note: NLIMS might return order data under 'order' or 'data.order'
|
|
94
89
|
order_data = lims_order['order'] || lims_order.dig('data', 'order') || lims_order
|
|
@@ -606,20 +601,20 @@ module Lab
|
|
|
606
601
|
}
|
|
607
602
|
end
|
|
608
603
|
|
|
609
|
-
def orders_pending_updates(patient_id = nil, start_date: nil)
|
|
604
|
+
def orders_pending_updates(patient_id = nil, start_date: nil, accession_numbers: [])
|
|
610
605
|
Rails.logger.info("Looking for orders that need to be updated... [patient_id=#{patient_id}] [start_date=#{start_date}]")
|
|
611
606
|
orders = {}
|
|
612
607
|
Rails.logger.info("Fetching orders without specimen...")
|
|
613
|
-
orders_without_specimen(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
|
|
608
|
+
orders_without_specimen(patient_id, start_date: start_date, accession_numbers: accession_numbers).each { |order| orders[order.order_id] = order }
|
|
614
609
|
Rails.logger.info("Fetching orders without results...")
|
|
615
|
-
orders_without_results(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
|
|
610
|
+
orders_without_results(patient_id, start_date: start_date, accession_numbers: accession_numbers).each { |order| orders[order.order_id] = order }
|
|
616
611
|
Rails.logger.info("Fetching orders without reason...")
|
|
617
|
-
orders_without_reason(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
|
|
612
|
+
orders_without_reason(patient_id, start_date: start_date, accession_numbers: accession_numbers).each { |order| orders[order.order_id] = order }
|
|
618
613
|
|
|
619
614
|
orders.values
|
|
620
615
|
end
|
|
621
616
|
|
|
622
|
-
def orders_without_specimen(patient_id = nil, start_date: nil)
|
|
617
|
+
def orders_without_specimen(patient_id = nil, start_date: nil, accession_numbers: [])
|
|
623
618
|
Rails.logger.debug('Looking for orders without a specimen')
|
|
624
619
|
unknown_specimen = ConceptName.where(name: Lab::Metadata::UNKNOWN_SPECIMEN)
|
|
625
620
|
.select(:concept_id)
|
|
@@ -627,21 +622,23 @@ module Lab
|
|
|
627
622
|
.where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
|
|
628
623
|
orders = orders.where(patient_id:) if patient_id
|
|
629
624
|
orders = orders.where('orders.date_created >= ?', start_date) if start_date
|
|
625
|
+
orders = orders.where(accession_number: accession_numbers) if accession_numbers.any?
|
|
630
626
|
|
|
631
627
|
orders
|
|
632
628
|
end
|
|
633
629
|
|
|
634
|
-
def orders_without_results(patient_id = nil, start_date: nil)
|
|
630
|
+
def orders_without_results(patient_id = nil, start_date: nil, accession_numbers: [])
|
|
635
631
|
Rails.logger.debug('Looking for orders without a result')
|
|
636
632
|
# Lab::OrdersSearchService.find_orders_without_results(patient_id: patient_id)
|
|
637
633
|
# .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id).where("pulled_at IS NULL"))
|
|
638
634
|
orders = Lab::OrdersSearchService.find_orders_without_results(patient_id:)
|
|
639
635
|
.where(order_id: Lab::LimsOrderMapping.select(:order_id))
|
|
640
636
|
orders = orders.where('orders.date_created >= ?', start_date) if start_date
|
|
637
|
+
orders = orders.where(accession_number: accession_numbers) if accession_numbers.any?
|
|
641
638
|
orders
|
|
642
639
|
end
|
|
643
640
|
|
|
644
|
-
def orders_without_reason(patient_id = nil, start_date: nil)
|
|
641
|
+
def orders_without_reason(patient_id = nil, start_date: nil, accession_numbers: [])
|
|
645
642
|
Rails.logger.debug('Looking for orders without a reason for test')
|
|
646
643
|
orders = Lab::LabOrder.joins(:reason_for_test)
|
|
647
644
|
.merge(Observation.where(value_coded: nil, value_text: nil))
|
|
@@ -649,6 +646,7 @@ module Lab
|
|
|
649
646
|
.where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
|
|
650
647
|
orders = orders.where(patient_id:) if patient_id
|
|
651
648
|
orders = orders.where('orders.date_created >= ?', start_date) if start_date
|
|
649
|
+
orders = orders.where(accession_number: accession_numbers) if accession_numbers.any?
|
|
652
650
|
|
|
653
651
|
orders
|
|
654
652
|
end
|
|
@@ -7,15 +7,17 @@ module Lab
|
|
|
7
7
|
##
|
|
8
8
|
# Pulls orders from a Lims API object and saves them to the local database.
|
|
9
9
|
class PullWorker
|
|
10
|
-
attr_reader :lims_api, :start_date
|
|
10
|
+
attr_reader :lims_api, :start_date, :accession_numbers
|
|
11
11
|
|
|
12
12
|
include Utils # for logger
|
|
13
13
|
|
|
14
14
|
LIMS_LOG_PATH = Rails.root.join('log', 'lims')
|
|
15
15
|
|
|
16
|
-
def initialize(lims_api, start_date: nil)
|
|
16
|
+
def initialize(lims_api, start_date: nil, accession_numbers: [], patient_id: nil)
|
|
17
17
|
@lims_api = lims_api
|
|
18
18
|
@start_date = start_date
|
|
19
|
+
@accession_numbers = accession_numbers
|
|
20
|
+
@patient_id = patient_id
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
##
|
|
@@ -23,7 +25,7 @@ module Lab
|
|
|
23
25
|
def pull_orders(batch_size: 10_000, **)
|
|
24
26
|
logger.info("Retrieving LIMS orders starting from #{last_seq}")
|
|
25
27
|
|
|
26
|
-
lims_api.consume_orders(from: last_seq, limit: batch_size, start_date: start_date, **) do |order_dto, context|
|
|
28
|
+
lims_api.consume_orders(from: last_seq, limit: batch_size, start_date: start_date, accession_numbers: accession_numbers, **) do |order_dto, context|
|
|
27
29
|
logger.debug("Retrieved order ##{order_dto[:tracking_number]}: #{order_dto}")
|
|
28
30
|
|
|
29
31
|
patient = find_patient_by_nhid(order_dto[:patient][:id], order_dto[:tracking_number])
|
|
@@ -395,7 +397,7 @@ module Lab
|
|
|
395
397
|
value_text: status_data['status'], # Store status as text
|
|
396
398
|
obs_datetime: timestamp,
|
|
397
399
|
comments: updated_by.to_json,
|
|
398
|
-
creator: User.current&.user_id
|
|
400
|
+
creator: User.current&.user_id,
|
|
399
401
|
location_id:,
|
|
400
402
|
date_created: Time.now,
|
|
401
403
|
uuid: SecureRandom.uuid
|
|
@@ -463,7 +465,7 @@ module Lab
|
|
|
463
465
|
value_text: status_data['status'], # Store status as text
|
|
464
466
|
obs_datetime: timestamp,
|
|
465
467
|
comments: updated_by.to_json,
|
|
466
|
-
creator: User.current&.user_id
|
|
468
|
+
creator: User.current&.user_id,
|
|
467
469
|
location_id:,
|
|
468
470
|
date_created: Time.now,
|
|
469
471
|
uuid: SecureRandom.uuid
|
|
@@ -5,16 +5,18 @@ module Lab
|
|
|
5
5
|
##
|
|
6
6
|
# Pushes all local orders to a LIMS Api object.
|
|
7
7
|
class PushWorker
|
|
8
|
-
attr_reader :lims_api, :start_date
|
|
8
|
+
attr_reader :lims_api, :start_date, :accession_numbers, :patient_id
|
|
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, start_date: nil)
|
|
15
|
+
def initialize(lims_api, start_date: nil, accession_numbers: [], patient_id: nil)
|
|
16
16
|
@lims_api = lims_api
|
|
17
17
|
@start_date = start_date
|
|
18
|
+
@accession_numbers = accession_numbers
|
|
19
|
+
@patient_id = patient_id
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def push_orders(batch_size: 1000, wait: false)
|
|
@@ -109,7 +111,8 @@ module Lab
|
|
|
109
111
|
else
|
|
110
112
|
query.where('orders.date_created >= ? AND orders.date_created <= ?', START_DATE, Date.today + 1.day)
|
|
111
113
|
end
|
|
112
|
-
|
|
114
|
+
query = query.where(accession_number: accession_numbers) if accession_numbers.any?
|
|
115
|
+
query = query.where(patient_id: patient_id) if patient_id
|
|
113
116
|
query.order(date_created: :desc)
|
|
114
117
|
end
|
|
115
118
|
|
|
@@ -130,11 +133,14 @@ module Lab
|
|
|
130
133
|
|
|
131
134
|
def voided_orders
|
|
132
135
|
Rails.logger.debug('Looking for voided orders that are being tracked by LIMS...')
|
|
133
|
-
Lab::LabOrder.unscoped
|
|
136
|
+
orders = Lab::LabOrder.unscoped
|
|
134
137
|
.where(order_type: OrderType.where(name: Lab::Metadata::ORDER_TYPE_NAME),
|
|
135
138
|
order_id: Lab::LimsOrderMapping.all.select(:order_id),
|
|
136
139
|
voided: 1)
|
|
137
|
-
|
|
140
|
+
orders = orders.where(accession_number: accession_numbers) if accession_numbers.any?
|
|
141
|
+
orders = orders.where(patient_id: patient_id) if patient_id
|
|
142
|
+
orders = orders.order(date_voided: :desc)
|
|
143
|
+
orders
|
|
138
144
|
end
|
|
139
145
|
|
|
140
146
|
##
|
|
@@ -9,46 +9,46 @@ 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(start_date: nil)
|
|
12
|
+
def self.start(start_date: nil, accession_numbers: [], patient_id: nil)
|
|
13
13
|
User.current = Utils.lab_user
|
|
14
14
|
|
|
15
15
|
# Eager load classes before forking to avoid autoloading issues in child processes
|
|
16
16
|
Rails.application.eager_load! if defined?(Rails) && Rails.env.development?
|
|
17
17
|
|
|
18
|
-
fork { start_push_worker(start_date: start_date) }
|
|
19
|
-
fork { start_pull_worker(start_date: start_date) }
|
|
20
|
-
fork { start_acknowledgement_worker(start_date: start_date) }
|
|
21
|
-
fork { start_realtime_pull_worker(start_date: start_date) } if realtime_updates_enabled?
|
|
18
|
+
fork { start_push_worker(start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id) }
|
|
19
|
+
fork { start_pull_worker(start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id) }
|
|
20
|
+
fork { start_acknowledgement_worker(start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id) }
|
|
21
|
+
fork { start_realtime_pull_worker(start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id) } if realtime_updates_enabled?
|
|
22
22
|
|
|
23
23
|
Process.waitall
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def self.start_push_worker(start_date: nil)
|
|
27
|
-
start_worker('push_worker') do
|
|
28
|
-
worker = PushWorker.new(lims_api, start_date: start_date)
|
|
26
|
+
def self.start_push_worker(start_date: nil, accession_numbers: [], patient_id: nil)
|
|
27
|
+
start_worker('push_worker', accession_numbers: accession_numbers, patient_id: patient_id) do
|
|
28
|
+
worker = PushWorker.new(lims_api, start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id)
|
|
29
29
|
|
|
30
30
|
worker.push_orders # (wait: true)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def self.start_acknowledgement_worker(start_date: nil)
|
|
35
|
-
start_worker('acknowledgement_worker') do
|
|
36
|
-
worker = AcknowledgementWorker.new(lims_api, start_date: start_date)
|
|
34
|
+
def self.start_acknowledgement_worker(start_date: nil, accession_numbers: [], patient_id: nil)
|
|
35
|
+
start_worker('acknowledgement_worker', accession_numbers: accession_numbers, patient_id: patient_id) do
|
|
36
|
+
worker = AcknowledgementWorker.new(lims_api, start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id)
|
|
37
37
|
worker.push_acknowledgement
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def self.start_pull_worker(start_date: nil)
|
|
42
|
-
start_worker('pull_worker') do
|
|
43
|
-
worker = PullWorker.new(lims_api, start_date: start_date)
|
|
41
|
+
def self.start_pull_worker(start_date: nil, accession_numbers: [], patient_id: nil)
|
|
42
|
+
start_worker('pull_worker', accession_numbers: accession_numbers, patient_id: patient_id) do
|
|
43
|
+
worker = PullWorker.new(lims_api, start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id)
|
|
44
44
|
|
|
45
45
|
worker.pull_orders
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def self.start_realtime_pull_worker(start_date: nil)
|
|
50
|
-
start_worker('realtime_pull_worker') do
|
|
51
|
-
worker = PullWorker.new(Lims::Api::WsApi.new(Lab::Lims::Config.updates_socket), start_date: start_date)
|
|
49
|
+
def self.start_realtime_pull_worker(start_date: nil, accession_numbers: [], patient_id: nil)
|
|
50
|
+
start_worker('realtime_pull_worker', accession_numbers: accession_numbers, patient_id: patient_id) do
|
|
51
|
+
worker = PullWorker.new(Lims::Api::WsApi.new(Lab::Lims::Config.updates_socket), start_date: start_date, accession_numbers: accession_numbers, patient_id: patient_id)
|
|
52
52
|
|
|
53
53
|
worker.pull_orders
|
|
54
54
|
end
|
|
@@ -57,7 +57,8 @@ module Lab
|
|
|
57
57
|
LOG_FILES_TO_KEEP = 5
|
|
58
58
|
LOG_FILE_SIZE = 500.megabytes
|
|
59
59
|
|
|
60
|
-
def self.start_worker(worker_name)
|
|
60
|
+
def self.start_worker(worker_name, accession_numbers: [], patient_id: nil)
|
|
61
|
+
worker_name = create_file_name(worker_name, accession_numbers: accession_numbers, patient_id: patient_id)
|
|
61
62
|
Rails.logger = LoggerMultiplexor.new(file_logger(worker_name), $stdout)
|
|
62
63
|
ActiveRecord::Base.logger = Rails.logger
|
|
63
64
|
Rails.logger.level = :debug
|
|
@@ -78,6 +79,15 @@ module Lab
|
|
|
78
79
|
Logger.new(log_path("#{worker_name}.log"), LOG_FILES_TO_KEEP, LOG_FILE_SIZE)
|
|
79
80
|
end
|
|
80
81
|
|
|
82
|
+
def self.create_file_name(worker_name, accession_numbers: [], patient_id: nil)
|
|
83
|
+
accession_numbers = accession_numbers.nil? ? [] : accession_numbers
|
|
84
|
+
accession_numbers = accession_numbers.map { |accession| accession.gsub(/[^a-zA-Z0-9]/, '') }.join('_')
|
|
85
|
+
filename = "#{worker_name}"
|
|
86
|
+
filename += "_#{accession_numbers}" unless accession_numbers.empty?
|
|
87
|
+
filename += "_#{patient_id}" if patient_id
|
|
88
|
+
filename
|
|
89
|
+
end
|
|
90
|
+
|
|
81
91
|
def self.log_path(filename)
|
|
82
92
|
Lab::Lims::Utils::LIMS_LOG_PATH.join(filename)
|
|
83
93
|
end
|
|
@@ -600,7 +600,7 @@ module Lab
|
|
|
600
600
|
value_text: status, # Store status as text
|
|
601
601
|
obs_datetime: timestamp,
|
|
602
602
|
comments: updated_by.to_json,
|
|
603
|
-
creator: User.current&.user_id
|
|
603
|
+
creator: User.current&.user_id,
|
|
604
604
|
location_id:,
|
|
605
605
|
date_created: Time.now,
|
|
606
606
|
uuid: SecureRandom.uuid
|
|
@@ -641,7 +641,7 @@ module Lab
|
|
|
641
641
|
value_text: status, # Store status as text
|
|
642
642
|
obs_datetime: timestamp,
|
|
643
643
|
comments: updated_by.to_json,
|
|
644
|
-
creator: User.current&.user_id
|
|
644
|
+
creator: User.current&.user_id,
|
|
645
645
|
location_id:,
|
|
646
646
|
date_created: Time.now,
|
|
647
647
|
uuid: SecureRandom.uuid
|
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.4.
|
|
4
|
+
version: 2.4.6
|
|
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-09-
|
|
11
|
+
date: 2026-09-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: couchrest
|