Class: Order

Inherits:
ApplicationRecord show all
Includes:
ModelExtensions::Order, Submission::AccessionBehaviour, Submission::AssetGroupBehaviour, Submission::ProjectValidation, Submission::RequestOptionsBehaviour, Uuid::Uuidable
Defined in:
app/models/order.rb

Overview

An Order is used as the main means of requesting work in Sequencescape. Its key components are: Assets/AssetGroup: The assets on which the work will be conducted Study: The study for which work is being undertaken Project: The project who will be charged for the work Request options: The parameters for the request which will be built. eg. read length Request Types: An array of request type ids which will be built by the order. This is populated based on the submission template used. Submission: Multiple orders may be grouped together in a submission. This associates the two sets of requests, and is usually used to determine what gets pooled together during multiplexing. As a result, sequencing requests may be shared between multiple orders.

Constant Summary collapse

AssetTypeError =

Ensure order methods behave correctly

Class.new(StandardError)
DEFAULT_ASSET_INPUT_METHODS =
['select an asset group'].freeze

Constants included from Submission::ProjectValidation

Submission::ProjectValidation::Error

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Submission::AccessionBehaviour

#can_check_data_release_and_accession?, #check_data_release_and_accession_for_submission, included, #request_types_require_accessioning?

Methods included from Submission::RequestOptionsBehaviour

included, #request_options=

Methods included from Submission::ProjectValidation

#checking_project?, included, #save_after_unmarshalling, #submittable?, #validating?

Methods included from Submission::AssetGroupBehaviour

#complete_building_asset_group, included

Methods included from Uuid::Uuidable

included, #unsaved_uuid!, #uuid

Methods inherited from ApplicationRecord

alias_association, convert_labware_to_receptacle_for, find_by_id_or_name, find_by_id_or_name!

Methods included from Squishify

extended

Instance Attribute Details

#asset_input_methodsObject



217
218
219
# File 'app/models/order.rb', line 217

def asset_input_methods
  @asset_input_methods ||= DEFAULT_ASSET_INPUT_METHODS
end

#info_differential=(value) ⇒ Object (writeonly)

Unused. Maintained because some submission templates attempt to set the info



36
37
38
# File 'app/models/order.rb', line 36

def info_differential=(value)
  @info_differential = value
end

#input_field_infosObject

Return the list of input fields to edit when creating a new submission Unless you are doing something fancy, fall back on the defaults



248
249
250
# File 'app/models/order.rb', line 248

def input_field_infos
  @input_field_infos ||= FieldInfo.for_request_types(request_types_list.flatten)
end

#request_type_ids_listObject



213
214
215
# File 'app/models/order.rb', line 213

def request_type_ids_list
  @request_type_ids_list ||= [[]]
end

Class Method Details

.render_classObject



96
97
98
# File 'app/models/order.rb', line 96

def render_class
  Api::OrderIo
end

Instance Method Details

#add_comment(comment_str, user) ⇒ Object



271
272
273
274
275
276
277
278
# File 'app/models/order.rb', line 271

def add_comment(comment_str, user)
  update!(comments: [comments, comment_str].compact.join('; '))

  submission
    .requests
    .for_order_including_submission_based_requests(self)
    .map { |request| request.add_comment(comment_str, user) }
end

#all_assetsObject



154
155
156
157
# File 'app/models/order.rb', line 154

def all_assets
  pull_assets_from_asset_group if assets.empty? && asset_group.present?
  assets
end

#all_samplesObject



149
150
151
152
# File 'app/models/order.rb', line 149

def all_samples
  # slightly less naive way
  all_assets.map(&:samples).flatten.uniq
end

#asset_uuidsObject



163
164
165
# File 'app/models/order.rb', line 163

def asset_uuids
  assets&.select(&:present?)&.map(&:uuid)
end

#assets=(assets_to_add) ⇒ Object



110
111
112
# File 'app/models/order.rb', line 110

def assets=(assets_to_add)
  super(assets_to_add.map { |a| a.is_a?(Receptacle) ? a : a.receptacle })
end

#autodetection_defaultObject



101
102
103
# File 'app/models/order.rb', line 101

def autodetection_default
  false
end

#building?Boolean

Are we still able to modify this instance?

Returns:

  • (Boolean)


258
259
260
# File 'app/models/order.rb', line 258

def building?
  submission.nil?
end

#building_submission?Boolean

We can’t destroy orders once the submission has been finalized for building

Returns:

  • (Boolean)


115
116
117
# File 'app/models/order.rb', line 115

def building_submission?
  throw :abort unless submission.building?
end

#collect_gigabases_expected?Boolean

Returns:

  • (Boolean)


267
268
269
# File 'app/models/order.rb', line 267

def collect_gigabases_expected?
  input_field_infos.any? { |k| k.key == :gigabases_expected }
end

#complete_buildingObject



105
106
107
108
# File 'app/models/order.rb', line 105

def complete_building
  check_project_details!
  complete_building_asset_group
end

#create_request_of_type!(request_type, attributes = {}) ⇒ Object

rubocop:todo Metrics/MethodLength



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'app/models/order.rb', line 176

def create_request_of_type!(request_type, attributes = {}) # rubocop:todo Metrics/AbcSize
  em = request_type.(request_options)
  request_type.create!(attributes) do |request|
    request.submission_id = submission_id
    request.study = study
    request.initial_project = project
    request.user = user
    request. = em
    request.state = request_type.initial_state
    request.order = self

    if request.asset.present?
      unless asset_applicable_to_type?(request_type, request.asset)
        raise AssetTypeError, 'Asset type does not match that expected by request type.'
      end
    end
  end
end

#cross_compatible?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'app/models/order.rb', line 138

def cross_compatible?
  false
end

#cross_project_allowedObject



134
135
136
# File 'app/models/order.rb', line 134

def cross_project_allowed
  false
end

#cross_study_allowedObject



130
131
132
# File 'app/models/order.rb', line 130

def cross_study_allowed
  false
end

#duplicates_within(timespan) {|matching_samples, matching_orders, matching_submissions| ... } ⇒ Object

rubocop:enable Metrics/MethodLength

Yields:

  • (matching_samples, matching_orders, matching_submissions)


197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'app/models/order.rb', line 197

def duplicates_within(timespan) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
  matching_orders =
    Order
      .containing_samples(all_samples)
      .where(template_name:)
      .includes(:submission, assets: :samples)
      .where.not(orders: { id: })
      .where('orders.created_at > ?', Time.current - timespan)
  return false if matching_orders.empty?

  matching_samples = matching_orders.map(&:samples).flatten & all_samples
  matching_submissions = matching_orders.map(&:submission).uniq
  yield matching_samples, matching_orders, matching_submissions if block_given?
  true
end

#first_request_typeObject



242
243
244
# File 'app/models/order.rb', line 242

def first_request_type
  @first_request_type ||= RequestType.find(request_types.first)
end

#friendly_nameObject



280
281
282
# File 'app/models/order.rb', line 280

def friendly_name
  asset_group.try(:name) || asset_group_name || id
end

#generate_broadcast_eventObject



288
289
290
# File 'app/models/order.rb', line 288

def generate_broadcast_event
  BroadcastEvent::OrderMade.create!(seed: self, user: user)
end

#json_rootObject



159
160
161
# File 'app/models/order.rb', line 159

def json_root
  'order'
end

#multiplexed?Boolean

Returns:

  • (Boolean)


167
168
169
# File 'app/models/order.rb', line 167

def multiplexed?
  RequestType.where(id: request_types).for_multiplexing.exists?
end

#multiplier_for(request_type_id) ⇒ Object



171
172
173
# File 'app/models/order.rb', line 171

def multiplier_for(request_type_id)
  (request_options.dig(:multiplier, request_type_id.to_s) || 1).to_i
end

#next_request_type_id(request_type_id) ⇒ Object



252
253
254
255
# File 'app/models/order.rb', line 252

def next_request_type_id(request_type_id)
  request_type_ids = request_types.map(&:to_i)
  request_type_ids[request_type_ids.index(request_type_id) + 1]
end

#not_ready_samplesObject

returns an array of samples, that potentially can not be included in submission



297
298
299
# File 'app/models/order.rb', line 297

def not_ready_samples
  all_samples.reject(&:can_be_included_in_submission?)
end

#on_delete_destroy_submissionObject



119
120
121
122
123
124
125
126
127
128
# File 'app/models/order.rb', line 119

def on_delete_destroy_submission
  if building_submission?
    # After destroying an order, if it is the last order on it's submission
    # destroy the submission too.
    orders = submission.orders
    submission.destroy unless orders.size > 1
    return true
  end
  false
end

#request_types_listObject

request_type_ids_list is set for orders created by submission templates It is used by the input_field_infos section, which controls rendering form fields appropriate to each request type in the submission interface request_type_ids is calculated from this in the various sub-classes and gets persisted to the database, and used for the actual construction. TODO: Simplify this - There are a few attributes which all refer to loosely the same thing, a list of request type ids: * request_type_ids_list - Set by submission templates, but also recalculated on the fly and used in various methods * request_types_ids - Setter on order subclasses. * request_types - Serialized version on order, persisted in the database - The request_types on the database should become the authoritative source. - request_type_ids_list should just be a setter, which populates request_types. It may need to transform the input slightly. Ideally we eliminate this entirely, and be consistent between templates and orders - There appear to be several methods which essentially do the same thing. They should be unified. - I’m not even 100% how request_types_ids factors in.



238
239
240
# File 'app/models/order.rb', line 238

def request_types_list
  request_type_ids_list.map { |ids| RequestType.find(ids) }
end

#samplesObject

TODO: Figure out why eager loading aliquots/samples returns [] even when we limit order_assets to receptacles.



144
145
146
147
# File 'app/models/order.rb', line 144

def samples
  # naive way
  assets.map(&:samples).flatten.uniq
end

#sequencing_order?Boolean

Returns true if this is an order for sequencing

Returns:

  • (Boolean)


263
264
265
# File 'app/models/order.rb', line 263

def sequencing_order?
  RequestType.find(request_types).any?(&:sequencing?)
end

#study_is_activeObject



292
293
294
# File 'app/models/order.rb', line 292

def study_is_active
  errors.add(:study, 'is not active') if study.present? && !study.active?
end

#subject_typeObject



284
285
286
# File 'app/models/order.rb', line 284

def subject_type
  'order'
end