his_emr_api_lab 0.0.4 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/lab/labels_controller.rb +2 -0
- data/app/services/lab/labelling_service/order_label.rb +20 -2
- data/app/services/lab/lims/migrator.rb +4 -2
- data/app/services/lab/lims/order_dto.rb +8 -2
- data/app/services/lab/lims/worker.rb +6 -4
- data/app/services/lab/orders_search_service.rb +26 -16
- data/lib/generators/lab/install/templates/swagger.yaml +32 -0
- data/lib/lab/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f94bc637e3770937243a3fe93f770909dc00e5de54fdf9e8c53c7cb8a4afcd2
|
|
4
|
+
data.tar.gz: a13aafea421131fd8d95c1175fedbdfc921c72772b6e3ca9196a9a189f69a5c0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 50c2770e1181641d3cdac4d355f209b663a1f6b1969b3b9c3fb5b449a8876ebf3171fd57c0034b48dfd7a1d24c789555048d00a982586e29fe718202af1ee15b
|
|
7
|
+
data.tar.gz: c8730aa9b485c346096238cb7837fc09b2ffe735ef2104990336ca49d6c40902205f7bc9676966210d19ddbd253ee32a67947ce427c3ad8d7ecccb173c40d612
|
|
@@ -27,7 +27,7 @@ module Lab
|
|
|
27
27
|
'',
|
|
28
28
|
drawer,
|
|
29
29
|
'',
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
16
|
-
orders =
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
33
|
-
|
|
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
|
|
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
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
|
+
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-
|
|
11
|
+
date: 2021-04-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: couchrest
|