diff --git a/app/components/participant_status_tag_component.rb b/app/components/participant_status_tag_component.rb index 61a88fdf5d..a630a67724 100644 --- a/app/components/participant_status_tag_component.rb +++ b/app/components/participant_status_tag_component.rb @@ -24,9 +24,9 @@ def tag_attributes return { text: "Eligible: Mentor at main school", colour: "green" } if eligible? && profile.primary_profile? return { text: "Eligible: Mentor at additional school", colour: "green" } if ineligible? && mentor_with_duplicate_profile? + return { text: "Not eligible: No QTS", colour: "red" } if participant_has_no_qts? return { text: "DfE checking eligibility", colour: "orange" } if profile.manual_check_needed? return { text: "Not eligible: NQT+1", colour: "red" } if nqt_plus_one? && ineligible? - return { text: "Not eligible: No QTS", colour: "red" } if participant_has_no_qts? && ineligible? return { text: "Eligible to start: ERO", colour: "green" } if ineligible? && mentor_was_in_early_rollout? && on_fip? return { text: "Eligible to start", colour: "green" } if ineligible? && mentor_was_in_early_rollout? return { text: "Not eligible", colour: "red" } if ineligible? diff --git a/app/models/ecf_participant_eligibility.rb b/app/models/ecf_participant_eligibility.rb index 3b0073cf32..9852b7fdc6 100644 --- a/app/models/ecf_participant_eligibility.rb +++ b/app/models/ecf_participant_eligibility.rb @@ -4,7 +4,9 @@ class ECFParticipantEligibility < ApplicationRecord has_paper_trail belongs_to :participant_profile, class_name: "ParticipantProfile::ECF", touch: true - before_validation :determine_status, on: :create + + validates :status, presence: true + validates :reason, presence: true scope :updated_before, ->(timestamp) { where(updated_at: ..timestamp) } @@ -28,31 +30,7 @@ class ECFParticipantEligibility < ApplicationRecord }, _suffix: true def duplicate_profile? - participant_profile&.mentor? && participant_profile&.secondary_profile? - end - - def determine_status - unless manually_validated? - self.status, self.reason = if active_flags? - %i[manual_check active_flags] - elsif previous_participation? # ERO mentors - %i[ineligible previous_participation] - elsif previous_induction? && participant_profile.ect? - %i[ineligible previous_induction] - elsif !qts? && !participant_profile.mentor? - %i[manual_check no_qts] - elsif different_trn? - %i[manual_check different_trn] - elsif duplicate_profile? - %i[ineligible duplicate_profile] - elsif exempt_from_induction? && participant_profile.ect? - %i[ineligible exempt_from_induction] - elsif no_induction? && participant_profile.ect? - %i[manual_check no_induction] - else - %i[eligible none] - end - end + participant_profile.mentor? && participant_profile.secondary_profile? end def ineligible_but_not_duplicated_or_previously_participated? diff --git a/app/services/participant_profile_status.rb b/app/services/participant_profile_status.rb index a0a8d4c291..cbcf655d07 100644 --- a/app/services/participant_profile_status.rb +++ b/app/services/participant_profile_status.rb @@ -20,15 +20,15 @@ def status_name elsif ineligible? && mentor_with_duplicate_profile? "training_or_eligible_for_training" + elsif participant_has_no_qts? + "checking_qts" + elsif participant_profile.manual_check_needed? "dfe_checking_eligibility" elsif nqt_plus_one? && ineligible? "not_eligible_for_funded_training" - elsif participant_has_no_qts? && ineligible? - "checking_qts" - elsif ineligible? && mentor_was_in_early_rollout? && on_fip? "training_or_eligible_for_training" diff --git a/app/services/participants/determine_eligibility_status.rb b/app/services/participants/determine_eligibility_status.rb new file mode 100644 index 0000000000..3d0d4cee29 --- /dev/null +++ b/app/services/participants/determine_eligibility_status.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +class Participants::DetermineEligibilityStatus < BaseService + delegate :active_flags?, + :previous_participation?, + :previous_induction?, + :qts?, + :different_trn?, + :exempt_from_induction?, + :no_induction?, + :manually_validated?, + :duplicate_profile?, + :participant_profile, + to: :participant_eligibility + + def call + return nil if participant_eligibility.nil? + + if revalidate_status? + status, reason = if active_flags? + %i[manual_check active_flags] + elsif previous_participation? # ERO mentors + %i[ineligible previous_participation] + elsif previous_induction? && participant_profile.ect? + %i[ineligible previous_induction] + elsif !qts? && !participant_profile.mentor? + %i[manual_check no_qts] + elsif different_trn? + %i[manual_check different_trn] + elsif duplicate_profile? + %i[ineligible duplicate_profile] + elsif exempt_from_induction? && participant_profile.ect? + %i[ineligible exempt_from_induction] + elsif no_induction? && participant_profile.ect? + %i[manual_check no_induction] + else + %i[eligible none] + end + + participant_eligibility.manually_validated = false + participant_eligibility.status = status + participant_eligibility.reason = reason + end + + # there might be updates to save even if we don't re-evaluate status + participant_eligibility.save! if save_record + end + +private + + attr_reader :participant_eligibility, :save_record, :force_validation + + def initialize(ecf_participant_eligibility:, save_record: true, force_validation: false) + @participant_eligibility = ecf_participant_eligibility + @save_record = save_record + @force_validation = force_validation + end + + def revalidate_status? + force_validation || !manually_validated? + end +end diff --git a/app/services/store_participant_eligibility.rb b/app/services/store_participant_eligibility.rb index fef5db8e14..3b9a53fef5 100644 --- a/app/services/store_participant_eligibility.rb +++ b/app/services/store_participant_eligibility.rb @@ -151,8 +151,8 @@ def update_and_store_eligibility_values! @participant_eligibility.assign_attributes(eligibility_options) end - @participant_eligibility.determine_status - @participant_eligibility.save! + Participants::DetermineEligibilityStatus.call(ecf_participant_eligibility: @participant_eligibility) + Analytics::UpsertECFParticipantProfileJob.perform_later(participant_profile:) end diff --git a/spec/components/appropriate_bodies/participants/table_row_spec.rb b/spec/components/appropriate_bodies/participants/table_row_spec.rb index 82c3230139..9af9f6796a 100644 --- a/spec/components/appropriate_bodies/participants/table_row_spec.rb +++ b/spec/components/appropriate_bodies/participants/table_row_spec.rb @@ -50,7 +50,7 @@ context "when the secondary profile is ineligible because it is a duplicate" do let(:participant_profile) { create(:mentor_participant_profile, :secondary_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :secondary_profile_state, participant_profile:) } it { is_expected.to have_text("Training or eligible for training") } end @@ -64,26 +64,27 @@ end context "full induction programme participant" do + let(:school_cohort) { create(:school_cohort, :fip) } + context "has submitted validation data" do - let(:school_cohort) { create(:school_cohort, :fip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, participant_profile:) } it { is_expected.to have_text("Training or eligible for training") } end context "was a participant in early roll out" do - let(:school_cohort) { create(:school_cohort, :fip) } let(:participant_profile) { create(:mentor_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, previous_participation: true, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :previous_participation_state, participant_profile:) } it { is_expected.to have_text("Training or eligible for training") } end end context "core induction programme participant" do + let(:school_cohort) { create(:school_cohort, :cip) } + context "has submitted validation data" do - let(:school_cohort) { create(:school_cohort, :cip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :manual_check, participant_profile:) } @@ -91,23 +92,20 @@ end context "has a previous induction reason" do - let(:school_cohort) { create(:school_cohort, :cip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, previous_induction: true, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :previous_induction_state, participant_profile:) } it { is_expected.to have_text("Not eligible for funded training") } end context "has no QTS reason" do - let(:school_cohort) { create(:school_cohort, :cip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, qts: false, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :no_qts_state, participant_profile:) } it { is_expected.to have_text("Checking QTS") } end context "has an ineligible status" do - let(:school_cohort) { create(:school_cohort, :cip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, participant_profile:) } @@ -115,8 +113,7 @@ end context "has a withdrawn status" do - let(:school_cohort) { create(:school_cohort, :cip) } - let(:participant_profile) { create(:ect_participant_profile, training_status: "withdrawn", school_cohort:, user: create(:user, email: "ray.clemence@example.com")) } + let(:participant_profile) { create(:ect_participant_profile, training_status: "withdrawn", school_cohort:) } it { is_expected.to have_text("No longer being trained") } end diff --git a/spec/components/delivery_partners/participants/table_row_spec.rb b/spec/components/delivery_partners/participants/table_row_spec.rb index 1a0c146202..0b27746ec1 100644 --- a/spec/components/delivery_partners/participants/table_row_spec.rb +++ b/spec/components/delivery_partners/participants/table_row_spec.rb @@ -16,7 +16,6 @@ pending: false, ) end - let!(:participant_profile) { create :ecf_participant_profile } let!(:participant_profile) { create(:ect_participant_profile, school_cohort:) } subject { render_inline(component) } @@ -56,14 +55,14 @@ context "when the primary profile is eligible" do let(:participant_profile) { create(:mentor_participant_profile, :primary_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, participant_profile:) } it { is_expected.to have_text("Training or eligible for training") } end context "when the secondary profile is ineligible because it is a duplicate" do let(:participant_profile) { create(:mentor_participant_profile, :secondary_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :secondary_profile_state, participant_profile:) } it { is_expected.to have_text("Training or eligible for training") } end @@ -77,59 +76,51 @@ end context "full induction programme participant" do + let(:school_cohort) { create(:school_cohort, :fip) } + context "has submitted validation data" do - let(:school_cohort) { create(:school_cohort, :fip) } - let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, participant_profile:) } it { is_expected.to have_text("Training or eligible for training") } end context "was a participant in early roll out" do - let(:school_cohort) { create(:school_cohort, :fip) } let(:participant_profile) { create(:mentor_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, previous_participation: true, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :previous_participation_state, participant_profile:) } it { is_expected.to have_text("Training or eligible for training") } end end context "core induction programme participant" do + let(:school_cohort) { create(:school_cohort, :cip) } + context "has submitted validation data" do - let(:school_cohort) { create(:school_cohort, :cip) } - let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :manual_check, participant_profile:) } it { is_expected.to have_text("DfE checking eligibility") } end context "has a previous induction reason" do - let(:school_cohort) { create(:school_cohort, :cip) } - let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, previous_induction: true, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :previous_induction_state, participant_profile:) } it { is_expected.to have_text("Not eligible for funded training") } end context "has no QTS reason" do - let(:school_cohort) { create(:school_cohort, :cip) } - let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, qts: false, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :no_qts_state, participant_profile:) } it { is_expected.to have_text("Checking QTS") } end context "has an ineligible status" do - let(:school_cohort) { create(:school_cohort, :cip) } - let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, participant_profile:) } it { is_expected.to have_text("Not eligible") } end context "has a withdrawn status" do - let(:school_cohort) { create(:school_cohort, :cip) } - let(:participant_profile) { create(:ect_participant_profile, training_status: "withdrawn", school_cohort:, user: create(:user, email: "ray.clemence@example.com")) } + let(:participant_profile) { create(:ect_participant_profile, training_status: "withdrawn", school_cohort:) } it { is_expected.to have_text("No longer being trained") } end diff --git a/spec/components/participant_status_tag_component_spec.rb b/spec/components/participant_status_tag_component_spec.rb index 60ef8fed26..f07891ea50 100644 --- a/spec/components/participant_status_tag_component_spec.rb +++ b/spec/components/participant_status_tag_component_spec.rb @@ -44,7 +44,7 @@ context "when the primary profile is eligible" do let(:participant_profile) { create(:mentor_participant_profile, :primary_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, participant_profile:) } before do participant_profile.reload @@ -56,7 +56,7 @@ context "when the secondary profile is ineligible because it is a duplicate" do let(:participant_profile) { create(:mentor_participant_profile, :secondary_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :secondary_profile_state, participant_profile:) } before do participant_profile.reload @@ -71,7 +71,7 @@ context "has submitted validation data" do let(:school_cohort) { create(:school_cohort, :fip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, participant_profile:) } before { render_inline(component) } @@ -81,7 +81,7 @@ context "was a participant in early roll out" do let(:school_cohort) { create(:school_cohort, :fip) } let(:participant_profile) { create(:mentor_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, previous_participation: true, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :previous_participation_state, participant_profile:) } before { render_inline(component) } @@ -103,7 +103,7 @@ context "has a previous induction reason" do let(:school_cohort) { create(:school_cohort, :cip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, previous_induction: true, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :previous_induction_state, participant_profile:) } before { render_inline(component) } @@ -113,7 +113,7 @@ context "has no QTS reason" do let(:school_cohort) { create(:school_cohort, :cip) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :ineligible, qts: false, participant_profile:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :no_qts_state, participant_profile:) } before { render_inline(component) } @@ -132,8 +132,8 @@ context "has a withdrawn status" do let(:school_cohort) { create(:school_cohort, :fip) } - let(:participant_profile) { create(:ect_participant_profile, training_status: "withdrawn", school_cohort:, user: create(:user, email: "ray.clemence@example.com")) } - let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile:) } + let(:participant_profile) { create(:ect_participant_profile, training_status: "withdrawn", school_cohort:) } + let!(:ecf_participant_eligibility) { create(:ecf_participant_eligibility, participant_profile:) } let(:induction_programme) { create(:induction_programme, :fip, school_cohort:) } let!(:induction_record) { Induction::Enrol.call(participant_profile:, induction_programme:) } diff --git a/spec/components/schools/participants/status_spec.rb b/spec/components/schools/participants/status_spec.rb index d26c20e986..15171f211b 100644 --- a/spec/components/schools/participants/status_spec.rb +++ b/spec/components/schools/participants/status_spec.rb @@ -46,7 +46,7 @@ let!(:validation_data) { create(:ecf_participant_validation_data, participant_profile: profile) } context "when the participant is eligible" do - let!(:eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, participant_profile: profile) } it "displays the eligible fip no partner content" do render_inline(component) @@ -67,7 +67,7 @@ end context "when the participant has no QTS" do - let!(:eligibility) { create(:ecf_participant_eligibility, qts: false, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :no_qts_state, participant_profile: profile) } subject! { render_inline(component) } @@ -78,7 +78,7 @@ end context "when the participant has a previous induction" do - let!(:eligibility) { create(:ecf_participant_eligibility, previous_induction: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :previous_induction_state, participant_profile: profile) } subject! { render_inline(component) } @@ -89,7 +89,7 @@ end context "when the participant has a TRN mismatch" do - let!(:eligibility) { create(:ecf_participant_eligibility, different_trn: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :different_trn_state, participant_profile: profile) } subject! { render_inline(component) } @@ -100,7 +100,7 @@ end context "when the participant has active flags and manual check status" do - let!(:eligibility) { create(:ecf_participant_eligibility, active_flags: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :active_flags_state, participant_profile: profile) } subject! { render_inline(component) } @@ -109,17 +109,6 @@ expect(rendered_content).to have_content I18n.t "schools.participants.status.checking_eligibility.content" end end - - context "when the participant has active flags and ineligible status" do - let!(:eligibility) { create(:ecf_participant_eligibility, :ineligible, active_flags: true, participant_profile: profile) } - - subject! { render_inline(component) } - - it "displays the ineligible flag content" do - expect(rendered_content).to have_content I18n.t "schools.participants.status.ineligible_flag.header" - expect(rendered_content).to have_content I18n.t "schools.participants.status.ineligible_flag.content" - end - end end context "when the participant is a mentor" do @@ -127,7 +116,7 @@ let!(:validation_data) { create(:ecf_participant_validation_data, participant_profile: profile) } context "when the participant is eligible" do - let!(:eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, participant_profile: profile) } it "displays the eligible fip no partner content" do render_inline(component) @@ -148,19 +137,8 @@ end end - context "when the participant has no QTS" do - let!(:eligibility) { create(:ecf_participant_eligibility, qts: false, participant_profile: profile) } - - subject! { render_inline(component) } - - it "displays the checking eligibility content" do - expect(rendered_content).to have_content I18n.t "schools.participants.status.eligible_fip_no_partner.header" - expect(rendered_content).to have_content I18n.t "schools.participants.status.eligible_fip_no_partner.content" - end - end - context "when the participant has a previous participation (ERO)" do - let!(:eligibility) { create(:ecf_participant_eligibility, previous_participation: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :previous_participation_state, participant_profile: profile) } subject! { render_inline(component) } @@ -171,7 +149,7 @@ end context "when the participant has a TRN mismatch" do - let!(:eligibility) { create(:ecf_participant_eligibility, different_trn: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :different_trn_state, participant_profile: profile) } subject! { render_inline(component) } @@ -183,7 +161,7 @@ context "when the participant is a duplicate profile" do let(:profile) { create(:mentor_participant_profile, :secondary_profile, school_cohort:) } - let!(:eligibility) { create(:ecf_participant_eligibility, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :secondary_profile_state, participant_profile: profile) } before do profile.reload @@ -209,7 +187,7 @@ end context "when the participant has active flags and manual check status" do - let!(:eligibility) { create(:ecf_participant_eligibility, active_flags: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :active_flags_state, participant_profile: profile) } subject! { render_inline(component) } @@ -218,17 +196,6 @@ expect(rendered_content).to have_content I18n.t "schools.participants.status.checking_eligibility.content" end end - - context "when the participant has active flags and ineligible status" do - let!(:eligibility) { create(:ecf_participant_eligibility, :ineligible, active_flags: true, participant_profile: profile) } - - subject! { render_inline(component) } - - it "displays the ineligible flag content" do - expect(rendered_content).to have_content I18n.t "schools.participants.status.ineligible_flag.header" - expect(rendered_content).to have_content I18n.t "schools.participants.status.ineligible_flag.content" - end - end end end @@ -239,7 +206,7 @@ let!(:validation_data) { create(:ecf_participant_validation_data, participant_profile: profile) } context "when the participant is eligible" do - let!(:eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, participant_profile: profile) } subject! { render_inline(component) } @@ -250,7 +217,7 @@ end context "when the participant has no QTS" do - let!(:eligibility) { create(:ecf_participant_eligibility, qts: false, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :no_qts_state, participant_profile: profile) } subject! { render_inline(component) } @@ -261,7 +228,7 @@ end context "when the participant has a previous induction" do - let!(:eligibility) { create(:ecf_participant_eligibility, previous_induction: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :previous_induction_state, participant_profile: profile) } subject! { render_inline(component) } @@ -272,7 +239,7 @@ end context "when the participant has a TRN mismatch" do - let!(:eligibility) { create(:ecf_participant_eligibility, different_trn: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :different_trn_state, participant_profile: profile) } subject! { render_inline(component) } @@ -283,18 +250,7 @@ end context "when the participant has active flags and manual check status" do - let!(:eligibility) { create(:ecf_participant_eligibility, active_flags: true, participant_profile: profile) } - - subject! { render_inline(component) } - - it "displays the eligible cip content" do - expect(rendered_content).to have_content I18n.t "schools.participants.status.eligible_cip.header" - expect(rendered_content).to have_content I18n.t "schools.participants.status.eligible_cip.content" - end - end - - context "when the participant has active flags and ineligible status" do - let!(:eligibility) { create(:ecf_participant_eligibility, :ineligible, active_flags: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :active_flags_state, participant_profile: profile) } subject! { render_inline(component) } @@ -312,7 +268,7 @@ subject! { render_inline(component) } context "when the participant is eligible" do - let!(:eligibility) { create(:ecf_participant_eligibility, :eligible, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, participant_profile: profile) } it "displays the eligible cip content" do expect(rendered_content).to have_content I18n.t "schools.participants.status.eligible_cip.header" @@ -321,7 +277,7 @@ end context "when the participant has no QTS" do - let!(:eligibility) { create(:ecf_participant_eligibility, qts: false, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :no_qts_state, participant_profile: profile) } subject! { render_inline(component) } @@ -332,7 +288,7 @@ end context "when the participant has a previous participation (ERO)" do - let!(:eligibility) { create(:ecf_participant_eligibility, previous_participation: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :previous_participation_state, participant_profile: profile) } subject! { render_inline(component) } @@ -343,7 +299,7 @@ end context "when the participant has a TRN mismatch" do - let!(:eligibility) { create(:ecf_participant_eligibility, different_trn: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :different_trn_state, participant_profile: profile) } subject! { render_inline(component) } @@ -354,18 +310,7 @@ end context "when the participant has active flags and manual check status" do - let!(:eligibility) { create(:ecf_participant_eligibility, active_flags: true, participant_profile: profile) } - - subject! { render_inline(component) } - - it "displays the eligible cip content" do - expect(rendered_content).to have_content I18n.t "schools.participants.status.eligible_cip.header" - expect(rendered_content).to have_content I18n.t "schools.participants.status.eligible_cip.content" - end - end - - context "when the participant has active flags and ineligible status" do - let!(:eligibility) { create(:ecf_participant_eligibility, :ineligible, active_flags: true, participant_profile: profile) } + let!(:eligibility) { create(:ecf_participant_eligibility, :active_flags_state, participant_profile: profile) } subject! { render_inline(component) } diff --git a/spec/factories/ecf_participant_eligibility.rb b/spec/factories/ecf_participant_eligibility.rb index efe791d7be..f8d1459401 100644 --- a/spec/factories/ecf_participant_eligibility.rb +++ b/spec/factories/ecf_participant_eligibility.rb @@ -10,36 +10,62 @@ previous_induction { false } no_induction { false } - transient do - reason {} + status { :eligible } + reason { :none } + + trait :ineligible do + status { :ineligible } end - after(:create) do |record, evaluator| - record.update!(reason: evaluator.reason) if evaluator.reason + trait :manual_check do + status { :manual_check } end - trait :eligible do - after(:create) do |record, _evaluator| - record.eligible_status! - end + trait :no_induction_state do + no_induction { true } + manual_check + reason { :no_induction } end - trait :ineligible do - after(:create) do |record, _evaluator| - record.ineligible_status! - end + trait :no_qts_state do + qts { false } + manual_check + reason { :no_qts } end - trait :matched do - after(:create) do |record, _evaluator| - record.matched_status! - end + trait :active_flags_state do + active_flags { true } + manual_check + reason { :active_flags } end - trait :manual_check do - after(:create) do |record, _evaluator| - record.manual_check_status! - end + trait :different_trn_state do + different_trn { true } + manual_check + reason { :different_trn } + end + + trait :previous_induction_state do + previous_induction { true } + ineligible + reason { :previous_induction } + end + + trait :previous_participation_state do + previous_participation { true } + ineligible + reason { :previous_participation } + end + + trait :secondary_profile_state do + ineligible + reason { :duplicate_profile } + end + + trait :exempt_from_induction_state do + exempt_from_induction { true } + ineligible + reason { :exempt_from_induction } end end end diff --git a/spec/factories/participant_profiles.rb b/spec/factories/participant_profiles.rb index dcf98e345c..b6bcfd63ef 100644 --- a/spec/factories/participant_profiles.rb +++ b/spec/factories/participant_profiles.rb @@ -95,13 +95,6 @@ trait :secondary_profile do profile_duplicity { :secondary } - - after(:create) do |profile, _evaluator| - if profile.ecf_participant_eligibility.present? - profile.ecf_participant_eligibility.determine_status - profile.ecf_participant_eligibility.save! - end - end end end end diff --git a/spec/forms/participants/participant_validation_form_spec.rb b/spec/forms/participants/participant_validation_form_spec.rb index 79b43fa49c..4f8ff1cf8d 100644 --- a/spec/forms/participants/participant_validation_form_spec.rb +++ b/spec/forms/participants/participant_validation_form_spec.rb @@ -27,6 +27,7 @@ let(:eligibility_record) do create( :ecf_participant_eligibility, + :secondary_profile_state, participant_profile:, ) end @@ -41,8 +42,8 @@ let(:eligibility_record) do create( :ecf_participant_eligibility, + :previous_participation_state, participant_profile:, - previous_participation: true, ) end it { is_expected.to eq :previous_participation } @@ -53,8 +54,8 @@ let(:eligibility_record) do create( :ecf_participant_eligibility, + :exempt_from_induction_state, participant_profile:, - exempt_from_induction: true, ) end it { is_expected.to eq :exempt_from_induction } diff --git a/spec/jobs/check_participants_induction_job_spec.rb b/spec/jobs/check_participants_induction_job_spec.rb index 802eb5b594..73e6e20c66 100644 --- a/spec/jobs/check_participants_induction_job_spec.rb +++ b/spec/jobs/check_participants_induction_job_spec.rb @@ -21,8 +21,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :manual_check, - no_induction: true, + :no_induction_state, participant_profile: profile, ) create( @@ -37,8 +36,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :manual_check, - no_induction: true, + :no_induction_state, participant_profile: profile, ) create( @@ -103,8 +101,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :ineligible, - previous_induction: true, + :previous_induction_state, participant_profile: profile, ) create( @@ -119,8 +116,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :ineligible, - previous_induction: true, + :previous_induction_state, participant_profile: profile, ) create( @@ -135,9 +131,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :ineligible, - exempt_from_induction: true, - no_induction: true, + :exempt_from_induction_state, participant_profile: profile, ) create( @@ -152,8 +146,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :ineligible, - previous_induction: true, + :previous_induction_state, manually_validated: true, participant_profile: profile, ) @@ -237,8 +230,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :manual_check, - qts: false, + :no_qts_state, participant_profile: profile, ) create( @@ -253,8 +245,7 @@ create(:ect_participant_profile).tap do |profile| create( :ecf_participant_eligibility, - :manual_check, - qts: false, + :no_qts_state, participant_profile: profile, ) create( diff --git a/spec/models/ecf_participant_eligibility_spec.rb b/spec/models/ecf_participant_eligibility_spec.rb index 6829fe5f6b..4542522088 100644 --- a/spec/models/ecf_participant_eligibility_spec.rb +++ b/spec/models/ecf_participant_eligibility_spec.rb @@ -6,7 +6,10 @@ let(:participant_profile) { create(:ect_participant_profile) } subject(:eligibility) { described_class.new(participant_profile:, active_flags: false, previous_participation: false, previous_induction: false, qts: true) } + it { is_expected.to validate_presence_of :status } + it { is_expected.to validate_presence_of :reason } it { is_expected.to belong_to(:participant_profile) } + it { is_expected.to define_enum_for(:status).with_values( eligible: "eligible", @@ -39,134 +42,6 @@ expect(user.reload.updated_at).to be_within(1.second).of Time.zone.now end - describe "#determine_status" do - context "when manually_validated is true" do - it "does not determine a new status and reason" do - eligibility.active_flags = true - eligibility.valid? - expect(eligibility).to be_manual_check_status - expect(eligibility).to be_active_flags_reason - - eligibility.status = :ineligible - eligibility.manually_validated = true - eligibility.determine_status - expect(eligibility).to be_ineligible_status - expect(eligibility).to be_active_flags_reason - end - end - - context "when active_flags are true" do - it "sets the status to manual_check" do - eligibility.active_flags = true - eligibility.valid? - expect(eligibility).to be_manual_check_status - expect(eligibility).to be_active_flags_reason - end - end - - context "when previous_participation is true" do - it "sets the status to ineligible" do - eligibility.previous_participation = true - eligibility.valid? - expect(eligibility).to be_ineligible_status - expect(eligibility).to be_previous_participation_reason - end - end - - context "when previous_induction is true" do - before do - eligibility.previous_induction = true - eligibility.valid? - end - - it "sets the status to ineligible" do - expect(eligibility).to be_ineligible_status - expect(eligibility).to be_previous_induction_reason - end - - context "when participant is a mentor" do - let!(:participant_profile) { create(:mentor_participant_profile) } - - it "does not consider the previous_induction flag" do - expect(eligibility).to be_eligible_status - expect(eligibility).to be_none_reason - end - end - end - - context "when QTS status is false and no other flags are set" do - it "sets the status to manual_check" do - eligibility.qts = false - eligibility.valid? - expect(eligibility).to be_manual_check_status - expect(eligibility).to be_no_qts_reason - end - end - - context "when QTS status is true and no other flags are set" do - it "sets the status to eligible" do - eligibility.qts = true - eligibility.valid? - expect(eligibility).to be_eligible_status - expect(eligibility).to be_none_reason - end - end - - context "when QTS status is false and the participant is a mentor" do - let(:participant_profile) { create(:mentor_participant_profile) } - subject(:eligibility) { described_class.new(participant_profile:, active_flags: false, previous_participation: false, previous_induction: false, qts: true) } - - it "sets the status to eligible" do - eligibility.qts = false - eligibility.valid? - expect(eligibility).to be_eligible_status - expect(eligibility).to be_none_reason - end - end - - context "when no_induction is set to true" do - context "the user is an ect" do - it "sets the status to manual_check and reason as no_induction" do - eligibility.no_induction = true - eligibility.valid? - expect(eligibility).to be_manual_check_status - expect(eligibility).to be_no_induction_reason - end - end - - context "the user is a mentor" do - let!(:participant_profile) { create(:mentor_participant_profile) } - - it "does not set the status to manual check" do - eligibility.no_induction = true - eligibility.valid? - expect(eligibility).to be_eligible_status - end - end - end - - context "when exempt_from_induction is set to true" do - context "the user is an ect" do - it "sets the status to ineligible" do - eligibility.exempt_from_induction = true - eligibility.valid? - expect(eligibility).to be_ineligible_status - expect(eligibility).to be_exempt_from_induction_reason - end - end - - context "the user is a mentor" do - let!(:participant_profile) { create(:mentor_participant_profile) } - - it "does not set the status to ineligible" do - eligibility.exempt_from_induction = true - eligibility.valid? - expect(eligibility).to be_eligible_status - end - end - end - end - describe "#ineligible_but_not_duplicated_or_previously_participated?" do (described_class.statuses.keys - %w[ineligible]).each do |status| context "when the status is #{status}" do diff --git a/spec/services/coc_set_participant_categories_spec.rb b/spec/services/coc_set_participant_categories_spec.rb index 353baa6ab7..1deccec16c 100644 --- a/spec/services/coc_set_participant_categories_spec.rb +++ b/spec/services/coc_set_participant_categories_spec.rb @@ -292,8 +292,7 @@ def setup_fip_participants fip_mentor_no_qts.ecf_participant_eligibility.update!(status: "manual_check", reason: "no_qts") [fip_primary_mentor, fip_secondary_mentor].each do |profile| - profile.ecf_participant_eligibility.determine_status - profile.ecf_participant_eligibility.save! + Participants::DetermineEligibilityStatus.call(ecf_participant_eligibility: profile.ecf_participant_eligibility) end end @@ -325,8 +324,7 @@ def setup_cip_participants cip_mentor_no_qts.ecf_participant_eligibility.update!(status: "manual_check", reason: "no_qts") [cip_primary_mentor, cip_secondary_mentor].each do |profile| - profile.ecf_participant_eligibility.determine_status - profile.ecf_participant_eligibility.save! + Participants::DetermineEligibilityStatus.call(ecf_participant_eligibility: profile.ecf_participant_eligibility) end end @ect_categories = service.call(school_cohort, induction_coordinator.user, ParticipantProfile::ECT) diff --git a/spec/services/manually_update_participant_eligibility_spec.rb b/spec/services/manually_update_participant_eligibility_spec.rb index 8dd7cdd3fb..fb75346869 100644 --- a/spec/services/manually_update_participant_eligibility_spec.rb +++ b/spec/services/manually_update_participant_eligibility_spec.rb @@ -9,7 +9,7 @@ let(:school_cohort) { create(:school_cohort, school:) } let(:teacher_profile) { create(:teacher_profile, school:, trn: nil) } let(:participant_profile) { create(:ect_participant_profile, school_cohort:, teacher_profile:) } - let!(:participant_eligibility) { create(:ecf_participant_eligibility, qts: false, participant_profile:) } + let!(:participant_eligibility) { create(:ecf_participant_eligibility, :no_qts_state, participant_profile:) } it "overrides the normal status determination" do service.call(participant_profile:, status: :eligible, reason: :none) diff --git a/spec/services/participants/determine_eligibility_status_spec.rb b/spec/services/participants/determine_eligibility_status_spec.rb new file mode 100644 index 0000000000..10c36575a0 --- /dev/null +++ b/spec/services/participants/determine_eligibility_status_spec.rb @@ -0,0 +1,193 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Participants::DetermineEligibilityStatus do + let(:participant_profile) { create(:ect_participant_profile) } + let(:eligibility) { create(:ecf_participant_eligibility, participant_profile:, active_flags: false, previous_participation: false, previous_induction: false, qts: true) } + let(:save_record) { true } + let(:force_validation) { false } + subject(:service_call) { described_class.call(ecf_participant_eligibility: eligibility, save_record:, force_validation:) } + + describe "#call" do + context "when manually_validated is true" do + before do + eligibility.status = :manual_check + eligibility.reason = :active_flags + eligibility.manually_validated = true + eligibility.save! + service_call + end + + it "does not determine a new status and reason" do + expect(eligibility).to be_manual_check_status + expect(eligibility).to be_active_flags_reason + end + + context "when the force_validation param is set" do + let(:force_validation) { true } + + it "determines a new status and reason" do + expect(eligibility).to be_eligible_status + expect(eligibility).to be_none_reason + end + + it "clears the manually_validated flag" do + expect(eligibility).not_to be_manually_validated + end + end + end + + context "when active_flags are true" do + before do + eligibility.active_flags = true + service_call + end + + it "sets the status to manual_check" do + expect(eligibility).to be_manual_check_status + expect(eligibility).to be_active_flags_reason + end + end + + context "when previous_participation is true" do + before do + eligibility.previous_participation = true + service_call + end + + it "sets the status to ineligible" do + expect(eligibility).to be_ineligible_status + expect(eligibility).to be_previous_participation_reason + end + end + + context "when previous_induction is true" do + before do + eligibility.previous_induction = true + service_call + end + + it "sets the status to ineligible" do + expect(eligibility).to be_ineligible_status + expect(eligibility).to be_previous_induction_reason + end + + context "when participant is a mentor" do + let!(:participant_profile) { create(:mentor_participant_profile) } + + it "does not consider the previous_induction flag" do + expect(eligibility).to be_eligible_status + expect(eligibility).to be_none_reason + end + end + end + + context "when different_trn is true" do + before do + eligibility.different_trn = true + service_call + end + + it "sets the status to manual_check" do + expect(eligibility).to be_manual_check_status + expect(eligibility).to be_different_trn_reason + end + end + + context "when profile is a secondary mentor profile" do + let!(:participant_profile) { create(:mentor_participant_profile, profile_duplicity: :secondary) } + + before do + service_call + end + + it "sets the status to ineligible" do + expect(eligibility).to be_ineligible_status + expect(eligibility).to be_duplicate_profile_reason + end + end + + context "when QTS status is false and no other flags are set" do + before do + eligibility.qts = false + service_call + end + + it "sets the status to manual_check" do + expect(eligibility).to be_manual_check_status + expect(eligibility).to be_no_qts_reason + end + end + + context "when QTS status is true and no other flags are set" do + before do + eligibility.qts = true + service_call + end + + it "sets the status to eligible" do + expect(eligibility).to be_eligible_status + expect(eligibility).to be_none_reason + end + end + + context "when QTS status is false and the participant is a mentor" do + let(:participant_profile) { create(:mentor_participant_profile) } + + before do + eligibility.qts = false + service_call + end + + it "sets the status to eligible" do + expect(eligibility).to be_eligible_status + expect(eligibility).to be_none_reason + end + end + + context "when no_induction is set to true" do + before do + eligibility.no_induction = true + service_call + end + + context "the user is an ect" do + it "sets the status to manual_check and reason as no_induction" do + expect(eligibility).to be_manual_check_status + expect(eligibility).to be_no_induction_reason + end + end + + context "the user is a mentor" do + let!(:participant_profile) { create(:mentor_participant_profile) } + + it "does not set the status to manual check" do + expect(eligibility).to be_eligible_status + end + end + end + + context "when exempt_from_induction is set to true" do + before do + eligibility.exempt_from_induction = true + service_call + end + + context "the user is an ect" do + it "sets the status to ineligible" do + expect(eligibility).to be_ineligible_status + expect(eligibility).to be_exempt_from_induction_reason + end + end + + context "the user is a mentor" do + let!(:participant_profile) { create(:mentor_participant_profile) } + + it "does not set the status to ineligible" do + expect(eligibility).to be_eligible_status + end + end + end + end +end diff --git a/spec/services/set_participant_categories_spec.rb b/spec/services/set_participant_categories_spec.rb index 1d62aa6619..445e6b6881 100644 --- a/spec/services/set_participant_categories_spec.rb +++ b/spec/services/set_participant_categories_spec.rb @@ -27,8 +27,7 @@ before do [primary_mentor, secondary_mentor].each do |profile| - profile.ecf_participant_eligibility.determine_status - profile.ecf_participant_eligibility.save! + Participants::DetermineEligibilityStatus.call(ecf_participant_eligibility: profile.ecf_participant_eligibility) end end