require " rails_helper "
RSpec . describe Validations :: Sales :: FinancialValidations do
subject ( :financial_validator ) { validator_class . new }
let ( :validator_class ) { Class . new { include Validations :: Sales :: FinancialValidations } }
describe " income validations for shared ownership " do
let ( :record ) { FactoryBot . create ( :sales_log , ownershipsch : 1 ) }
context " when buying in a non london borough " do
before do
record . update! ( la : " E08000035 " )
record . reload
end
it " adds errors if buyer 1 has income over 80,000 " do
record . income1 = 85_000
financial_validator . validate_income1 ( record )
expect ( record . errors [ " income1 " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
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.outside_non_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
end
it " does not add errors if buyer 1 has income above 0 and below 80_000 " do
record . income1 = 75_000
financial_validator . validate_income1 ( record )
expect ( record . errors ) . to be_empty
end
it " does not add errors if buyer 2 has income above 0 and below 80_000 " do
record . income2 = 75_000
financial_validator . validate_income2 ( record )
expect ( record . errors ) . to be_empty
end
it " adds errors if buyer 1 has income below 0 " do
record . income1 = - 500
financial_validator . validate_income1 ( record )
expect ( record . errors [ " income1 " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
end
it " adds errors if buyer 2 has income below 0 " do
record . income2 = - 5
financial_validator . validate_income2 ( record )
expect ( record . errors [ " income2 " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_non_london_income_range " ) )
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
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
record . update! ( la : " E09000030 " )
record . reload
end
it " adds errors if buyer 1 has income over 90,000 " do
record . income1 = 95_000
financial_validator . validate_income1 ( record )
expect ( record . errors [ " income1 " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
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.outside_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
end
it " does not add errors if buyer 1 has income above 0 and below 90_000 " do
record . income1 = 75_000
financial_validator . validate_income1 ( record )
expect ( record . errors ) . to be_empty
end
it " does not add errors if buyer 2 has income above 0 and below 90_000 " do
record . income2 = 75_000
financial_validator . validate_income2 ( record )
expect ( record . errors ) . to be_empty
end
it " adds errors if buyer 1 has income below 0 " do
record . income1 = - 500
financial_validator . validate_income1 ( record )
expect ( record . errors [ " income1 " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
end
it " adds errors if buyer 2 has income below 0 " do
record . income2 = - 2
financial_validator . validate_income2 ( record )
expect ( record . errors [ " income2 " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " ownershipsch " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " la " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
expect ( record . errors [ " postcode_full " ] ) . to include ( match I18n . t ( " validations.financial.income.outside_london_income_range " ) )
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
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
describe " # validate_mortgage " do
let ( :record ) { FactoryBot . create ( :sales_log ) }
it " adds an error is the mortgage is zero " do
record . mortgageused = 1
record . mortgage = 0
financial_validator . validate_mortgage ( record )
expect ( record . errors [ :mortgage ] ) . to include I18n . t ( " validations.financial.mortgage " )
end
it " does not add an error is the mortgage is positive " do
record . mortgageused = 1
record . mortgage = 234
financial_validator . validate_mortgage ( record )
expect ( record . errors ) . to be_empty
end
end
describe " # validate_percentage_bought_not_greater_than_percentage_owned " do
let ( :record ) { FactoryBot . create ( :sales_log ) }
it " does not add an error if the percentage bought is less than the percentage owned " do
record . stairbought = 20
record . stairowned = 40
financial_validator . validate_percentage_bought_not_greater_than_percentage_owned ( record )
expect ( record . errors ) . to be_empty
end
it " does not add an error if the percentage bought is equal to the percentage owned " do
record . stairbought = 30
record . stairowned = 30
financial_validator . validate_percentage_bought_not_greater_than_percentage_owned ( record )
expect ( record . errors ) . to be_empty
end
it " adds an error to stairowned and not stairbought if the percentage bought is more than the percentage owned for joint purchase " do
record . stairbought = 50
record . stairowned = 40
record . jointpur = 1
financial_validator . validate_percentage_bought_not_greater_than_percentage_owned ( record )
expect ( record . errors [ " stairowned " ] ) . to include ( " Total percentage buyers now own must be more than percentage bought in this transaction " )
end
it " adds an error to stairowned and not stairbought if the percentage bought is more than the percentage owned for non joint purchase " do
record . stairbought = 50
record . stairowned = 40
record . jointpur = 2
financial_validator . validate_percentage_bought_not_greater_than_percentage_owned ( record )
expect ( record . errors [ " stairowned " ] ) . to include ( " Total percentage buyer now owns must be more than percentage bought in this transaction " )
end
end
describe " # validate_percentage_bought_not_equal_percentage_owned " do
let ( :record ) { FactoryBot . create ( :sales_log ) }
context " with 24/25 logs " do
before do
record . saledate = Time . zone . local ( 2024 , 4 , 3 )
record . save! ( validate : false )
end
it " does not add an error if the percentage bought is less than the percentage owned " do
record . stairbought = 20
record . stairowned = 40
financial_validator . validate_percentage_bought_not_equal_percentage_owned ( record )
expect ( record . errors ) . to be_empty
end
it " adds an error if the percentage bought is equal to the percentage owned " do
record . stairbought = 30
record . stairowned = 30
financial_validator . validate_percentage_bought_not_equal_percentage_owned ( record )
expect ( record . errors [ " stairowned " ] ) . to include ( " The percentage bought is 30% and the percentage owned in total is 30%. These figures cannot be the same. " )
expect ( record . errors [ " stairbought " ] ) . to include ( " The percentage bought is 30% and the percentage owned in total is 30%. These figures cannot be the same. " )
end
it " does not add an error to stairowned and not stairbought if the percentage bought is more than the percentage owned " do
record . stairbought = 50
record . stairowned = 40
financial_validator . validate_percentage_bought_not_equal_percentage_owned ( record )
expect ( record . errors ) . to be_empty
end
end
context " with 23/24 logs " do
before do
record . saledate = Time . zone . local ( 2023 , 4 , 3 )
record . save! ( validate : false )
end
it " does not add an error if the percentage bought is equal to the percentage owned " do
record . stairbought = 30
record . stairowned = 30
financial_validator . validate_percentage_bought_not_equal_percentage_owned ( record )
expect ( record . errors ) . to be_empty
end
end
end
describe " # validate_monthly_leasehold_charges " do
let ( :record ) { FactoryBot . create ( :sales_log ) }
it " does not add an error if monthly leasehold charges are positive " do
record . mscharge = 2345
financial_validator . validate_monthly_leasehold_charges ( record )
expect ( record . errors ) . to be_empty
end
it " adds an error if monthly leasehold charges are zero " do
record . mscharge = 0
financial_validator . validate_monthly_leasehold_charges ( record )
expect ( record . errors [ :mscharge ] ) . to include I18n . t ( " validations.financial.monthly_leasehold_charges.not_zero " )
end
end
describe " # validate_percentage_bought_at_least_threshold " do
let ( :record ) { FactoryBot . create ( :sales_log ) }
it " adds an error to stairbought and type if the percentage bought is less than the threshold (which is 1% by default, but higher for some shared ownership types) " do
record . stairbought = 9
[ 2 , 16 , 18 , 24 ] . each do | type |
record . type = type
financial_validator . validate_percentage_bought_at_least_threshold ( record )
expect ( record . errors [ " stairbought " ] ) . to eq ( [ " The minimum increase in equity while staircasing is 10% " ] )
expect ( record . errors [ " type " ] ) . to eq ( [ " The minimum increase in equity while staircasing is 10% for this shared ownership type " ] )
record . errors . clear
end
record . stairbought = 0
[ 28 , 30 , 31 , 32 ] . each do | type |
record . type = type
financial_validator . validate_percentage_bought_at_least_threshold ( record )
expect ( record . errors [ " stairbought " ] ) . to eq ( [ " The minimum increase in equity while staircasing is 1% " ] )
expect ( record . errors [ " type " ] ) . to eq ( [ " The minimum increase in equity while staircasing is 1% for this shared ownership type " ] )
record . errors . clear
end
end
it " doesn't add an error to stairbought and type if the percentage bought is less than the threshold (which is 1% by default, but higher for some shared ownership types) " do
record . stairbought = 10
[ 2 , 16 , 18 , 24 ] . each do | type |
record . type = type
financial_validator . validate_percentage_bought_at_least_threshold ( record )
expect ( record . errors ) . to be_empty
record . errors . clear
end
record . stairbought = 1
[ 28 , 30 , 31 , 32 ] . each do | type |
record . type = type
financial_validator . validate_percentage_bought_at_least_threshold ( record )
expect ( record . errors ) . to be_empty
record . errors . clear
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 . saledate = Time . zone . local ( 2023 , 4 , 3 )
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 . saledate = Time . zone . local ( 2023 , 4 , 3 )
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
it " does not add an error if the saledate is before the 23/24 collection window " do
record . saledate = Time . zone . local ( 2022 , 4 , 3 )
record . ecstat2 = 9
record . income2 = 40_000
financial_validator . validate_child_income ( record )
expect ( record . errors ) . to be_empty
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 . return
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 : 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
end
describe " # validate_equity_less_than_staircase_difference " do
let ( :record ) { FactoryBot . create ( :sales_log , saledate : now ) }
around do | example |
Timecop . freeze ( now ) do
Singleton . __init__ ( FormHandler )
example . run
end
Timecop . return
Singleton . __init__ ( FormHandler )
end
context " with a log in the 23/24 collection year " do
let ( :now ) { Time . zone . local ( 2023 , 4 , 1 ) }
it " does not add an error " do
record . stairbought = 2
record . stairowned = 3
record . equity = 2
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors ) . to be_empty
end
end
context " with a log in 24/25 collection year " do
let ( :now ) { Time . zone . local ( 2024 , 4 , 1 ) }
it " adds errors if equity is more than stairowned - stairbought for joint purchase " do
record . stairbought = 2
record . stairowned = 3
record . equity = 2
record . jointpur = 1
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors [ " equity " ] ) . to include ( " The initial equity stake is 2% and the percentage owned in total minus the percentage bought is 1%. In a staircasing transaction, the equity stake purchased cannot be larger than the percentage the buyers own minus the percentage bought. " )
expect ( record . errors [ " stairowned " ] ) . to include ( " The initial equity stake is 2% and the percentage owned in total minus the percentage bought is 1%. In a staircasing transaction, the equity stake purchased cannot be larger than the percentage the buyers own minus the percentage bought. " )
expect ( record . errors [ " stairbought " ] ) . to include ( " The initial equity stake is 2% and the percentage owned in total minus the percentage bought is 1%. In a staircasing transaction, the equity stake purchased cannot be larger than the percentage the buyers own minus the percentage bought. " )
end
it " adds errors if equity is more than stairowned - stairbought for non joint purchase " do
record . stairbought = 2
record . stairowned = 3
record . equity = 2
record . jointpur = 2
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors [ " equity " ] ) . to include ( " The initial equity stake is 2% and the percentage owned in total minus the percentage bought is 1%. In a staircasing transaction, the equity stake purchased cannot be larger than the percentage the buyer owns minus the percentage bought. " )
expect ( record . errors [ " stairowned " ] ) . to include ( " The initial equity stake is 2% and the percentage owned in total minus the percentage bought is 1%. In a staircasing transaction, the equity stake purchased cannot be larger than the percentage the buyer owns minus the percentage bought. " )
expect ( record . errors [ " stairbought " ] ) . to include ( " The initial equity stake is 2% and the percentage owned in total minus the percentage bought is 1%. In a staircasing transaction, the equity stake purchased cannot be larger than the percentage the buyer owns minus the percentage bought. " )
end
it " does not add errors if equity is less than stairowned - stairbought " do
record . stairbought = 2
record . stairowned = 10
record . equity = 2
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors ) . to be_empty
end
it " does not add errors if equity is equal stairowned - stairbought " do
record . stairbought = 2
record . stairowned = 10
record . equity = 8
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors ) . to be_empty
end
it " does not add errors if stairbought is not given " do
record . stairbought = nil
record . stairowned = 10
record . equity = 2
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors ) . to be_empty
end
it " does not add errors if stairowned is not given " do
record . stairbought = 2
record . stairowned = nil
record . equity = 2
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors ) . to be_empty
end
it " does not add errors if equity is not given " do
record . stairbought = 2
record . stairowned = 10
record . equity = 0
financial_validator . validate_equity_less_than_staircase_difference ( record )
expect ( record . errors ) . to be_empty
end
end
end
end