his_emr_api_lab 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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