Class: Order
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
Submission::ProjectValidation::Error
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
included, #request_options=
#checking_project?, included, #save_after_unmarshalling, #submittable?, #validating?
#complete_building_asset_group, included
included, #unsaved_uuid!, #uuid
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
#info_differential=(value) ⇒ Object
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
|
Return the list of input fields to edit when creating a new submission
Unless you are doing something fancy, fall back on the defaults
266
267
268
|
# File 'app/models/order.rb', line 266
def input_field_infos
@input_field_infos ||= FieldInfo.for_request_types(request_types_list.flatten)
end
|
#request_type_ids_list ⇒ Object
231
232
233
|
# File 'app/models/order.rb', line 231
def request_type_ids_list
@request_type_ids_list ||= [[]]
end
|
Class Method Details
.render_class ⇒ Object
100
101
102
|
# File 'app/models/order.rb', line 100
def render_class
Api::OrderIo
end
|
Instance Method Details
289
290
291
292
293
294
295
296
|
# File 'app/models/order.rb', line 289
def (, user)
update!(comments: [, ].compact.join('; '))
submission
.requests
.for_order_including_submission_based_requests(self)
.map { |request| request.(, user) }
end
|
#all_assets ⇒ Object
158
159
160
161
|
# File 'app/models/order.rb', line 158
def all_assets
pull_assets_from_asset_group if assets.empty? && asset_group.present?
assets
end
|
#all_samples ⇒ Object
153
154
155
156
|
# File 'app/models/order.rb', line 153
def all_samples
all_assets.map(&:samples).flatten.uniq
end
|
#asset_uuids ⇒ Object
167
168
169
|
# File 'app/models/order.rb', line 167
def asset_uuids
assets&.select(&:present?)&.map(&:uuid)
end
|
#assets=(assets_to_add) ⇒ Object
114
115
116
|
# File 'app/models/order.rb', line 114
def assets=(assets_to_add)
super(assets_to_add.map { |a| a.is_a?(Receptacle) ? a : a.receptacle })
end
|
#autodetection_default ⇒ Object
105
106
107
|
# File 'app/models/order.rb', line 105
def autodetection_default
false
end
|
#building? ⇒ Boolean
Are we still able to modify this instance?
276
277
278
|
# File 'app/models/order.rb', line 276
def building?
submission.nil?
end
|
#building_submission? ⇒ Boolean
We can't destroy orders once the submission has been finalized for building
119
120
121
|
# File 'app/models/order.rb', line 119
def building_submission?
throw :abort unless submission.building?
end
|
Determines and returns calculated request metadata based on the request type key.
This is to cover calculated metadata that does not require user input
181
182
183
184
185
186
187
188
189
190
|
# File 'app/models/order.rb', line 181
def calculated_request_metadata_by_request_key(request_type_key)
case request_type_key
when 'limber_scrna_core_cdna_prep_gem_x_5p'
request_options['allowance_band'].present? ? { 'allowance_band' => request_options['allowance_band'] } : {}
else
{}
end
end
|
#collect_gigabases_expected? ⇒ Boolean
285
286
287
|
# File 'app/models/order.rb', line 285
def collect_gigabases_expected?
input_field_infos.any? { |k| k.key == :gigabases_expected }
end
|
#complete_building ⇒ Object
109
110
111
112
|
# File 'app/models/order.rb', line 109
def complete_building
check_project_details!
complete_building_asset_group
end
|
#create_request_of_type!(request_type, attributes = {}) ⇒ Object
rubocop:todo Metrics/MethodLength
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
# File 'app/models/order.rb', line 193
def create_request_of_type!(request_type, attributes = {}) request_metadata = request_type.(request_options)
request_metadata = request_metadata.merge(calculated_request_metadata_by_request_key(request_type.key))
request_type.create!(attributes) do |request|
request.submission_id = submission_id
request.study = study
request.initial_project = project
request.user = user
request.request_metadata_attributes = request_metadata
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
142
143
144
|
# File 'app/models/order.rb', line 142
def cross_compatible?
false
end
|
#cross_project_allowed ⇒ Object
138
139
140
|
# File 'app/models/order.rb', line 138
def cross_project_allowed
false
end
|
#cross_study_allowed ⇒ Object
134
135
136
|
# File 'app/models/order.rb', line 134
def cross_study_allowed
false
end
|
#duplicates_within(timespan) {|matching_samples, matching_orders, matching_submissions| ... } ⇒ Object
rubocop:enable Metrics/MethodLength
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'app/models/order.rb', line 215
def duplicates_within(timespan) 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_type ⇒ Object
260
261
262
|
# File 'app/models/order.rb', line 260
def first_request_type
@first_request_type ||= RequestType.find(request_types.first)
end
|
#friendly_name ⇒ Object
298
299
300
|
# File 'app/models/order.rb', line 298
def friendly_name
asset_group.try(:name) || asset_group_name || id
end
|
#generate_broadcast_event ⇒ Object
306
307
308
|
# File 'app/models/order.rb', line 306
def generate_broadcast_event
BroadcastEvent::OrderMade.create!(seed: self, user: user)
end
|
#json_root ⇒ Object
163
164
165
|
# File 'app/models/order.rb', line 163
def json_root
'order'
end
|
#multiplexed? ⇒ Boolean
171
172
173
|
# File 'app/models/order.rb', line 171
def multiplexed?
RequestType.where(id: request_types).for_multiplexing.exists?
end
|
#multiplier_for(request_type_id) ⇒ Object
175
176
177
|
# File 'app/models/order.rb', line 175
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
270
271
272
273
|
# File 'app/models/order.rb', line 270
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_samples ⇒ Object
returns an array of samples, that potentially can not be included in submission
315
316
317
|
# File 'app/models/order.rb', line 315
def not_ready_samples
all_samples.reject(&:can_be_included_in_submission?)
end
|
#on_delete_destroy_submission ⇒ Object
123
124
125
126
127
128
129
130
131
132
|
# File 'app/models/order.rb', line 123
def on_delete_destroy_submission
if building_submission?
orders = submission.orders
submission.destroy unless orders.size > 1
return true
end
false
end
|
#project_not_set ⇒ Object
67
68
69
|
# File 'app/models/order.rb', line 67
def project_not_set
project.blank?
end
|
#request_types_list ⇒ Object
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.
256
257
258
|
# File 'app/models/order.rb', line 256
def request_types_list
request_type_ids_list.map { |ids| RequestType.find(ids) }
end
|
#samples ⇒ Object
TODO: Figure out why eager loading aliquots/samples returns [] even when
we limit order_assets to receptacles.
148
149
150
151
|
# File 'app/models/order.rb', line 148
def samples
assets.map(&:samples).flatten.uniq
end
|
#sequencing_order? ⇒ Boolean
Returns true if this is an order for sequencing
281
282
283
|
# File 'app/models/order.rb', line 281
def sequencing_order?
RequestType.find(request_types).any?(&:sequencing?)
end
|
#study_is_active ⇒ Object
310
311
312
|
# File 'app/models/order.rb', line 310
def study_is_active
errors.add(:study, 'is not active') if study.present? && !study.active?
end
|
#subject_type ⇒ Object
302
303
304
|
# File 'app/models/order.rb', line 302
def subject_type
'order'
end
|