sanger/limber

View on GitHub
app/models/labware_creators/pooled_tubes_base.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
93%
# frozen_string_literal: true

module LabwareCreators
  # Creates a new tube per pool, and transfers from wells into that pool
  # Leaves the pooling logic - allocation of wells to pools - to subclasses to implement
  # TODO: transfer_request_attributes currently assumes the pool identifier is
  # the submission uuid - this should be changed
  class PooledTubesBase < Base
    include SupportParent::TaggedPlateOnly

    include LabwareCreators::SupportV2SourcePlate

    attr_reader :tube_transfer, :child_stock_tubes
    attr_writer :metadata_stock_barcode

    def create_labware!
      @child_stock_tubes = create_child_stock_tubes
      perform_transfers
      true
    end

    def create_child_stock_tubes
      api
        .specific_tube_creation
        .create!(
          user: user_uuid,
          parent: parent_uuid,
          child_purposes: [purpose_uuid] * pool_uuids.length,
          tube_attributes: tube_attributes
        )
        .children
        .index_by(&:name)
    end

    def perform_transfers
      api.transfer_request_collection.create!(user: user_uuid, transfer_requests: transfer_request_attributes)
    end

    def transfer_request_attributes
      pools.each_with_object([]) do |(pool_identifier, pool), transfer_requests|
        # this currently assumes that pool_identifier will be the submission_uuid
        # (it would have always been, historically)
        pool.each do |location|
          transfer_requests <<
            request_hash(
              well_locations.fetch(location).uuid,
              child_stock_tubes.fetch(name_for(pool)).uuid,
              pool_identifier
            )
        end
      end
    end

    def request_hash(source, target, submission)
      { 'source_asset' => source, 'target_asset' => target, 'submission' => submission }
    end

    def pool_uuids
      pools.keys
    end

    # We may create multiple tubes, so cant redirect onto any particular
    # one. Redirecting back to the parent is a little grim, so we'll need
    # to come up with a better solution.
    # 1) Redirect to the transfer/creation and list the tubes that way
    # 2) Once tube racks are implemented, we can redirect there.
    def redirection_target
      parent
    end

    def anchor
      'relatives_tab'
    end

    private

    def tube_attributes
      pools.values.map { |pool_details| { name: name_for(pool_details) } }
    end

    def name_for(pool_details)
      first, last = WellHelpers.first_and_last_in_columns(pool_details)
      "#{stock_plate_barcode} #{first}:#{last}"
    end

    def legacy_barcode
      ("#{parent.stock_plate.barcode.prefix}#{parent.stock_plate.barcode.number}" if parent.stock_plate) || nil
    end

    def stock_plate_barcode
      metadata_stock_barcode || legacy_barcode
    end

    def metadata_stock_barcode
      @metadata_stock_barcode ||= parent_metadata.fetch('stock_barcode', nil)
    end

    def parent_metadata
      if source_plate
        LabwareMetadata.new(labware: source_plate).metadata
      else
        LabwareMetadata.new(barcode: parent.barcode.machine).metadata
      end || {}
    end

    # Maps well locations to the corresponding uuid
    #
    # @return [Hash] Hash with well locations (eg. 'A1') as keys, and uuids as values
    def well_locations
      @well_locations ||= parent.wells.index_by(&:location)
    end

    # pools should return a hash of pools with the following minimal information
    # { 'unique-pool-identifier' => <Array of well locations> }
    #
    # @return [<type>] <description>
    #
    def pools
      raise '#pools must be implemented on subclasses'
    end
  end
end