Class: SampleManifest

Inherits:
ApplicationRecord show all
Extended by:
Document::Associations, StateMachine
Includes:
ModelExtensions::SampleManifest, BarcodePrinterBehaviour, CoreBehaviour, Uuid::Uuidable
Defined in:
app/models/sample_manifest.rb

Overview

A SampleManifest is the primary way in which new samples enter Sequencescape. When the manifest is generated Sequencescape registers the labware, and reserves a series of Sanger sample ids for the potential samples. It also generates a SampleManifestExcel spreadsheet which gets sent to the customer.

The labware that gets generate is determined by the #asset_type which switches out the CoreBehaviour#core_behaviour module CoreBehaviour. This is concerned with generating Labware and receptacles, generating any event specific to the asset type, and setting manifest specific properties on Aliquot

All samples in a given manifest will initially belong to a single Study, although it is possible for them to become associated with additional studies over time.

Defined Under Namespace

Modules: Associations, BarcodePrinterBehaviour, CoreBehaviour, LibraryPlateBehaviour, LibraryTubeBehaviour, MultiplexedLibraryBehaviour, PlateBehaviour, SampleTubeBehaviour, SharedTubeBehaviour, StateMachine, TubeRackBehaviour, UnspecifiedBehaviour Classes: Generator, Uploader

Constant Summary collapse

LIMIT_ERROR_LENGTH =

While the maximum length of the column is 65536 we place a shorter restriction to allow for: 1) Subsequent serialization by the delayed job 2) The addition of a 'too many errors' message

50_000
INDIVIDUAL_ERROR_LIMIT =

In addition we truncate individual messages, this ensures that we don't inadvertently filter out ALL our errors if the first message is especially long. We don't re-use the figure above as that would prevent any display of subsequent messages, which probably indicate a different issue.

LIMIT_ERROR_LENGTH / 10
SAMPLES_PER_EVENT =

Samples have a similar issue when generating update events This limit sets a very comfortable safety margin.

3000

Constants included from CoreBehaviour

CoreBehaviour::BEHAVIOURS

Constants included from BarcodePrinterBehaviour

BarcodePrinterBehaviour::ASSET_TYPE_TO_PRINTER_TYPE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from StateMachine

extended

Methods included from Document::Associations

has_uploaded_document

Methods included from CoreBehaviour

#core_behaviour, included

Methods included from BarcodePrinterBehaviour

#applicable_barcode_printers

Methods included from Uuid::Uuidable

included, #unsaved_uuid!, #uuid

Methods inherited from ApplicationRecord

convert_labware_to_receptacle_for, find_by_id_or_name, find_by_id_or_name!

Methods included from Squishify

extended

Instance Attribute Details

#only_first_labelObject

Returns the value of attribute only_first_label.


51
52
53
# File 'app/models/sample_manifest.rb', line 51

def only_first_label
  @only_first_label
end

#overrideObject

Returns the value of attribute override.


51
52
53
# File 'app/models/sample_manifest.rb', line 51

def override
  @override
end

Instance Method Details

#barcode_printerObject

Needed for the UI to work!


59
# File 'app/models/sample_manifest.rb', line 59

def barcode_printer; end

#create_sample(sanger_sample_id) ⇒ Object


169
170
171
172
173
# File 'app/models/sample_manifest.rb', line 169

def create_sample(sanger_sample_id)
  Sample
    .create!(name: sanger_sample_id, sanger_sample_id: sanger_sample_id, sample_manifest: self)
    .tap { |sample| sample.events.created_using_sample_manifest!(user) }
end

#create_sample_and_aliquot(sanger_sample_id, asset) ⇒ Object


165
166
167
# File 'app/models/sample_manifest.rb', line 165

def create_sample_and_aliquot(sanger_sample_id, asset)
  core_behaviour.generate_sample_and_aliquot(sanger_sample_id, asset)
end

#created_broadcast_eventObject


175
176
177
# File 'app/models/sample_manifest.rb', line 175

def created_broadcast_event
  BroadcastEvent::SampleManifestCreated.create!(seed: self, user: user)
end

#default_asset_typeObject


121
122
123
# File 'app/models/sample_manifest.rb', line 121

def default_asset_type
  self.asset_type = 'plate' if asset_type.blank?
end

#default_filenameObject


129
130
131
# File 'app/models/sample_manifest.rb', line 129

def default_filename
  "#{study_id}stdy_manifest_#{id}_#{created_at.to_formatted_s(:dmy)}"
end

#find_or_create_qc_assay!Object

rubocop:disable Naming/MemoizedInstanceVariableName


227
228
229
# File 'app/models/sample_manifest.rb', line 227

def find_or_create_qc_assay!
  @qc_assay ||= QcAssay.find_or_create_by!(lot_number: "sample_manifest_id:#{id}")
end

#generateObject


156
157
158
159
160
161
162
163
# File 'app/models/sample_manifest.rb', line 156

def generate
  ActiveRecord::Base.transaction do
    self.barcodes = []
    core_behaviour.generate
  end
  created_broadcast_event
  nil
end

#indexed_manifest_assetsObject


193
194
195
# File 'app/models/sample_manifest.rb', line 193

def indexed_manifest_assets
  sample_manifest_assets.includes(*core_behaviour.included_resources).index_by(&:sanger_sample_id)
end

#nameObject


125
126
127
# File 'app/models/sample_manifest.rb', line 125

def name
  "Manifest_#{id}"
end

#purposeObject

Fall back to stock plate by default


204
205
206
# File 'app/models/sample_manifest.rb', line 204

def purpose
  super || default_purpose
end

#purpose_idObject


208
209
210
# File 'app/models/sample_manifest.rb', line 208

def purpose_id
  super || purpose.id
end

#qc_assayObject

Upon upload, sample manifests might generate qc_results for certain specialised fields. We want to keep one qc_assay per sample manifest.


222
223
224
# File 'app/models/sample_manifest.rb', line 222

def qc_assay
  @qc_assay ||= QcAssay.find_by(lot_number: "sample_manifest_id:#{id}")
end

#templateObject


61
# File 'app/models/sample_manifest.rb', line 61

def template; end

#truncate_errorsObject

rubocop:todo Metrics/MethodLength


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/models/sample_manifest.rb', line 100

def truncate_errors # rubocop:todo Metrics/MethodLength
  if last_errors && last_errors.join.length > LIMIT_ERROR_LENGTH
    # First we truncate individual error messages. This ensures that it the first message is already
    # longer than out max limit, we still show something.
    full_last_errors = last_errors.map { |error| error.truncate(INDIVIDUAL_ERROR_LIMIT) }

    removed_errors = 0

    while full_last_errors.join.length > LIMIT_ERROR_LENGTH
      full_last_errors.pop
      removed_errors += 1
    end

    if removed_errors.positive?
      full_last_errors << "There were too many errors to record. #{removed_errors} additional errors are not shown."
    end

    self.last_errors = full_last_errors
  end
end

#tube_rack_purposeObject


212
213
214
# File 'app/models/sample_manifest.rb', line 212

def tube_rack_purpose
  super || default_tube_rack_purpose
end

#tube_rack_purpose_idObject


216
217
218
# File 'app/models/sample_manifest.rb', line 216

def tube_rack_purpose_id
  super || tube_rack_purpose.id
end

#update_barcodesObject

updates the manifest barcode list e.g. after applying a foreign barcode


198
199
200
201
# File 'app/models/sample_manifest.rb', line 198

def update_barcodes
  self.barcodes = labware.map(&:human_barcode)
  save!
end

#updated_broadcast_event(user_updating_manifest, updated_samples_ids) ⇒ Object


179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'app/models/sample_manifest.rb', line 179

def updated_broadcast_event(user_updating_manifest, updated_samples_ids)
  # We chunk samples into groups of 3000 to avoid issues with the column size in broadcast_events.properties
  # In practice we have 11 characters per sample with current id lengths. This allows for up to 21 characters
  updated_samples_ids.each_slice(SAMPLES_PER_EVENT) do |chunked_sample_ids|
    BroadcastEvent::SampleManifestUpdated.create!(
      seed: self,
      user: user_updating_manifest,
      properties: {
        updated_samples_ids: chunked_sample_ids
      }
    )
  end
end