diff --git a/app/models/plate_purpose.rb b/app/models/plate_purpose.rb index 67111d0671..d48f7e5102 100644 --- a/app/models/plate_purpose.rb +++ b/app/models/plate_purpose.rb @@ -88,7 +88,11 @@ def pool_wells(wells) # rubocop:todo Metrics/MethodLength has_many :plates def self.stock_plate_purpose - PlatePurpose.create_with(stock_plate: true, cherrypickable_target: true).find_or_create_by!(name: 'Stock Plate') + PlatePurpose.create_with( + stock_plate: true, + cherrypickable_target: true, + type: 'PlatePurpose::Input' + ).find_or_create_by!(name: 'Stock Plate') end def size diff --git a/app/models/tag_layout.rb b/app/models/tag_layout.rb index f4976bad9f..a2fe9aaa1a 100644 --- a/app/models/tag_layout.rb +++ b/app/models/tag_layout.rb @@ -49,7 +49,6 @@ class TagLayout < ApplicationRecord # The plate we'll be laying out the tags into belongs_to :plate, optional: false - validates :direction, inclusion: { in: DIRECTION_ALGORITHMS.keys } validates :walking_by, inclusion: { in: WALKING_ALGORITHMS.keys } @@ -57,8 +56,8 @@ class TagLayout < ApplicationRecord validates :walking_algorithm, presence: true # After creating the instance we can layout the tags into the wells. - after_create :layout_tags_into_wells, if: :valid? + after_create :layout_tags_into_wells, if: :valid? set_target_for_owner(:plate) delegate :direction, to: :direction_algorithm_module diff --git a/config/default_records/plate_purposes/005_limber_purposes.yml b/config/default_records/plate_purposes/005_limber_purposes.yml index e0fa1efcc2..714c2dce12 100644 --- a/config/default_records/plate_purposes/005_limber_purposes.yml +++ b/config/default_records/plate_purposes/005_limber_purposes.yml @@ -18,6 +18,8 @@ LTN Cherrypick: *limber_input_96 LHR RT: *limber_input_96 LTHR RT: *limber_input_96 LTHR Cherrypick: *limber_input_96 +Stock Plate: *limber_input_96 + PF Cherrypicked: <<: *limber_input_96 default_state: passed diff --git a/config/default_records/request_types/005_limber_bespoke.yml b/config/default_records/request_types/005_limber_bespoke.yml index 060bd2364f..36969088f0 100644 --- a/config/default_records/request_types/005_limber_bespoke.yml +++ b/config/default_records/request_types/005_limber_bespoke.yml @@ -10,6 +10,7 @@ limber_pcr_bespoke: acceptable_purposes: - LBB Cherrypick - LBC Cherrypick + - Stock Plate library_types: - ChIP-Seq Auto - Chromium single cell HTO diff --git a/db/seeds/0001_snp_plate_purposes.rb b/db/seeds/0001_snp_plate_purposes.rb index f63210b454..6ec0a1d0b1 100644 --- a/db/seeds/0001_snp_plate_purposes.rb +++ b/db/seeds/0001_snp_plate_purposes.rb @@ -8,9 +8,6 @@ cherrypickable_target: true stock_plate: false prefix: WD - - name: Stock Plate - stock_plate: true - cherrypickable_target: true - name: 40ng - name: Whole Genome Amplification cherrypickable_target: true diff --git a/features/api/tag_layout_templates.feature b/features/api/tag_layout_templates.feature index b9c5a38776..e25e4846e8 100644 --- a/features/api/tag_layout_templates.feature +++ b/features/api/tag_layout_templates.feature @@ -40,7 +40,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled in columns to the plate "Testing the tagging" @@ -290,7 +290,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 96 And "F11-F12" of the plate "Testing the tagging" have been failed @@ -460,7 +460,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled in columns to the plate "Testing the tagging" @@ -550,7 +550,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4, 8, 4 @@ -633,7 +633,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 8, 2, 10, 4, 8, 2, 10, 4, 8, 2, 10, 4, 8, 8, 8 @@ -706,7 +706,7 @@ Feature: Access tag layout templates through the API And the UUID for the plate "Testing the API" is "11111111-2222-3333-4444-000000000002" And all wells on the plate "Testing the API" have unique samples - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 96 @@ -747,7 +747,7 @@ Feature: Access tag layout templates through the API And all wells on the plate "Testing the API" have unique samples And H12 on the plate "Testing the API" is empty - Given a "Stock plate" plate called "Testing the tagging" exists + Given a "Stock plate" input plate called "Testing the tagging" exists And the UUID for the plate "Testing the tagging" is "11111111-2222-3333-4444-000000000001" And the wells for the plate "Testing the API" have been pooled to the plate "Testing the tagging" according to the pooling strategy 95 diff --git a/features/support/step_definitions/plate_steps.rb b/features/support/step_definitions/plate_steps.rb index 4ce301e7ea..adf7bd7050 100644 --- a/features/support/step_definitions/plate_steps.rb +++ b/features/support/step_definitions/plate_steps.rb @@ -121,6 +121,13 @@ Given /^a "([^"]+)" plate called "([^"]+)" exists$/ do |name, plate_name| plate_purpose = PlatePurpose.find_by!(name: name) + # binding.pry + plate_purpose.create!(name: plate_name) +end + +Given /^a "([^"]+)" input plate called "([^"]+)" exists$/ do |name, plate_name| + plate_purpose = PlatePurpose.find_by!(name: name) + # binding.pry plate_purpose.create!(name: plate_name) end diff --git a/features/support/step_definitions/tag_layout_steps.rb b/features/support/step_definitions/tag_layout_steps.rb index b2c4798335..e4f8512742 100644 --- a/features/support/step_definitions/tag_layout_steps.rb +++ b/features/support/step_definitions/tag_layout_steps.rb @@ -54,12 +54,12 @@ def plate_view_of_oligos(label, mapping) # rubocop:todo Metrics/AbcSize def check_tag_layout(name, well_range, expected_wells_to_oligos) # rubocop:todo Metrics/MethodLength plate = Plate.find_by(name: name) or raise StandardError, "Cannot find plate #{name.inspect}" + wells_to_oligos = plate .wells .filter_map do |w| next unless well_range.include?(w) - [w.map.description, w.primary_aliquot.try(:tag).try(:oligo) || ''] end .to_h @@ -112,27 +112,53 @@ def check_tag2_layout(name, well_range, expected_wells_to_oligos) # rubocop:todo set_uuid_for(TagLayout.find(id).plate, uuid_value) end +# Pooling from source plate ("Testing the API") to destination plate ("Testing the tagging") with a specified pooling +# strategy +# # rubocop:todo Metrics/MethodLength def pool_by_strategy(source, destination, pooling_strategy) # rubocop:todo Metrics/AbcSize unless pooling_strategy.sum == source.size Rails.logger.info("Pooling strategy does not fit plate size #{source.size}: #{pooling_strategy.inspect}") end + + # Column major: reads columns from left to right, top to bottom + # Row major: reads rows from top to bottom, left to right + # For example, a 96-well plate would be read as: A1, B1, C1, D1, E1, F1, G1, H1, A2, B2, C2, D2, E2, F2, G2, H2, ... source_wells = source.wells.in_column_major_order.to_a destination_wells = destination.wells.in_column_major_order.to_a pooling_strategy.each_with_index do |pool, _old_submission_id| - submission_id = Submission.create!(user: User.first || User.create!(login: 'a')).id + # This will generate a new submission for each pool. So the number of submissions will be equal to the number of + # pools. For example, for a pooling strategy of [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], there will be 12 submissions. + submission = Submission.create!(user: User.first || User.create!(login: 'a')) + submission_id = submission.id + # Slice operation cuts the array in place (i.e., removes the elements cut from the well array), + # so we need to assign the result to a new variable wells_for_source, wells_for_destination = source_wells.slice!(0, pool), destination_wells.slice!(0, pool) wells_for_source .zip(wells_for_destination) .each do |w| + # Because of the way we use zip w.first would be the source, w.last would be the destination + # This is the transfer request that would be created by the API. + # Note that transfer request behavior not used for input plates. For input plates, it is overridden + # to use requests (see app/models/well.rb:120). + # Creating TransferRequests invokes a callback that transfers aliquots from source to destination wells. TransferRequest.create!(asset: w.first, target_asset: w.last, submission_id: submission_id) + # This request is for the source plate. FactoryBot.create :request_without_submission, asset: w.first, target_asset: w.last, submission_id: submission_id end end + + # Create a request for each well in the destination plate + # This is required for input plates + if destination.purpose.is_a?(PlatePurpose::Input) + destination.wells.each do |well| + FactoryBot.create(:customer_request, asset: well, sti_type: 'Request::LibraryCreation', state: 'pending') + end + end end # rubocop:enable Metrics/MethodLength # This fakes out the transfers so that they look like they came from different submissions, effectively meaning diff --git a/spec/support/download_helper.rb b/spec/support/download_helper.rb index f9af020af6..c5dc2c49ac 100644 --- a/spec/support/download_helper.rb +++ b/spec/support/download_helper.rb @@ -14,7 +14,6 @@ def self.downloads end def self.downloaded_file(file, timeout: TIMEOUT) - # binding.pry wait_for_download(file, timeout) File.read(path_to(file)) ensure