Class: Request

Inherits:
ApplicationRecord show all
Extended by:
EventfulRecord, Metadata, Statistics
Includes:
AASM, AASM::Extensions, Aliquot::DeprecatedBehaviours::Request, Api::RequestIO::Extensions, Batch::RequestBehaviour, Commentable, ModelExtensions::Request, CustomerResponsibility, Statemachine, StandardNamedScopes, Uuid::Uuidable
Defined in:
app/models/request.rb,
app/models/request/traction.rb,
app/models/request/traction/grid_ion.rb

Overview

A Request represents work which needs to be done, either to fulfil a customers needs CustomerRequest or for internal reasons SystemRequest. The progress of a request is tracked through its state machine.

Direct Known Subclasses

CustomerRequest, SystemRequest

Defined Under Namespace

Modules: AccessioningRequired, CustomerResponsibility, GroupingHelpers, HasNoTargetAsset, HasPrimerPanel, LibraryManufacture, Statemachine, Statistics, Traction Classes: AutoMultiplexing, ChangeDecision, LibraryCreation, Multiplexing, None

Constant Summary

Constants included from Metadata

Metadata::SECTION_FIELDS

Constants included from Statemachine

Statemachine::ACTIVE, Statemachine::COMPLETED_STATE, Statemachine::INACTIVE, Statemachine::OPENED_STATE, Statemachine::SORT_ORDER

Constants included from StandardNamedScopes

StandardNamedScopes::SORT_FIELDS, StandardNamedScopes::SORT_ORDERS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Metadata

has_metadata

Methods included from EventfulRecord

has_many_events, has_many_lab_events, has_one_event_with_family

Methods included from Statistics

asset_statistics, progress_statistics, sample_statistics_new

Methods included from CustomerResponsibility

included

Methods included from Batch::RequestBehaviour

included, #recycle_from_batch!, #return_for_inbox!, #with_batch_id

Methods included from Statemachine

#cancellable?, #change_decision!, #closed?, #failed_downstream!, #failed_upstream!, #finished?, #on_blocked, #on_cancelled, #on_failed, #on_hold, #on_passed, #on_started, #open?, #terminated?, #transfer_aliquots

Methods included from StandardNamedScopes

included

Methods included from Commentable

#after_comment_addition

Methods included from AASM::Extensions

#transition_to

Methods included from Uuid::Uuidable

included, #unsaved_uuid!, #uuid

Methods included from Api::RequestIO::Extensions

included, #json_root

Methods included from Aliquot::DeprecatedBehaviours::Request

#sample_name, #tag, #tag_number

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

Class Method Details

.accessioning_required?Boolean

Returns:

  • (Boolean)

316
317
318
# File 'app/models/request.rb', line 316

def self.accessioning_required?
  false
end

.delegate_validatorObject


304
305
306
# File 'app/models/request.rb', line 304

def self.delegate_validator
  DelegateValidation::AlwaysValidValidator
end

.for_study(study) ⇒ Object


308
309
310
# File 'app/models/request.rb', line 308

def self.for_study(study)
  Request.for_study_id(study.id)
end

.number_expected_for_submission_id_and_request_type_id(submission_id, request_type_id) ⇒ Object


312
313
314
# File 'app/models/request.rb', line 312

def self.number_expected_for_submission_id_and_request_type_id(submission_id, request_type_id)
  Request.where(submission_id: submission_id, request_type_id: request_type_id)
end

Instance Method Details

#add_comment(comment, user, title = nil) ⇒ Object


475
476
477
# File 'app/models/request.rb', line 475

def add_comment(comment, user, title = nil)
  comments.create(description: comment, user: user, title: title)
end

#aliquot_attributesHash

Passed into cloned aliquots at the beginning of a pipeline to set appropriate options

Returns:

  • (Hash)

    A hash of aliquot attributes


395
396
397
398
399
400
401
# File 'app/models/request.rb', line 395

def aliquot_attributes
  {
    study_id: initial_study_id,
    project_id: initial_project_id,
    request_id: id
  }
end

#associated_studiesObject


380
381
382
383
384
385
386
# File 'app/models/request.rb', line 380

def associated_studies
  return [initial_study] if initial_study.present?
  return asset.studies.uniq if asset.present?
  return submission.studies if submission.present?

  []
end

#billing_product_identifierObject


550
# File 'app/models/request.rb', line 550

def billing_product_identifier; end

#cancelable?Boolean

Returns:

  • (Boolean)

499
500
501
# File 'app/models/request.rb', line 499

def cancelable?
  batch_request.nil? && (pending? || blocked?)
end

#copyObject


495
496
497
# File 'app/models/request.rb', line 495

def copy
  RequestFactory.copy_request(self)
end

#current_request_eventObject


336
337
338
339
340
341
342
# File 'app/models/request.rb', line 336

def current_request_event
  if request_events.loaded?
    request_events.detect(&:current?)
  else
    request_events.current.last
  end
end

#customer_accepts_responsibility!Object


516
517
518
# File 'app/models/request.rb', line 516

def customer_accepts_responsibility!
  # Do nothing
end

#event_value_for(name, batch = nil) ⇒ Object


420
421
422
423
424
# File 'app/models/request.rb', line 420

def event_value_for(name, batch = nil)
  list = (batch.present? ? lab_events_for_batch(batch) : lab_events)
  list.each { |event| desc = event.descriptor_value_for(name) and return desc }
  ''
end

#event_with_key_value(k, v = nil) ⇒ Object


438
439
440
# File 'app/models/request.rb', line 438

def event_with_key_value(k, v = nil)
  v.nil? ? false : lab_events.with_descriptor(k, v).first
end

#eventful_studiesObject


332
333
334
# File 'app/models/request.rb', line 332

def eventful_studies
  initial_study.present? ? [initial_study] : asset_studies
end

#format_qc_informationObject


483
484
485
486
487
488
489
490
491
492
493
# File 'app/models/request.rb', line 483

def format_qc_information
  return [] if lab_events.empty?

  events.map do |event|
    next if event.family.nil? || %w[pass fail].exclude?(event.family.downcase)

    message = event.message.presence || '(No message was specified)'
    { 'event_id' => event.id, 'status' => event.family.downcase, 'message' => message,
      'created_at' => event.created_at }
  end.compact
end

#get_value(request_information_type) ⇒ Object


403
404
405
406
407
408
409
410
# File 'app/models/request.rb', line 403

def get_value(request_information_type)
  return '' unless .respond_to?(request_information_type.key)

  value = .send(request_information_type.key)
  return value.to_s if value.blank? || (request_information_type.data_type != 'Date')

  value.to_date.strftime('%d %B %Y')
end

#has_passed(batch, task) ⇒ Object


426
427
428
# File 'app/models/request.rb', line 426

def has_passed(batch, task)
  lab_events_for_batch(batch).any? { |event| event.description == task.name }
end

#lab_events_for_batch(batch) ⇒ Object


430
431
432
433
434
435
436
# File 'app/models/request.rb', line 430

def lab_events_for_batch(batch)
  if lab_events.loaded?
    lab_events.select { |le| le.batch_id == batch.id }
  else
    lab_events.where(batch_id: batch.id)
  end
end

#manifest_processed!Object


548
# File 'app/models/request.rb', line 548

def manifest_processed!; end

#next_request_type_idObject


448
449
450
451
452
453
# File 'app/models/request.rb', line 448

def next_request_type_id
  # May be nil, so can't use lazy assignment
  return @next_request_type_id if instance_variable_defined?('@next_request_type_id')

  @next_request_type_id = calculate_next_request_type_id
end

#next_requestsObject


442
443
444
445
446
# File 'app/models/request.rb', line 442

def next_requests
  return [] if submission.nil? || next_request_type_id.nil?

  next_requests_via_asset || next_requests_via_submission
end

#next_requests_via_assetObject

CAUTION!: This may not behaves as expected. I'll be deprecating this soon.


456
457
458
459
460
461
# File 'app/models/request.rb', line 456

def next_requests_via_asset
  if target_asset.present?
    target_asset.requests.where(submission_id: submission_id,
                                request_type_id: next_request_type_id)
  end
end

#next_requests_via_submissionObject


463
464
465
# File 'app/models/request.rb', line 463

def next_requests_via_submission
  submission.next_requests_via_submission(self)
end

#previous_failed_requests?Boolean

Returns:

  • (Boolean)

471
472
473
# File 'app/models/request.rb', line 471

def previous_failed_requests?
  asset.requests.any?(&:failed?)
end

#priorityObject


508
509
510
# File 'app/models/request.rb', line 508

def priority
  submission.try(:priority) || 0
end

#product_lineObject


544
545
546
# File 'app/models/request.rb', line 544

def product_line
  _product_line&.name
end

#project=(project) ⇒ Object


362
363
364
365
366
# File 'app/models/request.rb', line 362

def project=(project)
  return unless project

  self.project_id = project.id
end

#project_id=(project_id) ⇒ Object

Raises:

  • (RuntimeError)

344
345
346
347
348
# File 'app/models/request.rb', line 344

def project_id=(project_id)
  raise RuntimeError, 'Initial project already set' if initial_project_id

  self.initial_project_id = project_id
end

#ready?Boolean

Returns:

  • (Boolean)

536
537
538
# File 'app/models/request.rb', line 536

def ready?
  true
end

#request_type_updatable?(_new_request_type) ⇒ Boolean

Returns:

  • (Boolean)

512
513
514
# File 'app/models/request.rb', line 512

def request_type_updatable?(_new_request_type)
  pending?
end

#return_pending_to_inbox!Object

Raises:

  • (StandardError)

479
480
481
# File 'app/models/request.rb', line 479

def return_pending_to_inbox!
  raise StandardError, "Can only return pending requests, request is #{state}" unless pending?
end

#run_eventsObject


320
321
322
323
324
325
326
# File 'app/models/request.rb', line 320

def run_events
  if events.loaded?
    events.select { |e| e.message.starts_with?('Run') }
  else
    where('message LIKE "Run%"')
  end
end

#source_labwareObject


328
329
330
# File 'app/models/request.rb', line 328

def source_labware
  asset.labware
end

#study=(study) ⇒ Object


374
375
376
377
378
# File 'app/models/request.rb', line 374

def study=(study)
  return unless study

  self.study_id = study.id
end

#study_id=(study_id) ⇒ Object

Raises:

  • (RuntimeError)

368
369
370
371
372
# File 'app/models/request.rb', line 368

def study_id=(study_id)
  raise RuntimeError, 'Initial study already set' if initial_study_id

  self.initial_study_id = study_id
end

#submission_plate_countObject


350
351
352
353
354
355
356
# File 'app/models/request.rb', line 350

def submission_plate_count
  submission.requests
            .where(request_type_id: request_type_id)
            .joins(:source_labware)
            .distinct
            .count('labware.id')
end

#submitted_atObject

The date at which the submission was made. In most cases this will be similar to the request's created_at timestamp. We go via submission to ensure that copied requests bear the original timestamp.


528
529
530
531
532
533
534
# File 'app/models/request.rb', line 528

def 
  # Hopefully we shouldn't get any requests that don't have a submission. But validation is turned off, so
  # we should assume it it possible.
  return '' if submission.nil?

  submission.created_at.strftime('%Y-%m-%d')
end

#target_purposeObject


540
541
542
# File 'app/models/request.rb', line 540

def target_purpose
  nil
end

#target_tubeObject


467
468
469
# File 'app/models/request.rb', line 467

def target_tube
  target_asset if target_asset.is_a?(Tube)
end

#update_pool_information(pool_information) ⇒ Object

Adds any pool information to the structure so that it can be reported to client applications


521
522
523
524
# File 'app/models/request.rb', line 521

def update_pool_information(pool_information)
  pool_information[:request_type] = request_type.key
  pool_information[:for_multiplexing] = request_type.for_multiplexing?
end

#update_priorityObject


503
504
505
506
# File 'app/models/request.rb', line 503

def update_priority
  priority = (self.priority + 1) % 4
  submission.update!(priority: priority)
end

#update_responsibilities!Object


358
359
360
# File 'app/models/request.rb', line 358

def update_responsibilities!
  # Do nothing
end

#value_for(name, batch = nil) ⇒ Object


412
413
414
415
416
417
418
# File 'app/models/request.rb', line 412

def value_for(name, batch = nil)
  rit = RequestInformationType.find_by(name: name)
  rit_value = get_value(rit) if rit.present?
  return rit_value if rit_value.present?

  event_value_for(name, batch)
end