Browse Source

CLDC-853 Added validations for sales income2 (#1101)

* CLDC-853 Added hard validations for sales income2

* CLDC-853 Added soft validation for sales income2

* CLDC-853 Fix tests broken by new code

* CLDC-853 Add new tests for new page and refactor slightly

* CLDC-853 Fix linting errors

* CLDC-853 Rename migration and update schema version

* CLDC-853 Fix broken sales income2 test

* CLDC-853 Rename migration

* CLDC-853 Move income 2 to cya card 2 and commonise combined income validation

* CLDC-853 Actually use the validate_combined_income method

* combine duplicate methods after rebase, ensure hard validations are triggered on all relevant fields

* move validation on child income to financial validations to stop it being triggered on lettings logs, minor amendments to tests broken by changes

* revamp financial validations tests against income to reflect updates

* amend child income validation to reflect specifications and write tests to cover this validation

* correct linting errors and play a little code golf

* change copy for some validations, add sales log method and amend interruption screen helper to support this

* extract duplicate code to private method

* update buyer 1 and 2 income value check to be consistent

* remove ecstat from income checks, the only ecstat we care about is child which is dealt with elsewhere

* rename constant struct with same anme as existing variable

* amend tests to reflect the chagnes in validations and copy

* enable currency formatting of numbers for inserting into informative_text or title_text

* update evil test in form handler spec

* rebase and fix conflicts and tests

* change a variable name and correct minor rebase errors

* update interruption screen helper tests

* correct linting errors, minor test failure and typo

* add tests for new sales log method for formatting currency

* fix merge conflicts

---------

Co-authored-by: Arthur Campbell <arfa.camble@gmail.com>
pull/1336/head
David May-Miller 2 years ago committed by GitHub
parent
commit
4a31906d45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 33
      app/helpers/interruption_screen_helper.rb
  2. 6
      app/models/form/sales/pages/about_price_shared_ownership_value_check.rb
  3. 15
      app/models/form/sales/pages/buyer1_income_value_check.rb
  4. 35
      app/models/form/sales/pages/buyer2_income_value_check.rb
  5. 2
      app/models/form/sales/questions/buyer1_income_value_check.rb
  6. 1
      app/models/form/sales/questions/buyer2_income.rb
  7. 25
      app/models/form/sales/questions/buyer2_income_value_check.rb
  8. 3
      app/models/form/sales/subsections/household_characteristics.rb
  9. 1
      app/models/form/sales/subsections/income_benefits_and_savings.rb
  10. 4
      app/models/log.rb
  11. 18
      app/models/sales_log.rb
  12. 61
      app/models/validations/sales/financial_validations.rb
  13. 12
      app/models/validations/sales/soft_validations.rb
  14. 12
      config/locales/en.yml
  15. 5
      db/migrate/20230105103134_add_income2_value_check.rb
  16. 1
      db/schema.rb
  17. 53
      spec/helpers/interruption_screen_helper_spec.rb
  18. 2
      spec/models/form/sales/questions/buyer1_income_value_check_spec.rb
  19. 6
      spec/models/form/sales/subsections/household_characteristics_spec.rb
  20. 2
      spec/models/form/sales/subsections/income_benefits_and_savings_spec.rb
  21. 4
      spec/models/form_handler_spec.rb
  22. 23
      spec/models/sales_log_spec.rb
  23. 176
      spec/models/validations/sales/financial_validations_spec.rb

33
app/helpers/interruption_screen_helper.rb

@ -1,17 +1,10 @@
module InterruptionScreenHelper module InterruptionScreenHelper
def display_informative_text(informative_text, lettings_log) def display_informative_text(informative_text, log)
return "" unless informative_text["arguments"] return "" unless informative_text["arguments"]
translation_params = {} translation_params = {}
informative_text["arguments"].each do |argument| informative_text["arguments"].each do |argument|
value = if argument["label"] value = get_value_from_argument(log, argument)
pre_casing_value = lettings_log.form.get_question(argument["key"], lettings_log).answer_label(lettings_log)
pre_casing_value.downcase
elsif argument["currency"]
number_to_currency(lettings_log.public_send(argument["key"]), delimiter: ",", format: "%n", unit: "£")
else
lettings_log.public_send(argument["key"])
end
translation_params[argument["i18n_template"].to_sym] = value translation_params[argument["i18n_template"].to_sym] = value
end end
@ -24,21 +17,27 @@ module InterruptionScreenHelper
end end
end end
def display_title_text(title_text, lettings_log) def display_title_text(title_text, log)
return "" if title_text.nil? return "" if title_text.nil?
translation_params = {} translation_params = {}
arguments = title_text["arguments"] || {} arguments = title_text["arguments"] || {}
arguments.each do |argument| arguments.each do |argument|
value = if argument["label"] value = get_value_from_argument(log, argument)
lettings_log.form.get_question(argument["key"], lettings_log).answer_label(lettings_log).downcase
elsif argument["currency"]
number_to_currency(lettings_log.public_send(argument["key"]), delimiter: ",", format: "%n", unit: "£")
else
lettings_log.public_send(argument["key"])
end
translation_params[argument["i18n_template"].to_sym] = value translation_params[argument["i18n_template"].to_sym] = value
end end
I18n.t(title_text["translation"], **translation_params).to_s I18n.t(title_text["translation"], **translation_params).to_s
end end
private
def get_value_from_argument(log, argument)
if argument["label"]
log.form.get_question(argument["key"], log).answer_label(log).downcase
elsif argument["arguments_for_key"]
log.public_send(argument["key"], argument["arguments_for_key"])
else
log.public_send(argument["key"])
end
end
end end

6
app/models/form/sales/pages/about_price_shared_ownership_value_check.rb

@ -20,14 +20,12 @@ class Form::Sales::Pages::AboutPriceSharedOwnershipValueCheck < ::Form::Page
"translation" => "soft_validations.purchase_price.hint_text", "translation" => "soft_validations.purchase_price.hint_text",
"arguments" => [ "arguments" => [
{ {
"key" => "purchase_price_soft_min_or_soft_max", "key" => "field_formatted_as_currency",
"label" => false, "arguments_for_key" => "purchase_price_soft_min_or_soft_max",
"i18n_template" => "soft_min_or_soft_max", "i18n_template" => "soft_min_or_soft_max",
"currency" => true,
}, },
{ {
"key" => "purchase_price_min_or_max_text", "key" => "purchase_price_min_or_max_text",
"label" => false,
"i18n_template" => "min_or_max", "i18n_template" => "min_or_max",
}, },
], ],

15
app/models/form/sales/pages/buyer1_income_value_check.rb

@ -6,6 +6,21 @@ class Form::Sales::Pages::Buyer1IncomeValueCheck < ::Form::Page
"income1_under_soft_min?" => true, "income1_under_soft_min?" => true,
}, },
] ]
@title_text = {
"translation" => "soft_validations.income.under_soft_min_for_economic_status",
"arguments" => [
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "income1",
"i18n_template" => "income",
},
{
"key" => "income_soft_min_for_ecstat",
"arguments_for_key" => "ecstat1",
"i18n_template" => "minimum",
},
],
}
@informative_text = {} @informative_text = {}
end end

35
app/models/form/sales/pages/buyer2_income_value_check.rb

@ -0,0 +1,35 @@
class Form::Sales::Pages::Buyer2IncomeValueCheck < ::Form::Page
def initialize(id, hsh, subsection)
super
@header = ""
@description = ""
@subsection = subsection
@depends_on = [
{
"income2_under_soft_min?" => true,
},
]
@title_text = {
"translation" => "soft_validations.income.under_soft_min_for_economic_status",
"arguments" => [
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "income2",
"i18n_template" => "income",
},
{
"key" => "income_soft_min_for_ecstat",
"arguments_for_key" => "ecstat2",
"i18n_template" => "minimum",
},
],
}
@informative_text = {}
end
def questions
@questions ||= [
Form::Sales::Questions::Buyer2IncomeValueCheck.new(nil, nil, self),
]
end
end

2
app/models/form/sales/questions/buyer1_income_value_check.rb

@ -3,7 +3,7 @@ class Form::Sales::Questions::Buyer1IncomeValueCheck < ::Form::Question
super super
@id = "income1_value_check" @id = "income1_value_check"
@check_answer_label = "Income confirmation" @check_answer_label = "Income confirmation"
@header = "Are you sure this income is correct?" @header = "Are you sure this is correct?"
@type = "interruption_screen" @type = "interruption_screen"
@answer_options = { @answer_options = {
"0" => { "value" => "Yes" }, "0" => { "value" => "Yes" },

1
app/models/form/sales/questions/buyer2_income.rb

@ -7,6 +7,7 @@ class Form::Sales::Questions::Buyer2Income < ::Form::Question
@type = "numeric" @type = "numeric"
@hint_text = "Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments." @hint_text = "Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments."
@min = 0 @min = 0
@max = 999_999
@step = 1 @step = 1
@width = 5 @width = 5
@prefix = "£" @prefix = "£"

25
app/models/form/sales/questions/buyer2_income_value_check.rb

@ -0,0 +1,25 @@
class Form::Sales::Questions::Buyer2IncomeValueCheck < ::Form::Question
def initialize(id, hsh, page)
super
@id = "income2_value_check"
@check_answer_label = "Income confirmation"
@header = "Are you sure this is correct?"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"income2_value_check" => 0,
},
{
"income2_value_check" => 1,
},
],
}
@check_answers_card_number = 2
@page = page
end
end

3
app/models/form/sales/subsections/household_characteristics.rb

@ -34,7 +34,8 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection
Form::Sales::Pages::RetirementValueCheck.new("gender_2_buyer_retirement_value_check", nil, self, person_index: 2), Form::Sales::Pages::RetirementValueCheck.new("gender_2_buyer_retirement_value_check", nil, self, person_index: 2),
ethnic_pages_for_buyer_2, ethnic_pages_for_buyer_2,
Form::Sales::Pages::Buyer2WorkingSituation.new(nil, nil, self), Form::Sales::Pages::Buyer2WorkingSituation.new(nil, nil, self),
Form::Sales::Pages::RetirementValueCheck.new("working_situation_2_buyer_retirement_value_check", nil, self, person_index: 2), Form::Sales::Pages::RetirementValueCheck.new("working_situation_2_retirement_value_check_joint_purchase", nil, self, person_index: 2),
Form::Sales::Pages::Buyer2IncomeValueCheck.new("working_situation_buyer_2_income_value_check", nil, self),
Form::Sales::Pages::Buyer2LiveInProperty.new(nil, nil, self), Form::Sales::Pages::Buyer2LiveInProperty.new(nil, nil, self),
Form::Sales::Pages::NumberOfOthersInProperty.new(nil, nil, self), Form::Sales::Pages::NumberOfOthersInProperty.new(nil, nil, self),
Form::Sales::Pages::PersonKnown.new("person_2_known", nil, self, person_index: 2), Form::Sales::Pages::PersonKnown.new("person_2_known", nil, self, person_index: 2),

1
app/models/form/sales/subsections/income_benefits_and_savings.rb

@ -15,6 +15,7 @@ class Form::Sales::Subsections::IncomeBenefitsAndSavings < ::Form::Subsection
Form::Sales::Pages::MortgageValueCheck.new("buyer_1_mortgage_value_check", nil, self, 1), Form::Sales::Pages::MortgageValueCheck.new("buyer_1_mortgage_value_check", nil, self, 1),
Form::Sales::Pages::Buyer2Income.new(nil, nil, self), Form::Sales::Pages::Buyer2Income.new(nil, nil, self),
Form::Sales::Pages::MortgageValueCheck.new("buyer_2_income_mortgage_value_check", nil, self, 2), Form::Sales::Pages::MortgageValueCheck.new("buyer_2_income_mortgage_value_check", nil, self, 2),
Form::Sales::Pages::Buyer2IncomeValueCheck.new("buyer_2_income_value_check", nil, self),
Form::Sales::Pages::Buyer2Mortgage.new(nil, nil, self), Form::Sales::Pages::Buyer2Mortgage.new(nil, nil, self),
Form::Sales::Pages::MortgageValueCheck.new("buyer_2_mortgage_value_check", nil, self, 2), Form::Sales::Pages::MortgageValueCheck.new("buyer_2_mortgage_value_check", nil, self, 2),
Form::Sales::Pages::HousingBenefits.new(nil, nil, self), Form::Sales::Pages::HousingBenefits.new(nil, nil, self),

4
app/models/log.rb

@ -147,4 +147,8 @@ private
self[is_inferred_key] = false self[is_inferred_key] = false
self[postcode_key] = nil self[postcode_key] = nil
end end
def format_as_currency(num_string)
ActionController::Base.helpers.number_to_currency(num_string, unit: "£")
end
end end

18
app/models/sales_log.rb

@ -124,6 +124,10 @@ class SalesLog < Log
la && LONDON_BOROUGHS.include?(la) la && LONDON_BOROUGHS.include?(la)
end end
def property_not_in_london?
!london_property?
end
def income1_used_for_mortgage? def income1_used_for_mortgage?
inc1mort == 1 inc1mort == 1
end end
@ -256,4 +260,18 @@ class SalesLog < Log
def purchase_price_soft_max def purchase_price_soft_max
LaSaleRange.find_by(start_year: collection_start_year, la:, bedrooms: beds).soft_max LaSaleRange.find_by(start_year: collection_start_year, la:, bedrooms: beds).soft_max
end end
def income_soft_min_for_ecstat(ecstat_field)
economic_status_code = public_send(ecstat_field)
return unless ALLOWED_INCOME_RANGES_SALES
soft_min = ALLOWED_INCOME_RANGES_SALES[economic_status_code]&.soft_min
format_as_currency(soft_min)
end
def field_formatted_as_currency(field_name)
field_value = public_send(field_name)
format_as_currency(field_value)
end
end end

61
app/models/validations/sales/financial_validations.rb

@ -3,21 +3,37 @@ module Validations::Sales::FinancialValidations
# or 'validate_' to run on submit as well # or 'validate_' to run on submit as well
def validate_income1(record) def validate_income1(record)
if record.ecstat1 && record.income1 && record.la && record.ownershipsch == 1 return unless record.income1 && record.la && record.shared_ownership_scheme?
if record.london_property?
record.errors.add :income1, I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000) if record.income1 > 90_000 relevant_fields = %i[income1 ownershipsch la postcode_full]
record.errors.add :ecstat1, I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000) if record.income1 > 90_000 if record.london_property? && record.income1 > 90_000
record.errors.add :ownershipsch, I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000) if record.income1 > 90_000 relevant_fields.each { |field| record.errors.add field, I18n.t("validations.financial.income.over_hard_max_for_london") }
record.errors.add :la, I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000) if record.income1 > 90_000 elsif record.property_not_in_london? && record.income1 > 80_000
record.errors.add :postcode_full, I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000) if record.income1 > 90_000 relevant_fields.each { |field| record.errors.add field, I18n.t("validations.financial.income.over_hard_max_for_outside_london") }
elsif record.income1 > 80_000
record.errors.add :income1, I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000)
record.errors.add :ecstat1, I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000)
record.errors.add :ownershipsch, I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000)
record.errors.add :la, I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000) if record.income1 > 80_000
record.errors.add :postcode_full, I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000) if record.income1 > 80_000
end end
end end
def validate_income2(record)
return unless record.income2 && record.la && record.shared_ownership_scheme?
relevant_fields = %i[income2 ownershipsch la postcode_full]
if record.london_property? && record.income2 > 90_000
relevant_fields.each { |field| record.errors.add field, I18n.t("validations.financial.income.over_hard_max_for_london") }
elsif record.property_not_in_london? && record.income2 > 80_000
relevant_fields.each { |field| record.errors.add field, I18n.t("validations.financial.income.over_hard_max_for_outside_london") }
end
end
def validate_combined_income(record)
return unless record.income1 && record.income2 && record.la && record.shared_ownership_scheme?
combined_income = record.income1 + record.income2
relevant_fields = %i[income1 income2 ownershipsch la postcode_full]
if record.london_property? && combined_income > 90_000
relevant_fields.each { |field| record.errors.add field, I18n.t("validations.financial.income.combined_over_hard_max_for_london") }
elsif record.property_not_in_london? && combined_income > 80_000
relevant_fields.each { |field| record.errors.add field, I18n.t("validations.financial.income.combined_over_hard_max_for_outside_london") }
end
end end
def validate_cash_discount(record) def validate_cash_discount(record)
@ -36,6 +52,15 @@ module Validations::Sales::FinancialValidations
end end
end end
def validate_child_income(record)
return unless record.income2 && record.ecstat2
if record.income2.positive? && is_economic_status_child?(record.ecstat2)
record.errors.add :ecstat2, I18n.t("validations.financial.income.child_has_income")
record.errors.add :income2, I18n.t("validations.financial.income.child_has_income")
end
end
def validate_percentage_owned_not_too_much_if_older_person(record) def validate_percentage_owned_not_too_much_if_older_person(record)
return unless record.old_persons_shared_ownership? && record.stairowned return unless record.old_persons_shared_ownership? && record.stairowned
@ -44,4 +69,14 @@ module Validations::Sales::FinancialValidations
record.errors.add :type, I18n.t("validations.financial.staircasing.older_person_percentage_owned_maximum_75") record.errors.add :type, I18n.t("validations.financial.staircasing.older_person_percentage_owned_maximum_75")
end end
end end
private
def is_relationship_child?(relationship)
relationship == "C"
end
def is_economic_status_child?(economic_status)
economic_status == 9
end
end end

12
app/models/validations/sales/soft_validations.rb

@ -1,5 +1,5 @@
module Validations::Sales::SoftValidations module Validations::Sales::SoftValidations
ALLOWED_INCOME_RANGES = { ALLOWED_INCOME_RANGES_SALES = {
1 => OpenStruct.new(soft_min: 5000), 1 => OpenStruct.new(soft_min: 5000),
2 => OpenStruct.new(soft_min: 1500), 2 => OpenStruct.new(soft_min: 1500),
3 => OpenStruct.new(soft_min: 1000), 3 => OpenStruct.new(soft_min: 1000),
@ -8,9 +8,15 @@ module Validations::Sales::SoftValidations
}.freeze }.freeze
def income1_under_soft_min? def income1_under_soft_min?
return false unless ecstat1 && income1 && ALLOWED_INCOME_RANGES[ecstat1] return false unless ecstat1 && income1 && ALLOWED_INCOME_RANGES_SALES[ecstat1]
income1 < ALLOWED_INCOME_RANGES[ecstat1][:soft_min] income1 < ALLOWED_INCOME_RANGES_SALES[ecstat1][:soft_min]
end
def income2_under_soft_min?
return false unless ecstat2 && income2 && ALLOWED_INCOME_RANGES_SALES[ecstat2]
income2 < ALLOWED_INCOME_RANGES_SALES[ecstat2][:soft_min]
end end
def staircase_bought_above_fifty? def staircase_bought_above_fifty?

12
config/locales/en.yml

@ -223,8 +223,12 @@ en:
under_hard_min: "Net income cannot be less than £%{hard_min} per week given the tenant’s working situation" under_hard_min: "Net income cannot be less than £%{hard_min} per week given the tenant’s working situation"
freq_missing: "Select how often the household receives income" freq_missing: "Select how often the household receives income"
earnings_missing: "Enter how much income the household has in total" earnings_missing: "Enter how much income the household has in total"
income1: income:
over_hard_max: "Income must be lower than £%{hard_max}" over_hard_max_for_london: "Income must not exceed £90,000 for properties within London local authorities"
over_hard_max_for_outside_london: "Income must not exceed £80,000 for properties outside London local authorities"
combined_over_hard_max_for_london: "Combined income must not exceed £90,000 for properties within London local authorities"
combined_over_hard_max_for_outside_london: "Combined income must not exceed £80,000 for properties outside London local authorities"
child_has_income: "Child's income must be £0"
negative_currency: "Enter an amount above 0" negative_currency: "Enter an amount above 0"
rent: rent:
less_than_shortfall: "Enter an amount that is more than the shortfall in basic rent" less_than_shortfall: "Enter an amount that is more than the shortfall in basic rent"
@ -467,6 +471,8 @@ en:
message: "Net income is lower than expected based on the lead tenant’s working situation. Are you sure this is correct?" message: "Net income is lower than expected based on the lead tenant’s working situation. Are you sure this is correct?"
in_soft_max_range: in_soft_max_range:
message: "Net income is higher than expected based on the lead tenant’s working situation. Are you sure this is correct?" message: "Net income is higher than expected based on the lead tenant’s working situation. Are you sure this is correct?"
income:
under_soft_min_for_economic_status: "You said income was %{income}, which is below this working situation's minimum (%{minimum})"
rent: rent:
outside_range_title: "You told us the rent is %{brent}" outside_range_title: "You told us the rent is %{brent}"
min_hint_text: "The minimum rent expected for this type of property in this local authority is £%{soft_min_for_period}." min_hint_text: "The minimum rent expected for this type of property in this local authority is £%{soft_min_for_period}."
@ -559,4 +565,4 @@ en:
one_argument: "This is based on the tenant’s work situation: %{ecstat1}" one_argument: "This is based on the tenant’s work situation: %{ecstat1}"
title_text: title_text:
no_argument: "Some test text" no_argument: "Some test text"
one_argument: "You said this: %{ecstat1}" one_argument: "You said this: %{argument}"

5
db/migrate/20230105103134_add_income2_value_check.rb

@ -0,0 +1,5 @@
class AddIncome2ValueCheck < ActiveRecord::Migration[7.0]
def change
add_column :sales_logs, :income2_value_check, :integer
end
end

1
db/schema.rb

@ -520,6 +520,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_02_10_143120) do
t.integer "value_value_check" t.integer "value_value_check"
t.integer "old_persons_shared_ownership_value_check" t.integer "old_persons_shared_ownership_value_check"
t.integer "staircase_bought_value_check" t.integer "staircase_bought_value_check"
t.integer "income2_value_check"
t.integer "monthly_charges_value_check" t.integer "monthly_charges_value_check"
t.integer "details_known_5" t.integer "details_known_5"
t.integer "details_known_6" t.integer "details_known_6"

53
spec/helpers/interruption_screen_helper_spec.rb

@ -13,6 +13,7 @@ RSpec.describe InterruptionScreenHelper do
earnings: 750, earnings: 750,
incfreq: 1, incfreq: 1,
created_by: user, created_by: user,
sex1: "F",
) )
end end
@ -94,6 +95,54 @@ RSpec.describe InterruptionScreenHelper do
.to eq("") .to eq("")
end end
end end
context "when an argument is given not for a label" do
translation = "test.title_text.one_argument"
it "returns the correct text" do
informative_text_hash = {
"translation" => translation,
"arguments" => [
{
"key" => "earnings",
"i18n_template" => "argument",
},
],
}
expect(display_informative_text(informative_text_hash, lettings_log)).to eq(I18n.t(translation, argument: lettings_log.earnings))
end
end
context "when and argument is given with a key and arguments for the key" do
it "makes the correct method call" do
informative_text_hash = {
"arguments" => [
{
"key" => "retirement_age_for_person",
"arguments_for_key" => 1,
"i18n_template" => "argument",
},
],
}
allow(lettings_log).to receive(:retirement_age_for_person)
display_informative_text(informative_text_hash, lettings_log)
expect(lettings_log).to have_received(:retirement_age_for_person).with(1)
end
it "returns the correct text" do
translation = "test.title_text.one_argument"
informative_text_hash = {
"translation" => translation,
"arguments" => [
{
"key" => "retirement_age_for_person",
"arguments_for_key" => 1,
"i18n_template" => "argument",
},
],
}
expect(display_informative_text(informative_text_hash, lettings_log)).to eq(I18n.t(translation, argument: lettings_log.retirement_age_for_person(1)))
end
end
end end
describe "display_title_text" do describe "display_title_text" do
@ -113,12 +162,12 @@ RSpec.describe InterruptionScreenHelper do
{ {
"key" => "ecstat1", "key" => "ecstat1",
"label" => true, "label" => true,
"i18n_template" => "ecstat1", "i18n_template" => "argument",
}, },
], ],
} }
expect(display_title_text(title_text, lettings_log)) expect(display_title_text(title_text, lettings_log))
.to eq(I18n.t("test.title_text.one_argument", ecstat1: lettings_log.form.get_question("ecstat1", lettings_log).answer_label(lettings_log).downcase)) .to eq(I18n.t("test.title_text.one_argument", argument: lettings_log.form.get_question("ecstat1", lettings_log).answer_label(lettings_log).downcase))
end end
end end

2
spec/models/form/sales/questions/buyer1_income_value_check_spec.rb

@ -16,7 +16,7 @@ RSpec.describe Form::Sales::Questions::Buyer1IncomeValueCheck, type: :model do
end end
it "has the correct header" do it "has the correct header" do
expect(question.header).to eq("Are you sure this income is correct?") expect(question.header).to eq("Are you sure this is correct?")
end end
it "has the correct check_answer_label" do it "has the correct check_answer_label" do

6
spec/models/form/sales/subsections/household_characteristics_spec.rb

@ -46,7 +46,8 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model
buyer_2_gender_identity buyer_2_gender_identity
gender_2_buyer_retirement_value_check gender_2_buyer_retirement_value_check
buyer_2_working_situation buyer_2_working_situation
working_situation_2_buyer_retirement_value_check working_situation_2_retirement_value_check_joint_purchase
working_situation_buyer_2_income_value_check
buyer_2_live_in_property buyer_2_live_in_property
number_of_others_in_property number_of_others_in_property
person_2_known person_2_known
@ -126,7 +127,8 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model
buyer_2_ethnic_background_mixed buyer_2_ethnic_background_mixed
buyer_2_ethnic_background_white buyer_2_ethnic_background_white
buyer_2_working_situation buyer_2_working_situation
working_situation_2_buyer_retirement_value_check working_situation_2_retirement_value_check_joint_purchase
working_situation_buyer_2_income_value_check
buyer_2_live_in_property buyer_2_live_in_property
number_of_others_in_property number_of_others_in_property
person_2_known person_2_known

2
spec/models/form/sales/subsections/income_benefits_and_savings_spec.rb

@ -27,6 +27,7 @@ RSpec.describe Form::Sales::Subsections::IncomeBenefitsAndSavings, type: :model
buyer_1_mortgage_value_check buyer_1_mortgage_value_check
buyer_2_income buyer_2_income
buyer_2_income_mortgage_value_check buyer_2_income_mortgage_value_check
buyer_2_income_value_check
buyer_2_mortgage buyer_2_mortgage
buyer_2_mortgage_value_check buyer_2_mortgage_value_check
housing_benefits housing_benefits
@ -52,6 +53,7 @@ RSpec.describe Form::Sales::Subsections::IncomeBenefitsAndSavings, type: :model
buyer_1_mortgage_value_check buyer_1_mortgage_value_check
buyer_2_income buyer_2_income
buyer_2_income_mortgage_value_check buyer_2_income_mortgage_value_check
buyer_2_income_value_check
buyer_2_mortgage buyer_2_mortgage
buyer_2_mortgage_value_check buyer_2_mortgage_value_check
housing_benefits housing_benefits

4
spec/models/form_handler_spec.rb

@ -54,14 +54,14 @@ RSpec.describe FormHandler do
it "is able to load a current sales form" do it "is able to load a current sales form" do
form = form_handler.get_form("current_sales") form = form_handler.get_form("current_sales")
expect(form).to be_a(Form) expect(form).to be_a(Form)
expect(form.pages.count).to eq(179) expect(form.pages.count).to eq(181)
expect(form.name).to eq("2022_2023_sales") expect(form.name).to eq("2022_2023_sales")
end end
it "is able to load a previous sales form" do it "is able to load a previous sales form" do
form = form_handler.get_form("previous_sales") form = form_handler.get_form("previous_sales")
expect(form).to be_a(Form) expect(form).to be_a(Form)
expect(form.pages.count).to eq(179) expect(form.pages.count).to eq(181)
expect(form.name).to eq("2021_2022_sales") expect(form.name).to eq("2021_2022_sales")
end end
end end

23
spec/models/sales_log_spec.rb

@ -266,6 +266,7 @@ RSpec.describe SalesLog, type: :model do
relat4: "X", relat4: "X",
relat5: "X", relat5: "X",
relat6: "P", relat6: "P",
income2: 0,
ecstat2: 9, ecstat2: 9,
ecstat3: 7, ecstat3: 7,
age1: 47, age1: 47,
@ -370,4 +371,26 @@ RSpec.describe SalesLog, type: :model do
expect(completed_sales_log.expected_shared_ownership_deposit_value).to eq(500) expect(completed_sales_log.expected_shared_ownership_deposit_value).to eq(500)
end end
end end
describe "#field_formatted_as_currency" do
let(:completed_sales_log) { FactoryBot.create(:sales_log, :completed) }
it "returns small numbers correctly formatted as currency" do
completed_sales_log.update!(savings: 4)
expect(completed_sales_log.field_formatted_as_currency("savings")).to eq("£4.00")
end
it "returns quite large numbers correctly formatted as currency" do
completed_sales_log.update!(savings: 40_000)
expect(completed_sales_log.field_formatted_as_currency("savings")).to eq("£40,000.00")
end
it "returns very large numbers correctly formatted as currency" do
completed_sales_log.update!(savings: 400_000_000)
expect(completed_sales_log.field_formatted_as_currency("savings")).to eq("£400,000,000.00")
end
end
end end

176
spec/models/validations/sales/financial_validations_spec.rb

@ -5,75 +5,110 @@ RSpec.describe Validations::Sales::FinancialValidations do
let(:validator_class) { Class.new { include Validations::Sales::FinancialValidations } } let(:validator_class) { Class.new { include Validations::Sales::FinancialValidations } }
describe "income validations" do describe "income validations for shared ownership" do
let(:record) { FactoryBot.create(:sales_log, ownershipsch: 1, la: "E08000035") } let(:record) { FactoryBot.create(:sales_log, ownershipsch: 1) }
context "with shared ownership" do context "when buying in a non london borough" do
context "and non london borough" do before do
(0..8).each do |ecstat| record.update!(la: "E08000035")
it "adds an error when buyer 1 income is over hard max for ecstat #{ecstat}" do record.reload
end
it "adds errors if buyer 1 has income over 80,000" do
record.income1 = 85_000 record.income1 = 85_000
record.ecstat1 = ecstat
financial_validator.validate_income1(record) financial_validator.validate_income1(record)
expect(record.errors["income1"]) expect(record.errors["income1"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000)) expect(record.errors["ownershipsch"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
expect(record.errors["ecstat1"]) expect(record.errors["la"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000)) expect(record.errors["postcode_full"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
expect(record.errors["ownershipsch"])
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000))
expect(record.errors["la"])
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000))
expect(record.errors["postcode_full"])
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 80_000))
end end
it "adds errors if buyer 2 has income over 80,000" do
record.income2 = 85_000
financial_validator.validate_income2(record)
expect(record.errors["income2"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
expect(record.errors["ownershipsch"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
expect(record.errors["la"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
expect(record.errors["postcode_full"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_outside_london"))
end end
it "validates that the income is within the expected range for the tenant’s employment status" do it "does not add errors if buyer 1 has income below 80_000" do
record.income1 = 75_000 record.income1 = 75_000
record.ecstat1 = 1
financial_validator.validate_income1(record) financial_validator.validate_income1(record)
expect(record.errors["income1"]).to be_empty expect(record.errors).to be_empty
expect(record.errors["ecstat1"]).to be_empty
expect(record.errors["ownershipsch"]).to be_empty
expect(record.errors["la"]).to be_empty
expect(record.errors["postcode_full"]).to be_empty
end end
it "does not add errors if buyer 2 has income below 80_000" do
record.income2 = 75_000
financial_validator.validate_income2(record)
expect(record.errors).to be_empty
end
it "adds errors when combined income is over 80_000" do
record.income1 = 45_000
record.income2 = 40_000
financial_validator.validate_combined_income(record)
expect(record.errors["income1"]).to include(match I18n.t("validations.financial.income.combined_over_hard_max_for_outside_london"))
expect(record.errors["income2"]).to include(match I18n.t("validations.financial.income.combined_over_hard_max_for_outside_london"))
end end
context "and a london borough" do it "does not add errors when combined income is under 80_000" do
record.income1 = 35_000
record.income2 = 40_000
financial_validator.validate_combined_income(record)
expect(record.errors).to be_empty
end
end
context "when buying in a london borough" do
before do before do
record.update!(la: "E09000030") record.update!(la: "E09000030")
record.reload record.reload
end end
(0..8).each do |ecstat| it "adds errors if buyer 1 has income over 90,000" do
it "adds an error when buyer 1 income is over hard max for ecstat #{ecstat}" do
record.income1 = 95_000 record.income1 = 95_000
record.ecstat1 = ecstat
financial_validator.validate_income1(record) financial_validator.validate_income1(record)
expect(record.errors["income1"]) expect(record.errors["income1"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000)) expect(record.errors["ownershipsch"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
expect(record.errors["ecstat1"]) expect(record.errors["la"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000)) expect(record.errors["postcode_full"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
expect(record.errors["ownershipsch"])
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000))
expect(record.errors["la"])
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000))
expect(record.errors["postcode_full"])
.to include(match I18n.t("validations.financial.income1.over_hard_max", hard_max: 90_000))
end end
it "adds errors if buyer 2 has income over 90,000" do
record.income2 = 95_000
financial_validator.validate_income2(record)
expect(record.errors["income2"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
expect(record.errors["ownershipsch"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
expect(record.errors["la"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
expect(record.errors["postcode_full"]).to include(match I18n.t("validations.financial.income.over_hard_max_for_london"))
end end
it "validates that the income is within the expected range for the tenant’s employment status" do it "does not add errors if buyer 1 has income below 90_000" do
record.income1 = 85_000 record.income1 = 75_000
record.ecstat1 = 1
financial_validator.validate_income1(record) financial_validator.validate_income1(record)
expect(record.errors["income1"]).to be_empty expect(record.errors).to be_empty
expect(record.errors["ecstat1"]).to be_empty end
expect(record.errors["ownershipsch"]).to be_empty
expect(record.errors["la"]).to be_empty it "does not add errors if buyer 2 has income below 90_000" do
expect(record.errors["postcode_full"]).to be_empty record.income2 = 75_000
financial_validator.validate_income2(record)
expect(record.errors).to be_empty
end
it "adds errors when combined income is over 90_000" do
record.income1 = 55_000
record.income2 = 40_000
financial_validator.validate_combined_income(record)
expect(record.errors["income1"]).to include(match I18n.t("validations.financial.income.combined_over_hard_max_for_london"))
expect(record.errors["income2"]).to include(match I18n.t("validations.financial.income.combined_over_hard_max_for_london"))
end end
it "does not add errors when combined income is under 90_000" do
record.income1 = 35_000
record.income2 = 40_000
financial_validator.validate_combined_income(record)
expect(record.errors).to be_empty
end end
end end
end end
@ -96,7 +131,7 @@ RSpec.describe Validations::Sales::FinancialValidations do
it "does not add an error if the cash discount is in the expected range" do it "does not add an error if the cash discount is in the expected range" do
record.cashdis = 10_000 record.cashdis = 10_000
financial_validator.validate_cash_discount(record) financial_validator.validate_cash_discount(record)
expect(record.errors["cashdis"]).to be_empty expect(record.errors).to be_empty
end end
end end
@ -107,16 +142,14 @@ RSpec.describe Validations::Sales::FinancialValidations do
record.stairbought = 20 record.stairbought = 20
record.stairowned = 40 record.stairowned = 40
financial_validator.validate_percentage_bought_not_greater_than_percentage_owned(record) financial_validator.validate_percentage_bought_not_greater_than_percentage_owned(record)
expect(record.errors["stairbought"]).to be_empty expect(record.errors).to be_empty
expect(record.errors["stairowned"]).to be_empty
end end
it "does not add an error if the percentage bought is equal to the percentage owned" do it "does not add an error if the percentage bought is equal to the percentage owned" do
record.stairbought = 30 record.stairbought = 30
record.stairowned = 30 record.stairowned = 30
financial_validator.validate_percentage_bought_not_greater_than_percentage_owned(record) financial_validator.validate_percentage_bought_not_greater_than_percentage_owned(record)
expect(record.errors["stairbought"]).to be_empty expect(record.errors).to be_empty
expect(record.errors["stairowned"]).to be_empty
end end
it "adds an error to stairowned and not stairbought if the percentage bought is more than the percentage owned" do it "adds an error to stairowned and not stairbought if the percentage bought is more than the percentage owned" do
@ -135,8 +168,7 @@ RSpec.describe Validations::Sales::FinancialValidations do
record.type = 2 record.type = 2
record.stairowned = 80 record.stairowned = 80
financial_validator.validate_percentage_owned_not_too_much_if_older_person(record) financial_validator.validate_percentage_owned_not_too_much_if_older_person(record)
expect(record.errors["stairowned"]).to be_empty expect(record.errors).to be_empty
expect(record.errors["type"]).to be_empty
end end
end end
@ -145,8 +177,7 @@ RSpec.describe Validations::Sales::FinancialValidations do
record.type = 24 record.type = 24
record.stairowned = 50 record.stairowned = 50
financial_validator.validate_percentage_owned_not_too_much_if_older_person(record) financial_validator.validate_percentage_owned_not_too_much_if_older_person(record)
expect(record.errors["stairowned"]).to be_empty expect(record.errors).to be_empty
expect(record.errors["type"]).to be_empty
end end
it "adds an error when percentage owned after staircasing transaction exceeds 75%" do it "adds an error when percentage owned after staircasing transaction exceeds 75%" do
@ -158,4 +189,39 @@ RSpec.describe Validations::Sales::FinancialValidations do
end end
end end
end end
describe "#validate_child_income" do
let(:record) { FactoryBot.create(:sales_log) }
context "when buyer 2 is not a child" do
before do
record.update!(ecstat2: rand(0..8))
record.reload
end
it "does not add an error if buyer 2 has an income" do
record.ecstat2 = rand(0..8)
record.income2 = 40_000
financial_validator.validate_child_income(record)
expect(record.errors).to be_empty
end
end
context "when buyer 2 is a child" do
it "does not add an error if buyer 2 has no income" do
record.ecstat2 = 9
record.income2 = 0
financial_validator.validate_child_income(record)
expect(record.errors).to be_empty
end
it "adds errors if buyer 2 has an income" do
record.ecstat2 = 9
record.income2 = 40_000
financial_validator.validate_child_income(record)
expect(record.errors["ecstat2"]).to include(match I18n.t("validations.financial.income.child_has_income"))
expect(record.errors["income2"]).to include(match I18n.t("validations.financial.income.child_has_income"))
end
end
end
end end

Loading…
Cancel
Save