From fa4e1a933abf11e65482b83ff8114ea9f37fa01b Mon Sep 17 00:00:00 2001 From: Richard Lynch Date: Fri, 20 Dec 2024 15:29:33 +0000 Subject: [PATCH] Block invalid policy combinations The business rules state that certain policy combinations aren't permitted, eg if a claimant has made an ECP claim they can't make a second claim for FE in the same academic year. In such an invalid claim scenario the requirement is to disable the approve button so admins can't approve the claim. --- app/models/claim.rb | 23 +++++- app/models/policies.rb | 18 +++++ ...laim_with_unpermitted_policy_combo_spec.rb | 77 +++++++++++++++++++ spec/models/claim_spec.rb | 48 ++++++++++++ 4 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 spec/features/admin/claim_with_unpermitted_policy_combo_spec.rb diff --git a/app/models/claim.rb b/app/models/claim.rb index bb0491bc35..cc1a6d3828 100644 --- a/app/models/claim.rb +++ b/app/models/claim.rb @@ -284,7 +284,12 @@ def approvable? (!decision_made? || awaiting_qa?) && !payment_prevented_by_other_claims? && attributes_flagged_by_risk_indicator.none? && - policy.approvable?(self) + policy.approvable?(self) && + !precluded_by_previous_claim? + end + + def approved? + decision_made? && latest_decision.approved? end def rejectable? @@ -296,7 +301,7 @@ def holdable? end def flaggable_for_qa? - decision_made? && latest_decision.approved? && below_min_qa_threshold? && !awaiting_qa? && !qa_completed? + approved? && below_min_qa_threshold? && !awaiting_qa? && !qa_completed? end # This method's intention is to help make a decision on whether a claim should @@ -570,4 +575,18 @@ def submittable_mobile_details? def submittable_email_details? email_address.present? && email_verified == true end + + def claims_from_same_claimant + @claims_from_same_claimant ||= MatchingAttributeFinder.new(self).matching_claims + end + + def precluded_by_previous_claim? + approved_claims = claims_from_same_claimant.select(&:approved?) + + other_claimed_policies = approved_claims.map(&:policy) + + policies_claimed = (other_claimed_policies + [policy]).uniq + + Policies.prohibited_policy_combination?(policies_claimed) + end end diff --git a/app/models/policies.rb b/app/models/policies.rb index 0b6a7ea8c2..611439b7e3 100644 --- a/app/models/policies.rb +++ b/app/models/policies.rb @@ -41,4 +41,22 @@ def self.constantize(policy) def self.with_attribute(attr) POLICIES.select { |policy| policy::Eligibility.has_attribute?(attr) } end + + # Claimants can't claim for these policy combinations in the same academic + # year + INVALID_POLICY_COMBINATIONS = [ + [EarlyCareerPayments, FurtherEducationPayments], + [EarlyCareerPayments, LevellingUpPremiumPayments], + [FurtherEducationPayments, LevellingUpPremiumPayments], + [FurtherEducationPayments, StudentLoans], + [FurtherEducationPayments, InternationalRelocationPayments], + [EarlyYearsPayments, EarlyCareerPayments], + [EarlyCareerPayments, LevellingUpPremiumPayments] + ] + + def self.prohibited_policy_combination?(policies) + policies.combination(2).any? do |policy1, policy2| + INVALID_POLICY_COMBINATIONS.include?([policy1, policy2].sort_by(&:to_s)) + end + end end diff --git a/spec/features/admin/claim_with_unpermitted_policy_combo_spec.rb b/spec/features/admin/claim_with_unpermitted_policy_combo_spec.rb new file mode 100644 index 0000000000..ce3557ff89 --- /dev/null +++ b/spec/features/admin/claim_with_unpermitted_policy_combo_spec.rb @@ -0,0 +1,77 @@ +require "rails_helper" + +RSpec.describe "Claim with unpermitted policy combo" do + context "when one of the claims has been approved" do + it "doesn't allow the admin to approve the other claim" do + create( + :claim, + :approved, + :current_academic_year, + policy: Policies::InternationalRelocationPayments, + email_address: "duplicate@example.com" + ) + + duplicate_claim = create( + :claim, + :submitted, + :current_academic_year, + policy: Policies::FurtherEducationPayments, + email_address: "duplicate@example.com" + ) + + sign_in_as_service_operator + + visit new_admin_claim_decision_path(duplicate_claim) + + approve_option = find("input[type=radio][value=approved]") + + expect(approve_option).to be_disabled + end + end + + context "when neither of the claims have been approved" do + it "allows the admin to approve one of the claims" do + irp_claim = create( + :claim, + :submitted, + :current_academic_year, + policy: Policies::InternationalRelocationPayments, + email_address: "duplicate@example.com" + ) + + fe_claim = create( + :claim, + :submitted, + :current_academic_year, + policy: Policies::FurtherEducationPayments, + email_address: "duplicate@example.com" + ) + + sign_in_as_service_operator + + visit new_admin_claim_decision_path(irp_claim) + + approve_option = find("input[type=radio][value=approved]") + + expect(approve_option).not_to be_disabled + + visit new_admin_claim_decision_path(fe_claim) + + approve_option = find("input[type=radio][value=approved]") + + expect(approve_option).not_to be_disabled + + choose "Approve" + + fill_in "Decision notes", with: "LGTM" + + click_on "Confirm decision" + + visit new_admin_claim_decision_path(irp_claim) + + approve_option = find("input[type=radio][value=approved]") + + expect(approve_option).to be_disabled + end + end +end diff --git a/spec/models/claim_spec.rb b/spec/models/claim_spec.rb index 1196df1bff..117277cac1 100644 --- a/spec/models/claim_spec.rb +++ b/spec/models/claim_spec.rb @@ -392,6 +392,54 @@ expect(subject).not_to be_approvable end end + + context "when the claimant has claimed for a policy that precludes them from this policy" do + subject do + create( + :claim, + :submitted, + :current_academic_year, + policy: Policies::FurtherEducationPayments, + email_address: "duplicate@example.com" + ) + end + + context "when the other claim has been approved" do + it "is not approvable" do + create( + :claim, + :approved, + :current_academic_year, + policy: Policies::EarlyCareerPayments, + email_address: "duplicate@example.com" + ) + + expect(subject).not_to be_approvable + end + end + + context "when the other claim has not been approved" do + it "is approvable" do + create( + :claim, + :submitted, + :current_academic_year, + policy: Policies::EarlyCareerPayments, + email_address: "duplicate@example.com" + ) + + create( + :claim, + :rejected, + :current_academic_year, + policy: Policies::EarlyCareerPayments, + email_address: "duplicate@example.com" + ) + + expect(subject).to be_approvable + end + end + end end describe "#rejectable?" do