his_emr_api_lab 1.1.22 → 1.1.23
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/MIT-LICENSE +20 -0
- data/README.md +71 -0
- data/Rakefile +32 -0
- data/app/controllers/lab/application_controller.rb +6 -0
- data/app/controllers/lab/labels_controller.rb +17 -0
- data/app/controllers/lab/orders_controller.rb +38 -0
- data/app/controllers/lab/reasons_for_test_controller.rb +9 -0
- data/app/controllers/lab/results_controller.rb +19 -0
- data/app/controllers/lab/specimen_types_controller.rb +15 -0
- data/app/controllers/lab/test_result_indicators_controller.rb +9 -0
- data/app/controllers/lab/test_types_controller.rb +15 -0
- data/app/controllers/lab/tests_controller.rb +26 -0
- data/app/jobs/lab/application_job.rb +4 -0
- data/app/jobs/lab/push_order_job.rb +12 -0
- data/app/jobs/lab/update_patient_orders_job.rb +32 -0
- data/app/jobs/lab/void_order_job.rb +17 -0
- data/app/mailers/lab/application_mailer.rb +6 -0
- data/app/models/lab/application_record.rb +5 -0
- data/app/models/lab/lab_accession_number_counter.rb +13 -0
- data/app/models/lab/lab_encounter.rb +7 -0
- data/app/models/lab/lab_order.rb +58 -0
- data/app/models/lab/lab_result.rb +31 -0
- data/app/models/lab/lab_test.rb +19 -0
- data/app/models/lab/lims_failed_import.rb +4 -0
- data/app/models/lab/lims_order_mapping.rb +10 -0
- data/app/serializers/lab/lab_order_serializer.rb +55 -0
- data/app/serializers/lab/result_serializer.rb +36 -0
- data/app/serializers/lab/test_serializer.rb +29 -0
- data/app/services/lab/accession_number_service.rb +77 -0
- data/app/services/lab/concepts_service.rb +82 -0
- data/app/services/lab/labelling_service/order_label.rb +106 -0
- data/app/services/lab/lims/api/blackhole_api.rb +21 -0
- data/app/services/lab/lims/api/couchdb_api.rb +53 -0
- data/app/services/lab/lims/api/mysql_api.rb +316 -0
- data/app/services/lab/lims/api/rest_api.rb +416 -0
- data/app/services/lab/lims/api/ws_api.rb +121 -0
- data/app/services/lab/lims/api_factory.rb +19 -0
- data/app/services/lab/lims/config.rb +100 -0
- data/app/services/lab/lims/exceptions.rb +11 -0
- data/app/services/lab/lims/migrator.rb +216 -0
- data/app/services/lab/lims/order_dto.rb +105 -0
- data/app/services/lab/lims/order_serializer.rb +244 -0
- data/app/services/lab/lims/pull_worker.rb +289 -0
- data/app/services/lab/lims/push_worker.rb +149 -0
- data/app/services/lab/lims/utils.rb +91 -0
- data/app/services/lab/lims/worker.rb +86 -0
- data/app/services/lab/metadata.rb +24 -0
- data/app/services/lab/orders_search_service.rb +66 -0
- data/app/services/lab/orders_service.rb +212 -0
- data/app/services/lab/results_service.rb +149 -0
- data/app/services/lab/tests_service.rb +93 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20210126092910_create_lab_lab_accession_number_counters.rb +12 -0
- data/db/migrate/20210310115457_create_lab_lims_order_mappings.rb +15 -0
- data/db/migrate/20210323080140_change_lims_id_to_string_in_lims_order_mapping.rb +15 -0
- data/db/migrate/20210326195504_add_order_revision_to_lims_order_mapping.rb +5 -0
- data/db/migrate/20210407071728_create_lab_lims_failed_imports.rb +19 -0
- data/db/migrate/20210610095024_fix_numeric_results_value_type.rb +20 -0
- data/db/migrate/20210807111531_add_default_to_lims_order_mapping.rb +7 -0
- data/lib/auto12epl.rb +201 -0
- data/lib/couch_bum/couch_bum.rb +92 -0
- data/lib/generators/lab/install/USAGE +9 -0
- data/lib/generators/lab/install/install_generator.rb +19 -0
- data/lib/generators/lab/install/templates/rswag-ui-lab.rb +5 -0
- data/lib/generators/lab/install/templates/start_worker.rb +32 -0
- data/lib/generators/lab/install/templates/swagger.yaml +714 -0
- data/lib/his_emr_api_lab.rb +5 -0
- data/lib/lab/engine.rb +15 -0
- data/lib/lab/version.rb +5 -0
- data/lib/logger_multiplexor.rb +38 -0
- data/lib/tasks/lab_tasks.rake +25 -0
- data/lib/tasks/loaders/data/reasons-for-test.csv +7 -0
- data/lib/tasks/loaders/data/test-measures.csv +225 -0
- data/lib/tasks/loaders/data/tests.csv +161 -0
- data/lib/tasks/loaders/loader_mixin.rb +53 -0
- data/lib/tasks/loaders/metadata_loader.rb +26 -0
- data/lib/tasks/loaders/reasons_for_test_loader.rb +23 -0
- data/lib/tasks/loaders/specimens_loader.rb +65 -0
- data/lib/tasks/loaders/test_result_indicators_loader.rb +54 -0
- metadata +81 -2
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
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'cgi'
|
|
4
|
+
require 'couchrest'
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# A CouchRest wrapper for the changes API.
|
|
8
|
+
#
|
|
9
|
+
# See: https://github.com/couchrest/couchrest
|
|
10
|
+
class CouchBum
|
|
11
|
+
cattr_accessor :logger
|
|
12
|
+
|
|
13
|
+
def initialize(database:, protocol: 'http', host: 'localhost', port: 5984, username: nil, password: nil)
|
|
14
|
+
@connection_string = make_connection_string(protocol, username, password, host, port, database)
|
|
15
|
+
|
|
16
|
+
CouchBum.logger ||= Logger.new(STDOUT)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Attaches to the Changes API and streams the updates to passed block.
|
|
21
|
+
#
|
|
22
|
+
# This is a blocking call that only stops when there are no more
|
|
23
|
+
# changes to pull or is explicitly terminated by calling +choke+
|
|
24
|
+
# within the passed block.
|
|
25
|
+
def binge_changes(since: 0, limit: nil, include_docs: nil, &block)
|
|
26
|
+
catch(:choke) do
|
|
27
|
+
logger.debug("Binging #{limit} changes from '#{since}'")
|
|
28
|
+
params = stringify_params(limit: limit, include_docs: include_docs)
|
|
29
|
+
params = "since=#{since}&#{params}" unless since.blank?
|
|
30
|
+
|
|
31
|
+
changes = couch_rest(:get, "_changes?#{params}")
|
|
32
|
+
context = BingeContext.new(changes)
|
|
33
|
+
changes['results'].each do |change|
|
|
34
|
+
context.current_seq = change['seq']
|
|
35
|
+
context.instance_exec(change, &block)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def couch_rest(method, route, *args, **kwargs)
|
|
41
|
+
url = expand_route(route)
|
|
42
|
+
CouchRest.send(method, url, *args, **kwargs)
|
|
43
|
+
rescue CouchRest::Exception => e
|
|
44
|
+
logger.error("Failed to communicate with CouchDB: Status: #{e.http_code} - #{e.http_body}")
|
|
45
|
+
raise e
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# Context under which the callback passed to binge_changes is executed.
|
|
51
|
+
class BingeContext
|
|
52
|
+
attr_accessor :current_seq
|
|
53
|
+
|
|
54
|
+
def initialize(changes)
|
|
55
|
+
@changes = changes
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def choke
|
|
59
|
+
throw :choke
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def last_seq
|
|
63
|
+
@changes['last_seq']
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def pending
|
|
67
|
+
@changes['pending']
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def make_connection_string(protocol, username, password, host, port, database)
|
|
72
|
+
auth = username ? "#{CGI.escape(username)}:#{CGI.escape(password)}@" : ''
|
|
73
|
+
|
|
74
|
+
"#{protocol}://#{auth}#{host}:#{port}/#{database}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def expand_route(route)
|
|
78
|
+
route = route.gsub(%r{^/+}, '')
|
|
79
|
+
|
|
80
|
+
"#{@connection_string}/#{route}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def stringify_params(params)
|
|
84
|
+
params.reduce('') do |str_params, entry|
|
|
85
|
+
name, value = entry
|
|
86
|
+
next params unless value
|
|
87
|
+
|
|
88
|
+
param = "#{name}=#{value}"
|
|
89
|
+
str_params.empty? ? param : "#{str_params}&#{param}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lab
|
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
|
5
|
+
source_root File.expand_path('templates', __dir__)
|
|
6
|
+
|
|
7
|
+
def copy_openapi_docs
|
|
8
|
+
copy_file('swagger.yaml', 'swagger/lab/v1/swagger.yaml')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def copy_rswag_initializer
|
|
12
|
+
copy_file('rswag-ui-lab.rb', 'config/initializers/rswag-ui-lab.rb')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def copy_worker
|
|
16
|
+
copy_file('start_worker.rb', 'bin/lab/start_worker.rb')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'logger_multiplexor'
|
|
4
|
+
|
|
5
|
+
Rails.logger = LoggerMultiplexor.new(Rails.root.join('log/lims-push.log'), $stdout)
|
|
6
|
+
api = Lab::Lims::Api.new
|
|
7
|
+
worker = Lab::Lims::Worker.new(api)
|
|
8
|
+
|
|
9
|
+
def with_lock(lock_file)
|
|
10
|
+
File.open("log/#{lock_file}", File::RDWR | File::CREAT, 0o644) do |file|
|
|
11
|
+
unless file.flock(File::LOCK_EX | File::LOCK_NB)
|
|
12
|
+
Rails.logger.warn("Failed to start new process due to lock: #{lock_file}")
|
|
13
|
+
exit 2
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
file.rewind
|
|
17
|
+
file.puts("Process ##{Process.pid} started at #{Time.now}")
|
|
18
|
+
|
|
19
|
+
yield
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
case ARGV[0]&.downcase
|
|
24
|
+
when 'push'
|
|
25
|
+
with_lock('lims-push.lock') { worker.push_orders }
|
|
26
|
+
when 'pull'
|
|
27
|
+
with_lock('lims-pull.lock') { worker.pull_orders }
|
|
28
|
+
else
|
|
29
|
+
warn 'Error: No or invalid action specified: Valid actions are push and pull'
|
|
30
|
+
warn 'USAGE: rails runner start_worker.rb push'
|
|
31
|
+
exit 1
|
|
32
|
+
end
|