his_emr_api_lab 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/lab/labels_controller.rb +15 -0
- data/app/controllers/lab/orders_controller.rb +2 -1
- data/app/models/lab/lab_order.rb +5 -1
- data/app/models/lab/lab_result.rb +10 -0
- data/app/models/lab/lab_test.rb +5 -0
- data/app/services/lab/labelling_service/order_label.rb +85 -0
- data/app/services/lab/lims/api.rb +7 -0
- data/app/services/lab/lims/exceptions.rb +11 -0
- data/app/services/lab/lims/migrator.rb +206 -0
- data/app/services/lab/lims/order_dto.rb +41 -122
- data/app/services/lab/lims/order_serializer.rb +28 -2
- data/app/services/lab/lims/utils.rb +45 -1
- data/app/services/lab/lims/worker.rb +227 -38
- data/app/services/lab/metadata.rb +1 -1
- data/app/services/lab/orders_service.rb +9 -8
- data/app/services/lab/results_service.rb +38 -6
- data/config/routes.rb +2 -0
- data/lib/auto12epl.rb +201 -0
- data/lib/couch_bum/couch_bum.rb +11 -1
- data/lib/lab/version.rb +1 -1
- data/lib/tasks/loaders/data/tests.csv +21 -0
- metadata +21 -2
@@ -27,7 +27,7 @@ module Lab
|
|
27
27
|
# },
|
28
28
|
# program_id: { type: :integer, required: false },
|
29
29
|
# patient_id: { type: :integer, required: false }
|
30
|
-
#
|
30
|
+
# specimen: { type: :object, properties: { concept_id: :integer }, required: %i[concept_id] },
|
31
31
|
# test_type_ids: {
|
32
32
|
# type: :array,
|
33
33
|
# items: {
|
@@ -71,11 +71,15 @@ module Lab
|
|
71
71
|
end
|
72
72
|
|
73
73
|
order = Lab::LabOrder.find(order_id)
|
74
|
-
unless order.concept_id == unknown_concept_id
|
74
|
+
unless order.concept_id == unknown_concept_id || params[:force_update]&.to_s&.casecmp?('true')
|
75
75
|
raise ::UnprocessableEntityError
|
76
76
|
end
|
77
77
|
|
78
|
-
order.update!(concept_id: specimen_id
|
78
|
+
order.update!(concept_id: specimen_id,
|
79
|
+
discontinued: true,
|
80
|
+
discontinued_by: User.current.user_id,
|
81
|
+
discontinued_date: params[:date]&.to_date || Date.today,
|
82
|
+
discontinued_reason_non_coded: 'Sample drawn/updated')
|
79
83
|
Lab::LabOrderSerializer.serialize_order(order)
|
80
84
|
end
|
81
85
|
|
@@ -87,10 +91,7 @@ module Lab
|
|
87
91
|
order.reason_for_test&.void(reason)
|
88
92
|
order.target_lab&.void(reason)
|
89
93
|
|
90
|
-
order.tests.each
|
91
|
-
test.result&.void(reason)
|
92
|
-
test.void(reason)
|
93
|
-
end
|
94
|
+
order.tests.each { |test| test.void(reason) }
|
94
95
|
|
95
96
|
order.void(reason)
|
96
97
|
end
|
@@ -119,7 +120,7 @@ module Lab
|
|
119
120
|
program_id: program_id,
|
120
121
|
type: EncounterType.find_by_name!(Lab::Metadata::ENCOUNTER_TYPE_NAME),
|
121
122
|
encounter_datetime: order_params[:date] || Date.today,
|
122
|
-
provider_id: order_params[:provider_id] || User.current
|
123
|
+
provider_id: order_params[:provider_id] || User.current.person.person_id
|
123
124
|
)
|
124
125
|
end
|
125
126
|
|
@@ -3,14 +3,26 @@
|
|
3
3
|
module Lab
|
4
4
|
module ResultsService
|
5
5
|
class << self
|
6
|
+
##
|
7
|
+
# Attach results to a test
|
8
|
+
#
|
9
|
+
# Params:
|
10
|
+
# test_id: The tests id (maps to obs_id of the test's observation in OpenMRS)
|
11
|
+
# params: A hash comprising the following fields
|
12
|
+
# - encounter_id: Encounter to create result under (can be ommitted but provider_id has to specified)
|
13
|
+
# - provider_id: Specify a provider for an encounter the result is going to be created under
|
14
|
+
# - date: Retrospective date when the result was received (can be ommitted, defaults to today)
|
15
|
+
# - measures: An array of measures. A measure is an object of the following structure
|
16
|
+
# - indicator: An object that has a concept_id field (concept_id of the indicator)
|
17
|
+
# - value_type: An enum that's limited to 'numeric', 'boolean', 'text', and 'coded'
|
6
18
|
def create_results(test_id, params)
|
7
19
|
ActiveRecord::Base.transaction do
|
8
20
|
test = Lab::LabTest.find(test_id)
|
9
21
|
encounter = find_encounter(test, encounter_id: params[:encounter_id],
|
10
|
-
date: params[:date],
|
22
|
+
date: params[:date]&.to_date,
|
11
23
|
provider_id: params[:provider_id])
|
12
24
|
|
13
|
-
results_obs = create_results_obs(encounter, test, params[:date])
|
25
|
+
results_obs = create_results_obs(encounter, test, params[:date], params[:comments])
|
14
26
|
params[:measures].map { |measure| add_measure_to_results(results_obs, measure, params[:date]) }
|
15
27
|
|
16
28
|
Lab::ResultSerializer.serialize(results_obs)
|
@@ -32,23 +44,41 @@ module Lab
|
|
32
44
|
end
|
33
45
|
|
34
46
|
# Creates the parent observation for results to which the different measures are attached
|
35
|
-
def create_results_obs(encounter, test, date)
|
47
|
+
def create_results_obs(encounter, test, date, comments = nil)
|
48
|
+
void_existing_results_obs(encounter, test)
|
49
|
+
|
36
50
|
Lab::LabResult.create!(
|
37
51
|
person_id: encounter.patient_id,
|
38
52
|
encounter_id: encounter.encounter_id,
|
39
|
-
concept_id:
|
53
|
+
concept_id: test_result_concept.concept_id,
|
40
54
|
order_id: test.order_id,
|
41
55
|
obs_group_id: test.obs_id,
|
42
|
-
obs_datetime: date&.to_datetime || DateTime.now
|
56
|
+
obs_datetime: date&.to_datetime || DateTime.now,
|
57
|
+
comments: comments
|
43
58
|
)
|
44
59
|
end
|
45
60
|
|
61
|
+
def void_existing_results_obs(encounter, test)
|
62
|
+
result = Lab::LabResult.find_by(person_id: encounter.patient_id,
|
63
|
+
concept_id: test_result_concept.concept_id,
|
64
|
+
obs_group_id: test.obs_id)
|
65
|
+
return unless result
|
66
|
+
|
67
|
+
result.measures.map { |child_obs| child_obs.void("Updated/overwritten by #{User.current.username}") }
|
68
|
+
result.void("Updated/overwritten by #{User.current.username}")
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_result_concept
|
72
|
+
ConceptName.find_by_name!(Lab::Metadata::TEST_RESULT_CONCEPT_NAME)
|
73
|
+
end
|
74
|
+
|
46
75
|
def add_measure_to_results(results_obs, params, date)
|
47
76
|
validate_measure_params(params)
|
48
77
|
|
49
78
|
Observation.create!(
|
50
79
|
person_id: results_obs.person_id,
|
51
80
|
encounter_id: results_obs.encounter_id,
|
81
|
+
order_id: results_obs.order_id,
|
52
82
|
concept_id: params[:indicator][:concept_id],
|
53
83
|
obs_group_id: results_obs.obs_id,
|
54
84
|
obs_datetime: date&.to_datetime || DateTime.now,
|
@@ -57,7 +87,9 @@ module Lab
|
|
57
87
|
end
|
58
88
|
|
59
89
|
def validate_measure_params(params)
|
60
|
-
|
90
|
+
if params[:value].blank?
|
91
|
+
raise InvalidParameterError, 'measures.value is required'
|
92
|
+
end
|
61
93
|
|
62
94
|
if params[:indicator]&.[](:concept_id).blank?
|
63
95
|
raise InvalidParameterError, 'measures.indicator.concept_id is required'
|
data/config/routes.rb
CHANGED
@@ -6,6 +6,8 @@ Lab::Engine.routes.draw do
|
|
6
6
|
resources :results, only: %i[index create destroy]
|
7
7
|
end
|
8
8
|
|
9
|
+
get 'api/v1/lab/labels/order', to: 'labels#print_order_label'
|
10
|
+
|
9
11
|
# Metadata
|
10
12
|
# TODO: Move the following to namespace /concepts
|
11
13
|
resources :specimen_types, only: %i[index], path: 'api/v1/lab/specimen_types'
|
data/lib/auto12epl.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# Jeremy Espino MD MS
|
3
|
+
# 28-JAN-2016
|
4
|
+
|
5
|
+
|
6
|
+
class Float
|
7
|
+
# function to round down a float to an integer value
|
8
|
+
def round_down n=0
|
9
|
+
n < 1 ? self.to_i.to_f : (self - 0.5 / 10**n).round(n)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Generates EPL code that conforms to the Auto12-A standard for specimen labeling
|
14
|
+
class Auto12Epl
|
15
|
+
|
16
|
+
attr_accessor :element_font
|
17
|
+
attr_accessor :barcode_human_font
|
18
|
+
|
19
|
+
DPI = 203
|
20
|
+
LABEL_WIDTH_IN = 2.0
|
21
|
+
LABEL_HEIGHT_IN = 0.5
|
22
|
+
|
23
|
+
# font constants
|
24
|
+
FONT_X_DOTS = [8, 10, 12, 14, 32]
|
25
|
+
FONT_Y_DOTS = [12, 16, 20, 24, 24]
|
26
|
+
FONT_PAD_DOTS = 2
|
27
|
+
|
28
|
+
# element heights
|
29
|
+
HEIGHT_MARGIN = 0.031
|
30
|
+
HEIGHT_ELEMENT = 0.1
|
31
|
+
HEIGHT_ELEMENT_SPACE = 0.01
|
32
|
+
HEIGHT_PID = 0.1
|
33
|
+
HEIGHT_BARCODE = 0.200
|
34
|
+
HEIGHT_BARCODE_HUMAN = 0.050
|
35
|
+
|
36
|
+
# element widths
|
37
|
+
WIDTH_ELEMENT = 1.94
|
38
|
+
WIDTH_BARCODE = 1.395
|
39
|
+
WIDTH_BARCODE_HUMAN = 1.688
|
40
|
+
|
41
|
+
# margins
|
42
|
+
L_MARGIN = 0.031
|
43
|
+
L_MARGIN_BARCODE = 0.25
|
44
|
+
|
45
|
+
# stat locations
|
46
|
+
L_MARGIN_BARCODE_W_STAT = 0.200
|
47
|
+
L_MARGIN_W_STAT = 0.150
|
48
|
+
STAT_WIDTH_ELEMENT = 1.78
|
49
|
+
STAT_WIDTH_BARCODE = 1.150
|
50
|
+
STAT_WIDTH_BARCODE_HUMAN = 1.400
|
51
|
+
|
52
|
+
# constants for generated EPL code
|
53
|
+
BARCODE_TYPE = '1A'
|
54
|
+
BARCODE_NARROW_WIDTH = '2'
|
55
|
+
BARCODE_WIDE_WIDTH = '2'
|
56
|
+
BARCODE_ROTATION = '0'
|
57
|
+
BARCODE_IS_HUMAN_READABLE = 'N'
|
58
|
+
ASCII_HORZ_MULT = 1
|
59
|
+
ASCII_VERT_MULT = 1
|
60
|
+
|
61
|
+
|
62
|
+
def initialize(element_font = 1, barcode_human_font = 1)
|
63
|
+
@element_font = element_font
|
64
|
+
@barcode_human_font = barcode_human_font
|
65
|
+
end
|
66
|
+
|
67
|
+
# Calculate the number of characters that will fit in a given length
|
68
|
+
def max_characters(font, length)
|
69
|
+
|
70
|
+
dots_per_char = FONT_X_DOTS.at(font-1) + FONT_PAD_DOTS
|
71
|
+
|
72
|
+
num_char = ( (length * DPI) / dots_per_char).round_down
|
73
|
+
|
74
|
+
num_char.to_int
|
75
|
+
end
|
76
|
+
|
77
|
+
# Use basic truncation rule to truncate the name element i.e., if > maxCharacters cutoff and trail with +
|
78
|
+
def truncate_name(last_name, first_name, middle_initial, is_stat)
|
79
|
+
if is_stat
|
80
|
+
name_max_characters = max_characters(@element_font, STAT_WIDTH_ELEMENT)
|
81
|
+
else
|
82
|
+
name_max_characters = max_characters(@element_font, WIDTH_ELEMENT)
|
83
|
+
end
|
84
|
+
|
85
|
+
if concatName(last_name, first_name, middle_initial).length > name_max_characters
|
86
|
+
# truncate last?
|
87
|
+
if last_name.length > 12
|
88
|
+
last_name = last_name[0..11] + '+'
|
89
|
+
end
|
90
|
+
|
91
|
+
# truncate first?
|
92
|
+
if concatName(last_name, first_name, middle_initial).length > name_max_characters && first_name.length > 7
|
93
|
+
first_name = first_name[0..7] + '+'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
concatName(last_name, first_name, middle_initial)
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
def concatName(last_name, first_name, middle_initial)
|
102
|
+
last_name + ', ' + first_name + (middle_initial == nil ? '' : ' ' + middle_initial)
|
103
|
+
end
|
104
|
+
|
105
|
+
# The main function to generate the EPL
|
106
|
+
def generate_epl(last_name, first_name, middle_initial, pid, dob, age, gender, col_date_time, col_name, tests, stat, acc_num, schema_track)
|
107
|
+
|
108
|
+
# format text and set margin
|
109
|
+
if stat == nil
|
110
|
+
name_text = truncate_name(last_name, first_name, middle_initial, false)
|
111
|
+
pid_dob_age_gender_text = full_justify(pid, dob + ' ' + age + ' ' + gender, @element_font, WIDTH_ELEMENT)
|
112
|
+
l_margin = L_MARGIN
|
113
|
+
l_margin_barcode = L_MARGIN_BARCODE
|
114
|
+
else
|
115
|
+
name_text = truncate_name(last_name, first_name, middle_initial, true)
|
116
|
+
pid_dob_age_gender_text = full_justify(pid, dob + ' ' + age + ' ' + gender, @element_font, STAT_WIDTH_ELEMENT)
|
117
|
+
stat_element_text = pad_stat_w_space(stat)
|
118
|
+
l_margin = L_MARGIN_W_STAT
|
119
|
+
l_margin_barcode = L_MARGIN_BARCODE_W_STAT
|
120
|
+
end
|
121
|
+
barcode_human_text = "#{acc_num} * #{schema_track.gsub(/\-/i, '')}"
|
122
|
+
collector_element_text = "Col: #{col_date_time} #{col_name}"
|
123
|
+
tests_element_text = tests
|
124
|
+
|
125
|
+
# generate EPL statements
|
126
|
+
name_element = generate_ascii_element(to_dots(l_margin), to_dots(HEIGHT_MARGIN), 0, @element_font, false, name_text)
|
127
|
+
pid_dob_age_gender_element = generate_ascii_element(to_dots(l_margin), to_dots(HEIGHT_MARGIN + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE), 0, @element_font, false, pid_dob_age_gender_text)
|
128
|
+
barcode_human_element = generate_ascii_element(to_dots(l_margin_barcode), to_dots(HEIGHT_MARGIN + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE + HEIGHT_BARCODE), 0, @barcode_human_font, false, barcode_human_text)
|
129
|
+
collector_element = generate_ascii_element(to_dots(l_margin), to_dots(HEIGHT_MARGIN + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE + HEIGHT_BARCODE + HEIGHT_BARCODE_HUMAN + HEIGHT_ELEMENT_SPACE), 0, @element_font, false, collector_element_text)
|
130
|
+
tests_element = generate_ascii_element(to_dots(l_margin), to_dots(HEIGHT_MARGIN + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE + HEIGHT_BARCODE + HEIGHT_BARCODE_HUMAN + HEIGHT_ELEMENT_SPACE + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE), 0, @element_font, false, tests_element_text)
|
131
|
+
barcode_element = generate_barcode_element(to_dots(l_margin_barcode), to_dots(HEIGHT_MARGIN + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE + HEIGHT_ELEMENT + HEIGHT_ELEMENT_SPACE), to_dots(HEIGHT_BARCODE)-4, schema_track)
|
132
|
+
stat_element = generate_ascii_element(to_dots(L_MARGIN)+FONT_Y_DOTS.at(@element_font - 1)+FONT_PAD_DOTS, to_dots(HEIGHT_MARGIN), 1, @element_font, true, stat_element_text)
|
133
|
+
|
134
|
+
# combine EPL statements
|
135
|
+
if stat == nil
|
136
|
+
"\nN\nR216,0\nZT\nS1\n#{name_element}\n#{pid_dob_age_gender_element}\n#{barcode_element}\n#{barcode_human_element}\n#{collector_element}\n#{tests_element}\nP3\n"
|
137
|
+
else
|
138
|
+
"\nN\nR216,0\nZT\nS1\n#{name_element}\n#{pid_dob_age_gender_element}\n#{barcode_element}\n#{barcode_human_element}\n#{collector_element}\n#{tests_element}\n#{stat_element}\nP3\n"
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
# Add spaces before and after the stat text so that black bars appear across the left edge of label
|
144
|
+
def pad_stat_w_space(stat)
|
145
|
+
num_char = max_characters(@element_font, LABEL_HEIGHT_IN)
|
146
|
+
spaces_needed = (num_char - stat.length) / 1
|
147
|
+
space = ''
|
148
|
+
spaces_needed.times do
|
149
|
+
space = space + ' '
|
150
|
+
end
|
151
|
+
space + stat + space
|
152
|
+
end
|
153
|
+
|
154
|
+
# Add spaces between the NPID and the dob/age/gender so that line is fully justified
|
155
|
+
def full_justify(pid, dag, font, length)
|
156
|
+
max_char = max_characters(font, length)
|
157
|
+
spaces_needed = max_char - pid.length - dag.length
|
158
|
+
space = ''
|
159
|
+
spaces_needed.times do
|
160
|
+
space = space + ' '
|
161
|
+
end
|
162
|
+
pid + space + dag
|
163
|
+
end
|
164
|
+
|
165
|
+
# convert inches to number of dots using DPI
|
166
|
+
def to_dots(inches)
|
167
|
+
(inches * DPI).round
|
168
|
+
end
|
169
|
+
|
170
|
+
# generate ascii EPL
|
171
|
+
def generate_ascii_element(x, y, rotation, font, is_reverse, text)
|
172
|
+
"A#{x.to_s},#{y.to_s},#{rotation.to_s},#{font.to_s},#{ASCII_HORZ_MULT},#{ASCII_VERT_MULT},#{is_reverse ? 'R' : 'N'},\"#{text}\""
|
173
|
+
end
|
174
|
+
|
175
|
+
# generate barcode EPL
|
176
|
+
def generate_barcode_element(x, y, height, schema_track)
|
177
|
+
schema_track = schema_track.gsub("-", "").strip
|
178
|
+
"B#{x.to_s},#{y.to_s},#{BARCODE_ROTATION},#{BARCODE_TYPE},#{BARCODE_NARROW_WIDTH},#{BARCODE_WIDE_WIDTH},#{height.to_s},#{BARCODE_IS_HUMAN_READABLE},\"#{schema_track}\""
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
if __FILE__ == $0
|
184
|
+
|
185
|
+
auto = Auto12Epl.new
|
186
|
+
|
187
|
+
puts auto.generate_epl("Banda", "Mary", "U", "Q23-HGF", "12-SEP-1997", "19y", "F", "01-JAN-2016 14:21", "byGD", "CHEM7,Ca,Mg", nil, "KCH-16-00001234", "1600001234")
|
188
|
+
puts "\n"
|
189
|
+
puts auto.generate_epl("Banda", "Mary", "U", "Q23-HGF", "12-SEP-1997", "19y", "F", "01-JAN-2016 14:21", "byGD", "CHEM7,Ca,Mg", "STAT CHEM", "KCH-16-00001234", "1600001234")
|
190
|
+
puts "\n"
|
191
|
+
puts auto.generate_epl("Bandajustrightlas", "Mary", "U", "Q23-HGF", "12-SEP-1997", "19y", "F", "01-JAN-2016 14:21", "byGD", "CHEM7,Ca,Mg", "STAT CHEM", "KCH-16-00001234", "1600001234")
|
192
|
+
puts "\n"
|
193
|
+
puts auto.generate_epl("Bandasuperlonglastnamethatwonfit", "Marysuperlonglastnamethatwonfit", "U", "Q23-HGF", "12-SEP-1997", "19y", "F", "01-JAN-2016 14:21", "byGD", "CHEM7,Ca,Mg", "STAT CHEM", "KCH-16-00001234", "1600001234")
|
194
|
+
puts "\n"
|
195
|
+
puts auto.generate_epl("Bandasuperlonglastnamethatwonfit", "Mary", "U", "Q23-HGF", "12-SEP-1997", "19y", "F", "01-JAN-2016 14:21", "byGD", "CHEM7,Ca,Mg", "STAT CHEM", "KCH-16-00001234", "1600001234")
|
196
|
+
puts "\n"
|
197
|
+
puts auto.generate_epl("Banda", "Marysuperlonglastnamethatwonfit", "U", "Q23-HGF", "12-SEP-1997", "19y", "F", "01-JAN-2016 14:21", "byGD", "CHEM7,Ca,Mg", "STAT CHEM", "KCH-16-00001234", "1600001234")
|
198
|
+
|
199
|
+
|
200
|
+
|
201
|
+
end
|
data/lib/couch_bum/couch_bum.rb
CHANGED
@@ -8,8 +8,12 @@ require 'couchrest'
|
|
8
8
|
#
|
9
9
|
# See: https://github.com/couchrest/couchrest
|
10
10
|
class CouchBum
|
11
|
+
cattr_accessor :logger
|
12
|
+
|
11
13
|
def initialize(database:, protocol: 'http', host: 'localhost', port: 5984, username: nil, password: nil)
|
12
14
|
@connection_string = make_connection_string(protocol, username, password, host, port, database)
|
15
|
+
|
16
|
+
CouchBum.logger ||= Logger.new(STDOUT)
|
13
17
|
end
|
14
18
|
|
15
19
|
##
|
@@ -29,7 +33,13 @@ class CouchBum
|
|
29
33
|
end
|
30
34
|
|
31
35
|
def couch_rest(method, route, *args, **kwargs)
|
32
|
-
|
36
|
+
url = expand_route(route)
|
37
|
+
|
38
|
+
logger.debug("CouchBum: Executing #{method} #{url}")
|
39
|
+
CouchRest.send(method, url, *args, **kwargs)
|
40
|
+
rescue CouchRest::Exception => e
|
41
|
+
logger.error("Failed to communicate with CouchDB: Status: #{e.http_code} - #{e.http_body}")
|
42
|
+
raise e
|
33
43
|
end
|
34
44
|
|
35
45
|
private
|
data/lib/lab/version.rb
CHANGED
@@ -35,6 +35,7 @@ Blood,"Liver Function Tests","2019-11-19 14:05:31"
|
|
35
35
|
Blood,"Renal Function Test","2019-11-19 14:05:31"
|
36
36
|
Blood,Lipogram,"2019-11-19 14:05:31"
|
37
37
|
Blood,FBC,"2019-11-19 14:05:31"
|
38
|
+
Blood,"FBS","2021-04-11 00:00:00"
|
38
39
|
Blood,Electrolytes,"2019-11-19 14:05:31"
|
39
40
|
Blood,Enzymes,"2019-11-19 14:05:31"
|
40
41
|
Blood,Glucose,"2019-11-19 14:05:31"
|
@@ -42,6 +43,22 @@ Blood,"Prothrombin Time","2019-11-19 14:05:31"
|
|
42
43
|
Blood,APTT,"2019-11-19 14:05:31"
|
43
44
|
Blood,INR,"2019-11-19 14:05:31"
|
44
45
|
Blood,ESR,"2019-11-19 14:05:31"
|
46
|
+
Blood,"D/Coombs","2021-04-11 00:00:00"
|
47
|
+
Blood,"creat","2021-04-11 00:00:00"
|
48
|
+
Blood,"Widal","2021-04-11 00:00:00"
|
49
|
+
Blood,"AAFB (3rd)","2021-04-11 00:00:00"
|
50
|
+
Blood,"Urine micro","2021-04-11 00:00:00"
|
51
|
+
Blood,"AAFB (1st)","2021-04-11 00:00:00"
|
52
|
+
Blood,ASOT,"2021-04-11 00:00:00"
|
53
|
+
Blood,"Blood C/S","2021-04-11 00:00:00"
|
54
|
+
Blood,"Cryptococcal Ag","2021-04-11 00:00:00"
|
55
|
+
Blood,"I/Ink","2021-04-11 00:00:00"
|
56
|
+
Blood,"Prot& Sugar","2021-04-11 00:00:00"
|
57
|
+
Blood,C_S,"2021-04-11 00:00:00"
|
58
|
+
Blood,hep,"2021-04-11 00:00:00"
|
59
|
+
Blood,"Cryptococcal Antigen","2021-04-11 00:00:00"
|
60
|
+
Blood,Resistance,"2021-04-11 00:00:00"
|
61
|
+
Blood,Sickle,"2021-04-11 00:00:00"
|
45
62
|
Blood,"Sickling Test","2019-11-19 14:05:31"
|
46
63
|
Blood,"Manual Differential & Cell Morphology","2019-11-19 14:05:31"
|
47
64
|
Blood,"Pancreatic Function Test","2019-11-19 14:05:31"
|
@@ -69,8 +86,12 @@ Blood,HbA1c,"2019-11-19 14:05:31"
|
|
69
86
|
Blood,Microalbumin,"2019-11-19 14:05:31"
|
70
87
|
Blood,Microprotein,"2019-11-19 14:05:31"
|
71
88
|
Blood,"Von Willebrand Factor","2019-11-19 14:05:31"
|
89
|
+
Blood,"HIV_viral_load","2021-04-13 00:00:00"
|
90
|
+
Blood,"Viral laod","2021-04-11 00:00:00"
|
72
91
|
Blood,"Viral Load","2019-11-19 14:05:31"
|
73
92
|
Blood,"Urine Lam","2019-11-19 14:05:31"
|
93
|
+
Blood,"Protein and Sugar","2021-04-16"
|
94
|
+
Blood,"White cell count","2021-04-16"
|
74
95
|
Blood,Urea,"2019-11-19 14:05:31"
|
75
96
|
Blood,Creatinine,"2019-11-19 14:05:31"
|
76
97
|
Blood,ALT,"2019-11-19 14:05:31"
|
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.3
|
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-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: couchrest
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: parallel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.20.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.20.1
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rails
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,6 +225,7 @@ files:
|
|
211
225
|
- README.md
|
212
226
|
- Rakefile
|
213
227
|
- app/controllers/lab/application_controller.rb
|
228
|
+
- app/controllers/lab/labels_controller.rb
|
214
229
|
- app/controllers/lab/orders_controller.rb
|
215
230
|
- app/controllers/lab/reasons_for_test_controller.rb
|
216
231
|
- app/controllers/lab/results_controller.rb
|
@@ -233,8 +248,11 @@ files:
|
|
233
248
|
- app/serializers/lab/test_serializer.rb
|
234
249
|
- app/services/lab/accession_number_service.rb
|
235
250
|
- app/services/lab/concepts_service.rb
|
251
|
+
- app/services/lab/labelling_service/order_label.rb
|
236
252
|
- app/services/lab/lims/api.rb
|
237
253
|
- app/services/lab/lims/config.rb
|
254
|
+
- app/services/lab/lims/exceptions.rb
|
255
|
+
- app/services/lab/lims/migrator.rb
|
238
256
|
- app/services/lab/lims/order_dto.rb
|
239
257
|
- app/services/lab/lims/order_serializer.rb
|
240
258
|
- app/services/lab/lims/utils.rb
|
@@ -250,6 +268,7 @@ files:
|
|
250
268
|
- db/migrate/20210323080140_change_lims_id_to_string_in_lims_order_mapping.rb
|
251
269
|
- db/migrate/20210326195504_add_order_revision_to_lims_order_mapping.rb
|
252
270
|
- db/migrate/20210407071728_create_lab_lims_failed_imports.rb
|
271
|
+
- lib/auto12epl.rb
|
253
272
|
- lib/couch_bum/couch_bum.rb
|
254
273
|
- lib/generators/lab/install/USAGE
|
255
274
|
- lib/generators/lab/install/install_generator.rb
|