From 18f40d5c1540a16dcab3fd2bc9c8ac7a946f0a6f Mon Sep 17 00:00:00 2001 From: natdeanlewissoftwire <94526761+natdeanlewissoftwire@users.noreply.github.com> Date: Fri, 17 Mar 2023 11:30:57 +0000 Subject: [PATCH] CLDC-2025 Add equity range validation to sales logs (#1400) * feat: add validation behaviour * feat: add tests * feat: respond to pr comments * refactor: lint * feat: fix tests * feat: fix tests * feat: respond to PR comments --- .../sales/financial_validations.rb | 37 +++++++++ config/locales/en.yml | 3 + .../sales/financial_validations_spec.rb | 81 +++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/app/models/validations/sales/financial_validations.rb b/app/models/validations/sales/financial_validations.rb index 255f12bf2..afb8593a8 100644 --- a/app/models/validations/sales/financial_validations.rb +++ b/app/models/validations/sales/financial_validations.rb @@ -85,6 +85,22 @@ module Validations::Sales::FinancialValidations end end + def validate_equity_in_range_for_year_and_type(record) + return unless record.type && record.equity && record.collection_start_year + + ranges = EQUITY_RANGES_BY_YEAR.fetch(record.collection_start_year, DEFAULT_EQUITY_RANGES) + + return unless (range = ranges[record.type]) + + if record.equity < range.min + record.errors.add :type, I18n.t("validations.financial.equity.under_min", min_equity: range.min) + record.errors.add :equity, I18n.t("validations.financial.equity.under_min", min_equity: range.min) + elsif record.equity > range.max + record.errors.add :type, I18n.t("validations.financial.equity.over_max", max_equity: range.max) + record.errors.add :equity, I18n.t("validations.financial.equity.over_max", max_equity: range.max) + end + end + private def is_relationship_child?(relationship) @@ -94,4 +110,25 @@ private def is_economic_status_child?(economic_status) economic_status == 9 end + + EQUITY_RANGES_BY_YEAR = { + 2022 => { + 2 => 25..75, + 30 => 10..75, + 18 => 25..75, + 16 => 10..75, + 24 => 25..75, + 31 => 0..75, + }, + }.freeze + + DEFAULT_EQUITY_RANGES = { + 2 => 10..75, + 30 => 25..75, + 18 => 25..75, + 16 => 10..75, + 24 => 25..75, + 31 => 0..75, + 32 => 0..75, + }.freeze end diff --git a/config/locales/en.yml b/config/locales/en.yml index f44ba1d41..2d17cf207 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -313,6 +313,9 @@ en: percentage_bought_must_be_greater_than_percentage_owned: "Total percentage buyer now owns must be more than percentage bought in this transaction" older_person_percentage_owned_maximum_75: "Percentage cannot be above 75% under Older Person's Shared Ownership" percentage_bought_must_be_at_least_threshold: "The minimum increase in equity while staircasing is %{threshold}%" + equity: + under_min: "The minimum initial equity stake for this type of shared ownership sale is %{min_equity}%" + over_max: "The maximum initial equity stake is %{max_equity}%" household: reasonpref: diff --git a/spec/models/validations/sales/financial_validations_spec.rb b/spec/models/validations/sales/financial_validations_spec.rb index d9406aec9..350cc66ef 100644 --- a/spec/models/validations/sales/financial_validations_spec.rb +++ b/spec/models/validations/sales/financial_validations_spec.rb @@ -266,4 +266,85 @@ RSpec.describe Validations::Sales::FinancialValidations do end end end + + describe "#validate_equity_in_range_for_year_and_type" do + let(:record) { FactoryBot.create(:sales_log, saledate: now) } + + around do |example| + Timecop.freeze(now) do + example.run + end + Timecop.unfreeze + end + + context "with a log in the 22/23 collection year" do + let(:now) { Time.zone.local(2023, 1, 1) } + + it "adds an error for type 2, equity below min with the correct percentage" do + record.type = 2 + record.equity = 1 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors["equity"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 25)) + expect(record.errors["type"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 25)) + end + + it "adds an error for type 30, equity below min with the correct percentage" do + record.type = 30 + record.equity = 1 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors["equity"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 10)) + expect(record.errors["type"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 10)) + end + + it "does not add an error for equity in range with the correct percentage" do + record.type = 2 + record.equity = 50 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors).to be_empty + end + + it "adds an error for equity above max with the correct percentage" do + record.type = 2 + record.equity = 90 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors["equity"]).to include(match I18n.t("validations.financial.equity.over_max", max_equity: 75)) + expect(record.errors["type"]).to include(match I18n.t("validations.financial.equity.over_max", max_equity: 75)) + end + end + + context "with a log in 23/24 collection year" do + let(:now) { Time.zone.local(2024, 1, 1) } + + it "adds an error for type 2, equity below min with the correct percentage" do + record.type = 2 + record.equity = 1 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors["equity"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 10)) + expect(record.errors["type"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 10)) + end + + it "adds an error for type 30, equity below min with the correct percentage" do + record.type = 30 + record.equity = 1 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors["equity"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 25)) + expect(record.errors["type"]).to include(match I18n.t("validations.financial.equity.under_min", min_equity: 25)) + end + + it "does not add an error for equity in range with the correct percentage" do + record.type = 2 + record.equity = 50 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors).to be_empty + end + + it "adds an error for equity above max with the correct percentage" do + record.type = 2 + record.equity = 90 + financial_validator.validate_equity_in_range_for_year_and_type(record) + expect(record.errors["equity"]).to include(match I18n.t("validations.financial.equity.over_max", max_equity: 75)) + expect(record.errors["type"]).to include(match I18n.t("validations.financial.equity.over_max", max_equity: 75)) + end + end + end end