diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index f6086a918..98517058e 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -279,11 +279,17 @@ class SalesLog < Log mortgage_amount + deposit_amount + cashdis_amount end + def value_times_equity + return unless value && equity + + value * equity / 100 + end + def mortgage_deposit_and_discount_error_fields [ "mortgage", "deposit", - cashdis.present? ? "discount" : nil, + cashdis.present? ? "cash discount" : nil, ].compact.to_sentence end diff --git a/app/models/validations/sales/financial_validations.rb b/app/models/validations/sales/financial_validations.rb index 410f6d250..59b84f7e3 100644 --- a/app/models/validations/sales/financial_validations.rb +++ b/app/models/validations/sales/financial_validations.rb @@ -92,6 +92,23 @@ module Validations::Sales::FinancialValidations end end + def validate_shared_ownership_deposit(record) + return unless record.saledate && record.form.start_year_after_2024? + return unless record.mortgage || record.mortgageused == 2 || record.mortgageused == 3 + return unless record.cashdis && record.deposit && record.value && record.equity + + mortgage_value = record.mortgage || 0 + + if mortgage_value + record.deposit + record.cashdis != record.value * record.equity / 100 + %i[mortgage value deposit ownershipsch cashdis equity].each do |field| + record.errors.add field, I18n.t("validations.financial.shared_ownership_deposit", + mortgage_deposit_and_discount_error_fields: record.mortgage_deposit_and_discount_error_fields, + mortgage_deposit_and_discount_total: record.field_formatted_as_currency("mortgage_deposit_and_discount_total"), + value_times_equity: record.field_formatted_as_currency("value_times_equity")) + end + end + end + private def is_relationship_child?(relationship) diff --git a/app/models/validations/sales/soft_validations.rb b/app/models/validations/sales/soft_validations.rb index d8d957988..fce544754 100644 --- a/app/models/validations/sales/soft_validations.rb +++ b/app/models/validations/sales/soft_validations.rb @@ -84,6 +84,7 @@ module Validations::Sales::SoftValidations end def shared_ownership_deposit_invalid? + return unless saledate && collection_start_year <= 2023 return unless mortgage || mortgageused == 2 || mortgageused == 3 return unless cashdis || !is_type_discount? return unless deposit && value && equity diff --git a/config/locales/en.yml b/config/locales/en.yml index 8a3e8cd77..2a8d86951 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -433,6 +433,7 @@ en: 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}%" mortgage: "Mortgage value cannot be £0 if a mortgage was used for the purchase of this property" + shared_ownership_deposit: "The %{mortgage_deposit_and_discount_error_fields} added together is %{mortgage_deposit_and_discount_total}. The value times the equity percentage is %{value_times_equity}. These figures should be the same" household: reasonable_preference_reason: diff --git a/spec/models/validations/sales/financial_validations_spec.rb b/spec/models/validations/sales/financial_validations_spec.rb index 68cf19a14..295b11c2c 100644 --- a/spec/models/validations/sales/financial_validations_spec.rb +++ b/spec/models/validations/sales/financial_validations_spec.rb @@ -339,4 +339,179 @@ RSpec.describe Validations::Sales::FinancialValidations do end end end + + describe "#validate_shared_ownership_deposit" do + let(:record) { FactoryBot.create(:sales_log, saledate: now) } + + around do |example| + Timecop.freeze(now) do + Singleton.__init__(FormHandler) + example.run + end + Timecop.return + end + + context "with a log in the 24/25 collection year" do + let(:now) { Time.zone.local(2024, 4, 2) } + + it "does not add an error if MORTGAGE + DEPOSIT + CASHDIS are equal VALUE * EQUITY/100" do + record.mortgage = 1000 + record.deposit = 1000 + record.cashdis = 1000 + record.value = 3000 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + + it "does not add an error if mortgage is used and no mortgage is given" do + record.mortgage = nil + record.deposit = 1000 + record.cashdis = 1000 + record.value = 3000 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + + it "adds an error if mortgage is not used and no mortgage is given" do + record.mortgage = nil + record.mortgageused = 2 + record.deposit = 1000 + record.cashdis = 1000 + record.value = 3000 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same") + expect(record.errors["deposit"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same") + expect(record.errors["cashdis"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same") + expect(record.errors["value"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same") + expect(record.errors["equity"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same") + end + + it "does not add an error if no deposit is given" do + record.mortgage = 1000 + record.deposit = nil + record.cashdis = 1000 + record.value = 3000 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + + it "does not add an error if no cashdis is given and cashdis is routed to" do + record.mortgage = 1000 + record.deposit = 1000 + record.type = 18 + record.cashdis = nil + record.value = 3000 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + + it "does not add an error if no cashdis is given and cashdis is not routed to" do + record.mortgageused = 1 + record.mortgage = 1000 + record.deposit = 1000 + record.type = 2 + record.cashdis = nil + record.value = 3000 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + + it "does not add an error if no value is given" do + record.mortgage = 1000 + record.deposit = 1000 + record.cashdis = 1000 + record.value = nil + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + + it "does not add an error if no equity is given" do + record.mortgage = 1000 + record.deposit = 1000 + record.cashdis = 1000 + record.value = 3000 + record.equity = nil + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + + it "adds an error if MORTGAGE + DEPOSIT + CASHDIS are not equal VALUE * EQUITY/100" do + record.mortgageused = 1 + record.mortgage = 1000 + record.deposit = 1000 + record.cashdis = 1000 + record.value = 4323 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same") + expect(record.errors["deposit"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same") + expect(record.errors["cashdis"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same") + expect(record.errors["value"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same") + expect(record.errors["equity"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same") + end + end + + context "with a log in 23/24 collection year" do + let(:now) { Time.zone.local(2024, 1, 1) } + + it "does not add an error if MORTGAGE + DEPOSIT + CASHDIS are not equal VALUE * EQUITY/100" do + record.mortgage = 1000 + record.deposit = 1000 + record.cashdis = 1000 + record.value = 4323 + record.equity = 100 + + financial_validator.validate_shared_ownership_deposit(record) + expect(record.errors["mortgage"]).to be_empty + expect(record.errors["deposit"]).to be_empty + expect(record.errors["cashdis"]).to be_empty + expect(record.errors["value"]).to be_empty + expect(record.errors["equity"]).to be_empty + end + end + end end diff --git a/spec/models/validations/sales/soft_validations_spec.rb b/spec/models/validations/sales/soft_validations_spec.rb index 4d0c1024a..6b9817277 100644 --- a/spec/models/validations/sales/soft_validations_spec.rb +++ b/spec/models/validations/sales/soft_validations_spec.rb @@ -400,6 +400,10 @@ RSpec.describe Validations::Sales::SoftValidations do end context "when validating shared ownership deposit" do + before do + record.saledate = Time.zone.local(2023, 4, 3) + end + it "returns false if MORTGAGE + DEPOSIT + CASHDIS are equal VALUE * EQUITY/100" do record.mortgage = 1000 record.deposit = 1000 @@ -501,6 +505,18 @@ RSpec.describe Validations::Sales::SoftValidations do expect(record) .to be_shared_ownership_deposit_invalid end + + it "returns false if startyear is after 2024" do + record.saledate = Time.zone.local(2025, 1, 1) + record.mortgage = 1000 + record.deposit = 1000 + record.cashdis = 1000 + record.value = 4323 + record.equity = 100 + + expect(record) + .not_to be_shared_ownership_deposit_invalid + end end end diff --git a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb index 9ecf31d21..5280c5be2 100644 --- a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb @@ -989,18 +989,6 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do expect(parser.errors.where(:field_31, category: :soft_validation).first.message).to eql("You told us this person is aged 22 years and retired.") end end - - context "when a soft validation is triggered that relates both to fields that are and are not routed to" do - let(:attributes) { valid_attributes.merge({ field_101: "300000" }) } - - it "adds errors to fields that are routed to" do - expect(parser.errors.where(:field_101, category: :soft_validation)).to be_present - end - - it "does not add errors to fields that are not routed to" do - expect(parser.errors.where(:field_112, category: :soft_validation)).not_to be_present - end - end end end