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-190: Use SS API V2 for Qcable resources #2135

Merged
merged 5 commits into from
Jan 13, 2025
Merged
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
9 changes: 6 additions & 3 deletions app/controllers/tag_plates_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# frozen_string_literal: true

# Receives AJAX requests when creating tag plates, returns the
# plate information eg. lot number, template, status
# plate information eg. lot number, template
# The front end makes a decision regarding suitability
class TagPlatesController < ApplicationController
INCLUDES = [:labware, { lot: [{ lot_type: :target_purpose }, :template] }].freeze

def show
qcable = Presenters::QcablePresenter.new(api.qcable.find(params[:id]))
respond_to { |format| format.json { render json: { 'qcable' => qcable } } }
qcable_resource = Sequencescape::Api::V2::Qcable.includes(*INCLUDES).find(uuid: params[:id]).first
qcable_presenter = Presenters::QcablePresenter.new(qcable_resource)
respond_to { |format| format.json { render json: { 'qcable' => qcable_presenter } } }
end
end
32 changes: 24 additions & 8 deletions app/models/presenters/qcable_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,31 @@
module Presenters
# Used for tag plates / tag 2 tubes. Rendered with default to_json behaviour.
class QcablePresenter
def initialize(qcable) # rubocop:todo Metrics/AbcSize
@uuid = qcable.uuid
@tag_layout = qcable.lot.template_name
@asset_uuid = qcable.asset.uuid
def initialize(qcable)
init_qcable_attributes(qcable)
init_lot_attributes(qcable.lot)
init_lot_type_attributes(qcable.lot.lot_type)
init_template_attributes(qcable.lot.template)
end

def init_qcable_attributes(qcable)
@asset_uuid = qcable.labware.uuid
@state = qcable.state
@type = qcable.lot.lot_type_name
@qcable_type = qcable.lot.lot_type.qcable_name
@template_uuid = qcable.lot.template.uuid
@lot_number = qcable.lot.lot_number
@uuid = qcable.uuid
end

def init_lot_attributes(lot)
@lot_number = lot.lot_number
end

def init_lot_type_attributes(lot_type)
@qcable_type = lot_type.target_purpose.name
@type = lot_type.name
end

def init_template_attributes(template)
@tag_layout = template.name
@template_uuid = template.uuid
end
end
end
10 changes: 10 additions & 0 deletions app/sequencescape/sequencescape/api/v2/lot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

# A Lot from sequencescape via the V2 API
class Sequencescape::Api::V2::Lot < Sequencescape::Api::V2::Base
has_one :lot_type

# The template is is a polymorphic relationship in Sequencescape, but we only want to access the UUID
# and so we don't need a specific class since all properties are accessible via the base class.
has_one :template, class_name: 'Sequencescape::Api::V2::Base'
end
6 changes: 6 additions & 0 deletions app/sequencescape/sequencescape/api/v2/lot_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

# A LotType from sequencescape via the V2 API
class Sequencescape::Api::V2::LotType < Sequencescape::Api::V2::Base
has_one :target_purpose, class_name: 'Sequencescape::Api::V2::Purpose'
end
1 change: 0 additions & 1 deletion app/sequencescape/sequencescape/api/v2/purpose.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# frozen_string_literal: true

class Sequencescape::Api::V2::Purpose < Sequencescape::Api::V2::Base
UNKNOWN = 'UNKNOWN'
end
7 changes: 7 additions & 0 deletions app/sequencescape/sequencescape/api/v2/qcable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

# A Qcable from sequencescape via the V2 API
class Sequencescape::Api::V2::Qcable < Sequencescape::Api::V2::Base
has_one :labware
has_one :lot
end
47 changes: 47 additions & 0 deletions spec/factories/qcable_factories.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,53 @@
# frozen_string_literal: true

FactoryBot.define do
# API V2 QCable
factory :v2_qcable, class: Sequencescape::Api::V2::Qcable, traits: [:barcoded_v2] do
skip_create

uuid
state { 'available' }

transient do
labware { create :v2_plate }
lot { create :v2_lot }
end

after(:build) do |qcable, factory|
qcable._cached_relationship(:labware) { factory.labware } if factory.labware
qcable._cached_relationship(:lot) { factory.lot } if factory.lot
qcable._cached_relationship(:asset) { factory.labware } if factory.labware # alias for labware
end
end

factory :v2_lot, class: Sequencescape::Api::V2::Lot do
skip_create

sequence(:lot_number) { |n| "UAT12345.#{n}" }

transient do
lot_type { create :v2_lot_type }
template { create :v2_tag_layout_template }
end

after(:build) do |lot, factory|
lot._cached_relationship(:lot_type) { factory.lot_type } if factory.lot_type
lot._cached_relationship(:template) { factory.template } if factory.template
end
end

factory :v2_lot_type, class: Sequencescape::Api::V2::LotType do
skip_create

sequence(:name) { |n| "LotType#{n}" }

transient { target_purpose { create :v2_purpose } }

after(:build) do |lot_type, factory|
lot_type._cached_relationship(:target_purpose) { factory.target_purpose } if factory.target_purpose
end
end

# API V1 Qcable (Records the QC status of eg. a tag plate)
factory :qcable, class: Limber::Qcable, traits: %i[api_object barcoded] do
with_belongs_to_associations 'lot', 'qcable_creator', 'asset'
Expand Down
51 changes: 26 additions & 25 deletions spec/features/creating_a_tag_plate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@
purpose_uuid: 'stock-plate-purpose-uuid'
)
end

let(:tag_plate_barcode) { SBCF::SangerBarcode.new(prefix: 'DN', number: 2).machine_barcode.to_s }
let(:tag_plate_qcable_uuid) { 'tag-plate-qcable' }
let(:tag_plate_uuid) { 'tag-plate-uuid' }
let(:tag_plate_qcable) { json :tag_plate_qcable, uuid: tag_plate_qcable_uuid, lot_uuid: 'lot-uuid' }
let(:tag_template_uuid) { 'tag-layout-template-0' }
let(:transfer_template_uuid) { 'custom-pooling' }

let(:qcable_template) { create :v2_tag_layout_template, uuid: tag_template_uuid }
let(:qcable_lot) { create :v2_lot, template: qcable_template }
let(:qcable_labware) { create :v2_plate, uuid: tag_plate_uuid }
let(:qcable) { create :v2_qcable, lot: qcable_lot, labware: qcable_labware, uuid: tag_plate_qcable_uuid }

let(:tag_plate_barcode) { qcable_labware.labware_barcode.machine }
let(:tag_plate_qcable) { json :tag_plate_qcable, uuid: tag_plate_qcable_uuid }
let(:expected_transfers) { WellHelpers.stamp_hash(96) }
let(:enforce_uniqueness) { true }

Expand Down Expand Up @@ -59,7 +63,7 @@
user_uuid: user_uuid,
source_uuid: parent_plate.uuid,
destination_uuid: tag_plate_uuid,
transfer_template_uuid: transfer_template_uuid,
transfer_template_uuid: 'custom-pooling',
transfers: expected_transfers
}
}
Expand All @@ -68,7 +72,6 @@

let(:help_text) { 'This plate does not appear to be part of a larger pool. Dual indexing is optional.' }

let(:tag_lot_number) { 'tag_lot_number' }
let(:enforce_same_template_within_pool) { false }

# Setup stubs
Expand All @@ -91,14 +94,8 @@
stub_v2_barcode_printers(create_list(:v2_plate_barcode_printer, 3))
stub_v2_tag_layout_templates(templates)

# TODO: {Y24-190} Get rid of these v1 stubs after tag_layout_templates are moved to v2 in tagged_plate.rb
stub_api_get(tag_template_uuid, body: json(:tag_layout_template, uuid: tag_template_uuid))
stub_api_post(tag_template_uuid, body: json(:tag_layout_template, uuid: tag_template_uuid))

# API v1 UUID requests for a qcable via qcable_presenter.
stub_api_get(tag_plate_qcable_uuid, body: tag_plate_qcable)
stub_api_get('lot-uuid', body: json(:tag_lot, lot_number: tag_lot_number, template_uuid: tag_template_uuid))
stub_api_get('tag-lot-type-uuid', body: json(:tag_lot_type))
# API v2 requests for the qcable
stub_v2_qcable(qcable)
end

shared_examples 'it supports the plate' do
Expand All @@ -110,6 +107,12 @@

stub_v2_plate(create(:v2_plate, uuid: tag_plate_uuid, purpose_uuid: 'stock-plate-purpose-uuid'))
stub_api_v2_post('StateChange')

stub_search_and_single_result(
'Find qcable by barcode',
{ 'search' => { 'barcode' => tag_plate_barcode } },
tag_plate_qcable
)
end

scenario 'creation with the plate' do
Expand All @@ -121,31 +124,29 @@
click_on('Add an empty Tag Purpose plate')
expect(page).to have_content('Tag plate addition')
expect(find('#tag-help')).to have_content(help_text)
stub_search_and_single_result(
'Find qcable by barcode',
{ 'search' => { 'barcode' => tag_plate_barcode } },
tag_plate_qcable
)
swipe_in('Tag plate barcode', with: tag_plate_barcode)
expect(page).to have_content(tag_lot_number)
expect(page).to have_content(qcable_lot.lot_number)
expect(find('#well_A2')).to have_content(a2_tag)
click_on('Create Plate')
expect(page).to have_content('New empty labware added to the system.')
end
end

shared_examples 'it rejects the candidate plate' do
before do
stub_search_and_single_result(
'Find qcable by barcode',
{ 'search' => { 'barcode' => tag_plate_barcode } },
tag_plate_qcable
)
end

scenario 'rejects the candidate plate' do
fill_in_swipecard_and_barcode user_swipecard, plate_barcode
plate_title = find('#plate-title')
expect(plate_title).to have_text('Limber Cherrypicked')
click_on('Add an empty Tag Purpose plate')
expect(page).to have_content('Tag plate addition')
stub_search_and_single_result(
'Find qcable by barcode',
{ 'search' => { 'barcode' => tag_plate_barcode } },
tag_plate_qcable
)
swipe_in('Tag plate barcode', with: tag_plate_barcode)
expect(page).to have_button('Create Plate', disabled: true)
expect(page).to have_content(tag_error)
Expand Down
8 changes: 8 additions & 0 deletions spec/support/api_url_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ def stub_v2_qc_file(qc_file)
allow(Sequencescape::Api::V2::QcFile).to receive(:find).with(*arguments).and_return([qc_file])
end

def stub_v2_qcable(qcable)
arguments = [{ uuid: qcable.uuid }]
query_builder = double

allow(Sequencescape::Api::V2::Qcable).to receive(:includes).and_return(query_builder)
allow(query_builder).to receive(:find).with(*arguments).and_return([qcable])
end

def stub_v2_study(study)
arguments = [{ name: study.name }]
allow(Sequencescape::Api::V2::Study).to receive(:find).with(*arguments).and_return([study])
Expand Down
Loading