diff --git a/app/helpers/admin/claims_helper.rb b/app/helpers/admin/claims_helper.rb index be8c73a699..e91e6ff0b6 100644 --- a/app/helpers/admin/claims_helper.rb +++ b/app/helpers/admin/claims_helper.rb @@ -74,7 +74,7 @@ def admin_decision_details(decision) def rejected_reasons_list(decision) decision.selected_rejected_reasons .sort_by { |k| Decision::REJECTED_REASONS.index(k) } - .map { |reason| t("admin.decision.rejected_reasons.#{reason}") } + .map { |reason| t("#{decision.policy.locale_key}.admin.decision.rejected_reasons.#{reason}") } .join(", ") end diff --git a/app/models/decision.rb b/app/models/decision.rb index 46e798e351..386ee637bd 100644 --- a/app/models/decision.rb +++ b/app/models/decision.rb @@ -2,18 +2,11 @@ class Decision < ApplicationRecord belongs_to :claim belongs_to :created_by, class_name: "DfeSignIn::User", optional: true - # NOTE: remember en.yml -> admin.decision.rejected_reasons - REJECTED_REASONS = [ - :ineligible_subject, - :ineligible_year, - :ineligible_school, - :ineligible_qualification, - :induction, - :no_qts_or_qtls, - :duplicate, - :no_response, - :other - ] + delegate :policy, to: :claim + + REJECTED_REASONS = Policies.all.flat_map do |policy| + policy::ADMIN_DECISION_REJECTED_REASONS + end.uniq store_accessor :rejected_reasons, *REJECTED_REASONS, prefix: true @@ -37,9 +30,7 @@ class Decision < ApplicationRecord } def self.rejected_reasons_for(policy) - REJECTED_REASONS.dup.tap do |reasons| - reasons.delete(:induction) unless policy == Policies::EarlyCareerPayments - end + policy::ADMIN_DECISION_REJECTED_REASONS end def readonly? @@ -48,7 +39,7 @@ def readonly? end def rejected_reasons_hash - REJECTED_REASONS.reduce({}) do |memo, reason| + policy::ADMIN_DECISION_REJECTED_REASONS.reduce({}) do |memo, reason| memo.merge("reason_#{reason}": public_send(:"rejected_reasons_#{reason}") || "0") end end diff --git a/app/models/policies/early_career_payments.rb b/app/models/policies/early_career_payments.rb index 1f6569aa95..7e8e9a2ca9 100644 --- a/app/models/policies/early_career_payments.rb +++ b/app/models/policies/early_career_payments.rb @@ -40,6 +40,19 @@ module EarlyCareerPayments # Percentage of claims to QA MIN_QA_THRESHOLD = 10 + # Options shown to admins when rejecting a claim + ADMIN_DECISION_REJECTED_REASONS = [ + :ineligible_subject, + :ineligible_year, + :ineligible_school, + :ineligible_qualification, + :induction, + :no_qts_or_qtls, + :duplicate, + :no_response, + :other + ] + def eligibility_page_url "https://www.gov.uk/guidance/early-career-payments-guidance-for-teachers-and-schools" end diff --git a/app/models/policies/further_education_payments.rb b/app/models/policies/further_education_payments.rb index a879b6241b..93b240015a 100644 --- a/app/models/policies/further_education_payments.rb +++ b/app/models/policies/further_education_payments.rb @@ -8,6 +8,15 @@ module FurtherEducationPayments URL_SPREADSHEET_ELIGIBLE_PROVIDERS = "https://assets.publishing.service.gov.uk/media/667300fe64e554df3bd0db92/List_of_eligible_FE_providers_and_payment_value_for_levelling_up_premium.xlsx".freeze + # Options shown to admins when rejecting a claim + ADMIN_DECISION_REJECTED_REASONS = [ + # FIXME RL: this `placeholder` is required to make the + # `spec/models/policies/further_education_payments/claim_personal_data_scrubber_spec.rb` + # test pass. Once we add a real rejection reason we can remove this + # placeholder. Figured this was better than removing the test! + :placeholder + ] + # TODO: This is needed once the reply-to email address has been added to Gov Notify def notify_reply_to_id nil diff --git a/app/models/policies/international_relocation_payments.rb b/app/models/policies/international_relocation_payments.rb index 75641260c1..b435637a19 100644 --- a/app/models/policies/international_relocation_payments.rb +++ b/app/models/policies/international_relocation_payments.rb @@ -9,6 +9,18 @@ module InternationalRelocationPayments # Percentage of claims to QA MIN_QA_THRESHOLD = 100 + # Options shown to admins when rejecting a claim + ADMIN_DECISION_REJECTED_REASONS = [ + :duplicate, + :ineligible_school, + :invalid_bank_details, + :ineligible_visa_or_entry_date, + :ineligible_employment_terms, + :no_response_from_school, + :suspected_fraud, + :information_mismatch_new_details_needed + ] + # NOTE RL: currently IRP only has a single reply to address, so notify # doesn't show the address id def notify_reply_to_id diff --git a/app/models/policies/levelling_up_premium_payments.rb b/app/models/policies/levelling_up_premium_payments.rb index 69837d6308..23c60af821 100644 --- a/app/models/policies/levelling_up_premium_payments.rb +++ b/app/models/policies/levelling_up_premium_payments.rb @@ -30,6 +30,18 @@ module LevellingUpPremiumPayments # Percentage of claims to QA MIN_QA_THRESHOLD = 10 + # Options shown to admins when rejecting a claim + ADMIN_DECISION_REJECTED_REASONS = [ + :ineligible_subject, + :ineligible_year, + :ineligible_school, + :ineligible_qualification, + :no_qts_or_qtls, + :duplicate, + :no_response, + :other + ] + def notify_reply_to_id "03ece7eb-2a5b-461b-9c91-6630d0051aa6" end diff --git a/app/models/policies/student_loans.rb b/app/models/policies/student_loans.rb index 71006ed7d9..004b6e6242 100644 --- a/app/models/policies/student_loans.rb +++ b/app/models/policies/student_loans.rb @@ -40,6 +40,18 @@ module StudentLoans # Percentage of claims to QA MIN_QA_THRESHOLD = 10 + # Options shown to admins when rejecting a claim + ADMIN_DECISION_REJECTED_REASONS = [ + :ineligible_subject, + :ineligible_year, + :ineligible_school, + :ineligible_qualification, + :no_qts_or_qtls, + :duplicate, + :no_response, + :other + ] + def eligibility_page_url "https://www.gov.uk/guidance/teachers-claim-back-your-student-loan-repayments" end diff --git a/app/views/admin/decisions/_decision_form.html.erb b/app/views/admin/decisions/_decision_form.html.erb index 610bd3bded..ffe191fdcf 100644 --- a/app/views/admin/decisions/_decision_form.html.erb +++ b/app/views/admin/decisions/_decision_form.html.erb @@ -70,7 +70,7 @@
<%= form.hidden_field reason_prefixed, value: false %> <%= form.check_box reason_prefixed, class: "govuk-checkboxes__input subject", id: reason_prefixed %> - <%= form.label reason_prefixed, t("admin.decision.rejected_reasons.#{reason}"), class: "govuk-label govuk-checkboxes__label", for: reason_prefixed %> + <%= form.label reason_prefixed, t("#{claim.policy.locale_key}.admin.decision.rejected_reasons.#{reason}"), class: "govuk-label govuk-checkboxes__label", for: reason_prefixed %>
<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 9e63f7e170..baf0208d95 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -128,16 +128,6 @@ en: notes: "Notes" created_by: "Created by" reasons: Reasons - rejected_reasons: - ineligible_subject: Ineligible subject - ineligible_year: Ineligible year - ineligible_school: Ineligible school - ineligible_qualification: Ineligible qualification - induction: Induction - ECP only - no_qts_or_qtls: No QTS or QTLS - duplicate: Duplicate - no_response: No response - other: Other duplicate_attributes_message: one: Details in this claim match another %{policy} claim other: Details in this claim match other %{policy} claims @@ -389,6 +379,16 @@ en: information_provided_further_details_link_text: claiming back your student loan repayments (opens in new tab) admin: claim_school: "Claim school" + decision: + rejected_reasons: + ineligible_subject: Ineligible subject + ineligible_year: Ineligible year + ineligible_school: Ineligible school + ineligible_qualification: Ineligible qualification + no_qts_or_qtls: No QTS or QTLS + duplicate: Duplicate + no_response: No response + other: Other subjects_taught: "Subjects taught" had_leadership_position: "Had leadership position?" mostly_performed_leadership_duties: "Mostly performed leadership duties?" @@ -624,6 +624,17 @@ en: employed_as_supply_teacher: "Employed as a supply teacher?" nqt_in_academic_year_after_itt: "Teaching as a qualified teacher?" induction_completed: "Has completed induction as an early-career teacher?" + decision: + rejected_reasons: + ineligible_subject: Ineligible subject + ineligible_year: Ineligible year + ineligible_school: Ineligible school + ineligible_qualification: Ineligible qualification + induction: Induction - ECP only + no_qts_or_qtls: No QTS or QTLS + duplicate: Duplicate + no_response: No response + other: Other task_questions: employment: title: "Does the claimant’s current school match the above information from their claim?" @@ -772,6 +783,16 @@ en: policy_short_name: "International Relocation Payments" policy_acronym: "IRP" admin: + decision: + rejected_reasons: + duplicate: Duplicate application + ineligible_school: Ineligible school + invalid_bank_details: Invalid bank details + ineligible_visa_or_entry_date: "Visa/entry date ineligible" + ineligible_employment_terms: Ineligible employment terms + no_response_from_school: No response from school + suspected_fraud: Suspected fraud + information_mismatch_new_details_needed: "Information mismatch - new details needed" eligibility_answers: nationality: "Nationality" passport_number: "Passport number" diff --git a/spec/factories/decisions.rb b/spec/factories/decisions.rb index dfc247ecb7..49310acd7a 100644 --- a/spec/factories/decisions.rb +++ b/spec/factories/decisions.rb @@ -9,7 +9,7 @@ trait :rejected do result { :rejected } - rejected_reasons_ineligible_subject { "1" } + rejected_reasons { {policy::ADMIN_DECISION_REJECTED_REASONS.first => "1"} } end trait :with_notes do diff --git a/spec/helpers/claim_mailer_helper_spec.rb b/spec/helpers/claim_mailer_helper_spec.rb index 3631c102d7..d6d92f61d8 100644 --- a/spec/helpers/claim_mailer_helper_spec.rb +++ b/spec/helpers/claim_mailer_helper_spec.rb @@ -3,7 +3,8 @@ describe ClaimMailerHelper do describe ".rejected_reasons_personalisation" do subject { rejected_reasons_personalisation(decision.rejected_reasons_hash) } - let(:decision) { create(:decision, :rejected, :with_notes, **rejected_reasons) } + let(:claim) { create(:claim, policy: Policies::EarlyCareerPayments) } + let(:decision) { create(:decision, :rejected, :with_notes, claim: claim, **rejected_reasons) } context "with rejected reasons that don't include 'other'" do let(:rejected_reasons) do diff --git a/spec/mailers/claim_mailer_spec.rb b/spec/mailers/claim_mailer_spec.rb index bafaae24dd..6fcf9c3b2c 100644 --- a/spec/mailers/claim_mailer_spec.rb +++ b/spec/mailers/claim_mailer_spec.rb @@ -11,7 +11,7 @@ class SomePolicy; end end it "sets the GOV.UK Notify reply_to_id according to the policy" do - expect(mail["reply_to_id"].value).to eql(policy.notify_reply_to_id) + expect(mail["reply_to_id"]&.value).to eql(policy.notify_reply_to_id) end it "mentions the type of claim in the subject and body" do @@ -37,7 +37,7 @@ class SomePolicy; end end it "sets the GOV.UK Notify reply_to_id according to the policy" do - expect(mail["reply_to_id"].value).to eql(policy.notify_reply_to_id) + expect(mail["reply_to_id"]&.value).to eql(policy.notify_reply_to_id) end it "includes a personalisation key for claim reference (ref_number)" do @@ -57,7 +57,7 @@ class SomePolicy; end end # Characteristics common to all policies - [Policies::EarlyCareerPayments, Policies::StudentLoans, Policies::LevellingUpPremiumPayments].each do |policy| + [Policies::EarlyCareerPayments, Policies::StudentLoans, Policies::LevellingUpPremiumPayments, Policies::InternationalRelocationPayments].each do |policy| context "with a #{policy} claim" do let!(:journey_configuration) { create(:journey_configuration, policy.to_s.underscore) } @@ -84,6 +84,12 @@ class SomePolicy; end expect(mail.template_id).to eq "f9e39fcd-301a-4427-9159-6831fd484e39" end end + + context "when InternationalRelocationPayments", if: policy == Policies::InternationalRelocationPayments do + it "uses the correct template" do + expect(mail.template_id).to eq "316d6c56-2354-4cb7-9d1d-3b61bc7e8c59" + end + end end describe "#approved" do @@ -109,6 +115,12 @@ class SomePolicy; end expect(mail.template_id).to eq "2032be01-6aee-4a1a-81ce-cf91e09de8d7" end end + + context "when InternationalRelocationPayments", if: policy == Policies::InternationalRelocationPayments do + it "uses the correct template" do + expect(mail.template_id).to eq "5cf5287f-3bdf-4d0b-b999-b61987b9c39f" + end + end end describe "#rejected" do @@ -126,19 +138,6 @@ class SomePolicy; end current_financial_year: (policy == Policies::StudentLoans) ? Policies::StudentLoans.current_financial_year : "" } end - let(:expected_rejected_reasons_keys) do - { - reason_ineligible_subject: "yes", - reason_ineligible_year: "no", - reason_ineligible_school: "no", - reason_ineligible_qualification: "no", - reason_induction: "no", - reason_no_qts_or_qtls: "no", - reason_duplicate: "no", - reason_no_response: "no", - reason_other: "no" - } - end let(:all_expected_keys) { expected_common_keys.merge(expected_rejected_reasons_keys) } it "uses the correct template" do @@ -161,18 +160,77 @@ class SomePolicy; end context "when EarlyCareerPayments", if: policy == Policies::EarlyCareerPayments do let(:expected_template_id) { "b78ffea4-a3d7-4c4a-b0f7-066744c6e79f" } + let(:expected_rejected_reasons_keys) do + { + reason_ineligible_subject: "yes", + reason_ineligible_year: "no", + reason_ineligible_school: "no", + reason_ineligible_qualification: "no", + reason_induction: "no", + reason_no_qts_or_qtls: "no", + reason_duplicate: "no", + reason_no_response: "no", + reason_other: "no" + } + end + include_examples "template id and personalisation keys" end context "when LevellingUpPremiumPayments", if: policy == Policies::LevellingUpPremiumPayments do let(:expected_template_id) { "c20e8d85-ef71-4395-8f8b-90fcbd824b86" } + let(:expected_rejected_reasons_keys) do + { + reason_ineligible_subject: "yes", + reason_ineligible_year: "no", + reason_ineligible_school: "no", + reason_ineligible_qualification: "no", + reason_no_qts_or_qtls: "no", + reason_duplicate: "no", + reason_no_response: "no", + reason_other: "no" + } + end + include_examples "template id and personalisation keys" end context "when StudentLoans", if: policy == Policies::StudentLoans do let(:expected_template_id) { "f719237d-6b2a-42d6-98f2-3d5b6585f32b" } + let(:expected_rejected_reasons_keys) do + { + reason_ineligible_subject: "yes", + reason_ineligible_year: "no", + reason_ineligible_school: "no", + reason_ineligible_qualification: "no", + reason_no_qts_or_qtls: "no", + reason_duplicate: "no", + reason_no_response: "no", + reason_other: "no" + } + end + + include_examples "template id and personalisation keys" + end + + context "when InternationalRelocationPayments", if: policy == Policies::InternationalRelocationPayments do + let(:expected_template_id) { "1edc468c-a1bf-4bea-bb79-042740cd8547" } + + let(:expected_rejected_reasons_keys) do + { + reason_duplicate: "yes", + reason_ineligible_school: "no", + reason_invalid_bank_details: "no", + reason_ineligible_visa_or_entry_date: "no", + reason_ineligible_employment_terms: "no", + reason_no_response_from_school: "no", + reason_suspected_fraud: "no", + reason_information_mismatch_new_details_needed: "no" + } + end + include_examples "template id and personalisation keys" end end diff --git a/spec/models/decision_spec.rb b/spec/models/decision_spec.rb index 6b691dbfea..2c91d0f168 100644 --- a/spec/models/decision_spec.rb +++ b/spec/models/decision_spec.rb @@ -148,29 +148,79 @@ describe "#rejected_reasons_hash" do subject { decision.rejected_reasons_hash } - let(:decision) { create(:decision, :rejected, **rejected_reasons) } - let(:rejected_reasons) do - { - rejected_reasons_ineligible_subject: "1", - rejected_reasons_no_qts_or_qtls: "1" - } + let(:decision) { create(:decision, :rejected, claim: claim, **rejected_reasons) } + + context "with an ECP claim" do + let(:claim) { create(:claim, policy: Policies::EarlyCareerPayments) } + + let(:rejected_reasons) do + { + rejected_reasons_ineligible_subject: "1", + rejected_reasons_no_qts_or_qtls: "1" + } + end + + it do + is_expected.to eq( + reason_ineligible_subject: "1", + reason_ineligible_year: "0", + reason_ineligible_school: "0", + reason_ineligible_qualification: "0", + reason_no_qts_or_qtls: "1", + reason_duplicate: "0", + reason_induction: "0", + reason_no_response: "0", + reason_other: "0" + ) + end end - let(:expected_hash) do - { - reason_ineligible_subject: "1", - reason_ineligible_year: "0", - reason_ineligible_school: "0", - reason_ineligible_qualification: "0", - reason_no_qts_or_qtls: "1", - reason_duplicate: "0", - reason_induction: "0", - reason_no_response: "0", - reason_other: "0" - } + + context "with an LUP claim" do + let(:claim) { create(:claim, policy: Policies::LevellingUpPremiumPayments) } + + let(:rejected_reasons) do + { + rejected_reasons_ineligible_subject: "1", + rejected_reasons_no_qts_or_qtls: "1" + } + end + + it do + is_expected.to eq( + reason_ineligible_subject: "1", + reason_ineligible_year: "0", + reason_ineligible_school: "0", + reason_ineligible_qualification: "0", + reason_no_qts_or_qtls: "1", + reason_duplicate: "0", + reason_no_response: "0", + reason_other: "0" + ) + end end - it "returns the complete hash of rejected reasons" do - is_expected.to eq(expected_hash) + context "with a TSLR claim" do + let(:rejected_reasons) do + { + rejected_reasons_ineligible_subject: "1", + rejected_reasons_no_qts_or_qtls: "1" + } + end + + let(:claim) { create(:claim, policy: Policies::StudentLoans) } + + it do + is_expected.to eq( + reason_ineligible_subject: "1", + reason_ineligible_year: "0", + reason_ineligible_school: "0", + reason_ineligible_qualification: "0", + reason_no_qts_or_qtls: "1", + reason_duplicate: "0", + reason_no_response: "0", + reason_other: "0" + ) + end end end