his_emr_api_lab 2.1.9.pre.alpha → 2.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cfef9418fc9d94d233f24d04883623d67e0c59c2aacea66bc15d3cca61192f78
4
- data.tar.gz: 2d6324bf11f30c87398819042e3a0835275596961bfd838d088a63ae7a4f93c2
3
+ metadata.gz: c59744a50921b0f2244c94e052d4d66cbf39096485f99755e84f9cb66c311a0b
4
+ data.tar.gz: 989cc056aa59acbcd9d24977d3fc34b330cd1793db5d35908ccce44ca08dab34
5
5
  SHA512:
6
- metadata.gz: c7eaa989ae6027aaba3bcd29e90136d1f93eda66854f7ee5bf84453420e0c66a40a928e460e00ee48bdee3fac8e2de05b7c030a7c71c8d4a6bf9457704dc7c6f
7
- data.tar.gz: 16048c52a25d2876d79d6b3526b13625c67de47c44717de48910f905a75bb02dbd1cd48d7ce22e8b58947e61a1cb603340ea3bbdb1cce7536bb1774f41a72d65
6
+ metadata.gz: 22429cb56bfb9c5af91e5b44e2da11b66551ac89d084eeea45f5b16bb06daf5cc4f99d41cb5f2e4f3d5a38443fb62c15e5a30a14c5e5fff85006a3233d8f71de
7
+ data.tar.gz: 622a040596dc790f1d5a3c05469f7afe131badeca6313eb2412f8da378e632b7b28643c6a12eba6f02c618b9bed680722a635ce6e2e57ea6863872eb5e9b0966
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Lab
4
4
  class OrdersController < ApplicationController
5
+ skip_before_action :authenticate, only: %i[order_status order_result summary]
5
6
  before_action :authenticate_request, only: %i[order_status order_result summary]
6
7
 
7
8
  def create
@@ -77,8 +78,26 @@ module Lab
77
78
  private
78
79
 
79
80
  def authenticate_request
80
- decoded_user = authorize_request
81
- user(decoded_user)
81
+ header = request.headers['Authorization']
82
+ content = header.split(' ')
83
+ auth_scheme = content.first
84
+ unless header
85
+ errors = ['Authorization token required']
86
+ render json: { errors: errors }, status: :unauthorized
87
+ return false
88
+ end
89
+ unless auth_scheme == 'Bearer'
90
+ errors = ['Authorization token bearer scheme required']
91
+ render json: { errors: errors }, status: :unauthorized
92
+ return false
93
+ end
94
+ process_token(content.last)
95
+ end
96
+
97
+ def process_token(token)
98
+ browser = Browser.new(request.user_agent)
99
+ decoded = Lab::JsonWebTokenService.decode(token, request.remote_ip + browser.name + browser.version)
100
+ user(decoded)
82
101
  end
83
102
 
84
103
  def user(decoded)
@@ -10,7 +10,7 @@ module Lab
10
10
  target_lab = target_lab&.value_text || order.target_lab&.value_text || Location.current_health_center&.name
11
11
 
12
12
  encounter = Encounter.find_by_encounter_id(order.encounter_id)
13
- program = Program.find_by_program_id(encounter.program_id)
13
+ program = Program.find_by_program_id(encounter&.program_id)
14
14
 
15
15
  ActiveSupport::HashWithIndifferentAccess.new(
16
16
  {
@@ -19,8 +19,8 @@ module Lab
19
19
  order_id: order.order_id, # Deprecated: Link to :id
20
20
  encounter_id: order.encounter_id,
21
21
  order_date: order.start_date,
22
- location_id: encounter.location_id,
23
- program_id: encounter.program_id,
22
+ location_id: encounter&.location_id,
23
+ program_id: encounter&.program_id,
24
24
  program_name: program&.name,
25
25
  patient_id: order.patient_id,
26
26
  accession_number: order.accession_number,
@@ -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
- .limit(batch_size)
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', 'test result already acknowledged electronically at facility'].include?(response['message'])
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).all
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
 
81
81
  # Always fetch the full order from NLIMS to get status trails
@@ -577,43 +577,47 @@ module Lab
577
577
  }
578
578
  end
579
579
 
580
- def orders_pending_updates(patient_id = nil)
580
+ def orders_pending_updates(patient_id = nil, start_date: nil)
581
581
  Rails.logger.info('Looking for orders that need to be updated...')
582
582
  orders = {}
583
583
 
584
- orders_without_specimen(patient_id).each { |order| orders[order.order_id] = order }
585
- orders_without_results(patient_id).each { |order| orders[order.order_id] = order }
586
- orders_without_reason(patient_id).each { |order| orders[order.order_id] = order }
584
+ orders_without_specimen(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
585
+ orders_without_results(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
586
+ orders_without_reason(patient_id, start_date: start_date).each { |order| orders[order.order_id] = order }
587
587
 
588
588
  orders.values
589
589
  end
590
590
 
591
- def orders_without_specimen(patient_id = nil)
591
+ def orders_without_specimen(patient_id = nil, start_date: nil)
592
592
  Rails.logger.debug('Looking for orders without a specimen')
593
593
  unknown_specimen = ConceptName.where(name: Lab::Metadata::UNKNOWN_SPECIMEN)
594
594
  .select(:concept_id)
595
595
  orders = Lab::LabOrder.where(concept_id: unknown_specimen)
596
596
  .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
597
597
  orders = orders.where(patient_id:) if patient_id
598
+ orders = orders.where('orders.date_created >= ?', start_date) if start_date
598
599
 
599
600
  orders
600
601
  end
601
602
 
602
- def orders_without_results(patient_id = nil)
603
+ def orders_without_results(patient_id = nil, start_date: nil)
603
604
  Rails.logger.debug('Looking for orders without a result')
604
605
  # Lab::OrdersSearchService.find_orders_without_results(patient_id: patient_id)
605
606
  # .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id).where("pulled_at IS NULL"))
606
- Lab::OrdersSearchService.find_orders_without_results(patient_id:)
607
- .where(order_id: Lab::LimsOrderMapping.select(:order_id))
607
+ orders = Lab::OrdersSearchService.find_orders_without_results(patient_id:)
608
+ .where(order_id: Lab::LimsOrderMapping.select(:order_id))
609
+ orders = orders.where('orders.date_created >= ?', start_date) if start_date
610
+ orders
608
611
  end
609
612
 
610
- def orders_without_reason(patient_id = nil)
613
+ def orders_without_reason(patient_id = nil, start_date: nil)
611
614
  Rails.logger.debug('Looking for orders without a reason for test')
612
615
  orders = Lab::LabOrder.joins(:reason_for_test)
613
616
  .merge(Observation.where(value_coded: nil, value_text: nil))
614
617
  .limit(1000)
615
618
  .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
616
619
  orders = orders.where(patient_id:) if patient_id
620
+ orders = orders.where('orders.date_created >= ?', start_date) if start_date
617
621
 
618
622
  orders
619
623
  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
- .unscoped
85
- .find(order_id)
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
- .where("accession_number IS NOT NULL AND accession_number !=''")
105
- .where(date_created: START_DATE..(Date.today + 1.day))
106
- .order(date_created: :desc)
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(&method(:start_push_worker))
16
- fork(&method(:start_pull_worker))
17
- fork(&method(:start_acknowledgement_worker))
18
- fork(&method(:start_realtime_pull_worker)) if realtime_updates_enabled?
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
@@ -300,6 +300,7 @@ module Lab
300
300
 
301
301
  concept = params.dig(:specimen, :concept)
302
302
  concept ||= params.dig(:specimen, :concept_id)
303
+ concept ||= unknown_concept_id
303
304
 
304
305
  order_type = nil
305
306
  order_type = OrderType.find_by_order_type_id!(params[:order_type_id])&.id if params[:order_type_id].present?
@@ -401,7 +402,7 @@ module Lab
401
402
  end
402
403
 
403
404
  def unknown_concept_id
404
- ConceptName.find_by_name!('Unknown').concept
405
+ ConceptName.find_by_name!('Unknown').concept_id
405
406
  end
406
407
 
407
408
  def update_reason_for_test(order, concept_id, force_update: false)
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.9-alpha'
4
+ VERSION = '2.2.1'
5
5
  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.9.pre.alpha
4
+ version: 2.2.1
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-03-04 00:00:00.000000000 Z
11
+ date: 2026-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: couchrest
@@ -341,9 +341,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
341
341
  version: '0'
342
342
  required_rubygems_version: !ruby/object:Gem::Requirement
343
343
  requirements:
344
- - - ">"
344
+ - - ">="
345
345
  - !ruby/object:Gem::Version
346
- version: 1.3.1
346
+ version: '0'
347
347
  requirements: []
348
348
  rubygems_version: 3.4.1
349
349
  signing_key: