Class: Batch
- Inherits:
-
ApplicationRecord
show all
- Extended by:
- EventfulRecord
- Includes:
- AASM, Api::BatchIo::Extensions, Api::Messages::FlowcellIo::Extensions, PipelineBehaviour, PolyMetadataBehaviour, StateMachineBehaviour, Commentable, HasPolyMetadata, SequencingQcBatch, StandardNamedScopes, UnderRepWellCommentsToBroadcast, Uuid::Uuidable
- Defined in:
- app/models/batch.rb
Overview
A Batch groups 1 or more requests together to enable processing in a
Pipeline. All requests in a batch get usually processed together, although it is
possible for requests to get removed from a batch in a handful of cases.
Defined Under Namespace
Modules: PipelineBehaviour, PolyMetadataBehaviour, RequestBehaviour, StateMachineBehaviour
Classes: RequestFailAndRemover
Constant Summary
collapse
- DEFAULT_VOLUME =
13
UnderRepWellCommentsToBroadcast::UNDER_REPRESENTED_KEY
StandardNamedScopes::SORT_FIELDS, StandardNamedScopes::SORT_ORDERS
SequencingQcBatch::VALID_QC_STATES
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
-
#all_requests_are_ready? ⇒ Boolean
-
#assign_positions_to_requests!(request_ids_in_position_order) ⇒ Object
Sets the position of the requests in the batch to their index in the supplied array.
-
#assigned_user ⇒ Object
-
#batch_id_matches(scanned_batch_id) ⇒ Object
-
#control ⇒ Object
-
#detach_request(request, current_user = nil) ⇒ Object
Remove a request from the batch and reset it to a point where it can be put back into the pending queue.
-
#displayed_status ⇒ Object
Summarise the state encapsulated by state and production_state Essentially a 'fail' production_state over-rides the 'state' We don't use production_state directly as it it 'fail' rather than ' failed' qc_state it kept separate as its a fairly distinct concept and is summarised elsewhere in the interface.
-
#downstream_requests_needing_asset(request) {|next_requests_needing_asset| ... } ⇒ Object
-
#event_with_description(name) ⇒ Object
-
#eventful_studies ⇒ Object
-
#fail(reason, comment, ignore_requests = false) ⇒ Object
Fail was removed from State Machine (as a state) to allow the addition of qc_state column and features.
-
#fail_requests(requests_to_fail, reason, comment, fail_but_charge = false) ⇒ Object
Fail specific requests on this batch.
-
#failed? ⇒ Boolean
-
#first_output_plate ⇒ Object
-
#flowcell ⇒ Object
-
#has_control? ⇒ Boolean
-
#has_event(event_name) ⇒ Object
Tests whether this Batch has any associated LabEvents.
-
#id_dup ⇒ Object
-
#input_labware_report ⇒ Labware::ActiveRecord_Relation
Returns a list of input labware including their barcodes, purposes, and a count of the number of requests associated with the batch.
-
#input_plate_group ⇒ Object
-
#npg_set_state ⇒ Object
-
#output_labware_report ⇒ Labware::ActiveRecord_Relation
Returns a list of output labware including their barcodes, purposes, and a count of the number of requests associated with the batch.
-
#output_plate_group ⇒ Object
-
#output_plate_purpose ⇒ Object
-
#output_plate_role ⇒ Object
-
#output_plates ⇒ Object
-
#pick_information? ⇒ Boolean
-
#plate_barcode(barcode) ⇒ Object
-
#plate_group_barcodes ⇒ Object
-
#plate_ids_in_study(study) ⇒ Object
rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity.
-
#rebroadcast ⇒ Object
-
#release_pending_requests ⇒ Object
-
#remove_request_ids(request_ids, reason = nil, comment = nil) ⇒ Object
Remove the request from the batch and remove asset information.
-
#request_count ⇒ Object
-
#reset!(current_user) ⇒ Object
rubocop:todo Metrics/MethodLength.
-
#return_request_to_inbox(request, current_user = nil) ⇒ Object
-
#robot_id ⇒ Object
-
#robot_verified!(user_id) ⇒ Object
-
#set_position_based_on_asset_barcode ⇒ Object
Sets the position of the requests in the batch based on their asset barcodes.
-
#source_labware ⇒ Object
Source Labware returns the physical pieces of labware (ie. a plate for wells, but tubes for tubes).
-
#start_requests ⇒ Object
-
#subject_type ⇒ Object
-
#swap(current_user, batch_info = {}) ⇒ Object
rubocop:todo Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize.
-
#total_volume_to_cherrypick ⇒ Object
-
#tube_barcode_matches(request, scanned_barcode) ⇒ Object
-
#underrun ⇒ Object
-
#update_batch_state(reason, comment) ⇒ Object
-
#verify_amp_plate_layout(barcodes, user = nil) ⇒ Bool
Used in the Ultima sequencing pipelines to check AMP plates are in the correct position.
-
#verify_amp_plate_position(request, barcodes) ⇒ Object
-
#verify_tube_layout(barcodes, user = nil) ⇒ Bool
Used in Sequencing pipelines to check tubes are in the correct position on the flowcell.
-
#verify_tube_position(request, barcodes) ⇒ Object
has_many_events, has_many_lab_events, has_one_event_with_family
#automatic_buffer_addition?, #buffer_volume_for_empty_wells, #plate_template_for_buffer_addition
#get_poly_metadata, #set_poly_metadata
#comments, #request_with_under_represented_wells, #under_represented_well_comments
#complete_with_user!, #editable?, #finished?, included, #release_with_user!, #start_with_user!
#has_item_limit?, included, #last_completed_task
included
included, #unsaved_uuid!, #uuid
#after_comment_addition
adjacent_state_helper, included, #processing_in_manual_qc?, #qc_manual_in_progress, #qc_previous_state!, #qc_states, state_transition_helper
included
alias_association, convert_labware_to_receptacle_for, find_by_id_or_name, find_by_id_or_name!
Methods included from Squishify
extended
Instance Attribute Details
#production_state ⇒ Object
Also referenced in StateMachineBehaviour. Either nil, or fail. This is updated in Batch#fail_requests and
Batch#fail. The former is used via BatchesController#fail_items, the latter seems to be unused.
Is intended to take precedence over both other states to track failures in-spite of QC results.
#qc_state ⇒ Object
Primarily for sequencing batches. See SequencingQcBatch. Holds the sequencing QC state
Class Method Details
.barcode_without_pick_number(code) ⇒ Object
546
547
548
|
# File 'app/models/batch.rb', line 546
def self.barcode_without_pick_number(code)
code.split('-').first
end
|
550
551
552
553
554
555
556
557
|
# File 'app/models/batch.rb', line 550
def self.(code)
split_code = code.split('-')
return Integer(split_code.last) if split_code.size > 1
1
end
|
.find_by_barcode(code) ⇒ Object
Also known as:
find_from_barcode
560
561
562
563
564
565
566
567
|
# File 'app/models/batch.rb', line 560
def find_by_barcode(code)
split_code = barcode_without_pick_number(code)
human_batch_barcode = Barcode.number_to_human(split_code)
batch = Batch.find_by(barcode: human_batch_barcode)
batch ||= Batch.find_by(id: human_batch_barcode)
batch
end
|
.prefix ⇒ Object
529
530
531
|
# File 'app/models/batch.rb', line 529
def self.prefix
'BA'
end
|
.valid_barcode?(code) ⇒ Boolean
533
534
535
536
537
538
539
540
541
542
543
544
|
# File 'app/models/batch.rb', line 533
def self.valid_barcode?(code)
begin
split_code = barcode_without_pick_number(code)
Barcode.barcode_to_human!(split_code, prefix)
rescue StandardError
return false
end
return false if find_from_barcode(code).nil?
true
end
|
Instance Method Details
#all_requests_are_ready? ⇒ Boolean
120
121
122
123
124
|
# File 'app/models/batch.rb', line 120
def all_requests_are_ready?
errors.add :base, 'All requests must be ready to be added to a batch' unless requests.all?(&:ready?)
end
|
#assign_positions_to_requests!(request_ids_in_position_order) ⇒ Object
Sets the position of the requests in the batch to their index in the supplied array.
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'app/models/batch.rb', line 217
def assign_positions_to_requests!(request_ids_in_position_order)
request_ids_in_batch = batch_requests.map(&:request_id)
missing_requests = request_ids_in_batch.any? { |id| request_ids_in_position_order.exclude?(id) }
= request_ids_in_position_order.any? { |id| request_ids_in_batch.exclude?(id) }
raise StandardError, 'Can only sort all the requests in the batch at once' if missing_requests ||
BatchRequest.transaction do
batch_requests.each do |batch_request|
batch_request.move_to_position!(request_ids_in_position_order.index(batch_request.request_id) + 1)
end
end
end
|
#assigned_user ⇒ Object
233
234
235
|
# File 'app/models/batch.rb', line 233
def assigned_user
assignee.try(:login) || ''
end
|
#batch_id_matches(scanned_batch_id) ⇒ Object
377
378
379
|
# File 'app/models/batch.rb', line 377
def batch_id_matches(scanned_batch_id)
scanned_batch_id == id.to_s
end
|
#control ⇒ Object
201
202
203
|
# File 'app/models/batch.rb', line 201
def control
requests.detect { |request| request.try(:asset).try(:resource?) }
end
|
#detach_request(request, current_user = nil) ⇒ Object
Remove a request from the batch and reset it to a point where it can be put back into
the pending queue.
402
403
404
405
406
407
408
409
|
# File 'app/models/batch.rb', line 402
def detach_request(request, current_user = nil)
ActiveRecord::Base.transaction do
unless current_user.nil?
request.("Used to belong to Batch #{id} removed at #{Time.zone.now}", current_user)
end
pipeline.detach_request_from_batch(self, request)
end
end
|
#displayed_status ⇒ Object
Summarise the state encapsulated by state and production_state
Essentially a 'fail' production_state over-rides the 'state'
We don't use production_state directly as it it 'fail' rather than
' failed'
qc_state it kept separate as its a fairly distinct concept and is
summarised elsewhere in the interface.
602
603
604
|
# File 'app/models/batch.rb', line 602
def displayed_status
failed? ? 'failed' : state
end
|
#downstream_requests_needing_asset(request) {|next_requests_needing_asset| ... } ⇒ Object
583
584
585
586
|
# File 'app/models/batch.rb', line 583
def downstream_requests_needing_asset(request)
next_requests_needing_asset = request.next_requests.select { |r| r.asset_id.blank? }
yield(next_requests_needing_asset) if next_requests_needing_asset.present?
end
|
#event_with_description(name) ⇒ Object
189
190
191
|
# File 'app/models/batch.rb', line 189
def event_with_description(name)
lab_events.order(id: :desc).find_by(description: name)
end
|
#eventful_studies ⇒ Object
130
131
132
|
# File 'app/models/batch.rb', line 130
def eventful_studies
requests.reduce([]) { |studies, request| studies.concat(request.eventful_studies) }.uniq
end
|
#fail(reason, comment, ignore_requests = false) ⇒ Object
Fail was removed from State Machine (as a state) to allow the addition of qc_state column and features
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# File 'app/models/batch.rb', line 139
def fail(reason, , ignore_requests = false)
raise StandardError, 'Can not fail batch without failing requests' if ignore_requests
failures.create(reason: reason, comment: , notify_remote: false)
requests.each do |request|
request.failures.create(reason: reason, comment: , notify_remote: true)
EventSender.send_fail_event(request, reason, , id) unless request.asset && request.asset.resource?
end
self.production_state = 'fail'
save!
end
|
#fail_requests(requests_to_fail, reason, comment, fail_but_charge = false) ⇒ Object
Fail specific requests on this batch
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
# File 'app/models/batch.rb', line 157
def fail_requests(requests_to_fail, reason, , fail_but_charge = false) ActiveRecord::Base.transaction do
requests
.find(requests_to_fail)
.each do |request|
logger.debug "SENDING FAIL FOR REQUEST #{request.id}, BATCH #{id}, WITH REASON #{reason}"
request.customer_accepts_responsibility! if fail_but_charge
request.failures.create(reason: reason, comment: , notify_remote: true)
EventSender.send_fail_event(request, reason, , id)
end
update_batch_state(reason, )
end
end
|
#failed? ⇒ Boolean
180
181
182
|
# File 'app/models/batch.rb', line 180
def failed?
production_state == 'fail'
end
|
#first_output_plate ⇒ Object
276
277
278
|
# File 'app/models/batch.rb', line 276
def first_output_plate
Plate.output_by_batch(self).with_wells_and_requests.first
end
|
#flowcell ⇒ Object
134
135
136
|
# File 'app/models/batch.rb', line 134
def flowcell
self if sequencing?
end
|
#has_control? ⇒ Boolean
205
206
207
|
# File 'app/models/batch.rb', line 205
def has_control?
control.present?
end
|
#has_event(event_name) ⇒ Object
Tests whether this Batch has any associated LabEvents
185
186
187
|
# File 'app/models/batch.rb', line 185
def has_event(event_name)
lab_events.any? { |event| event_name.downcase == event.description.try(:downcase) }
end
|
#id_dup ⇒ Object
298
299
300
|
# File 'app/models/batch.rb', line 298
def id_dup
id
end
|
Returns a list of input labware including their barcodes,
purposes, and a count of the number of requests associated with the
batch. Output depends on Pipeline. Some pipelines return an empty relationship
246
247
248
|
# File 'app/models/batch.rb', line 246
def input_labware_report
pipeline.input_labware requests
end
|
259
260
261
|
# File 'app/models/batch.rb', line 259
def input_plate_group
source_assets.group_by(&:plate)
end
|
#npg_set_state ⇒ Object
575
576
577
578
579
580
581
|
# File 'app/models/batch.rb', line 575
def npg_set_state
if all_requests_qced?
self.state = 'released'
qc_complete
save!
end
end
|
#output_labware_report ⇒ Labware::ActiveRecord_Relation
Returns a list of output labware including their barcodes,
purposes, and a count of the number of requests associated with the
batch. Output depends on Pipeline. Some pipelines return an empty relationship
255
256
257
|
# File 'app/models/batch.rb', line 255
def output_labware_report
pipeline.output_labware requests.with_target
end
|
#output_plate_group ⇒ Object
This looks odd. Why would a request have the same asset as target asset? Why are we filtering them out here?
264
265
266
|
# File 'app/models/batch.rb', line 264
def output_plate_group
requests.select { |r| r.target_asset != r.asset }.map(&:target_asset).select(&:present?).group_by(&:plate)
end
|
#output_plate_purpose ⇒ Object
280
281
282
|
# File 'app/models/batch.rb', line 280
def output_plate_purpose
output_plates[0].plate_purpose unless output_plates[0].nil?
end
|
#output_plate_role ⇒ Object
284
285
286
|
# File 'app/models/batch.rb', line 284
def output_plate_role
requests.first.try(:role)
end
|
#output_plates ⇒ Object
268
269
270
271
272
273
274
|
# File 'app/models/batch.rb', line 268
def output_plates
return output_labware.sort_by(&:id) if output_labware.loaded?
output_labware.reorder(id: :asc)
end
|
592
593
594
|
# File 'app/models/batch.rb', line 592
def pick_information?
pipeline.pick_information?(self)
end
|
#plate_barcode(barcode) ⇒ Object
294
295
296
|
# File 'app/models/batch.rb', line 294
def plate_barcode(barcode)
barcode.presence || requests.first.target_asset.plate.human_barcode
end
|
#plate_group_barcodes ⇒ Object
288
289
290
291
292
|
# File 'app/models/batch.rb', line 288
def plate_group_barcodes
return nil unless pipeline.group_by_parent || requests.first.target_asset.is_a?(Well)
output_plate_group.presence || input_plate_group
end
|
#plate_ids_in_study(study) ⇒ Object
rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
506
507
508
|
# File 'app/models/batch.rb', line 506
def plate_ids_in_study(study)
Plate.plate_ids_from_requests(requests.for_studies(study))
end
|
#rebroadcast ⇒ Object
588
589
590
|
# File 'app/models/batch.rb', line 588
def rebroadcast
messengers.each(&:resend)
end
|
#release_pending_requests ⇒ Object
381
382
383
384
385
|
# File 'app/models/batch.rb', line 381
def release_pending_requests
requests.each { |request| detach_request(request) if request.started? }
end
|
#remove_request_ids(request_ids, reason = nil, comment = nil) ⇒ Object
Remove the request from the batch and remove asset information
388
389
390
391
392
393
394
395
396
397
398
|
# File 'app/models/batch.rb', line 388
def remove_request_ids(request_ids, reason = nil, = nil)
ActiveRecord::Base.transaction do
Request
.find(request_ids)
.each do |request|
request.failures.create(reason: reason, comment: , notify_remote: true)
detach_request(request)
end
update_batch_state(reason, )
end
end
|
#request_count ⇒ Object
571
572
573
|
# File 'app/models/batch.rb', line 571
def request_count
requests.count
end
|
#reset!(current_user) ⇒ Object
rubocop:todo Metrics/MethodLength
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
|
# File 'app/models/batch.rb', line 424
def reset!(current_user) ActiveRecord::Base.transaction do
discard!
requests.each do |request|
request.batch = nil
return_request_to_inbox(request, current_user)
end
if requests.last.submission_id.present?
Request
.where(submission_id: requests.last.submission_id, state: 'pending')
.where.not(request_type_id: pipeline.request_type_ids)
.find_each do |request|
request.asset_id = nil
request.save!
end
end
end
end
|
#return_request_to_inbox(request, current_user = nil) ⇒ Object
411
412
413
414
415
416
417
418
419
420
421
|
# File 'app/models/batch.rb', line 411
def return_request_to_inbox(request, current_user = nil)
ActiveRecord::Base.transaction do
unless current_user.nil?
request.(
"Used to belong to Batch #{id} returned to inbox unstarted at #{Time.zone.now}",
current_user
)
end
request.return_pending_to_inbox!
end
end
|
#robot_id ⇒ Object
193
194
195
|
# File 'app/models/batch.rb', line 193
def robot_id
event_with_description('Cherrypick Layout Set')&.descriptor_value('robot_id')
end
|
#robot_verified!(user_id) ⇒ Object
518
519
520
521
522
523
524
525
526
527
|
# File 'app/models/batch.rb', line 518
def robot_verified!(user_id)
return if has_event('robot verified')
pipeline.robot_verified!(self)
lab_events.create(
description: 'Robot verified',
message: 'Robot verification completed and source volumes updated.',
user_id: user_id
)
end
|
#set_position_based_on_asset_barcode ⇒ Object
Sets the position of the requests in the batch based on their asset barcodes.
This was done at Lab request to make it easier to order the tubes in the batch.
211
212
213
214
|
# File 'app/models/batch.rb', line 211
def set_position_based_on_asset_barcode
request_ids_in_position_order = requests.sort_by { |r| r.asset.human_barcode }.map(&:id)
assign_positions_to_requests!(request_ids_in_position_order)
end
|
#source_labware ⇒ Object
Source Labware returns the physical pieces of labware (ie. a plate for wells, but tubes for tubes)
303
304
305
|
# File 'app/models/batch.rb', line 303
def source_labware
input_labware
end
|
#start_requests ⇒ Object
237
238
239
|
# File 'app/models/batch.rb', line 237
def start_requests
requests.with_assets_for_starting_requests.not_failed.map(&:start!)
end
|
#subject_type ⇒ Object
126
127
128
|
# File 'app/models/batch.rb', line 126
def subject_type
sequencing? ? 'flowcell' : 'batch'
end
|
#swap(current_user, batch_info = {}) ⇒ Object
rubocop:todo Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
|
# File 'app/models/batch.rb', line 448
def swap(current_user, batch_info = {}) return false if batch_info.empty?
batch_request_left =
BatchRequest.find_by(batch_id: batch_info['batch_1']['id'], position: batch_info['batch_1']['lane']) or
errors.add('Swap: ', 'The first lane cannot be found')
batch_request_right =
BatchRequest.find_by(batch_id: batch_info['batch_2']['id'], position: batch_info['batch_2']['lane']) or
errors.add('Swap: ', 'The second lane cannot be found')
return unless batch_request_left.present? && batch_request_right.present?
ActiveRecord::Base.transaction do
batch_request_left.request.lab_events.each do |event|
event.update!(batch_id: batch_request_right.batch_id) if event.batch_id == batch_request_left.batch_id
end
batch_request_right.request.lab_events.each do |event|
event.update!(batch_id: batch_request_left.batch_id) if event.batch_id == batch_request_right.batch_id
end
original_left_batch_id, original_left_position, original_right_request_id =
batch_request_left.batch_id,
batch_request_left.position,
batch_request_right.request_id
batch_request_right.destroy
batch_request_left.update!(batch_id: batch_request_right.batch_id, position: batch_request_right.position)
batch_request_right =
BatchRequest.create!(
batch_id: original_left_batch_id,
position: original_left_position,
request_id: original_right_request_id
)
batch_request_left.batch.lab_events.create!(
description: 'Lane swap',
message:
"Lane #{batch_request_right.position} moved to #{batch_request_left.batch_id} " \
"lane #{batch_request_left.position}",
user_id: current_user.id
)
batch_request_right.batch.lab_events.create!(
description: 'Lane swap',
message:
"Lane #{batch_request_left.position} moved to #{batch_request_right.batch_id} " \
"lane #{batch_request_right.position}",
user_id: current_user.id
)
end
true
end
|
#total_volume_to_cherrypick ⇒ Object
510
511
512
513
514
515
516
|
# File 'app/models/batch.rb', line 510
def total_volume_to_cherrypick
request = requests.first
return DEFAULT_VOLUME unless request.asset.is_a?(Well)
return DEFAULT_VOLUME unless request.target_asset.is_a?(Well)
request.target_asset.get_requested_volume
end
|
#tube_barcode_matches(request, scanned_barcode) ⇒ Object
373
374
375
|
# File 'app/models/batch.rb', line 373
def tube_barcode_matches(request, scanned_barcode)
scanned_barcode == request.asset.machine_barcode || scanned_barcode == request.asset.human_barcode
end
|
#underrun ⇒ Object
197
198
199
|
# File 'app/models/batch.rb', line 197
def underrun
has_limit? ? (item_limit - batch_requests.size) : 0
end
|
#update_batch_state(reason, comment) ⇒ Object
172
173
174
175
176
177
178
|
# File 'app/models/batch.rb', line 172
def update_batch_state(reason, )
if requests.all?(&:terminated?)
failures.create(reason: reason, comment: , notify_remote: false)
self.production_state = 'fail'
save!
end
end
|
#verify_amp_plate_layout(barcodes, user = nil) ⇒ Bool
Used in the Ultima sequencing pipelines to check AMP plates are in the correct position.
Verifies that provided barcodes are in the correct locations according to the
request 'position' within the batch.
Logs an event if the layout is correct.
351
352
353
354
355
356
357
358
359
360
|
# File 'app/models/batch.rb', line 351
def verify_amp_plate_layout(barcodes, user = nil)
requests.each { |request| verify_amp_plate_position(request, barcodes) }
if errors.empty?
lab_events.create(description: 'AMP plate layout verified', user: user)
true
else
false
end
end
|
#verify_amp_plate_position(request, barcodes) ⇒ Object
362
363
364
365
366
367
368
369
370
371
|
# File 'app/models/batch.rb', line 362
def verify_amp_plate_position(request, barcodes)
divider = '-'
scanned_barcode = barcodes[request.position - 1]
scanned_batch_id, tube_barcode = scanned_barcode.split(divider)
unless batch_id_matches(scanned_batch_id) && tube_barcode_matches(request, tube_barcode)
expected_barcode = "#{id}#{divider}#{request.asset.human_barcode}"
errors.add(:base, "The barcode at position #{request.position} is incorrect: expected #{expected_barcode}.")
end
end
|
#verify_tube_layout(barcodes, user = nil) ⇒ Bool
Used in Sequencing pipelines to check tubes are in the correct position on the flowcell.
Verifies that provided barcodes are in the correct locations according to the
request 'position' within the batch.
Logs an event if the layout is correct.
319
320
321
322
323
324
325
326
327
328
|
# File 'app/models/batch.rb', line 319
def verify_tube_layout(barcodes, user = nil)
requests.each { |request| verify_tube_position(request, barcodes) }
if errors.empty?
lab_events.create(description: 'Tube layout verified', user: user)
true
else
false
end
end
|
#verify_tube_position(request, barcodes) ⇒ Object
330
331
332
333
334
335
336
337
|
# File 'app/models/batch.rb', line 330
def verify_tube_position(request, barcodes)
scanned_barcode = barcodes[request.position - 1]
unless tube_barcode_matches(request, scanned_barcode)
expected_barcode = request.asset.human_barcode
errors.add(:base, "The tube at position #{request.position} is incorrect: expected #{expected_barcode}.")
end
end
|