Skip to content

Commit

Permalink
Merge branch 'develop' into y24-475-bug-improve-integration-suite-uat…
Browse files Browse the repository at this point in the history
…-actions-error-message
  • Loading branch information
yoldas committed Jan 16, 2025
2 parents 9e2777b + 644d4c1 commit e324a76
Show file tree
Hide file tree
Showing 49 changed files with 2,186 additions and 317 deletions.
2 changes: 2 additions & 0 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ Metrics/AbcSize:
- 'app/controllers/api/v2/transfers_controller.rb'
- 'app/jobs/export_pool_xp_to_traction_job.rb'
- 'app/sample_manifest_excel/sample_manifest_excel/manifest_type_list.rb'
- 'spec/models/bulk_submission_scrna_spec.rb'

# Offense count: 1
# Configuration parameters: CountComments, Max, CountAsOne.
Expand Down Expand Up @@ -856,6 +857,7 @@ RSpec/LetSetup:
- 'spec/models/transfer_request_collection_spec.rb'
- 'spec/requests/api/v2/comments_spec.rb'
- 'spec/requests/api/v2/plates_spec.rb'
- 'spec/models/bulk_submission_scrna_spec.rb'

# Offense count: 40
# Configuration parameters: EnforcedStyle.
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ GEM
rexml
ruby-prof (1.7.1)
ruby-progressbar (1.13.0)
ruby-units (4.0.3)
ruby-units (4.1.0)
ruby-vips (2.2.1)
ffi (~> 1.12)
ruby2_keywords (0.0.5)
Expand Down
19 changes: 17 additions & 2 deletions app/models/bulk_submission.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ def initialize(attrs = {})
self.encoding = attrs.fetch(:encoding, DEFAULT_ENCODING)
end

# Returns the warnings collection for the BulkSubmission object.
# Initialises the warnings collection if it does not exist yet. The collection
# is used for showing informative warning messages to the user after the bulk
# submission has been processed successfully.
# @return [ActiveModel::Errors] the warnings collection
def warnings
@warnings ||= ActiveModel::Errors.new(self)
end

include ManifestUtil

# rubocop:todo Metrics/MethodLength
Expand Down Expand Up @@ -231,7 +240,7 @@ def process # rubocop:todo Metrics/CyclomaticComplexity
'gigabases expected',
'priority',
'flowcell type',
'scrna core number of samples per pool',
'scrna core number of pools',
'scrna core cells per chip well'
].freeze

Expand Down Expand Up @@ -312,6 +321,12 @@ def add_study_to_assets(assets, study)
assets.map(&:samples).flatten.uniq.each { |sample| sample.studies << study unless sample.studies.include?(study) }
end

# Assigns a value from the source object to the target object if the source value is present.
#
# @param [Hash] source_obj The source object containing the value to be assigned.
# @param [String, Symbol] source_key The key to look up the value in the source object.
# @param [Hash] target_obj The target object where the value will be assigned.
# @param [String, Symbol] target_key The key to assign the value in the target object.
def assign_value_if_source_present(source_obj, source_key, target_obj, target_key)
target_obj[target_key] = source_obj[source_key] if source_obj[source_key].present?
end
Expand All @@ -329,7 +344,7 @@ def extract_request_options(details)
['gigabases expected', 'gigabases_expected'],
['primer panel', 'primer_panel_name'],
['flowcell type', 'requested_flowcell_type'],
['scrna core number of samples per pool', 'number_of_samples_per_pool'],
['scrna core number of pools', 'number_of_pools'],
['scrna core cells per chip well', 'cells_per_chip_well']
].each do |source_key, target_key|
assign_value_if_source_present(details, source_key, request_options, target_key)
Expand Down
2 changes: 1 addition & 1 deletion app/models/pbmc_pooling_customer_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# A class for customer requests that need the extra metadata fields used for PBMC pooling calculations
class PbmcPoolingCustomerRequest < CustomerRequest
has_metadata as: Request do
custom_attribute(:number_of_samples_per_pool, integer: true, required: false, default: nil)
custom_attribute(:cells_per_chip_well, integer: true, required: false, default: nil)
custom_attribute(:number_of_pools, integer: true, required: false, default: nil)
end
end
86 changes: 70 additions & 16 deletions app/models/study.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,28 @@ class Study < ApplicationRecord # rubocop:todo Metrics/ClassLength
DATA_RELEASE_TIMING_IMMEDIATE,
DATA_RELEASE_TIMING_DELAYED
].freeze
DATA_RELEASE_PREVENTION_REASONS = ['data validity', 'legal', 'replication of data subset'].freeze

DATA_RELEASE_DELAY_FOR_OTHER = 'other'
DATA_RELEASE_DELAY_REASONS_STANDARD = ['phd study', DATA_RELEASE_DELAY_FOR_OTHER].freeze
DATA_RELEASE_DELAY_REASONS_ASSAY = ['phd study', 'assay of no other use', DATA_RELEASE_DELAY_FOR_OTHER].freeze
OLD_DATA_RELEASE_PREVENTION_REASONS = ['data validity', 'legal', 'replication of data subset'].freeze
DATA_RELEASE_PREVENTION_REASON_OTHER = 'Other (please specify)'
DATA_RELEASE_PREVENTION_REASONS = [
'Pilot or validation studies - DAC approval not required',
'Collaborators will share data in a research repository - DAC approval not required',
'Prevent harm (e.g sensitive studies or biosecurity) - DAC approval required',
'Protecting IP - DAC approval required',
DATA_RELEASE_PREVENTION_REASON_OTHER
].freeze

OLD_DATA_RELEASE_DELAY_FOR_OTHER = 'other'
DATA_RELEASE_DELAY_FOR_OTHER = 'Other (please specify below)'
OLD_DATA_RELEASE_DELAY_REASONS = ['other', 'phd study'].freeze
DATA_RELEASE_DELAY_REASONS_STANDARD = [
'PhD study',
'Capacity building',
'Intellectual property protection',
'Additional time to make data FAIR',
DATA_RELEASE_DELAY_FOR_OTHER
].freeze
DATA_RELEASE_DELAY_REASONS_ASSAY = ['assay of no other use'].freeze

DATA_RELEASE_DELAY_PERIODS = ['3 months', '6 months', '9 months', '12 months', '18 months'].freeze

Expand Down Expand Up @@ -214,14 +231,15 @@ class Study < ApplicationRecord # rubocop:todo Metrics/ClassLength
custom_attribute(
:data_release_delay_reason,
required: true,
in: DATA_RELEASE_DELAY_REASONS_ASSAY,
in: [*DATA_RELEASE_DELAY_REASONS_STANDARD, *DATA_RELEASE_DELAY_REASONS_ASSAY, *OLD_DATA_RELEASE_DELAY_REASONS],
if: :delayed_release?
)

custom_attribute(:data_release_delay_period, required: true, in: DATA_RELEASE_DELAY_PERIODS, if: :delayed_release?)
custom_attribute(:bam, default: true)

with_options(required: true, if: :delayed_for_other_reasons?) do
custom_attribute(:data_release_delay_other_comment)
with_options(if: :delayed_for_other_reasons?) do
custom_attribute(:data_release_delay_other_comment, required: true)
custom_attribute(:data_release_delay_reason_comment)
end

Expand All @@ -231,14 +249,19 @@ class Study < ApplicationRecord # rubocop:todo Metrics/ClassLength
custom_attribute(:ega_policy_accession_number)
custom_attribute(:array_express_accession_number)

with_options(if: :delayed_for_long_time?, required: true) do
custom_attribute(:data_release_delay_approval, in: YES_OR_NO, default: NO)
end

with_options(if: :never_release?, required: true) do
custom_attribute(:data_release_prevention_reason, in: DATA_RELEASE_PREVENTION_REASONS)
custom_attribute(:data_release_prevention_approval, in: YES_OR_NO)
custom_attribute(:data_release_prevention_reason_comment)
with_options(if: :never_release?) do
custom_attribute(
:data_release_prevention_reason,
in: [*DATA_RELEASE_PREVENTION_REASONS, *OLD_DATA_RELEASE_PREVENTION_REASONS],
required: true
)
custom_attribute(
:data_release_prevention_other_comment,
required: true,
if: :data_release_prevention_reason_other?
)
custom_attribute(:data_release_prevention_reason_comment, required: true)
custom_attribute(:data_release_prevention_approval)
end

# NOTE: Additional validation in Study::Metadata Class to validate_presence_of :data_access_group, if: :managed
Expand Down Expand Up @@ -567,6 +590,33 @@ def poly_metadatum_by_key(key)
poly_metadata.find { |pm| pm.key == key.to_s }
end

# Helper method for edit dropdowns to support backwards compatibility with old options.
#
# @return [Array<String>] the list of options for the data release prevention reason dropdown
def data_release_prevention_options
additional_options = []
if OLD_DATA_RELEASE_PREVENTION_REASONS.include? study_metadata.data_release_prevention_reason
additional_options << study_metadata.data_release_prevention_reason
end

DATA_RELEASE_PREVENTION_REASONS + additional_options
end

# Helper method for edit dropdowns to support backwards compatibility with old options.
#
# @param [Boolean] assay_option - whether to include assay-specific options
# @return [Array<String>] the list of options for the data release delay reason dropdown
def data_release_delay_options(assay_option: false)
# If the current value is an old one, then we need to include it in the list of options
additional_options = []
if OLD_DATA_RELEASE_DELAY_REASONS.include? study_metadata.data_release_delay_reason
additional_options << study_metadata.data_release_delay_reason
end

additional_options.concat(DATA_RELEASE_DELAY_REASONS_ASSAY) if assay_option
DATA_RELEASE_DELAY_REASONS_STANDARD + additional_options
end

private

def valid_ethically_approved?
Expand Down Expand Up @@ -601,7 +651,11 @@ def never_release?
end

def delayed_for_other_reasons?
data_release_delay_reason == DATA_RELEASE_DELAY_FOR_OTHER
[DATA_RELEASE_DELAY_FOR_OTHER, OLD_DATA_RELEASE_DELAY_FOR_OTHER].include?(data_release_delay_reason)
end

def data_release_prevention_reason_other?
data_release_prevention_reason == DATA_RELEASE_PREVENTION_REASON_OTHER
end

def delayed_for_long_time?
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# frozen_string_literal: true

# This module provides methods for calculating the full allowance volume and the
# final resuspension volume for scRNA core cDNA prep feasibility validations.
module Submission::ScrnaCoreCdnaPrepFeasibilityCalculator
# This method calculates the full allowance volume (in microlitres) for the
# specified number of cells per chip well, which is typically specified in
# in a bulk submission per study and project. It uses the pooling settings
# from the scRNA config. It first calculates the chip loading volume for the
# given number of cells per chip well, and then the full allowance for that
# chip loading volume.
#
# @param number_of_cells_per_chip_well [Integer] the number of cells per chip well from the bulk submission
# @return [Float] the full allowance volume
def calculate_full_allowance(number_of_cells_per_chip_well)
# "Full allowance" = ( "Chip loading volume" * 2) + 25
# 2 is because this is for 2 runs
# 25 is 2 lots of 10ul for cell counting, and 5ul for wastage when transferring between labware
chip_loading_volume = calculate_chip_loading_volume(number_of_cells_per_chip_well)
(chip_loading_volume * scrna_config[:desired_number_of_runs]) +
(scrna_config[:desired_number_of_runs] * scrna_config[:volume_taken_for_cell_counting]) +
scrna_config[:wastage_volume]
end

# This method calculates the chip loading volume (in microlitres) for the
# specified number of cells per chip well, which is typically specified in
# in a bulk submission per study and project. It uses the pooling settings
# from the scRNA config.
#
# @param number_of_cells_per_chip_well [Integer] the number of cells per chip well from the bulk submission
# @return [Float] the chip loading volume
def calculate_chip_loading_volume(number_of_cells_per_chip_well)
# "Chip loading volume" = "Number of cells per chip well" / "Chip loading concentration"
number_of_cells_per_chip_well / scrna_config[:desired_chip_loading_concentration]
end

# This method calculates the resuspension volume (in microlitres) for the
# specified number of samples in a pool, which is typically taken as the
# number of samples in the smallest pool for a study and project. It uses the
# pooling settings from the scRNA config. It first calculates the total cells
# in 300ul for the given number of samples in the pool, and then the
# resuspension volume for that total cell count.
#
# @param count_of_samples_in_pool [Integer] the number of samples in the pool
# @return [Float] the resuspension volume
def calculate_resuspension_volume(count_of_samples_in_pool)
total_cells_in_300ul = calculate_total_cells_in_300ul(count_of_samples_in_pool)
total_cells_in_300ul / scrna_config[:desired_chip_loading_concentration]
end

# This method calculates the total cells in 300ul for the specified number of
# samples in a pool, which is typically taken as the number of samples in the
# smallest pool for a study and project. It uses the pooling settings from the
# scRNA config.
#
# @param count_of_samples_in_pool [Integer] the number of samples in the pool
# @return [Integer] the total cells in 300ul
def calculate_total_cells_in_300ul(count_of_samples_in_pool)
(count_of_samples_in_pool * scrna_config[:required_number_of_cells_per_sample_in_pool]) *
scrna_config[:wastage_factor]
end

private

# This method returns the scRNA config from the Rails application config.
# @return [Hash] the scRNA config
def scrna_config
Rails.application.config.scrna_config
end
end
Loading

0 comments on commit e324a76

Please sign in to comment.