diff --git a/app/models/validations/sales/sale_information_validations.rb b/app/models/validations/sales/sale_information_validations.rb index 32bf2a716..cec4a16ff 100644 --- a/app/models/validations/sales/sale_information_validations.rb +++ b/app/models/validations/sales/sale_information_validations.rb @@ -370,6 +370,21 @@ module Validations::Sales::SaleInformationValidations end end + def validate_staircasing_purchase_price(record) + return unless record.form.start_year_2026_or_later? + return unless record.is_staircase? && record.value && record.stairbought&.positive? + + full_purchase_price = record.value * 100 / record.stairbought + if full_purchase_price < 15_000 + %i[value stairbought].each do |field| + record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.full_purchase_price_below_min", + value: record.field_formatted_as_currency("value"), + stairbought: record.stairbought, + full_purchase_price: format_as_currency(full_purchase_price)) + end + end + end + def validate_mortgage_used_dont_know(record) return unless record.mortgage_use_unknown? return if record.form.start_year_2026_or_later? diff --git a/config/locales/validations/sales/sale_information.en.yml b/config/locales/validations/sales/sale_information.en.yml index 3c39608cc..9d932ade4 100644 --- a/config/locales/validations/sales/sale_information.en.yml +++ b/config/locales/validations/sales/sale_information.en.yml @@ -54,6 +54,7 @@ en: mortgage_used: "The mortgage (%{mortgage}) and cash deposit (%{deposit}) added together is %{mortgage_and_deposit_total}.

The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.

These two amounts should be the same." mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.

The full purchase price (%{value}) multiplied by the percentage bought (%{stairbought}) is %{stairbought_part_of_value}.

These two amounts should be the same." value: + full_purchase_price_below_min: "Based on the purchase price of %{value} and the percentage bought of %{stairbought}%, the implied full property value is %{full_purchase_price}. The full property value must be at least £15,000." discounted_ownership_value: "The mortgage%{mortgage}%{deposit_and_grant_sentence} added together is %{mortgage_deposit_and_grant_total}.

The full purchase price%{discount_sentence} is %{value_with_discount}.

These two amounts should be the same." outright_sale_value: "The mortgage%{mortgage} and cash deposit (%{deposit}) when added together is %{mortgage_and_deposit_total}.

The full purchase price is %{value}.

These two amounts should be the same." value_over_discounted_london_max: "The percentage discount multiplied by the purchase price is %{discount_value}. This figure should not be more than £137,400 for properties in London." @@ -76,7 +77,7 @@ en: mortgage_not_used: "The cash deposit is %{deposit}.

The full purchase price (%{value}) multiplied by the percentage bought is %{expected_shared_ownership_deposit_value}.

These two amounts should be the same." mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.

The full purchase price (%{value}) multiplied by the percentage equity stake purchased (%{equity}) is %{expected_shared_ownership_deposit_value}.

These two amounts should be the same." mortgage_not_used_socialhomebuy: "The cash deposit (%{deposit}) and cash discount (%{cashdis}) added together is %{deposit_and_discount_total}.

The full purchase price (%{value}) multiplied by the percentage bought (%{equity}) is %{expected_shared_ownership_deposit_value}.

These two amounts should be the same." - staircasing_mortgage: # this key + staircasing_mortgage: mortgage_used: "The mortgage (%{mortgage}) and cash deposit (%{deposit}) added together is %{mortgage_and_deposit_total}.

The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.

These two amounts should be the same." mortgage_not_used: "The cash deposit is %{deposit}.

The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.

These two amounts should be the same." mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.

The full purchase price (%{value}) multiplied by the percentage bought (%{stairbought}) is %{stairbought_part_of_value}.

These two amounts should be the same." @@ -117,6 +118,7 @@ en: mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.

The full purchase price (%{value}) multiplied by the percentage bought (%{stairbought}) is %{stairbought_part_of_value}.

These two amounts should be the same." mortgage_not_used_socialhomebuy: "The cash deposit (%{deposit}) and cash discount (%{cashdis}) added together is %{deposit_and_discount_total}.

The full purchase price (%{value}) multiplied by the percentage bought (%{stairbought}) is %{stairbought_part_of_value}.

These two amounts should be the same." stairbought: + full_purchase_price_below_min: "Based on the purchase price of %{value} and the percentage bought of %{stairbought}%, the implied full property value is %{full_purchase_price}. The full property value must be at least £15,000." stairbought_over_max: "The percentage bought in this staircasing transaction cannot be higher than %{max_stairbought}% for %{type} sales." staircasing_mortgage: mortgage_used: "The mortgage (%{mortgage}) and cash deposit (%{deposit}) added together is %{mortgage_and_deposit_total}.

The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.

These two amounts should be the same." diff --git a/spec/models/validations/sales/sale_information_validations_spec.rb b/spec/models/validations/sales/sale_information_validations_spec.rb index 8d4eb4cea..446a6e033 100644 --- a/spec/models/validations/sales/sale_information_validations_spec.rb +++ b/spec/models/validations/sales/sale_information_validations_spec.rb @@ -994,6 +994,62 @@ RSpec.describe Validations::Sales::SaleInformationValidations do end end + describe "#validate_staircasing_purchase_price" do + let(:saledate) { Time.zone.local(2026, 4, 1) } + let(:record) { build(:sales_log, ownershipsch: 1, staircase: 1, saledate:) } + + it "does not add an error when not staircasing" do + record.staircase = 2 + record.value = 5_000 + record.stairbought = 10 + sale_information_validator.validate_staircasing_purchase_price(record) + + expect(record.errors).to be_empty + end + + it "does not add an error when value is nil" do + record.value = nil + record.stairbought = 10 + sale_information_validator.validate_staircasing_purchase_price(record) + + expect(record.errors).to be_empty + end + + it "does not add an error when stairbought is nil" do + record.value = 5_000 + record.stairbought = nil + sale_information_validator.validate_staircasing_purchase_price(record) + + expect(record.errors).to be_empty + end + + it "does not add an error when full purchase price is at least 15,000" do + record.value = 1_500 + record.stairbought = 10 + sale_information_validator.validate_staircasing_purchase_price(record) + + expect(record.errors).to be_empty + end + + it "adds an error when full purchase price is below 15,000" do + record.value = 1_000 + record.stairbought = 10 + sale_information_validator.validate_staircasing_purchase_price(record) + + expect(record.errors[:value]).to be_present + expect(record.errors[:stairbought]).to be_present + end + + it "does not add an error for years before 2026" do + record.saledate = Time.zone.local(2025, 4, 1) + record.value = 1_000 + record.stairbought = 10 + sale_information_validator.validate_staircasing_purchase_price(record) + + expect(record.errors).to be_empty + end + end + describe "#validate_discount_and_value" do let(:record) { FactoryBot.build(:sales_log, value: 200_000, discount: 50, ownershipsch: 2, type: 9, saledate:) } let(:saledate) { current_collection_start_date }