Skip to content

Commit

Permalink
Merge pull request #4831 from DFE-Digital/CST-2575-closing-2021-allow…
Browse files Browse the repository at this point in the history
…-cohort-changes-for-participants-from-payments-closed-cohorts

CST-2575: closing 2021 allow cohort changes for participants from payments-frozen cohorts
  • Loading branch information
ltello authored May 30, 2024
2 parents 3836909 + 00efb07 commit 9ef4faa
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 34 deletions.
8 changes: 4 additions & 4 deletions app/models/cohort.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ def npq_plus_one_or_earlier?
start_year <= NPQ_PLUS_1_YEAR
end

def previous
self.class.find_by(start_year: start_year - 1)
end

def payments_frozen?
payments_frozen_at.present?
end

def previous
self.class.find_by(start_year: start_year - 1)
end

# e.g. "2022"
def to_param
start_year.to_s
Expand Down
2 changes: 2 additions & 0 deletions app/models/participant_profile/ect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def self.archivable(restrict_to_participant_ids: [])
.where("induction_start_date IS NULL OR induction_start_date < make_date(cohorts.start_year, 9, 1)")
end

alias_method :completed_training?, :completed_induction?

def ect?
true
end
Expand Down
71 changes: 58 additions & 13 deletions app/services/induction/amend_participant_cohort.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# frozen_string_literal: true

# Change the current cohort of an ECF participant.
# Change the cohort of an ECF participant.
# In doing so it will add an IR with an induction_programme and schedule on the new cohort.
# Also, the participant profile will get their cohort and schedule updated.
#
# The induction_programme will be the default one for the new cohort in the current school.
# The schedule will be the provided one or the equivalent to the current but in destination cohort with start year :target_cohort_start_year
# The schedule will be the provided one or the equivalent to the current one in the cohort with start year :target_cohort_start_year
#
# Several validations are run before allowing the change. Specially important are existing declarations.
#
# Examples:
# - This will set induction_programme and schedule for the participant_profile to 2022/23 cohort checking they sits currently
# in 2021/2022
# - This will set induction_programme and schedule for the participant_profile to 2022/23 cohort
# checking they are sitting currently in 2021/2022
# Induction::AmendParticipantCohort.new(participant_profile:,
# source_cohort_start_year: 2021,
# target_cohort_start_year: 2022).save
Expand All @@ -22,6 +22,10 @@
# source_cohort_start_year: 2021,
# schedule:).save
#
# - For cohort changes on participants whose current cohort has been payments_frozen and are transferred to
# the active registration cohort, it will automatically flag the participant_profile as
# cohort_changed_after_payments_frozen: true
#
module Induction
class AmendParticipantCohort
include ActiveModel::Model
Expand Down Expand Up @@ -66,10 +70,14 @@ class AmendParticipantCohort
validate :target_cohort_start_year_matches_schedule

validates :participant_profile,
participant_profile_active: true
active_participant_profile: true

validate :transfer_from_payments_frozen_cohort, if: :transfer_from_payments_frozen_cohort?
validate :transfer_to_payments_frozen_cohort, if: :back_to_payments_frozen_cohort?

validates :participant_declarations,
absence: { message: :billable_or_submitted }
absence: { message: :billable_or_submitted },
unless: :payments_frozen_transfer?

validates :induction_record,
presence: {
Expand Down Expand Up @@ -102,10 +110,22 @@ def initialize(*)
@target_cohort_start_year = (@target_cohort_start_year || @schedule&.cohort_start_year).to_i
end

def back_to_payments_frozen_cohort?
participant_profile&.cohort_changed_after_payments_frozen? && target_cohort&.payments_frozen?
end

def billable_declarations_in_cohort?(cohort)
participant_profile.participant_declarations.where(cohort:).billable.exists?
end

def current_induction_record_updated?
ActiveRecord::Base.transaction do
Induction::ChangeInductionRecord.call(induction_record:, changes: { induction_programme:, schedule: })
participant_profile.update!(school_cohort: target_school_cohort, schedule:)
Induction::ChangeInductionRecord.call(induction_record:,
changes: { induction_programme:,
schedule: })
participant_profile.update!(school_cohort: target_school_cohort,
schedule:,
cohort_changed_after_payments_frozen:)
rescue ActiveRecord::RecordInvalid => e
errors.add(:induction_record, induction_record.errors.full_messages.first) if induction_record.errors.any?
errors.add(:participant_profile, participant_profile.errors.full_messages.first) if participant_profile.errors.any?
Expand All @@ -127,7 +147,6 @@ def induction_record

@induction_record ||= participant_profile.induction_records
.active_induction_status
.training_status_active
.joins(induction_programme: { school_cohort: :cohort })
.where(cohorts: { start_year: source_cohort_start_year })
.latest
Expand All @@ -147,11 +166,12 @@ def in_target_schedule?(induction_record)

def participant_declarations
return false unless participant_profile
return @participant_declarations if instance_variable_defined?(:@participant_declarations)

@participant_declarations ||= participant_profile
.participant_declarations
.billable_or_changeable
.exists?
@participant_declarations = participant_profile
.participant_declarations
.billable_or_changeable
.exists?
end

def schedule
Expand All @@ -176,7 +196,32 @@ def target_school_cohort
@target_school_cohort ||= SchoolCohort.find_by(school:, cohort: target_cohort)
end

def payments_frozen_transfer?
transfer_from_payments_frozen_cohort? || back_to_payments_frozen_cohort?
end

def transfer_from_payments_frozen_cohort?
source_cohort&.payments_frozen? && target_cohort == Cohort.active_registration_cohort
end

alias_method :cohort_changed_after_payments_frozen, :transfer_from_payments_frozen_cohort?

# Validations

def transfer_from_payments_frozen_cohort
unless participant_profile.eligible_to_change_cohort_and_continue_training?(cohort: target_cohort)
errors.add(:participant_profile, :not_eligible_to_be_transferred_from_current_cohort)
end
end

def transfer_to_payments_frozen_cohort
unless participant_profile.eligible_to_change_cohort_back_to_their_payments_frozen_original?(cohort: target_cohort, current_cohort: source_cohort)
errors.add(:participant_profile, :billable_declarations_in_cohort) if billable_declarations_in_cohort?(source_cohort)
errors.add(:participant_profile, :no_billable_declarations_in_cohort) unless billable_declarations_in_cohort?(target_cohort)
errors.add(:participant_profile, :not_eligible_to_be_transferred_back)
end
end

def target_cohort_start_year_matches_schedule
if schedule && target_cohort_start_year != schedule.cohort_start_year
errors.add(:target_cohort_start_year, :incompatible_with_schedule)
Expand Down
16 changes: 16 additions & 0 deletions app/validators/active_participant_profile_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class ActiveParticipantProfileValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors.add(attribute, I18n.t("errors.participant_profile.not_a_participant_profile")) unless participant_profile?(value)
record.errors.add(attribute, I18n.t("errors.participant_profile.not_active")) unless active?(value)
end

def active?(instance)
instance&.active_record?
end

def participant_profile?(instance)
instance.is_a?(ParticipantProfile)
end
end
11 changes: 0 additions & 11 deletions app/validators/participant_profile_active_validator.rb

This file was deleted.

6 changes: 5 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ en:
participant_profile:
blank: "Not registered"
not_active: "Not active"
not_a_participant_profile: "Not a participant profile record"
programme:
blank: "Select a programme type"
provider:
Expand Down Expand Up @@ -319,12 +320,15 @@ en:
no_default_induction_programme: "No default induction programme set for %{start_academic_year} academic year by school %{school_name}"
school_cohort_not_setup: "%{start_academic_year} academic year not setup by school %{school_name}"
participant_declarations:
exist: "The participant must have no declarations"
billable_or_submitted: "The participant has billable or submitted declarations"
completed: "The participant has not had a 'completed' declaration submitted for them. Therefore you cannot update their outcome."
participant_profile:
billable_declarations_in_cohort: "The participant has billable declarations in their current cohort"
no_billable_declarations_in_cohort: "The participant has no billable declarations in destination cohort"
blank: "Not registered"
not_active: "Not active"
not_eligible_to_be_transferred_back: "Not eligible to be transferred back to their original cohort"
not_eligible_to_be_transferred_from_current_cohort: "Not eligible to be transferred from their current cohort"
source_cohort_start_year:
invalid: "Invalid value. Must be an integer between %{start} and %{end}"
target_cohort_start_year:
Expand Down
Loading

0 comments on commit 9ef4faa

Please sign in to comment.