his_emr_api_lab 0.0.4 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f53ca7acc69718ba31cf2ae278b6fdbdc4996d3ad6a28db0a08d3945d1463998
4
- data.tar.gz: 77b2cfdc430706b9864e9ec71b2f4b64c2ec11a5695b45b81984c86a8fefefd4
3
+ metadata.gz: 3f94bc637e3770937243a3fe93f770909dc00e5de54fdf9e8c53c7cb8a4afcd2
4
+ data.tar.gz: a13aafea421131fd8d95c1175fedbdfc921c72772b6e3ca9196a9a189f69a5c0
5
5
  SHA512:
6
- metadata.gz: 19f53f3c471dd4552f64bf1200a6bbd8051e7bc7bc7e0670b2079bea4af61621575a9c0e7f5cdc06c43ac7b80c2534e6ca704fd06e43b0deed3475ea66690017
7
- data.tar.gz: cbe4e02964f635b60e7e7b0c6b53ac3b406ab9bff55da582371a3de38a8d65901bcca1771a7b3cf0d8be83e31ac8bf0a15e9c752f7131bb631f1011df95fa713
6
+ metadata.gz: 50c2770e1181641d3cdac4d355f209b663a1f6b1969b3b9c3fb5b449a8876ebf3171fd57c0034b48dfd7a1d24c789555048d00a982586e29fe718202af1ee15b
7
+ data.tar.gz: c8730aa9b485c346096238cb7837fc09b2ffe735ef2104990336ca49d6c40902205f7bc9676966210d19ddbd253ee32a67947ce427c3ad8d7ecccb173c40d612
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Lab
4
4
  class LabelsController < ApplicationController
5
+ skip_before_action :authenticate
6
+
5
7
  def print_order_label
6
8
  order_id = params.require(:order_id)
7
9
 
@@ -27,7 +27,7 @@ module Lab
27
27
  '',
28
28
  drawer,
29
29
  '',
30
- specimen,
30
+ tests,
31
31
  reason_for_test,
32
32
  order.accession_number,
33
33
  order.accession_number)
@@ -36,7 +36,7 @@ module Lab
36
36
  def reason_for_test
37
37
  return 'Unknown' unless order.reason_for_test
38
38
 
39
- ConceptName.find_by_concept_id(order.reason_for_test.value_coded)&.name || 'Unknown'
39
+ short_concept_name(order.reason_for_test.value_coded) || 'Unknown'
40
40
  end
41
41
 
42
42
  def patient
@@ -73,6 +73,24 @@ module Lab
73
73
  ConceptName.find_by_concept_id(order.concept_id)&.name || 'Unknown'
74
74
  end
75
75
 
76
+ def tests
77
+ tests = order.tests.map do |test|
78
+ name = short_concept_name(test.value_coded) || 'Unknown'
79
+
80
+ next 'VL' if name.match?(/Viral load/i)
81
+
82
+ name.size > 7 ? name[0..6] : name
83
+ end
84
+
85
+ tests.join(', ')
86
+ end
87
+
88
+ def short_concept_name(concept_id)
89
+ ConceptName.where(concept_id: concept_id)
90
+ .min_by { |concept| concept.name.size }
91
+ &.name
92
+ end
93
+
76
94
  def unknown_concept
77
95
  ConceptName.find_by_name('Unknown')
78
96
  end
@@ -142,9 +142,10 @@ module Lab
142
142
  MIGRATION_REJECTIONS_CSV_PATH = LIMS_LOG_PATH.join('migration-rejections.csv')
143
143
 
144
144
  def self.export_rejections(rejections)
145
- headers = ['Accession number', 'NHID', 'First name', 'Last name', 'Reason']
145
+ headers = ['doc_id', 'Accession number', 'NHID', 'First name', 'Last name', 'Reason']
146
146
  rows = (rejections || []).map do |rejection|
147
147
  [
148
+ rejection.order[:_id],
148
149
  rejection.order[:tracking_number],
149
150
  rejection.order[:patient][:id],
150
151
  rejection.order[:patient][:first_name],
@@ -159,9 +160,10 @@ module Lab
159
160
  MIGRATION_FAILURES_CSV_PATH = LIMS_LOG_PATH.join('migration-failures.csv')
160
161
 
161
162
  def self.export_failures
162
- headers = ['Accession number', 'NHID', 'Reason', 'Difference']
163
+ headers = ['doc_id', 'Accession number', 'NHID', 'Reason', 'Difference']
163
164
  rows = Lab::LimsFailedImport.all.map do |failure|
164
165
  [
166
+ failure.lims_id,
165
167
  failure.tracking_number,
166
168
  failure.patient_nhid,
167
169
  failure.reason,
@@ -30,9 +30,9 @@ module Lab
30
30
 
31
31
  # Translates a LIMS specimen name to an OpenMRS concept_id
32
32
  def specimen_type_id
33
- lims_specimen_name = self['sample_type']
33
+ lims_specimen_name = self['sample_type']&.strip&.downcase
34
34
 
35
- if %w[specimen_not_collected not_assigned].include?(lims_specimen_name)
35
+ if %w[specimen_not_collected not_assigned not_specified].include?(lims_specimen_name)
36
36
  return ConceptName.select(:concept_id).find_by_name!('Unknown').concept_id
37
37
  end
38
38
 
@@ -53,6 +53,8 @@ module Lab
53
53
 
54
54
  # Extract requesting clinician name from LIMS
55
55
  def requesting_clinician
56
+ return 'Unknown' unless self['who_order_test']
57
+
56
58
  # TODO: Extend requesting clinician to an obs tree having extra parameters
57
59
  # like phone number and ID to closely match the lims user.
58
60
  first_name = self['who_order_test']['first_name'] || ''
@@ -67,6 +69,10 @@ module Lab
67
69
  end
68
70
 
69
71
  def start_date
72
+ if self['date_created'].blank?
73
+ raise LimsException, 'Order missing created date'
74
+ end
75
+
70
76
  Utils.parse_date(self['date_created'])
71
77
  end
72
78
 
@@ -28,7 +28,9 @@ module Lab
28
28
  fout.write("Worker ##{Process.pid} started at #{Time.now}")
29
29
  worker = new(Api.new)
30
30
  worker.pull_orders
31
- worker.push_orders
31
+ # TODO: Verify that names being pushed to LIMS are of the correct format (ie matching
32
+ # LIMS naming conventions). Enable pushing when that is done
33
+ # worker.push_orders
32
34
  end
33
35
  end
34
36
 
@@ -282,12 +284,12 @@ module Lab
282
284
  indicator: { concept_id: indicator.concept_id },
283
285
  value_type: value_type,
284
286
  value: value_type == 'numeric' ? value.to_f : value,
285
- value_modifier: value_modifier
287
+ value_modifier: value_modifier.blank? ? '=' : value_modifier
286
288
  )
287
289
  end
288
290
 
289
291
  def parse_lims_result_value(value)
290
- value = value['result_value']
292
+ value = value['result_value']&.strip
291
293
  return nil, nil, nil if value.blank?
292
294
 
293
295
  match = value&.match(/^(>|=|<|<=|>=)(.*)$/)
@@ -297,7 +299,7 @@ module Lab
297
299
  end
298
300
 
299
301
  def guess_result_datatype(result)
300
- return 'numeric' if result.match?(/^[+-]?(\d+(\.\d+)|\.\d+)?$/)
302
+ return 'numeric' if result.strip.match?(/^[+-]?(\d+(\.\d+)|\.\d+)?$/)
301
303
 
302
304
  'text'
303
305
  end
@@ -5,44 +5,54 @@ module Lab
5
5
  module OrdersSearchService
6
6
  class << self
7
7
  def find_orders(filters)
8
- date = filters.delete(:date)
9
- status = filters.delete(:status)
8
+ extra_filters = pop_filters(filters, :date, :end_date, :status)
10
9
 
11
10
  orders = Lab::LabOrder.prefetch_relationships
12
11
  .where(filters)
13
12
  .order(start_date: :desc)
14
13
 
15
- orders = filter_orders_by_date(orders, date) if date
16
- orders = filter_orders_by_status(orders, status) if status
14
+ orders = filter_orders_by_status(orders, pop_filters(extra_filters, :status))
15
+ orders = filter_orders_by_date(orders, extra_filters)
17
16
 
18
17
  orders.map { |order| Lab::LabOrderSerializer.serialize_order(order) }
19
18
  end
20
19
 
21
- def filter_orders_by_date(orders, date)
22
- orders.where('start_date < DATE(?)', date.to_date + 1.day)
23
- end
20
+ def filter_orders_by_date(orders, date: nil, end_date: nil)
21
+ date = date&.to_date
22
+ end_date = end_date&.to_date
24
23
 
25
- def filter_orders_by_status(orders, status)
26
- case status.downcase
27
- when 'ordered' then orders.where(concept_id: unknown_concept_id)
28
- when 'drawn' then orders.where.not(concept_id: unknown_concept_id)
24
+ if date && end_date
25
+ return orders.where('start_date BETWEEN ? AND ?', date, end_date + 1.day)
29
26
  end
30
- end
31
27
 
32
- def unknown_concept_id
33
- ConceptName.find_by_name!('Unknown').concept_id
28
+ if date
29
+ return orders.where('start_date BETWEEN ? AND ?', date, date + 1.day)
30
+ end
31
+
32
+ return orders.where('start_date < ?', end_date + 1.day) if end_date
33
+
34
+ orders
34
35
  end
35
36
 
36
- def filter_orders_by_status(orders, status)
37
- case status.downcase
37
+ def filter_orders_by_status(orders, status: nil)
38
+ case status&.downcase
38
39
  when 'ordered' then orders.where(concept_id: unknown_concept_id)
39
40
  when 'drawn' then orders.where.not(concept_id: unknown_concept_id)
41
+ else orders
40
42
  end
41
43
  end
42
44
 
43
45
  def unknown_concept_id
44
46
  ConceptName.find_by_name!('Unknown').concept_id
45
47
  end
48
+
49
+ def pop_filters(params, *filters)
50
+ filters.each_with_object({}) do |filter, popped_params|
51
+ next unless params.key?(filter)
52
+
53
+ popped_params[filter.to_sym] = params.delete(filter)
54
+ end
55
+ end
46
56
  end
47
57
  end
48
58
  end
@@ -175,6 +175,12 @@ paths:
175
175
  description: 'Filter by sample status: ordered, drawn'
176
176
  schema:
177
177
  type: string
178
+ - name: end_date
179
+ in: query
180
+ required: false
181
+ description: Select all results before this date
182
+ schema:
183
+ type: date
178
184
  responses:
179
185
  '200':
180
186
  description: Success
@@ -396,6 +402,32 @@ paths:
396
402
  responses:
397
403
  '204':
398
404
  description: No Content
405
+ "/api/v1/lab/reasons_for_test":
406
+ get:
407
+ summary: Reasons for test
408
+ description: Retrieve default reasons for test concept set
409
+ tags:
410
+ - Concepts
411
+ security:
412
+ - api_key: []
413
+ responses:
414
+ '200':
415
+ description: Success
416
+ content:
417
+ application/json:
418
+ schema:
419
+ type: array
420
+ items:
421
+ type: object
422
+ properties:
423
+ concept_id:
424
+ type: integer
425
+ name:
426
+ type: string
427
+ example: Routine
428
+ required:
429
+ - concept_id
430
+ - name
399
431
  "/api/v1/lab/tests/{test_id}/results":
400
432
  post:
401
433
  summary: Add results to order
data/lib/lab/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lab
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.9'
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: 0.0.4
4
+ version: 0.0.9
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: 2021-04-20 00:00:00.000000000 Z
11
+ date: 2021-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: couchrest