Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Y24 102 tube rack banking bed verification #4611

Open
wants to merge 7 commits into
base: y24-088-tuberacks-epic
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/models/specific_tube_rack_creation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ def redirect_existing_barcode(existing_barcode_record, new_tube_rack, tube_rack_

if existing_labware.is_a?(TubeRack)
existing_barcode_record.labware = new_tube_rack
existing_barcode_record.save!
else
error_message =
"The tube rack barcode '#{tube_rack_barcode}' is already in use by " \
Expand Down
27 changes: 27 additions & 0 deletions app/models/tube_rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,19 @@ class TubeRack < Labware

# Requests comming out out the tubes contained in the rack
has_many :requests_as_source, through: :tubes
has_many :requests_as_target, through: :tubes
has_many :transfer_requests_as_source, through: :tube_receptacles
has_many :transfer_requests_as_target, through: :tube_receptacles
has_many :aliquots, through: :tubes

LAYOUTS = { 48 => { rows: 6, columns: 8 }, 96 => { rows: 8, columns: 12 } }.freeze

TUBE_RACK_STATES = %w[started qc_complete pending passed failed cancelled mixed empty].freeze

STATES_TO_FILTER_OUT = %w[cancelled failed].freeze
STATE_EMPTY = 'empty'
STATE_MIXED = 'mixed'

validates :size, inclusion: { in: LAYOUTS.keys }

def self.invalid_coordinates(rack_size, list_coordinates)
Expand Down Expand Up @@ -90,4 +99,22 @@ def after_comment_addition(comment)
# tubes that don't have submissions. Or even a mixed rack.
comments.add_comment_to_tubes(comment)
end

# The state of a tube rack is based on the transfer requests in the tubes.
# If they are all in the same state then it takes that state.
def state
# fetch states from ther transfer requests in all racked tubes in the rack.
unique_states = transfer_requests_as_target.map(&:state).uniq

return STATE_EMPTY if unique_states.empty?
return unique_states.first if unique_states.size == 1

STATES_TO_FILTER_OUT.each do |filter|
unique_states.delete(filter)
return unique_states.first if unique_states.one?
end

# we still have tubes with a mixed state
STATE_MIXED
end
end
1 change: 1 addition & 0 deletions app/resources/api/v2/tube_rack_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class TubeRackResource < BaseResource
attribute :name, delegate: :display_name, write_once: true
attribute :tube_locations, writeonly: true
attribute :uuid, readonly: true
attribute :state, readonly: true

attribute :created_at, readonly: true
attribute :updated_at, readonly: true
Expand Down
5 changes: 5 additions & 0 deletions app/uat_actions/uat_actions/tube_submission.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def validate_submission_template_exists
# @return [void]
def validate_tubes_exist
return if tube_barcodes.blank? # already validated by presence

barcodes =
tube_barcodes
.gsub(/(\\[trfvn])+/, ' ')
Expand All @@ -130,6 +131,10 @@ def validate_tubes_exist
Tube.find_by_barcode(barcode).blank? # not found
end

# return if all tubes exist
return if barcodes.blank?

# add error message listing tubes that do not exist
message = format(ERROR_TUBES_DO_NOT_EXIST, barcodes.join(', '))
errors.add(:tube_barcodes, message)
end
Expand Down
62 changes: 62 additions & 0 deletions spec/models/tube_rack_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,68 @@
end
end

describe '#state' do
let(:class_with_state) do
Class.new do
attr_accessor :state

def initialize(state)
@state = state
end
end
end

let(:tube_rack) { create(:tube_rack) }

context 'when there are no transfer requests' do
it 'returns STATE_EMPTY' do
allow(tube_rack).to receive(:transfer_requests_as_target).and_return([])
expect(tube_rack.state).to eq(TubeRack::STATE_EMPTY)
end
end

context 'when all transfer requests have the same state' do
let(:tube_state) { 'pending' }
let(:transfer_requests) do
[class_with_state.new(tube_state), class_with_state.new(tube_state), class_with_state.new(tube_state)]
end

it 'returns the single state' do
allow(tube_rack).to receive(:transfer_requests_as_target).and_return(transfer_requests)
expect(tube_rack.state).to eq('pending')
end
end

context 'when there are multiple states including states to filter out' do
let(:tube1_state) { 'pending' }
let(:tube2_state) { 'cancelled' }
let(:tube3_state) { 'failed' }
let(:transfer_requests) do
[class_with_state.new(tube1_state), class_with_state.new(tube2_state), class_with_state.new(tube3_state)]
end

it 'returns the remaining state after filtering' do
allow(tube_rack).to receive(:transfer_requests_as_target).and_return(transfer_requests)

expect(tube_rack.state).to eq('pending')
end
end

context 'when there are multiple states and filtering still results in multiple states' do
let(:tube1_state) { 'pending' }
let(:tube2_state) { 'started' }
let(:tube3_state) { 'failed' }
let(:transfer_requests) do
[class_with_state.new(tube1_state), class_with_state.new(tube2_state), class_with_state.new(tube3_state)]
end

it 'returns STATE_MIXED' do
allow(tube_rack).to receive(:transfer_requests_as_target).and_return(transfer_requests)
expect(tube_rack.state).to eq(TubeRack::STATE_MIXED)
end
end
end

describe 'scope #contained_samples' do
let(:num_tubes) { locations.length }
let(:tube_rack) { create(:tube_rack) }
Expand Down
Loading