his_emr_api_lab 1.1.19 → 1.1.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- metadata +8 -86
- data/MIT-LICENSE +0 -20
- data/README.md +0 -71
- data/Rakefile +0 -32
- data/app/controllers/lab/application_controller.rb +0 -6
- data/app/controllers/lab/labels_controller.rb +0 -17
- data/app/controllers/lab/orders_controller.rb +0 -38
- data/app/controllers/lab/reasons_for_test_controller.rb +0 -9
- data/app/controllers/lab/results_controller.rb +0 -19
- data/app/controllers/lab/specimen_types_controller.rb +0 -15
- data/app/controllers/lab/test_result_indicators_controller.rb +0 -9
- data/app/controllers/lab/test_types_controller.rb +0 -15
- data/app/controllers/lab/tests_controller.rb +0 -26
- data/app/jobs/lab/application_job.rb +0 -4
- data/app/jobs/lab/push_order_job.rb +0 -12
- data/app/jobs/lab/update_patient_orders_job.rb +0 -32
- data/app/jobs/lab/void_order_job.rb +0 -17
- data/app/mailers/lab/application_mailer.rb +0 -6
- data/app/models/lab/application_record.rb +0 -5
- data/app/models/lab/lab_accession_number_counter.rb +0 -13
- data/app/models/lab/lab_encounter.rb +0 -7
- data/app/models/lab/lab_order.rb +0 -54
- data/app/models/lab/lab_result.rb +0 -31
- data/app/models/lab/lab_test.rb +0 -19
- data/app/models/lab/lims_failed_import.rb +0 -4
- data/app/models/lab/lims_order_mapping.rb +0 -10
- data/app/serializers/lab/lab_order_serializer.rb +0 -55
- data/app/serializers/lab/result_serializer.rb +0 -36
- data/app/serializers/lab/test_serializer.rb +0 -29
- data/app/services/lab/accession_number_service.rb +0 -77
- data/app/services/lab/concepts_service.rb +0 -82
- data/app/services/lab/labelling_service/order_label.rb +0 -106
- data/app/services/lab/lims/api/blackhole_api.rb +0 -21
- data/app/services/lab/lims/api/couchdb_api.rb +0 -53
- data/app/services/lab/lims/api/mysql_api.rb +0 -316
- data/app/services/lab/lims/api/rest_api.rb +0 -413
- data/app/services/lab/lims/api/ws_api.rb +0 -121
- data/app/services/lab/lims/api_factory.rb +0 -19
- data/app/services/lab/lims/config.rb +0 -100
- data/app/services/lab/lims/exceptions.rb +0 -11
- data/app/services/lab/lims/migrator.rb +0 -216
- data/app/services/lab/lims/order_dto.rb +0 -105
- data/app/services/lab/lims/order_serializer.rb +0 -216
- data/app/services/lab/lims/pull_worker.rb +0 -289
- data/app/services/lab/lims/push_worker.rb +0 -144
- data/app/services/lab/lims/utils.rb +0 -91
- data/app/services/lab/lims/worker.rb +0 -86
- data/app/services/lab/metadata.rb +0 -24
- data/app/services/lab/orders_search_service.rb +0 -66
- data/app/services/lab/orders_service.rb +0 -212
- data/app/services/lab/results_service.rb +0 -122
- data/app/services/lab/tests_service.rb +0 -93
- data/config/routes.rb +0 -17
- data/db/migrate/20210126092910_create_lab_lab_accession_number_counters.rb +0 -12
- data/db/migrate/20210310115457_create_lab_lims_order_mappings.rb +0 -15
- data/db/migrate/20210323080140_change_lims_id_to_string_in_lims_order_mapping.rb +0 -15
- data/db/migrate/20210326195504_add_order_revision_to_lims_order_mapping.rb +0 -5
- data/db/migrate/20210407071728_create_lab_lims_failed_imports.rb +0 -19
- data/db/migrate/20210610095024_fix_numeric_results_value_type.rb +0 -20
- data/db/migrate/20210807111531_add_default_to_lims_order_mapping.rb +0 -7
- data/lib/auto12epl.rb +0 -201
- data/lib/couch_bum/couch_bum.rb +0 -92
- data/lib/generators/lab/install/USAGE +0 -9
- data/lib/generators/lab/install/install_generator.rb +0 -19
- data/lib/generators/lab/install/templates/rswag-ui-lab.rb +0 -5
- data/lib/generators/lab/install/templates/start_worker.rb +0 -32
- data/lib/generators/lab/install/templates/swagger.yaml +0 -714
- data/lib/his_emr_api_lab.rb +0 -5
- data/lib/lab/engine.rb +0 -15
- data/lib/lab/version.rb +0 -5
- data/lib/logger_multiplexor.rb +0 -38
- data/lib/tasks/lab_tasks.rake +0 -25
- data/lib/tasks/loaders/data/reasons-for-test.csv +0 -7
- data/lib/tasks/loaders/data/test-measures.csv +0 -225
- data/lib/tasks/loaders/data/tests.csv +0 -161
- data/lib/tasks/loaders/loader_mixin.rb +0 -53
- data/lib/tasks/loaders/metadata_loader.rb +0 -26
- data/lib/tasks/loaders/reasons_for_test_loader.rb +0 -23
- data/lib/tasks/loaders/specimens_loader.rb +0 -65
- data/lib/tasks/loaders/test_result_indicators_loader.rb +0 -54
@@ -1,316 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lab
|
4
|
-
module Lims
|
5
|
-
module Api
|
6
|
-
class MysqlApi
|
7
|
-
def self.start
|
8
|
-
instance = MysqlApi.new
|
9
|
-
orders_processed = 0
|
10
|
-
instance.consume_orders(from: 0, limit: 1000) do |order|
|
11
|
-
puts "Order ##{orders_processed}"
|
12
|
-
pp order
|
13
|
-
orders_processed += 1
|
14
|
-
puts
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize(processes: 1, on_merge_processes: nil)
|
19
|
-
@processes = processes
|
20
|
-
@on_merge_processes = on_merge_processes
|
21
|
-
@mysql_connection_pool = {}
|
22
|
-
end
|
23
|
-
|
24
|
-
def multiprocessed?
|
25
|
-
@processes > 1
|
26
|
-
end
|
27
|
-
|
28
|
-
def consume_orders(from: nil, limit: 1000)
|
29
|
-
loop do
|
30
|
-
specimens_to_process = specimens(from, limit)
|
31
|
-
break if specimens_to_process.size.zero?
|
32
|
-
|
33
|
-
processes = multiprocessed? ? @processes : 0
|
34
|
-
on_merge_processes = ->(_item, index, _result) { @on_merge_processes&.call(from + index) }
|
35
|
-
|
36
|
-
Parallel.map(specimens_to_process, in_processes: processes, finish: on_merge_processes) do |specimen|
|
37
|
-
User.current ||= Utils.lab_user
|
38
|
-
|
39
|
-
tests = specimen_tests(specimen['specimen_id'])
|
40
|
-
results = tests.each_with_object({}) do |test, object|
|
41
|
-
object[test['test_name']] = test_results(test['test_id'])
|
42
|
-
end
|
43
|
-
|
44
|
-
dto = make_order_dto(
|
45
|
-
specimen: specimen,
|
46
|
-
patient: specimen_patient(specimen['specimen_id']),
|
47
|
-
test_results: results,
|
48
|
-
specimen_status_trail: specimen_status_trail(specimen['specimen_id']),
|
49
|
-
test_status_trail: tests.each_with_object({}) do |test, trails|
|
50
|
-
trails[test['test_name']] = test_status_trail(test['test_id'])
|
51
|
-
end
|
52
|
-
)
|
53
|
-
|
54
|
-
yield dto, OpenStruct.new(last_seq: from)
|
55
|
-
end
|
56
|
-
|
57
|
-
from += limit
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def parallel_map(items, on_merge: nil, &block); end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def specimens(start_id, limit)
|
66
|
-
query = <<~SQL
|
67
|
-
SELECT specimen.id AS specimen_id,
|
68
|
-
specimen.couch_id AS doc_id,
|
69
|
-
specimen_types.name AS specimen_name,
|
70
|
-
specimen.tracking_number,
|
71
|
-
specimen.priority,
|
72
|
-
specimen.target_lab,
|
73
|
-
specimen.sending_facility,
|
74
|
-
specimen.drawn_by_id,
|
75
|
-
specimen.drawn_by_name,
|
76
|
-
specimen.drawn_by_phone_number,
|
77
|
-
specimen.ward_id,
|
78
|
-
specimen_statuses.name AS specimen_status,
|
79
|
-
specimen.district,
|
80
|
-
specimen.date_created AS order_date
|
81
|
-
FROM specimen
|
82
|
-
INNER JOIN specimen_types ON specimen_types.id = specimen.specimen_type_id
|
83
|
-
INNER JOIN specimen_statuses ON specimen_statuses.id = specimen.specimen_status_id
|
84
|
-
SQL
|
85
|
-
|
86
|
-
query = "#{query} WHERE specimen.id > #{sql_escape(start_id)}" if start_id
|
87
|
-
query = "#{query} LIMIT #{limit.to_i}"
|
88
|
-
|
89
|
-
Rails.logger.debug(query)
|
90
|
-
query(query)
|
91
|
-
end
|
92
|
-
|
93
|
-
##
|
94
|
-
# Pull patient associated with given specimen
|
95
|
-
def specimen_patient(specimen_id)
|
96
|
-
results = query <<~SQL
|
97
|
-
SELECT patients.patient_number AS nhid,
|
98
|
-
patients.name,
|
99
|
-
patients.gender,
|
100
|
-
DATE(patients.dob) AS birthdate
|
101
|
-
FROM patients
|
102
|
-
INNER JOIN tests
|
103
|
-
ON tests.patient_id = patients.id
|
104
|
-
AND tests.specimen_id = #{sql_escape(specimen_id)}
|
105
|
-
LIMIT 1
|
106
|
-
SQL
|
107
|
-
|
108
|
-
results.first
|
109
|
-
end
|
110
|
-
|
111
|
-
def specimen_tests(specimen_id)
|
112
|
-
query <<~SQL
|
113
|
-
SELECT tests.id AS test_id,
|
114
|
-
test_types.name AS test_name,
|
115
|
-
tests.created_by AS drawn_by_name
|
116
|
-
FROM tests
|
117
|
-
INNER JOIN test_types ON test_types.id = tests.test_type_id
|
118
|
-
WHERE tests.specimen_id = #{sql_escape(specimen_id)}
|
119
|
-
SQL
|
120
|
-
end
|
121
|
-
|
122
|
-
def specimen_status_trail(specimen_id)
|
123
|
-
query <<~SQL
|
124
|
-
SELECT specimen_statuses.name AS status_name,
|
125
|
-
specimen_status_trails.who_updated_id AS updated_by_id,
|
126
|
-
specimen_status_trails.who_updated_name AS updated_by_name,
|
127
|
-
specimen_status_trails.who_updated_phone_number AS updated_by_phone_number,
|
128
|
-
specimen_status_trails.time_updated AS date
|
129
|
-
FROM specimen_status_trails
|
130
|
-
INNER JOIN specimen_statuses
|
131
|
-
ON specimen_statuses.id = specimen_status_trails.specimen_status_id
|
132
|
-
WHERE specimen_status_trails.specimen_id = #{sql_escape(specimen_id)}
|
133
|
-
SQL
|
134
|
-
end
|
135
|
-
|
136
|
-
def test_status_trail(test_id)
|
137
|
-
query <<~SQL
|
138
|
-
SELECT test_statuses.name AS status_name,
|
139
|
-
test_status_trails.who_updated_id AS updated_by_id,
|
140
|
-
test_status_trails.who_updated_name AS updated_by_name,
|
141
|
-
test_status_trails.who_updated_phone_number AS updated_by_phone_number,
|
142
|
-
COALESCE(test_status_trails.time_updated, test_status_trails.created_at) AS date
|
143
|
-
FROM test_status_trails
|
144
|
-
INNER JOIN test_statuses
|
145
|
-
ON test_statuses.id = test_status_trails.test_status_id
|
146
|
-
WHERE test_status_trails.test_id = #{sql_escape(test_id)}
|
147
|
-
SQL
|
148
|
-
end
|
149
|
-
|
150
|
-
def test_results(test_id)
|
151
|
-
query <<~SQL
|
152
|
-
SELECT measures.name AS measure_name,
|
153
|
-
test_results.result,
|
154
|
-
test_results.time_entered AS date
|
155
|
-
FROM test_results
|
156
|
-
INNER JOIN measures ON measures.id = test_results.measure_id
|
157
|
-
WHERE test_results.test_id = #{sql_escape(test_id)}
|
158
|
-
SQL
|
159
|
-
end
|
160
|
-
|
161
|
-
def make_order_dto(specimen:, patient:, test_status_trail:, specimen_status_trail:, test_results:)
|
162
|
-
drawn_by_first_name, drawn_by_last_name = specimen['drawn_by_name']&.split
|
163
|
-
patient_first_name, patient_last_name = patient['name'].split
|
164
|
-
|
165
|
-
OrderDTO.new(
|
166
|
-
_id: specimen['doc_id'].blank? ? SecureRandom.uuid : specimen['doc_id'],
|
167
|
-
_rev: '0',
|
168
|
-
tracking_number: specimen['tracking_number'],
|
169
|
-
date_created: specimen['order_date'],
|
170
|
-
sample_type: specimen['specimen_name'],
|
171
|
-
tests: test_status_trail.keys,
|
172
|
-
districy: specimen['district'], # districy [sic] - That's how it's named
|
173
|
-
order_location: specimen['ward_id'],
|
174
|
-
sending_facility: specimen['sending_facility'],
|
175
|
-
receiving_facility: specimen['target_lab'],
|
176
|
-
priority: specimen['priority'],
|
177
|
-
patient: {
|
178
|
-
id: patient['nhid'],
|
179
|
-
first_name: patient_first_name,
|
180
|
-
last_name: patient_last_name,
|
181
|
-
gender: patient['gender'],
|
182
|
-
birthdate: patient['birthdate'],
|
183
|
-
email: nil,
|
184
|
-
phone_number: nil
|
185
|
-
},
|
186
|
-
type: 'Order',
|
187
|
-
who_order_test: {
|
188
|
-
first_name: drawn_by_first_name,
|
189
|
-
last_name: drawn_by_last_name,
|
190
|
-
id: specimen['drawn_by_id'],
|
191
|
-
phone_number: specimen['drawn_by_phone_number']
|
192
|
-
},
|
193
|
-
sample_status: specimen['specimen_status'],
|
194
|
-
sample_statuses: specimen_status_trail.each_with_object({}) do |trail_entry, object|
|
195
|
-
first_name, last_name = trail_entry['updated_by_name'].split
|
196
|
-
|
197
|
-
object[format_date(trail_entry['date'])] = {
|
198
|
-
status: trail_entry['status_name'],
|
199
|
-
updated_by: {
|
200
|
-
first_name: first_name,
|
201
|
-
last_name: last_name,
|
202
|
-
phone_number: trail_entry['updated_by_phone_number'],
|
203
|
-
id: trail_entry['updated_by_id']
|
204
|
-
}
|
205
|
-
}
|
206
|
-
end,
|
207
|
-
test_statuses: test_status_trail.each_with_object({}) do |trail_entry, formatted_trail|
|
208
|
-
test_name, test_statuses = trail_entry
|
209
|
-
|
210
|
-
formatted_trail[test_name] = test_statuses.each_with_object({}) do |test_status, formatted_statuses|
|
211
|
-
updated_by_first_name, updated_by_last_name = test_status['updated_by_name'].split
|
212
|
-
|
213
|
-
formatted_statuses[format_date(test_status['date'])] = {
|
214
|
-
status: test_status['status_name'],
|
215
|
-
updated_by: {
|
216
|
-
first_name: updated_by_first_name,
|
217
|
-
last_name: updated_by_last_name,
|
218
|
-
phone_number: test_status['updated_by_phone_number'],
|
219
|
-
id: test_status['updated_by_id']
|
220
|
-
}
|
221
|
-
}
|
222
|
-
end
|
223
|
-
end,
|
224
|
-
test_results: test_results.each_with_object({}) do |results_entry, formatted_results|
|
225
|
-
test_name, results = results_entry
|
226
|
-
|
227
|
-
formatted_results[test_name] = format_test_result_for_dto(test_name, specimen, results, test_status_trail)
|
228
|
-
end
|
229
|
-
)
|
230
|
-
end
|
231
|
-
|
232
|
-
def format_test_result_for_dto(test_name, specimen, results, test_status_trail)
|
233
|
-
return {} if results.size.zero?
|
234
|
-
|
235
|
-
result_create_event = test_status_trail[test_name]&.find do |trail_entry|
|
236
|
-
trail_entry['status_name'].casecmp?('drawn')
|
237
|
-
end
|
238
|
-
|
239
|
-
result_creator_first_name, result_creator_last_name = result_create_event&.fetch('updated_by_name')&.split
|
240
|
-
unless result_creator_first_name
|
241
|
-
result_creator_first_name, result_creator_last_name = specimen['drawn_by_name']&.split
|
242
|
-
end
|
243
|
-
|
244
|
-
{
|
245
|
-
results: results.each_with_object({}) do |result, formatted_measures|
|
246
|
-
formatted_measures[result['measure_name']] = {
|
247
|
-
result_value: result['result']
|
248
|
-
}
|
249
|
-
end,
|
250
|
-
date_result_entered: format_date(result_create_event&.fetch('date') || specimen['order_date'], :iso),
|
251
|
-
result_entered_by: {
|
252
|
-
first_name: result_creator_first_name,
|
253
|
-
last_name: result_creator_last_name,
|
254
|
-
phone_number: result_create_event&.fetch('updated_by_phone_number') || specimen['drawn_by_phone_number'],
|
255
|
-
id: result_create_event&.fetch('updated_by_id') || specimen['updated_by_id']
|
256
|
-
}
|
257
|
-
}
|
258
|
-
end
|
259
|
-
|
260
|
-
def mysql
|
261
|
-
return mysql_connection if mysql_connection
|
262
|
-
|
263
|
-
config = lambda do |key|
|
264
|
-
@config ||= Lab::Lims::Config.database
|
265
|
-
@config['default'][key] || @config['development'][key]
|
266
|
-
end
|
267
|
-
|
268
|
-
connection = Mysql2::Client.new(host: config['host'] || 'localhost',
|
269
|
-
username: config['username'] || 'root',
|
270
|
-
password: config['password'],
|
271
|
-
port: config['port'] || '3306',
|
272
|
-
database: config['database'],
|
273
|
-
reconnect: true)
|
274
|
-
|
275
|
-
self.mysql_connection = connection
|
276
|
-
end
|
277
|
-
|
278
|
-
def pid
|
279
|
-
return -1 if Parallel.worker_number.nil?
|
280
|
-
|
281
|
-
Parallel.worker_number
|
282
|
-
end
|
283
|
-
|
284
|
-
def mysql_connection=(connection)
|
285
|
-
@mysql_connection_pool[pid] = connection
|
286
|
-
end
|
287
|
-
|
288
|
-
def mysql_connection
|
289
|
-
@mysql_connection_pool[pid]
|
290
|
-
end
|
291
|
-
|
292
|
-
def query(sql)
|
293
|
-
Rails.logger.debug("#{MysqlApi}: #{sql}")
|
294
|
-
mysql.query(sql)
|
295
|
-
end
|
296
|
-
|
297
|
-
def sql_escape(value)
|
298
|
-
mysql.escape(value.to_s)
|
299
|
-
end
|
300
|
-
|
301
|
-
##
|
302
|
-
# Lims has some weird date formatting standards...
|
303
|
-
def format_date(date, format = nil)
|
304
|
-
date = date&.to_time
|
305
|
-
|
306
|
-
case format
|
307
|
-
when :iso
|
308
|
-
date&.strftime('%Y-%m-%d %H:%M:%S')
|
309
|
-
else
|
310
|
-
date&.strftime('%Y%m%d%H%M%S')
|
311
|
-
end
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|