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

And 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

convert_labware_to_receptacle_for, find_by_id_or_name, find_by_id_or_name!

Methods included from Squishify

extended

Methods included from Warren::BroadcastMessages

#broadcast, included, #queue_associated_for_broadcast, #queue_for_broadcast, #warren

Instance Attribute Details

#asset_input_methodsObject


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

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


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

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


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

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

#request_type_ids_listObject


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

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


261
262
263
264
265
266
267
# File 'app/models/order.rb', line 261

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

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

#all_assetsObject


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

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

#all_samplesObject


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

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

#asset_uuidsObject


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

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

#assets=(assets_to_add) ⇒ Object


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

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

#building?Boolean

Are we still able to modify this instance?

Returns:

  • (Boolean)

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

def building?
  submission.nil?
end

#building_submission?Boolean

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

Returns:

  • (Boolean)

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

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

#collect_gigabases_expected?Boolean

Returns:

  • (Boolean)

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

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

#complete_buildingObject


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

def complete_building
  check_project_details!
  complete_building_asset_group
end

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


171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'app/models/order.rb', line 171

def create_request_of_type!(request_type, attributes = {})
  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?
      raise AssetTypeError, 'Asset type does not match that expected by request type.' unless asset_applicable_to_type?(
        request_type, request.asset
      )
    end
  end
end

#cross_compatible?Boolean

Returns:

  • (Boolean)

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

def cross_compatible?
  false
end

#cross_project_allowedObject


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

def cross_project_allowed
  false
end

#cross_study_allowedObject


126
127
128
# File 'app/models/order.rb', line 126

def cross_study_allowed
  false
end

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

Yields:

  • (matching_samples, matching_orders, matching_submissions)

190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'app/models/order.rb', line 190

def duplicates_within(timespan)
  matching_orders = Order.containing_samples(all_samples)
                         .where(template_name: template_name)
                         .includes(:submission, assets: :samples)
                         .where.not(orders: { id: 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


232
233
234
# File 'app/models/order.rb', line 232

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

#friendly_nameObject


269
270
271
# File 'app/models/order.rb', line 269

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

#generate_broadcast_eventObject


277
278
279
# File 'app/models/order.rb', line 277

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

#json_rootObject


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

def json_root
  'order'
end

#multiplexed?Boolean

Returns:

  • (Boolean)

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

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

#multiplier_for(request_type_id) ⇒ Object


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

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


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

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


286
287
288
# File 'app/models/order.rb', line 286

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

#on_delete_destroy_submissionObject


115
116
117
118
119
120
121
122
123
124
# File 'app/models/order.rb', line 115

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.


228
229
230
# File 'app/models/order.rb', line 228

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.


140
141
142
143
# File 'app/models/order.rb', line 140

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

#sequencing_order?Boolean

Returns true if this is an order for sequencing

Returns:

  • (Boolean)

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

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

#study_is_activeObject


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

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

#subject_typeObject


273
274
275
# File 'app/models/order.rb', line 273

def subject_type
  'order'
end