his_emr_api_lab 1.2.0 → 2.0.0

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -1
  3. data/app/controllers/lab/application_controller.rb +5 -0
  4. data/app/controllers/lab/orders_controller.rb +3 -3
  5. data/app/controllers/lab/specimen_types_controller.rb +1 -1
  6. data/app/controllers/lab/test_result_indicators_controller.rb +6 -4
  7. data/app/controllers/lab/test_types_controller.rb +1 -1
  8. data/app/controllers/lab/tests_controller.rb +20 -17
  9. data/app/jobs/lab/application_job.rb +2 -0
  10. data/app/jobs/lab/update_patient_orders_job.rb +1 -1
  11. data/app/mailers/lab/application_mailer.rb +2 -0
  12. data/app/models/lab/application_record.rb +2 -0
  13. data/app/models/lab/lab_order.rb +1 -1
  14. data/app/models/lab/lims_failed_import.rb +2 -0
  15. data/app/serializers/lab/lab_order_serializer.rb +2 -2
  16. data/app/serializers/lab/result_serializer.rb +2 -2
  17. data/app/services/lab/accession_number_service.rb +2 -2
  18. data/app/services/lab/concepts_service.rb +2 -2
  19. data/app/services/lab/labelling_service/order_label.rb +2 -2
  20. data/app/services/lab/lims/api/blackhole_api.rb +1 -1
  21. data/app/services/lab/lims/api/couchdb_api.rb +3 -3
  22. data/app/services/lab/lims/api/mysql_api.rb +6 -6
  23. data/app/services/lab/lims/api/rest_api.rb +378 -372
  24. data/app/services/lab/lims/api/ws_api.rb +1 -1
  25. data/app/services/lab/lims/api_factory.rb +1 -1
  26. data/app/services/lab/lims/config.rb +1 -1
  27. data/app/services/lab/lims/exceptions.rb +1 -0
  28. data/app/services/lab/lims/migrator.rb +11 -12
  29. data/app/services/lab/lims/order_dto.rb +4 -4
  30. data/app/services/lab/lims/order_serializer.rb +12 -12
  31. data/app/services/lab/lims/pull_worker.rb +14 -13
  32. data/app/services/lab/lims/push_worker.rb +5 -5
  33. data/app/services/lab/lims/utils.rb +4 -6
  34. data/app/services/lab/lims/worker.rb +1 -1
  35. data/app/services/lab/orders_search_service.rb +3 -3
  36. data/app/services/lab/orders_service.rb +5 -5
  37. data/app/services/lab/results_service.rb +3 -3
  38. data/app/services/lab/tests_service.rb +5 -5
  39. data/db/migrate/20210126092910_create_lab_lab_accession_number_counters.rb +2 -0
  40. data/db/migrate/20210310115457_create_lab_lims_order_mappings.rb +2 -0
  41. data/db/migrate/20210326195504_add_order_revision_to_lims_order_mapping.rb +2 -0
  42. data/db/migrate/20210610095024_fix_numeric_results_value_type.rb +2 -0
  43. data/db/migrate/20210807111531_add_default_to_lims_order_mapping.rb +2 -0
  44. data/lib/auto12epl.rb +55 -53
  45. data/lib/couch_bum/couch_bum.rb +4 -4
  46. data/lib/generators/lab/install/templates/rswag-ui-lab.rb +2 -0
  47. data/lib/his_emr_api_lab.rb +2 -0
  48. data/lib/lab/engine.rb +2 -0
  49. data/lib/lab/version.rb +1 -1
  50. data/lib/logger_multiplexor.rb +2 -2
  51. data/lib/tasks/lab_tasks.rake +2 -0
  52. data/lib/tasks/loaders/loader_mixin.rb +4 -4
  53. data/lib/tasks/loaders/reasons_for_test_loader.rb +1 -1
  54. data/lib/tasks/loaders/specimens_loader.rb +6 -7
  55. data/lib/tasks/loaders/test_result_indicators_loader.rb +5 -5
  56. metadata +12 -17
@@ -1,433 +1,439 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Lab::Lims::Api::RestApi
4
- class LimsApiError < GatewayError; end
3
+ module Lab
4
+ module Lims
5
+ module Api
6
+ class RestApi
7
+ class LimsApiError < GatewayError; end
5
8
 
6
- class AuthenticationTokenExpired < LimsApiError; end
9
+ class AuthenticationTokenExpired < LimsApiError; end
7
10
 
8
- class InvalidParameters < LimsApiError; end
11
+ class InvalidParameters < LimsApiError; end
9
12
 
10
- def initialize(config)
11
- @config = config
12
- end
13
-
14
- def create_order(order_dto)
15
- response = in_authenticated_session do |headers|
16
- Rails.logger.info("Pushing order ##{order_dto[:tracking_number]} to LIMS")
17
-
18
- if order_dto['sample_type'].casecmp?('not_specified')
19
- RestClient.post(expand_uri('request_order', api_version: 'v2'), make_create_params(order_dto), headers)
20
- else
21
- RestClient.post(expand_uri('create_order'), make_create_params(order_dto), headers)
22
- end
23
- end
24
-
25
- data = JSON.parse(response.body)
26
- update_order_results(order_dto) unless data['message'].casecmp?('Order already available')
27
-
28
- ActiveSupport::HashWithIndifferentAccess.new(
29
- id: order_dto.fetch(:_id, order_dto[:tracking_number]),
30
- rev: 0,
31
- tracking_number: order_dto[:tracking_number]
32
- )
33
- end
34
-
35
- def acknowledge(acknowledgement_dto)
36
- Rails.logger.info("Acknowledging order ##{acknowledgement_dto} in LIMS")
37
- response = in_authenticated_session do |headers|
38
- RestClient.post(expand_uri('/acknowledge/test/results/recipient'), acknowledgement_dto, headers)
39
- end
40
- Rails.logger.info("Acknowledged order ##{acknowledgement_dto} in LIMS. Response: #{response}")
41
- JSON.parse(response)
42
- end
43
-
44
- def update_order(_id, order_dto)
45
- in_authenticated_session do |headers|
46
- RestClient.post(expand_uri('update_order'), make_update_params(order_dto), headers)
47
- end
13
+ def initialize(config)
14
+ @config = config
15
+ end
48
16
 
49
- update_order_results(order_dto)
17
+ def create_order(order_dto)
18
+ response = in_authenticated_session do |headers|
19
+ Rails.logger.info("Pushing order ##{order_dto[:tracking_number]} to LIMS")
20
+
21
+ if order_dto['sample_type'].casecmp?('not_specified')
22
+ RestClient.post(expand_uri('request_order', api_version: 'v2'), make_create_params(order_dto), headers)
23
+ else
24
+ RestClient.post(expand_uri('create_order'), make_create_params(order_dto), headers)
25
+ end
26
+ end
27
+
28
+ data = JSON.parse(response.body)
29
+ update_order_results(order_dto) unless data['message'].casecmp?('Order already available')
30
+
31
+ ActiveSupport::HashWithIndifferentAccess.new(
32
+ id: order_dto.fetch(:_id, order_dto[:tracking_number]),
33
+ rev: 0,
34
+ tracking_number: order_dto[:tracking_number]
35
+ )
36
+ end
50
37
 
51
- { tracking_number: order_dto[:tracking_number] }
52
- end
38
+ def acknowledge(acknowledgement_dto)
39
+ Rails.logger.info("Acknowledging order ##{acknowledgement_dto} in LIMS")
40
+ response = in_authenticated_session do |headers|
41
+ RestClient.post(expand_uri('/acknowledge/test/results/recipient'), acknowledgement_dto, headers)
42
+ end
43
+ Rails.logger.info("Acknowledged order ##{acknowledgement_dto} in LIMS. Response: #{response}")
44
+ JSON.parse(response)
45
+ end
53
46
 
54
- def consume_orders(*_args, patient_id: nil, **_kwargs)
55
- orders_pending_updates(patient_id).each do |order|
56
- order_dto = Lab::Lims::OrderSerializer.serialize_order(order)
47
+ def update_order(_id, order_dto)
48
+ in_authenticated_session do |headers|
49
+ RestClient.post(expand_uri('update_order'), make_update_params(order_dto), headers)
50
+ end
57
51
 
58
- if order_dto['priority'].nil? || order_dto['sample_type'].casecmp?('not_specified')
59
- patch_order_dto_with_lims_order!(order_dto, find_lims_order(order.accession_number))
60
- end
52
+ update_order_results(order_dto)
61
53
 
62
- if order_dto['test_results'].empty?
63
- begin
64
- patch_order_dto_with_lims_results!(order_dto, find_lims_results(order.accession_number))
65
- rescue InvalidParameters => e # LIMS responds with a 401 when a result is not found :(
66
- Rails.logger.error("Failed to fetch results for ##{order.accession_number}: #{e.message}")
54
+ { tracking_number: order_dto[:tracking_number] }
67
55
  end
68
- end
69
-
70
- yield order_dto, OpenStruct.new(last_seq: 0)
71
- rescue LimsApiError => e
72
- Rails.logger.error("Failed to fetch updates for ##{order.accession_number}: #{e.class} - #{e.message}")
73
- sleep(1)
74
- end
75
- end
76
-
77
- def delete_order(_id, order_dto)
78
- tracking_number = order_dto.fetch('tracking_number')
79
56
 
80
- order_dto['tests'].each do |test|
81
- Rails.logger.info("Voiding test '#{test}' (#{tracking_number}) in LIMS")
82
- in_authenticated_session do |headers|
83
- date_voided, voided_status = find_test_status(order_dto, test, 'Voided')
84
- params = make_void_test_params(tracking_number, test, voided_status['updated_by'], date_voided)
85
- RestClient.post(expand_uri('update_test'), params, headers)
86
- end
87
- end
88
- end
57
+ def consume_orders(*_args, patient_id: nil, **_kwargs)
58
+ orders_pending_updates(patient_id).each do |order|
59
+ order_dto = Lab::Lims::OrderSerializer.serialize_order(order)
60
+
61
+ if order_dto['priority'].nil? || order_dto['sample_type'].casecmp?('not_specified')
62
+ patch_order_dto_with_lims_order!(order_dto, find_lims_order(order.accession_number))
63
+ end
64
+
65
+ if order_dto['test_results'].empty?
66
+ begin
67
+ patch_order_dto_with_lims_results!(order_dto, find_lims_results(order.accession_number))
68
+ rescue InvalidParameters => e # LIMS responds with a 401 when a result is not found :(
69
+ Rails.logger.error("Failed to fetch results for ##{order.accession_number}: #{e.message}")
70
+ end
71
+ end
72
+
73
+ yield order_dto, OpenStruct.new(last_seq: 0)
74
+ rescue LimsApiError => e
75
+ Rails.logger.error("Failed to fetch updates for ##{order.accession_number}: #{e.class} - #{e.message}")
76
+ sleep(1)
77
+ end
78
+ end
89
79
 
90
- def verify_tracking_number(tracking_number)
91
- find_lims_order(tracking_number)
92
- rescue InvalidParameters => e
93
- Rails.logger.error("Failed to verify tracking number #{tracking_number}: #{e.message}")
94
- false
95
- end
80
+ def delete_order(_id, order_dto)
81
+ tracking_number = order_dto.fetch('tracking_number')
82
+
83
+ order_dto['tests'].each do |test|
84
+ Rails.logger.info("Voiding test '#{test}' (#{tracking_number}) in LIMS")
85
+ in_authenticated_session do |headers|
86
+ date_voided, voided_status = find_test_status(order_dto, test, 'Voided')
87
+ params = make_void_test_params(tracking_number, test, voided_status['updated_by'], date_voided)
88
+ RestClient.post(expand_uri('update_test'), params, headers)
89
+ end
90
+ end
91
+ end
96
92
 
97
- private
98
-
99
- attr_reader :config
100
-
101
- MAX_LIMS_RETRIES = 5 # LIMS API Calls can only fail this number of times before we give up on it
102
-
103
- ##
104
- # Execute LIMS API calls within an authenticated session.
105
- #
106
- # Method automatically checks authenticates with LIMS if necessary and passes
107
- # down the necessary headers for authentication to the REST call being made.
108
- #
109
- # Example:
110
- #
111
- # response = in_authenticated_session do |headers|
112
- # RestClient.get(expand_uri('query_results_by_tracking_number/XXXXXX'), headers)
113
- # end
114
- #
115
- # pp JSON.parse(response.body) if response.code == 200
116
- def in_authenticated_session
117
- retries ||= MAX_LIMS_RETRIES
118
-
119
- self.authentication_token = authenticate unless authentication_token
120
-
121
- response = yield 'token' => authentication_token, 'Content-type' => 'application/json'
122
- check_response!(response)
123
- rescue AuthenticationTokenExpired => e
124
- self.authentication_token = nil
125
- retry if (retries -= 1).positive?
126
- rescue RestClient::ExceptionWithResponse => e
127
- Rails.logger.error("LIMS Error: #{e.response&.code} - #{e.response&.body}")
128
- raise e unless e.response&.code == 401
129
-
130
- self.authentication_token = nil
131
- retry if (retries -= 1).positive?
132
- end
93
+ def verify_tracking_number(tracking_number)
94
+ find_lims_order(tracking_number)
95
+ rescue InvalidParameters => e
96
+ Rails.logger.error("Failed to verify tracking number #{tracking_number}: #{e.message}")
97
+ false
98
+ end
133
99
 
134
- def authenticate
135
- username = config.fetch(:username)
136
- password = config.fetch(:password)
100
+ private
101
+
102
+ attr_reader :config
103
+
104
+ MAX_LIMS_RETRIES = 5 # LIMS API Calls can only fail this number of times before we give up on it
105
+
106
+ ##
107
+ # Execute LIMS API calls within an authenticated session.
108
+ #
109
+ # Method automatically checks authenticates with LIMS if necessary and passes
110
+ # down the necessary headers for authentication to the REST call being made.
111
+ #
112
+ # Example:
113
+ #
114
+ # response = in_authenticated_session do |headers|
115
+ # RestClient.get(expand_uri('query_results_by_tracking_number/XXXXXX'), headers)
116
+ # end
117
+ #
118
+ # pp JSON.parse(response.body) if response.code == 200
119
+ def in_authenticated_session
120
+ retries ||= MAX_LIMS_RETRIES
121
+
122
+ self.authentication_token = authenticate unless authentication_token
123
+
124
+ response = yield 'token' => authentication_token, 'Content-type' => 'application/json'
125
+ check_response!(response)
126
+ rescue AuthenticationTokenExpired => e
127
+ self.authentication_token = nil
128
+ retry if (retries -= 1).positive?
129
+ rescue RestClient::ExceptionWithResponse => e
130
+ Rails.logger.error("LIMS Error: #{e.response&.code} - #{e.response&.body}")
131
+ raise e unless e.response&.code == 401
132
+
133
+ self.authentication_token = nil
134
+ retry if (retries -= 1).positive?
135
+ end
137
136
 
138
- Rails.logger.debug("Authenticating with LIMS as: #{username}")
139
- response = RestClient.get(expand_uri("re_authenticate/#{username}/#{password}"),
140
- headers: { 'Content-type' => 'application/json' })
141
- response_body = JSON.parse(response.body)
137
+ def authenticate
138
+ username = config.fetch(:username)
139
+ password = config.fetch(:password)
142
140
 
143
- if response_body['status'] == 401
144
- Rails.logger.error("Failed to authenticate with LIMS as #{config.fetch(:username)}: #{response_body['message']}")
145
- raise LimsApiError, 'LIMS authentication failed'
146
- end
141
+ Rails.logger.debug("Authenticating with LIMS as: #{username}")
142
+ response = RestClient.get(expand_uri("re_authenticate/#{username}/#{password}"),
143
+ headers: { 'Content-type' => 'application/json' })
144
+ response_body = JSON.parse(response.body)
147
145
 
148
- response_body['data']['token']
149
- end
146
+ if response_body['status'] == 401
147
+ Rails.logger.error("Failed to authenticate with LIMS as #{config.fetch(:username)}: #{response_body['message']}")
148
+ raise LimsApiError, 'LIMS authentication failed'
149
+ end
150
150
 
151
- def authentication_token=(token)
152
- Thread.current[:lims_authentication_token] = token
153
- end
151
+ response_body['data']['token']
152
+ end
154
153
 
155
- def authentication_token
156
- Thread.current[:lims_authentication_token]
157
- end
154
+ def authentication_token=(token)
155
+ Thread.current[:lims_authentication_token] = token
156
+ end
158
157
 
159
- ##
160
- # Examines a response from LIMS to check if token has expired.
161
- #
162
- # LIMS' doesn't properly use HTTP status codes; the codes are embedded in the
163
- # response body. 200 is used for success responses and 401 for everything else.
164
- # We have this work around to examine the response body and
165
- # throw errors accordingly. The following are the errors thrown:
166
- #
167
- # Lims::AuthenticationTokenExpired
168
- # Lims::InvalidParameters
169
- # Lims::ApiError - Thrown when we couldn't make sense of the error
170
- def check_response!(response)
171
- body = JSON.parse(response.body)
172
- return response if body['status'] == 200
173
-
174
- Rails.logger.error("Lims Api Error: #{response.body}")
175
-
176
- raise LimsApiError, "#{body['status']} - #{body['message']}" if body['status'] != 401
177
-
178
- if body['message'].match?(/token expired/i)
179
- raise AuthenticationTokenExpired, "Authentication token expired: #{body['message']}"
180
- end
158
+ def authentication_token
159
+ Thread.current[:lims_authentication_token]
160
+ end
181
161
 
182
- raise InvalidParameters, body['message']
183
- end
162
+ ##
163
+ # Examines a response from LIMS to check if token has expired.
164
+ #
165
+ # LIMS' doesn't properly use HTTP status codes; the codes are embedded in the
166
+ # response body. 200 is used for success responses and 401 for everything else.
167
+ # We have this work around to examine the response body and
168
+ # throw errors accordingly. The following are the errors thrown:
169
+ #
170
+ # Lims::AuthenticationTokenExpired
171
+ # Lims::InvalidParameters
172
+ # Lims::ApiError - Thrown when we couldn't make sense of the error
173
+ def check_response!(response)
174
+ body = JSON.parse(response.body)
175
+ return response if body['status'] == 200
176
+
177
+ Rails.logger.error("Lims Api Error: #{response.body}")
178
+
179
+ raise LimsApiError, "#{body['status']} - #{body['message']}" if body['status'] != 401
180
+
181
+ if body['message'].match?(/token expired/i)
182
+ raise AuthenticationTokenExpired, "Authentication token expired: #{body['message']}"
183
+ end
184
+
185
+ raise InvalidParameters, body['message']
186
+ end
184
187
 
185
- ##
186
- # Takes a LIMS API relative URI and converts it to a full URL.
187
- def expand_uri(uri, api_version: 'v1')
188
- protocol = config.fetch(:protocol)
189
- host = config.fetch(:host)
190
- port = config.fetch(:port)
191
- uri = uri.gsub(%r{^/+}, '')
188
+ ##
189
+ # Takes a LIMS API relative URI and converts it to a full URL.
190
+ def expand_uri(uri, api_version: 'v1')
191
+ protocol = config.fetch(:protocol)
192
+ host = config.fetch(:host)
193
+ port = config.fetch(:port)
194
+ uri = uri.gsub(%r{^/+}, '')
192
195
 
193
- "#{protocol}://#{host}:#{port}/api/#{api_version}/#{uri}"
194
- end
196
+ "#{protocol}://#{host}:#{port}/api/#{api_version}/#{uri}"
197
+ end
195
198
 
196
- ##
197
- # Converts an OrderDTO to parameters for POST /create_order
198
- def make_create_params(order_dto)
199
- {
200
- tracking_number: order_dto.fetch(:tracking_number),
201
- district: current_district,
202
- health_facility_name: order_dto.fetch(:sending_facility),
203
- first_name: order_dto.fetch(:patient).fetch(:first_name),
204
- last_name: order_dto.fetch(:patient).fetch(:last_name),
205
- phone_number: order_dto.fetch(:patient).fetch(:phone_number),
206
- gender: order_dto.fetch(:patient).fetch(:gender),
207
- arv_number: order_dto.fetch(:patient).fetch(:arv_number),
208
- art_regimen: order_dto.fetch(:patient).fetch(:art_regimen),
209
- art_start_date: order_dto.fetch(:patient).fetch(:art_start_date),
210
- date_of_birth: order_dto.fetch(:patient).fetch(:dob),
211
- national_patient_id: order_dto.fetch(:patient).fetch(:id),
212
- requesting_clinician: requesting_clinician(order_dto),
213
- sample_type: order_dto.fetch(:sample_type),
214
- tests: order_dto.fetch(:tests),
215
- date_sample_drawn: sample_drawn_date(order_dto),
216
- sample_priority: order_dto.fetch(:priority) || 'Routine',
217
- sample_status: order_dto.fetch(:sample_status),
218
- target_lab: order_dto.fetch(:receiving_facility),
219
- order_location: order_dto.fetch(:order_location) || 'Unknown',
220
- who_order_test_first_name: order_dto.fetch(:who_order_test).fetch(:first_name),
221
- who_order_test_last_name: order_dto.fetch(:who_order_test).fetch(:last_name)
222
- }
223
- end
199
+ ##
200
+ # Converts an OrderDto to parameters for POST /create_order
201
+ def make_create_params(order_dto)
202
+ {
203
+ tracking_number: order_dto.fetch(:tracking_number),
204
+ district: current_district,
205
+ health_facility_name: order_dto.fetch(:sending_facility),
206
+ first_name: order_dto.fetch(:patient).fetch(:first_name),
207
+ last_name: order_dto.fetch(:patient).fetch(:last_name),
208
+ phone_number: order_dto.fetch(:patient).fetch(:phone_number),
209
+ gender: order_dto.fetch(:patient).fetch(:gender),
210
+ arv_number: order_dto.fetch(:patient).fetch(:arv_number),
211
+ art_regimen: order_dto.fetch(:patient).fetch(:art_regimen),
212
+ art_start_date: order_dto.fetch(:patient).fetch(:art_start_date),
213
+ date_of_birth: order_dto.fetch(:patient).fetch(:dob),
214
+ national_patient_id: order_dto.fetch(:patient).fetch(:id),
215
+ requesting_clinician: requesting_clinician(order_dto),
216
+ sample_type: order_dto.fetch(:sample_type),
217
+ tests: order_dto.fetch(:tests),
218
+ date_sample_drawn: sample_drawn_date(order_dto),
219
+ sample_priority: order_dto.fetch(:priority) || 'Routine',
220
+ sample_status: order_dto.fetch(:sample_status),
221
+ target_lab: order_dto.fetch(:receiving_facility),
222
+ order_location: order_dto.fetch(:order_location) || 'Unknown',
223
+ who_order_test_first_name: order_dto.fetch(:who_order_test).fetch(:first_name),
224
+ who_order_test_last_name: order_dto.fetch(:who_order_test).fetch(:last_name)
225
+ }
226
+ end
224
227
 
225
- ##
226
- # Converts an OrderDTO to parameters for POST /update_order
227
- def make_update_params(order_dto)
228
- date_updated, status = sample_drawn_status(order_dto)
229
-
230
- {
231
- tracking_number: order_dto.fetch(:tracking_number),
232
- who_updated: status.fetch(:updated_by),
233
- date_updated: date_updated,
234
- specimen_type: order_dto.fetch(:sample_type),
235
- status: 'specimen_collected'
236
- }
237
- end
228
+ ##
229
+ # Converts an OrderDto to parameters for POST /update_order
230
+ def make_update_params(order_dto)
231
+ date_updated, status = sample_drawn_status(order_dto)
232
+
233
+ {
234
+ tracking_number: order_dto.fetch(:tracking_number),
235
+ who_updated: status.fetch(:updated_by),
236
+ date_updated:,
237
+ specimen_type: order_dto.fetch(:sample_type),
238
+ status: 'specimen_collected'
239
+ }
240
+ end
238
241
 
239
- def current_district
240
- health_centre = Location.current_health_center
241
- raise 'Current health centre not set' unless health_centre
242
+ def current_district
243
+ health_centre = Location.current_health_center
244
+ raise 'Current health centre not set' unless health_centre
242
245
 
243
- district = health_centre.district || Lab::Lims::Config.application['district']
246
+ district = health_centre.district || Lab::Lims::Config.application['district']
244
247
 
245
- unless district
246
- health_centre_name = "##{health_centre.id} - #{health_centre.name}"
247
- raise "Current health centre district not set: #{health_centre_name}"
248
- end
248
+ unless district
249
+ health_centre_name = "##{health_centre.id} - #{health_centre.name}"
250
+ raise "Current health centre district not set: #{health_centre_name}"
251
+ end
249
252
 
250
- district
251
- end
253
+ district
254
+ end
252
255
 
253
- ##
254
- # Extracts sample drawn status from an OrderDTO
255
- def sample_drawn_status(order_dto)
256
- order_dto[:sample_statuses].each do |trail_entry|
257
- date, status = trail_entry.each_pair.find { |_date, status| status['status'].casecmp?('Drawn') }
258
- next unless date
256
+ ##
257
+ # Extracts sample drawn status from an OrderDto
258
+ def sample_drawn_status(order_dto)
259
+ order_dto[:sample_statuses].each do |trail_entry|
260
+ date, status = trail_entry.each_pair.find { |_date, status| status['status'].casecmp?('Drawn') }
261
+ next unless date
259
262
 
260
- return Date.strptime(date, '%Y%m%d%H%M%S').strftime('%Y-%m-%d'), status
261
- end
263
+ return Date.strptime(date, '%Y%m%d%H%M%S').strftime('%Y-%m-%d'), status
264
+ end
262
265
 
263
- [order_dto['date_created'], nil]
264
- end
266
+ [order_dto['date_created'], nil]
267
+ end
265
268
 
266
- ##
267
- # Extracts a sample drawn date from a LIMS OrderDTO.
268
- def sample_drawn_date(order_dto)
269
- sample_drawn_status(order_dto).first
270
- end
269
+ ##
270
+ # Extracts a sample drawn date from a LIMS OrderDto.
271
+ def sample_drawn_date(order_dto)
272
+ sample_drawn_status(order_dto).first
273
+ end
271
274
 
272
- ##
273
- # Extracts the requesting clinician from a LIMS OrderDTO
274
- def requesting_clinician(order_dto)
275
- orderer = order_dto[:who_order_test]
275
+ ##
276
+ # Extracts the requesting clinician from a LIMS OrderDto
277
+ def requesting_clinician(order_dto)
278
+ orderer = order_dto[:who_order_test]
276
279
 
277
- "#{orderer[:first_name]} #{orderer[:last_name]}"
278
- end
280
+ "#{orderer[:first_name]} #{orderer[:last_name]}"
281
+ end
279
282
 
280
- def find_lims_order(tracking_number)
281
- response = in_authenticated_session do |headers|
282
- Rails.logger.info("Fetching order ##{tracking_number}")
283
- RestClient.get(expand_uri("query_order_by_tracking_number/#{tracking_number}"), headers)
284
- end
283
+ def find_lims_order(tracking_number)
284
+ response = in_authenticated_session do |headers|
285
+ Rails.logger.info("Fetching order ##{tracking_number}")
286
+ RestClient.get(expand_uri("query_order_by_tracking_number/#{tracking_number}"), headers)
287
+ end
285
288
 
286
- Rails.logger.info("Order ##{tracking_number} found... Parsing...")
287
- JSON.parse(response).fetch('data')
288
- end
289
+ Rails.logger.info("Order ##{tracking_number} found... Parsing...")
290
+ JSON.parse(response).fetch('data')
291
+ end
289
292
 
290
- def find_lims_results(tracking_number)
291
- response = in_authenticated_session do |headers|
292
- Rails.logger.info("Fetching results for order ##{tracking_number}")
293
- RestClient.get(expand_uri("query_results_by_tracking_number/#{tracking_number}"), headers)
294
- end
293
+ def find_lims_results(tracking_number)
294
+ response = in_authenticated_session do |headers|
295
+ Rails.logger.info("Fetching results for order ##{tracking_number}")
296
+ RestClient.get(expand_uri("query_results_by_tracking_number/#{tracking_number}"), headers)
297
+ end
295
298
 
296
- Rails.logger.info("Result for order ##{tracking_number} found... Parsing...")
297
- JSON.parse(response).fetch('data').fetch('results')
298
- end
299
+ Rails.logger.info("Result for order ##{tracking_number} found... Parsing...")
300
+ JSON.parse(response).fetch('data').fetch('results')
301
+ end
299
302
 
300
- ##
301
- # Make a copy of the order_dto with the results from LIMS parsed
302
- # and appended to it.
303
- def patch_order_dto_with_lims_results!(order_dto, results)
304
- order_dto.merge!(
305
- '_id' => order_dto[:tracking_number],
306
- '_rev' => 0,
307
- 'test_results' => results.each_with_object({}) do |result, formatted_results|
308
- test_name, measures = result
309
- result_date = measures.delete('result_date')
310
-
311
- formatted_results[test_name] = {
312
- results: measures.each_with_object({}) do |measure, processed_measures|
313
- processed_measures[measure[0]] = { 'result_value' => measure[1] }
314
- end,
315
- result_date: result_date,
316
- result_entered_by: {}
317
- }
318
- end
319
- )
320
- end
303
+ ##
304
+ # Make a copy of the order_dto with the results from LIMS parsed
305
+ # and appended to it.
306
+ def patch_order_dto_with_lims_results!(order_dto, results)
307
+ order_dto.merge!(
308
+ '_id' => order_dto[:tracking_number],
309
+ '_rev' => 0,
310
+ 'test_results' => results.each_with_object({}) do |result, formatted_results|
311
+ test_name, measures = result
312
+ result_date = measures.delete('result_date')
313
+
314
+ formatted_results[test_name] = {
315
+ results: measures.each_with_object({}) do |measure, processed_measures|
316
+ processed_measures[measure[0]] = { 'result_value' => measure[1] }
317
+ end,
318
+ result_date:,
319
+ result_entered_by: {}
320
+ }
321
+ end
322
+ )
323
+ end
321
324
 
322
- def patch_order_dto_with_lims_order!(order_dto, lims_order)
323
- order_dto.merge!(
324
- 'sample_type' => lims_order['other']['sample_type'],
325
- 'sample_status' => lims_order['other']['specimen_status'],
326
- 'priority' => lims_order['other']['priority']
327
- )
328
- end
325
+ def patch_order_dto_with_lims_order!(order_dto, lims_order)
326
+ order_dto.merge!(
327
+ 'sample_type' => lims_order['other']['sample_type'],
328
+ 'sample_status' => lims_order['other']['specimen_status'],
329
+ 'priority' => lims_order['other']['priority']
330
+ )
331
+ end
329
332
 
330
- def update_order_results(order_dto)
331
- return nil if order_dto['test_results'].nil? || order_dto['test_results'].empty?
333
+ def update_order_results(order_dto)
334
+ return nil if order_dto['test_results'].nil? || order_dto['test_results'].empty?
332
335
 
333
- order_dto['test_results'].each do |test_name, results|
334
- Rails.logger.info("Pushing result for order ##{order_dto['tracking_number']}")
335
- in_authenticated_session do |headers|
336
- params = make_update_test_params(order_dto['tracking_number'], test_name, results)
336
+ order_dto['test_results'].each do |test_name, results|
337
+ Rails.logger.info("Pushing result for order ##{order_dto['tracking_number']}")
338
+ in_authenticated_session do |headers|
339
+ params = make_update_test_params(order_dto['tracking_number'], test_name, results)
337
340
 
338
- RestClient.post(expand_uri('update_test'), params, headers)
339
- end
340
- end
341
- end
341
+ RestClient.post(expand_uri('update_test'), params, headers)
342
+ end
343
+ end
344
+ end
342
345
 
343
- def make_update_test_params(tracking_number, test_name, results, test_status = 'Drawn')
344
- {
345
- tracking_number: tracking_number,
346
- test_name: test_name,
347
- result_date: results['result_date'],
348
- time_updated: results['result_date'],
349
- who_updated: {
350
- first_name: results[:result_entered_by][:first_name],
351
- last_name: results[:result_entered_by][:last_name],
352
- id_number: results[:result_entered_by][:id]
353
- },
354
- test_status: test_status,
355
- results: results['results']&.each_with_object({}) do |measure, formatted_results|
356
- measure_name, measure_value = measure
357
-
358
- formatted_results[measure_name] = measure_value['result_value']
359
- end
360
- }
361
- end
346
+ def make_update_test_params(tracking_number, test_name, results, test_status = 'Drawn')
347
+ {
348
+ tracking_number:,
349
+ test_name:,
350
+ result_date: results['result_date'],
351
+ time_updated: results['result_date'],
352
+ who_updated: {
353
+ first_name: results[:result_entered_by][:first_name],
354
+ last_name: results[:result_entered_by][:last_name],
355
+ id_number: results[:result_entered_by][:id]
356
+ },
357
+ test_status:,
358
+ results: results['results']&.each_with_object({}) do |measure, formatted_results|
359
+ measure_name, measure_value = measure
360
+
361
+ formatted_results[measure_name] = measure_value['result_value']
362
+ end
363
+ }
364
+ end
362
365
 
363
- def find_test_status(order_dto, target_test, target_status)
364
- order_dto['test_statuses'].each do |test, statuses|
365
- next unless test.casecmp?(target_test)
366
+ def find_test_status(order_dto, target_test, target_status)
367
+ order_dto['test_statuses'].each do |test, statuses|
368
+ next unless test.casecmp?(target_test)
366
369
 
367
- statuses.each do |date, status|
368
- next unless status['status'].casecmp?(target_status)
370
+ statuses.each do |date, status|
371
+ next unless status['status'].casecmp?(target_status)
369
372
 
370
- return [Date.strptime(date, '%Y%m%d%H%M%S'), status]
371
- end
372
- end
373
+ return [Date.strptime(date, '%Y%m%d%H%M%S'), status]
374
+ end
375
+ end
373
376
 
374
- nil
375
- end
377
+ nil
378
+ end
376
379
 
377
- def make_void_test_params(tracking_number, test_name, voided_by, void_date = nil)
378
- void_date ||= Time.now
379
-
380
- {
381
- tracking_number: tracking_number,
382
- test_name: test_name,
383
- time_updated: void_date,
384
- who_updated: {
385
- first_name: voided_by[:first_name],
386
- last_name: voided_by[:last_name],
387
- id_number: voided_by[:id]
388
- },
389
- test_status: 'voided'
390
- }
391
- end
380
+ def make_void_test_params(tracking_number, test_name, voided_by, void_date = nil)
381
+ void_date ||= Time.now
382
+
383
+ {
384
+ tracking_number:,
385
+ test_name:,
386
+ time_updated: void_date,
387
+ who_updated: {
388
+ first_name: voided_by[:first_name],
389
+ last_name: voided_by[:last_name],
390
+ id_number: voided_by[:id]
391
+ },
392
+ test_status: 'voided'
393
+ }
394
+ end
392
395
 
393
- def orders_pending_updates(patient_id = nil)
394
- Rails.logger.info('Looking for orders that need to be updated...')
395
- orders = {}
396
+ def orders_pending_updates(patient_id = nil)
397
+ Rails.logger.info('Looking for orders that need to be updated...')
398
+ orders = {}
396
399
 
397
- orders_without_specimen(patient_id).each { |order| orders[order.order_id] = order }
398
- orders_without_results(patient_id).each { |order| orders[order.order_id] = order }
399
- orders_without_reason(patient_id).each { |order| orders[order.order_id] = order }
400
+ orders_without_specimen(patient_id).each { |order| orders[order.order_id] = order }
401
+ orders_without_results(patient_id).each { |order| orders[order.order_id] = order }
402
+ orders_without_reason(patient_id).each { |order| orders[order.order_id] = order }
400
403
 
401
- orders.values
402
- end
404
+ orders.values
405
+ end
403
406
 
404
- def orders_without_specimen(patient_id = nil)
405
- Rails.logger.debug('Looking for orders without a specimen')
406
- unknown_specimen = ConceptName.where(name: Lab::Metadata::UNKNOWN_SPECIMEN)
407
- .select(:concept_id)
408
- orders = Lab::LabOrder.where(concept_id: unknown_specimen)
409
- .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
410
- orders = orders.where(patient_id: patient_id) if patient_id
407
+ def orders_without_specimen(patient_id = nil)
408
+ Rails.logger.debug('Looking for orders without a specimen')
409
+ unknown_specimen = ConceptName.where(name: Lab::Metadata::UNKNOWN_SPECIMEN)
410
+ .select(:concept_id)
411
+ orders = Lab::LabOrder.where(concept_id: unknown_specimen)
412
+ .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
413
+ orders = orders.where(patient_id:) if patient_id
411
414
 
412
- orders
413
- end
415
+ orders
416
+ end
414
417
 
415
- def orders_without_results(patient_id = nil)
416
- Rails.logger.debug('Looking for orders without a result')
417
- # Lab::OrdersSearchService.find_orders_without_results(patient_id: patient_id)
418
- # .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id).where("pulled_at IS NULL"))
419
- Lab::OrdersSearchService.find_orders_without_results(patient_id: patient_id)
420
- .where(order_id: Lab::LimsOrderMapping.select(:order_id))
421
- end
418
+ def orders_without_results(patient_id = nil)
419
+ Rails.logger.debug('Looking for orders without a result')
420
+ # Lab::OrdersSearchService.find_orders_without_results(patient_id: patient_id)
421
+ # .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id).where("pulled_at IS NULL"))
422
+ Lab::OrdersSearchService.find_orders_without_results(patient_id:)
423
+ .where(order_id: Lab::LimsOrderMapping.select(:order_id))
424
+ end
422
425
 
423
- def orders_without_reason(patient_id = nil)
424
- Rails.logger.debug('Looking for orders without a reason for test')
425
- orders = Lab::LabOrder.joins(:reason_for_test)
426
- .merge(Observation.where(value_coded: nil, value_text: nil))
427
- .limit(1000)
428
- .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
429
- orders = orders.where(patient_id: patient_id) if patient_id
426
+ def orders_without_reason(patient_id = nil)
427
+ Rails.logger.debug('Looking for orders without a reason for test')
428
+ orders = Lab::LabOrder.joins(:reason_for_test)
429
+ .merge(Observation.where(value_coded: nil, value_text: nil))
430
+ .limit(1000)
431
+ .where.not(accession_number: Lab::LimsOrderMapping.select(:lims_id))
432
+ orders = orders.where(patient_id:) if patient_id
430
433
 
431
- orders
434
+ orders
435
+ end
436
+ end
437
+ end
432
438
  end
433
439
  end