Browse Source

Merge d5717659f2 into fd10147e14

pull/3329/merge
Samuel Young 3 months ago committed by GitHub
parent
commit
16bbcfc516
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 43
      app/models/form/sales/pages/discounted_sale_value_check.rb
  2. 35
      app/models/form/sales/pages/extra_borrowing_value_check.rb
  3. 35
      app/models/form/sales/pages/shared_ownership_deposit_value_check.rb
  4. 22
      app/models/form/sales/questions/discounted_sale_value_check.rb
  5. 22
      app/models/form/sales/questions/extra_borrowing_value_check.rb
  6. 22
      app/models/form/sales/questions/shared_ownership_deposit_value_check.rb
  7. 8
      app/models/form/sales/subsections/discounted_ownership_scheme.rb
  8. 3
      app/models/form/sales/subsections/shared_ownership_initial_purchase.rb
  9. 3
      app/models/form/sales/subsections/shared_ownership_scheme.rb
  10. 1
      app/models/form/sales/subsections/shared_ownership_staircasing_transaction.rb
  11. 22
      app/models/validations/date_validations.rb
  12. 94
      app/models/validations/household_validations.rb
  13. 3
      app/models/validations/property_validations.rb
  14. 28
      app/models/validations/sales/financial_validations.rb
  15. 102
      app/models/validations/sales/household_validations.rb
  16. 17
      app/models/validations/sales/property_validations.rb
  17. 19
      app/models/validations/sales/sale_information_validations.rb
  18. 25
      app/models/validations/sales/soft_validations.rb
  19. 2
      app/models/validations/tenancy_validations.rb
  20. 4
      spec/models/bulk_upload_spec.rb
  21. 10
      spec/models/form/lettings/pages/net_income_value_check_spec.rb
  22. 53
      spec/models/form/sales/pages/discounted_sale_value_check_spec.rb
  23. 44
      spec/models/form/sales/pages/shared_ownership_deposit_value_check_spec.rb
  24. 45
      spec/models/form/sales/questions/discounted_sale_value_check_spec.rb
  25. 45
      spec/models/form/sales/questions/shared_ownership_deposit_value_check_spec.rb
  26. 61
      spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb
  27. 9
      spec/models/form/sales/subsections/shared_ownership_initial_purchase_spec.rb
  28. 3
      spec/models/form/sales/subsections/shared_ownership_scheme_spec.rb
  29. 2
      spec/models/form/sales/subsections/shared_ownership_staircasing_transaction_spec.rb
  30. 12
      spec/models/lettings_log_spec.rb
  31. 16
      spec/models/sales_log_spec.rb
  32. 91
      spec/models/validations/household_validations_spec.rb
  33. 294
      spec/models/validations/property_validations_spec.rb
  34. 98
      spec/models/validations/sales/household_validations_spec.rb
  35. 136
      spec/models/validations/sales/property_validations_spec.rb
  36. 30
      spec/models/validations/sales/sale_information_validations_spec.rb
  37. 303
      spec/models/validations/sales/soft_validations_spec.rb
  38. 226
      spec/services/bulk_upload/lettings/year2023/csv_parser_spec.rb
  39. 2875
      spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
  40. 254
      spec/services/bulk_upload/lettings/year2024/csv_parser_spec.rb
  41. 3157
      spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
  42. 170
      spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb
  43. 1454
      spec/services/bulk_upload/sales/year2023/row_parser_spec.rb
  44. 191
      spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb
  45. 2109
      spec/services/bulk_upload/sales/year2024/row_parser_spec.rb

43
app/models/form/sales/pages/discounted_sale_value_check.rb

@ -1,43 +0,0 @@
class Form::Sales::Pages::DiscountedSaleValueCheck < ::Form::Page
def initialize(id, hsh, subsection, person_index = nil)
super(id, hsh, subsection)
@depends_on = depends_on
@copy_key = "sales.soft_validations.discounted_sale_value_check"
@title_text = {
"translation" => "forms.#{form.start_date.year}.#{@copy_key}.title_text",
"arguments" => [
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "value_with_discount",
"i18n_template" => "value_with_discount",
},
],
}
@informative_text = {
"translation" => "forms.#{form.start_date.year}.#{@copy_key}.informative_text",
"arguments" => [
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "mortgage_deposit_and_grant_total",
"i18n_template" => "mortgage_deposit_and_grant_total",
},
],
}
@person_index = person_index
@depends_on = [
{
"discounted_ownership_value_invalid?" => true,
},
]
end
def questions
@questions ||= [
Form::Sales::Questions::DiscountedSaleValueCheck.new(nil, nil, self),
]
end
def interruption_screen_question_ids
%w[value deposit ownershipsch mortgage mortgageused discount grant type]
end
end

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

@ -1,35 +0,0 @@
class Form::Sales::Pages::ExtraBorrowingValueCheck < Form::Page
def initialize(id, hsh, subsection)
super
@depends_on = [
{
"extra_borrowing_expected_but_not_reported?" => true,
},
]
@copy_key = "sales.soft_validations.extra_borrowing_value_check"
@title_text = {
"translation" => "forms.#{form.start_date.year}.#{@copy_key}.title_text",
"arguments" => [
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "mortgage_and_deposit_total",
"i18n_template" => "mortgage_and_deposit_total",
},
],
}
@informative_text = {
"translation" => "forms.#{form.start_date.year}.#{@copy_key}.informative_text",
"arguments" => [],
}
end
def questions
@questions ||= [
Form::Sales::Questions::ExtraBorrowingValueCheck.new(nil, nil, self),
]
end
def interruption_screen_question_ids
%w[extrabor mortgage deposit value discount]
end
end

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

@ -1,35 +0,0 @@
class Form::Sales::Pages::SharedOwnershipDepositValueCheck < ::Form::Page
def initialize(id, hsh, subsection)
super
@depends_on = [
{
"shared_ownership_deposit_invalid?" => true,
},
]
@copy_key = "sales.soft_validations.shared_ownership_deposit_value_check"
@title_text = {
"translation" => "forms.#{form.start_date.year}.#{@copy_key}.title_text",
"arguments" => [
{
"key" => "mortgage_deposit_and_discount_error_fields",
"i18n_template" => "mortgage_deposit_and_discount_error_fields",
},
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "mortgage_deposit_and_discount_total",
"i18n_template" => "mortgage_deposit_and_discount_total",
},
],
}
end
def questions
@questions ||= [
Form::Sales::Questions::SharedOwnershipDepositValueCheck.new(nil, nil, self),
]
end
def interruption_screen_question_ids
%w[mortgage mortgageused cashdis type deposit value equity]
end
end

22
app/models/form/sales/questions/discounted_sale_value_check.rb

@ -1,22 +0,0 @@
class Form::Sales::Questions::DiscountedSaleValueCheck < ::Form::Question
def initialize(id, hsh, page)
super
@id = "discounted_sale_value_check"
@copy_key = "sales.soft_validations.discounted_sale_value_check"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"discounted_sale_value_check" => 0,
},
{
"discounted_sale_value_check" => 1,
},
],
}
end
end

22
app/models/form/sales/questions/extra_borrowing_value_check.rb

@ -1,22 +0,0 @@
class Form::Sales::Questions::ExtraBorrowingValueCheck < ::Form::Question
def initialize(id, hsh, page)
super(id, hsh, page)
@id = "extrabor_value_check"
@copy_key = "sales.soft_validations.extra_borrowing_value_check"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"extrabor_value_check" => 0,
},
{
"extrabor_value_check" => 1,
},
],
}
end
end

22
app/models/form/sales/questions/shared_ownership_deposit_value_check.rb

@ -1,22 +0,0 @@
class Form::Sales::Questions::SharedOwnershipDepositValueCheck < ::Form::Question
def initialize(id, hsh, page)
super
@id = "shared_ownership_deposit_value_check"
@copy_key = "sales.soft_validations.shared_ownership_deposit_value_check"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"shared_ownership_deposit_value_check" => 0,
},
{
"shared_ownership_deposit_value_check" => 1,
},
],
}
end
end

8
app/models/form/sales/subsections/discounted_ownership_scheme.rb

@ -13,34 +13,26 @@ class Form::Sales::Subsections::DiscountedOwnershipScheme < ::Form::Subsection
Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_discounted_ownership", nil, self, ownershipsch: 2, joint_purchase: false),
Form::Sales::Pages::PurchasePrice.new(nil, nil, self),
Form::Sales::Pages::Discount.new(nil, nil, self),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_price_value_check", nil, self),
Form::Sales::Pages::PercentageDiscountValueCheck.new("percentage_discount_value_check", nil, self),
Form::Sales::Pages::Grant.new(nil, nil, self),
Form::Sales::Pages::GrantValueCheck.new(nil, nil, self),
Form::Sales::Pages::PurchasePriceOutrightOwnership.new("purchase_price_discounted_ownership", nil, self, ownershipsch: 2),
Form::Sales::Pages::DiscountedSaleValueCheck.new("discounted_sale_grant_value_check", nil, self),
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_discounted_ownership_value_check", nil, self),
Form::Sales::Pages::DepositAndMortgageValueCheck.new("discounted_ownership_deposit_and_mortgage_value_check_after_value_and_discount", nil, self),
Form::Sales::Pages::Mortgageused.new("mortgage_used_discounted_ownership", nil, self, ownershipsch: 2),
Form::Sales::Pages::MortgageValueCheck.new("discounted_ownership_mortgage_used_mortgage_value_check", nil, self),
Form::Sales::Pages::DiscountedSaleValueCheck.new("discounted_sale_mortgage_used_value_check", nil, self),
Form::Sales::Pages::MortgageAmount.new("mortgage_amount_discounted_ownership", nil, self, ownershipsch: 2),
Form::Sales::Pages::MortgageValueCheck.new("discounted_ownership_mortgage_amount_mortgage_value_check", nil, self),
Form::Sales::Pages::DiscountedSaleValueCheck.new("discounted_sale_mortgage_value_check", nil, self),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_mortgage_value_check", nil, self),
Form::Sales::Pages::DepositAndMortgageValueCheck.new("discounted_ownership_deposit_and_mortgage_value_check_after_mortgage", nil, self),
mortgage_lender_questions,
(Form::Sales::Pages::MortgageLength.new("mortgage_length_discounted_ownership", nil, self, ownershipsch: 2) unless form.start_year_2026_or_later?),
(Form::Sales::Pages::MortgageLengthNotInterviewed.new("mortgage_length_discounted_ownership_not_interviewed", nil, self, ownershipsch: 2) if form.start_year_2026_or_later?),
(Form::Sales::Pages::MortgageLengthInterviewed.new("mortgage_length_discounted_ownership_interviewed", nil, self, ownershipsch: 2) if form.start_year_2026_or_later?),
Form::Sales::Pages::ExtraBorrowing.new("extra_borrowing_discounted_ownership", nil, self, ownershipsch: 2),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_value_check", nil, self),
Form::Sales::Pages::Deposit.new("deposit_discounted_ownership", nil, self, ownershipsch: 2, optional: false),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_deposit_value_check", nil, self),
Form::Sales::Pages::DepositValueCheck.new("discounted_ownership_deposit_joint_purchase_value_check", nil, self, joint_purchase: true),
Form::Sales::Pages::DepositValueCheck.new("discounted_ownership_deposit_value_check", nil, self, joint_purchase: false),
Form::Sales::Pages::DepositAndMortgageValueCheck.new("discounted_ownership_deposit_and_mortgage_value_check_after_deposit", nil, self),
Form::Sales::Pages::DiscountedSaleValueCheck.new("discounted_sale_deposit_value_check", nil, self),
Form::Sales::Pages::LeaseholdCharges.new("leasehold_charges_discounted_ownership", nil, self, ownershipsch: 2),
Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_discounted_ownership_value_check", nil, self),
].flatten.compact

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

@ -22,11 +22,9 @@ class Form::Sales::Subsections::SharedOwnershipInitialPurchase < ::Form::Subsect
Form::Sales::Pages::ValueSharedOwnership.new("value_shared_ownership", nil, self),
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_shared_ownership_value_check", nil, self),
Form::Sales::Pages::Equity.new("initial_equity", nil, self),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_equity_value_check", nil, self),
Form::Sales::Pages::Mortgageused.new("mortgage_used_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::MortgageValueCheck.new("mortgage_used_mortgage_value_check", nil, self),
Form::Sales::Pages::MortgageAmount.new("mortgage_amount_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_mortgage_amount_value_check", nil, self),
Form::Sales::Pages::MortgageValueCheck.new("mortgage_amount_mortgage_value_check", nil, self),
(Form::Sales::Pages::MortgageLength.new("mortgage_length_shared_ownership", nil, self, ownershipsch: 1) unless form.start_year_2026_or_later?),
(Form::Sales::Pages::MortgageLengthNotInterviewed.new("mortgage_length_shared_ownership_not_interviewed", nil, self, ownershipsch: 1) if form.start_year_2026_or_later?),
@ -37,7 +35,6 @@ class Form::Sales::Subsections::SharedOwnershipInitialPurchase < ::Form::Subsect
Form::Sales::Pages::DepositValueCheck.new("deposit_value_check", nil, self, joint_purchase: false),
Form::Sales::Pages::DepositDiscount.new("deposit_discount", nil, self, optional: false),
Form::Sales::Pages::DepositDiscount.new("deposit_discount_optional", nil, self, optional: true),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_deposit_value_check", nil, self),
Form::Sales::Pages::MonthlyRent.new(nil, nil, self),
Form::Sales::Pages::ServiceCharge.new("service_charge", nil, self),
Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_initial_purchase_value_check", nil, self),

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

@ -30,11 +30,9 @@ class Form::Sales::Subsections::SharedOwnershipScheme < ::Form::Subsection
Form::Sales::Pages::ValueSharedOwnership.new("value_shared_ownership", nil, self),
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_shared_ownership_value_check", nil, self),
Form::Sales::Pages::Equity.new("equity", nil, self),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_equity_value_check", nil, self),
Form::Sales::Pages::Mortgageused.new("mortgage_used_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::MortgageValueCheck.new("mortgage_used_mortgage_value_check", nil, self),
Form::Sales::Pages::MortgageAmount.new("mortgage_amount_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_mortgage_amount_value_check", nil, self),
Form::Sales::Pages::MortgageValueCheck.new("mortgage_amount_mortgage_value_check", nil, self),
Form::Sales::Pages::MortgageLender.new("mortgage_lender_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::MortgageLenderOther.new("mortgage_lender_other_shared_ownership", nil, self, ownershipsch: 1),
@ -46,7 +44,6 @@ class Form::Sales::Subsections::SharedOwnershipScheme < ::Form::Subsection
Form::Sales::Pages::DepositValueCheck.new("deposit_value_check", nil, self, joint_purchase: false),
Form::Sales::Pages::DepositDiscount.new("deposit_discount", nil, self, optional: false),
(Form::Sales::Pages::DepositDiscount.new("deposit_discount_optional", nil, self, optional: true) if form.start_year_2024_or_later?),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_deposit_value_check", nil, self),
Form::Sales::Pages::MonthlyRent.new(nil, nil, self),
Form::Sales::Pages::LeaseholdCharges.new("leasehold_charges_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_shared_ownership_value_check", nil, self),

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

@ -21,7 +21,6 @@ class Form::Sales::Subsections::SharedOwnershipStaircasingTransaction < ::Form::
Form::Sales::Pages::ValueSharedOwnership.new("value_shared_ownership_staircase", nil, self),
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_shared_ownership_value_check_staircasing", nil, self),
Form::Sales::Pages::Equity.new("staircase_equity", nil, self),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_equity_value_check_staircasing", nil, self),
Form::Sales::Pages::Mortgageused.new("staircase_mortgage_used_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::MonthlyRentStaircasingOwned.new(nil, nil, self),
Form::Sales::Pages::MonthlyRentStaircasing.new(nil, nil, self),

22
app/models/validations/date_validations.rb

@ -14,14 +14,9 @@ module Validations::DateValidations
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.after_major_repair_date")
end
if record.form.start_year_2025_or_later?
if record["startdate"].to_date - 20.years > record["mrcdate"].to_date
record.errors.add :mrcdate, I18n.t("validations.lettings.date.mrcdate.twenty_years_before_tenancy_start")
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.twenty_years_after_mrc_date")
end
elsif record["startdate"].to_date - 10.years > record["mrcdate"].to_date
record.errors.add :mrcdate, I18n.t("validations.lettings.date.mrcdate.ten_years_before_tenancy_start")
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.ten_years_after_mrc_date")
if record["startdate"].to_date - 20.years > record["mrcdate"].to_date
record.errors.add :mrcdate, I18n.t("validations.lettings.date.mrcdate.twenty_years_before_tenancy_start")
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.twenty_years_after_mrc_date")
end
end
@ -39,14 +34,9 @@ module Validations::DateValidations
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.after_void_date")
end
if record.form.start_year_2025_or_later?
if record["startdate"].to_date - 20.years > record["voiddate"].to_date
record.errors.add :voiddate, I18n.t("validations.lettings.date.void_date.twenty_years_before_tenancy_start")
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.twenty_years_after_void_date")
end
elsif record["startdate"].to_date - 10.years > record["voiddate"].to_date
record.errors.add :voiddate, I18n.t("validations.lettings.date.void_date.ten_years_before_tenancy_start")
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.ten_years_after_void_date")
if record["startdate"].to_date - 20.years > record["voiddate"].to_date
record.errors.add :voiddate, I18n.t("validations.lettings.date.void_date.twenty_years_before_tenancy_start")
record.errors.add :startdate, I18n.t("validations.lettings.date.startdate.twenty_years_after_void_date")
end
end

94
app/models/validations/household_validations.rb

@ -30,8 +30,6 @@ module Validations::HouseholdValidations
end
validate_other_field(record, 20, :reason, :reasonother)
return unless record.form.start_year_2024_or_later?
if record.reason == 20 && PHRASES_INDICATING_HOMELESSNESS_REGEX.match?(record.reasonother)
record.errors.add :reason, I18n.t("validations.lettings.household.reason.leaving_last_settled_home.other_not_settled")
end
@ -46,41 +44,12 @@ module Validations::HouseholdValidations
end
end
def validate_partner_count(record)
return if record.form.start_year_2024_or_later?
partner_numbers = (2..8).select { |n| person_is_partner?(record["relat#{n}"]) }
if partner_numbers.count > 1
partner_numbers.each do |n|
record.errors.add "relat#{n}", I18n.t("validations.lettings.household.relat.one_partner")
end
end
end
def validate_person_1_economic(record)
return unless record.age1 && record.ecstat1 && !record.form.start_year_2024_or_later?
if record.age1 < 16 && !economic_status_is_child_other_or_refused?(record.ecstat1)
record.errors.add "ecstat1", I18n.t("validations.lettings.household.ecstat.child_under_16", person_num: 1)
record.errors.add "age1", I18n.t("validations.lettings.household.age.child_under_16_ecstat", person_num: 1)
end
if tenant_is_economic_child?(record.ecstat1) && record.age1 > 16
record.errors.add "ecstat1", I18n.t("validations.lettings.household.ecstat.child_over_16", person_num: 1)
record.errors.add "age1", I18n.t("validations.lettings.household.age.child_over_16", person_num: 1)
end
end
def validate_person_age_matches_economic_status(record)
(2..8).each do |person_num|
age = record.public_send("age#{person_num}")
economic_status = record.public_send("ecstat#{person_num}")
next unless age && economic_status
if age < 16 && !economic_status_is_child_other_or_refused?(economic_status) && !record.form.start_year_2024_or_later?
record.errors.add "ecstat#{person_num}", I18n.t("validations.lettings.household.ecstat.child_under_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.lettings.household.age.child_under_16_ecstat", person_num:)
end
if tenant_is_economic_child?(economic_status) && age > 16
record.errors.add "ecstat#{person_num}", I18n.t("validations.lettings.household.ecstat.child_over_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.lettings.household.age.child_over_16", person_num:)
@ -88,49 +57,6 @@ module Validations::HouseholdValidations
end
end
def validate_person_age_matches_relationship(record)
return unless record.startdate && !record.form.start_year_2024_or_later?
(2..8).each do |person_num|
age = record.public_send("age#{person_num}")
relationship = record.public_send("relat#{person_num}")
next unless age && relationship
if age < 16 && !relationship_is_child_other_or_refused?(relationship)
record.errors.add "relat#{person_num}", I18n.t("validations.lettings.household.relat.child_under_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.lettings.household.age.child_under_16_relat", person_num:)
end
end
end
def validate_person_age_and_relationship_matches_economic_status(record)
return unless record.startdate && !record.form.start_year_2024_or_later?
(2..8).each do |person_num|
age = record.public_send("age#{person_num}")
economic_status = record.public_send("ecstat#{person_num}")
relationship = record.public_send("relat#{person_num}")
next unless age && economic_status && relationship
age_between_16_19 = age.between?(16, 19)
student = tenant_is_fulltime_student?(economic_status)
economic_status_refused = tenant_economic_status_refused?(economic_status)
child = tenant_is_child?(relationship)
if age_between_16_19 && !(student || economic_status_refused) && child
record.errors.add "ecstat#{person_num}", I18n.t("validations.lettings.household.ecstat.student_16_19.must_be_student")
record.errors.add "age#{person_num}", I18n.t("validations.lettings.household.age.student_16_19.cannot_be_16_19.child_not_student")
record.errors.add "relat#{person_num}", I18n.t("validations.lettings.household.relat.student_16_19.cannot_be_child.16_19_not_student")
end
next unless !age_between_16_19 && student && child
record.errors.add "age#{person_num}", I18n.t("validations.lettings.household.age.student_16_19.must_be_16_19")
record.errors.add "ecstat#{person_num}", I18n.t("validations.lettings.household.ecstat.student_16_19.cannot_be_student.child_not_16_19")
record.errors.add "relat#{person_num}", I18n.t("validations.lettings.household.relat.student_16_19.cannot_be_child.student_not_16_19")
end
end
def validate_condition_effects(record)
all_options = [record.illness_type_1, record.illness_type_2, record.illness_type_3, record.illness_type_4, record.illness_type_5, record.illness_type_6, record.illness_type_7, record.illness_type_8, record.illness_type_9, record.illness_type_10]
if all_options.count(1) >= 1 && household_no_illness?(record)
@ -253,24 +179,4 @@ private
def tenant_is_economic_child?(economic_status)
economic_status == 9
end
def tenant_is_fulltime_student?(economic_status)
economic_status == 7
end
def tenant_economic_status_refused?(economic_status)
economic_status == 10
end
def economic_status_is_child_other_or_refused?(economic_status)
[9, 0, 10].include?(economic_status)
end
def tenant_is_child?(relationship)
relationship == "C"
end
def relationship_is_child_other_or_refused?(relationship)
%w[C X R].include?(relationship)
end
end

3
app/models/validations/property_validations.rb

@ -70,7 +70,6 @@ module Validations::PropertyValidations
# see also: this validation in sales/property_validations.rb
def validate_la_in_england(record)
return unless record.form.start_year_2025_or_later?
return unless record.la
return if record.la.in?(LocalAuthority.england.pluck(:code))
@ -94,7 +93,7 @@ module Validations::PropertyValidations
# see also: this validation in sales/property_validations.rb
def validate_la_is_active(record)
return unless record.form.start_year_2025_or_later? && record.startdate.present?
return if record.startdate.blank?
return unless record.la
la = LocalAuthority.england.find_by(code: record.la)

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

@ -55,7 +55,7 @@ module Validations::Sales::FinancialValidations
def validate_percentage_bought_not_equal_percentage_owned(record)
return unless record.stairbought && record.stairowned
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
if record.stairbought == record.stairowned
record.errors.add :stairbought, I18n.t("validations.sales.financial.stairbought.percentage_bought_equal_percentage_owned", stairbought: sprintf("%g", record.stairbought), stairowned: sprintf("%g", record.stairowned))
@ -91,9 +91,7 @@ module Validations::Sales::FinancialValidations
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])
return unless (range = DEFAULT_EQUITY_RANGES[record.type])
if record.equity < range.min
record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sales.financial.type.equity_under_min", min_equity: range.min)
@ -107,7 +105,7 @@ module Validations::Sales::FinancialValidations
def validate_staircase_difference(record)
return unless record.equity && record.stairbought && record.stairowned
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
percentage_left = record.stairowned - record.stairbought - record.equity
@ -158,26 +156,6 @@ private
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,
},
2023 => {
2 => 25..75,
30 => 10..75,
18 => 25..75,
16 => 10..75,
24 => 25..75,
31 => 0..75,
32 => 0..75,
},
}.freeze
DEFAULT_EQUITY_RANGES = {
2 => 25..75,
30 => 10..75,

102
app/models/validations/sales/household_validations.rb

@ -1,17 +1,6 @@
module Validations::Sales::HouseholdValidations
include Validations::SharedValidations
def validate_partner_count(record)
return if record.form.start_year_2024_or_later?
partner_numbers = (2..6).select { |n| person_is_partner?(record["relat#{n}"]) }
if partner_numbers.count > 1
partner_numbers.each do |n|
record.errors.add "relat#{n}", I18n.t("validations.sales.household.relat.one_partner")
end
end
end
def validate_buyers_living_in_property(record)
if record.buyers_will_live_in? && record.buyer_one_will_not_live_in_property? && record.buyer_two_will_not_live_in_property?
record.errors.add :buylivein, I18n.t("validations.sales.household.buylivein.buyers_will_live_in_property_values_inconsistent")
@ -21,7 +10,7 @@ module Validations::Sales::HouseholdValidations
end
def validate_buyer1_previous_tenure(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
return unless record.discounted_ownership_sale? && record.prevten
if [3, 4, 5, 6, 7, 9, 0].include?(record.prevten)
@ -30,62 +19,12 @@ module Validations::Sales::HouseholdValidations
end
end
def validate_person_age_matches_relationship(record)
return unless record.saledate && !record.form.start_year_2024_or_later?
(2..6).each do |person_num|
age = record.public_send("age#{person_num}")
relationship = record.public_send("relat#{person_num}")
next unless age && relationship
if age < 16 && !relationship_is_child_other_or_refused?(relationship)
record.errors.add "age#{person_num}", I18n.t("validations.sales.household.age.child_under_16", person_num:)
record.errors.add "relat#{person_num}", I18n.t("validations.sales.household.relat.child_under_16", person_num:)
elsif age >= 20 && person_is_child?(relationship)
record.errors.add "age#{person_num}", I18n.t("validations.sales.household.age.child_over_20")
record.errors.add "relat#{person_num}", I18n.t("validations.sales.household.relat.child_over_20")
end
end
end
def validate_person_age_and_relationship_matches_economic_status(record)
return unless record.saledate && !record.form.start_year_2024_or_later?
(2..6).each do |person_num|
age = record.public_send("age#{person_num}")
economic_status = record.public_send("ecstat#{person_num}")
relationship = record.public_send("relat#{person_num}")
next unless age && economic_status && relationship
age_between_16_19 = age.between?(16, 19)
student = person_is_fulltime_student?(economic_status)
economic_status_refused = person_economic_status_refused?(economic_status)
child = person_is_child?(relationship)
if age_between_16_19 && !(student || economic_status_refused) && child
record.errors.add "ecstat#{person_num}", I18n.t("validations.sales.household.ecstat.student_16_19.must_be_student")
record.errors.add "age#{person_num}", I18n.t("validations.sales.household.age.student_16_19.cannot_be_16_19.child_not_student")
record.errors.add "relat#{person_num}", I18n.t("validations.sales.household.relat.student_16_19.cannot_be_child.16_19_not_student")
end
next unless !age_between_16_19 && student && child
record.errors.add "age#{person_num}", I18n.t("validations.sales.household.age.student_16_19.must_be_16_19")
record.errors.add "ecstat#{person_num}", I18n.t("validations.sales.household.ecstat.student_16_19.cannot_be_student.child_not_16_19")
record.errors.add "relat#{person_num}", I18n.t("validations.sales.household.relat.student_16_19.cannot_be_child.student_not_16_19")
end
end
def validate_person_age_matches_economic_status(record)
(2..6).each do |person_num|
age = record.public_send("age#{person_num}")
economic_status = record.public_send("ecstat#{person_num}")
next unless age && economic_status
if age < 16 && !economic_status_is_child_other_or_refused?(economic_status) && !record.form.start_year_2024_or_later?
record.errors.add "ecstat#{person_num}", I18n.t("validations.sales.household.ecstat.child_under_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.sales.household.age.child_under_16_ecstat", person_num:)
end
if person_is_economic_child?(economic_status) && age > 16
record.errors.add "ecstat#{person_num}", I18n.t("validations.sales.household.ecstat.child_over_16", person_num:)
record.errors.add "age#{person_num}", I18n.t("validations.sales.household.age.child_over_16", person_num:)
@ -93,25 +32,8 @@ module Validations::Sales::HouseholdValidations
end
end
def validate_child_12_years_younger(record)
return unless record.saledate && !record.form.start_year_2024_or_later?
(2..6).each do |person_num|
buyer_1_age = record.public_send("age1")
person_age = record.public_send("age#{person_num}")
relationship = record.public_send("relat#{person_num}")
next unless buyer_1_age && person_age && relationship
next unless person_age > buyer_1_age - 12 && person_is_child?(relationship)
record.errors.add "age1", I18n.t("validations.sales.household.age1.child_12_years_younger")
record.errors.add "age#{person_num}", I18n.t("validations.sales.household.age.child_12_years_younger")
record.errors.add "relat#{person_num}", I18n.t("validations.sales.household.relat.child_12_years_younger")
end
end
def validate_buyer_not_child(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
record.errors.add "ecstat1", I18n.t("validations.sales.household.ecstat1.buyer_cannot_be_child") if person_is_economic_child?(record.ecstat1)
record.errors.add "ecstat2", I18n.t("validations.sales.household.ecstat2.buyer_cannot_be_child") if person_is_economic_child?(record.ecstat2) && record.joint_purchase?
@ -119,31 +41,11 @@ module Validations::Sales::HouseholdValidations
private
def person_is_fulltime_student?(economic_status)
economic_status == 7
end
def person_is_economic_child?(economic_status)
economic_status == 9
end
def person_economic_status_refused?(economic_status)
economic_status == 10
end
def economic_status_is_child_other_or_refused?(economic_status)
[9, 0, 10].include?(economic_status)
end
def person_is_partner?(relationship)
relationship == "P"
end
def person_is_child?(relationship)
relationship == "C"
end
def relationship_is_child_other_or_refused?(relationship)
%w[C X R].include?(relationship)
end
end

17
app/models/validations/sales/property_validations.rb

@ -1,17 +1,4 @@
module Validations::Sales::PropertyValidations
def validate_postcodes_match_if_discounted_ownership(record)
return unless record.saledate && !record.form.start_year_2024_or_later?
return unless record.ppostcode_full.present? && record.postcode_full.present?
if record.discounted_ownership_sale? && record.ppostcode_full != record.postcode_full
joint_purchase_id = record.joint_purchase? ? "joint_purchase" : "not_joint_purchase"
record.errors.add :postcode_full, I18n.t("validations.sales.property_information.postcode_full.postcode_must_match_previous.#{joint_purchase_id}")
record.errors.add :ppostcode_full, I18n.t("validations.sales.property_information.ppostcode_full.postcode_must_match_previous.#{joint_purchase_id}")
record.errors.add :ownershipsch, I18n.t("validations.sales.property_information.ownershipsch.postcode_must_match_previous.#{joint_purchase_id}")
record.errors.add :uprn, I18n.t("validations.sales.property_information.uprn.postcode_must_match_previous.#{joint_purchase_id}")
end
end
def validate_bedsit_number_of_beds(record)
return unless record.proptype.present? && record.beds.present?
@ -43,7 +30,7 @@ module Validations::Sales::PropertyValidations
# see also: this validation in validations/property_validations.rb
def validate_la_in_england(record)
return unless record.form.start_year_2025_or_later? && record.la.present?
return if record.la.blank?
return if record.la.in?(LocalAuthority.england.pluck(:code))
record.errors.add :la, I18n.t("validations.sales.property_information.la.not_in_england")
@ -59,7 +46,7 @@ module Validations::Sales::PropertyValidations
# see also: this validation in validations/property_validations.rb
def validate_la_is_active(record)
return unless record.form.start_year_2025_or_later? && record.la.present? && record.startdate.present?
return unless record.la.present? && record.startdate.present?
la = LocalAuthority.england.find_by(code: record.la)

19
app/models/validations/sales/sale_information_validations.rb

@ -12,12 +12,9 @@ module Validations::Sales::SaleInformationValidations
record.errors.add :saledate, I18n.t("validations.sales.sale_information.saledate.must_be_after_hodate")
end
if (record.saledate - 5.years) >= record.hodate && record.form.start_year_2025_or_later?
if (record.saledate - 5.years) >= record.hodate
record.errors.add :hodate, I18n.t("validations.sales.sale_information.hodate.must_be_less_than_5_years_from_saledate")
record.errors.add :saledate, I18n.t("validations.sales.sale_information.saledate.must_be_less_than_5_years_from_hodate")
elsif (record.saledate - 3.years) >= record.hodate && record.startdate.year <= 2024
record.errors.add :hodate, I18n.t("validations.sales.sale_information.hodate.must_be_less_than_3_years_from_saledate")
record.errors.add :saledate, I18n.t("validations.sales.sale_information.saledate.must_be_less_than_3_years_from_hodate")
end
end
@ -75,7 +72,7 @@ module Validations::Sales::SaleInformationValidations
end
def validate_discounted_ownership_value(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
return unless record.value && record.deposit && record.ownershipsch
return unless record.mortgage || record.mortgageused == 2
return unless record.discount || record.grant || record.type == 29
@ -103,7 +100,7 @@ module Validations::Sales::SaleInformationValidations
end
def validate_outright_sale_value_matches_mortgage_plus_deposit(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
return unless record.outright_sale?
return unless record.mortgage_used? && record.mortgage
return unless record.deposit && record.value
@ -134,7 +131,7 @@ module Validations::Sales::SaleInformationValidations
end
def validate_grant_amount(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
return unless record.grant && [8, 21].include?(record.type)
unless record.grant.between?(9_000, 16_000)
@ -144,7 +141,7 @@ module Validations::Sales::SaleInformationValidations
def validate_stairbought(record)
return unless record.stairbought && record.type
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
max_stairbought = case record.type
when 30, 16, 28, 31, 32
@ -162,7 +159,7 @@ module Validations::Sales::SaleInformationValidations
end
def validate_discount_and_value(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
return unless record.discount && record.value && record.la
if record.london_property? && record.discount_value > 137_400
@ -177,7 +174,7 @@ module Validations::Sales::SaleInformationValidations
end
def validate_non_staircasing_mortgage(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
return unless record.value && record.deposit && record.equity
return unless record.shared_ownership_scheme? && record.type && record.mortgageused && record.is_not_staircasing?
@ -189,7 +186,7 @@ module Validations::Sales::SaleInformationValidations
end
def validate_staircasing_mortgage(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.saledate
return unless record.value && record.deposit && record.stairbought
return unless record.shared_ownership_scheme? && record.type && record.mortgageused && record.is_staircase?

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

@ -87,13 +87,6 @@ module Validations::Sales::SoftValidations
deposit > savings * 4 / 3
end
def extra_borrowing_expected_but_not_reported?
return unless saledate && !form.start_year_2024_or_later?
return unless extrabor && mortgage && deposit && value && discount
extrabor != 1 && mortgage + deposit > value - value * discount / 100
end
def purchase_price_out_of_soft_range?
return unless value && beds && la && sale_range
@ -106,15 +99,6 @@ module Validations::Sales::SoftValidations
type == 24 && stairowned.between?(76, 100)
end
def shared_ownership_deposit_invalid?
return unless saledate && collection_start_year <= 2023
return unless mortgage || mortgageused == 2 || mortgageused == 3
return unless cashdis || !social_homebuy?
return unless deposit && value && equity
over_tolerance?(mortgage_deposit_and_discount_total, value * equity / 100, 1)
end
def mortgage_plus_deposit_less_than_discounted_value?
return unless mortgage && deposit && value && discount
return if form.start_year_2026_or_later?
@ -168,15 +152,6 @@ module Validations::Sales::SoftValidations
end
end
def discounted_ownership_value_invalid?
return unless saledate && collection_start_year <= 2023
return unless value && deposit && ownershipsch
return unless mortgage || mortgageused == 2 || mortgageused == 3
return unless discount || grant || type == 29
mortgage_deposit_and_grant_total != value_with_discount && discounted_ownership_sale?
end
def buyer1_livein_wrong_for_ownership_type?
return unless ownershipsch && buy1livein

2
app/models/validations/tenancy_validations.rb

@ -66,7 +66,7 @@ module Validations::TenancyValidations
def validate_joint_tenancy(record)
return unless record.collection_start_year && record.joint
if record.hhmemb == 1 && record.joint == 1 && record.collection_start_year >= 2022
if record.hhmemb == 1 && record.joint == 1
record.errors.add :joint, :not_joint_tenancy, message: I18n.t("validations.lettings.tenancy.joint.sole_tenancy")
record.errors.add :hhmemb, I18n.t("validations.lettings.tenancy.joint.multiple_members_required")
end

4
spec/models/bulk_upload_spec.rb

@ -38,7 +38,7 @@ RSpec.describe BulkUpload, type: :model do
let(:log) { build(:sales_log, saledate:, bulk_upload:) }
it "has the correct number of value checks to be set as confirmed" do
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[value_value_check monthly_charges_value_check percentage_discount_value_check income1_value_check income2_value_check combined_income_value_check retirement_value_check old_persons_shared_ownership_value_check buyer_livein_value_check wheel_value_check mortgage_value_check savings_value_check deposit_value_check staircase_bought_value_check stairowned_value_check hodate_check shared_ownership_deposit_value_check extrabor_value_check grant_value_check discounted_sale_value_check deposit_and_mortgage_value_check multiple_partners_value_check partner_under_16_value_check]
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[value_value_check monthly_charges_value_check percentage_discount_value_check income1_value_check income2_value_check combined_income_value_check retirement_value_check old_persons_shared_ownership_value_check buyer_livein_value_check wheel_value_check mortgage_value_check savings_value_check deposit_value_check staircase_bought_value_check stairowned_value_check hodate_check grant_value_check deposit_and_mortgage_value_check multiple_partners_value_check partner_under_16_value_check]
end
end
end
@ -59,7 +59,7 @@ RSpec.describe BulkUpload, type: :model do
let(:log) { build(:sales_log, saledate:, bulk_upload:) }
it "has the correct number of value checks to be set as confirmed" do
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[value_value_check monthly_charges_value_check percentage_discount_value_check income1_value_check income2_value_check combined_income_value_check retirement_value_check old_persons_shared_ownership_value_check buyer_livein_value_check wheel_value_check mortgage_value_check savings_value_check deposit_value_check staircase_bought_value_check stairowned_value_check hodate_check shared_ownership_deposit_value_check extrabor_value_check grant_value_check discounted_sale_value_check deposit_and_mortgage_value_check multiple_partners_value_check partner_under_16_value_check]
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[value_value_check monthly_charges_value_check percentage_discount_value_check income1_value_check income2_value_check combined_income_value_check retirement_value_check old_persons_shared_ownership_value_check buyer_livein_value_check wheel_value_check mortgage_value_check savings_value_check deposit_value_check staircase_bought_value_check stairowned_value_check hodate_check grant_value_check deposit_and_mortgage_value_check multiple_partners_value_check partner_under_16_value_check]
end
end
end

10
spec/models/form/lettings/pages/net_income_value_check_spec.rb

@ -1,11 +1,13 @@
require "rails_helper"
RSpec.describe Form::Lettings::Pages::NetIncomeValueCheck, type: :model do
include CollectionTimeHelper
subject(:page) { described_class.new(page_id, page_definition, subsection) }
let(:page_id) { "shared_ownership_deposit_value_check" }
let(:page_id) { "net_income_value_check" }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2024, 4, 1))) }
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: current_collection_start_date)) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
@ -24,13 +26,13 @@ RSpec.describe Form::Lettings::Pages::NetIncomeValueCheck, type: :model do
end
it "has the correct title_text" do
expect(page.title_text).to eq({ "translation" => "forms.2024.lettings.soft_validations.net_income_value_check.title_text", "arguments" => [{ "i18n_template" => "incfreq", "key" => "incfreq", "label" => true }, { "arguments_for_key" => "earnings", "i18n_template" => "earnings", "key" => "field_formatted_as_currency" }] })
expect(page.title_text).to eq({ "translation" => "forms.#{current_collection_start_year}.lettings.soft_validations.net_income_value_check.title_text", "arguments" => [{ "i18n_template" => "incfreq", "key" => "incfreq", "label" => true }, { "arguments_for_key" => "earnings", "i18n_template" => "earnings", "key" => "field_formatted_as_currency" }] })
end
it "has the correct informative_text" do
expect(page.informative_text).to eq({
"arguments" => [{ "i18n_template" => "net_income_higher_or_lower_text", "key" => "net_income_higher_or_lower_text", "label" => false }],
"translation" => "forms.2024.lettings.soft_validations.net_income_value_check.informative_text",
"translation" => "forms.#{current_collection_start_year}.lettings.soft_validations.net_income_value_check.informative_text",
})
end
end

53
spec/models/form/sales/pages/discounted_sale_value_check_spec.rb

@ -1,53 +0,0 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::DiscountedSaleValueCheck, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection, index) }
let(:page_id) { "discounted_sale_value_check" }
let(:page_definition) { nil }
let(:index) { 1 }
let(:form) { instance_double(Form, start_date: Time.zone.local(2024, 4, 1)) }
let(:subsection) { instance_double(Form::Subsection, form:) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[discounted_sale_value_check])
end
it "has the correct id" do
expect(page.id).to eq("discounted_sale_value_check")
end
it "has the correct title_text" do
expect(page.title_text).to eq({
"translation" => "forms.2024.sales.soft_validations.discounted_sale_value_check.title_text",
"arguments" => [{ "arguments_for_key" => "value_with_discount", "i18n_template" => "value_with_discount", "key" => "field_formatted_as_currency" }],
})
end
it "has the correct informative_text" do
expect(page.informative_text).to eq({
"translation" => "forms.2024.sales.soft_validations.discounted_sale_value_check.informative_text",
"arguments" => [{ "arguments_for_key" => "mortgage_deposit_and_grant_total", "i18n_template" => "mortgage_deposit_and_grant_total", "key" => "field_formatted_as_currency" }],
})
end
it "is interruption screen page" do
expect(page.interruption_screen?).to be(true)
end
it "has correct depends_on" do
expect(page.depends_on).to eq([
{
"discounted_ownership_value_invalid?" => true,
},
])
end
it "has correct interruption_screen_question_ids" do
expect(page.interruption_screen_question_ids).to eq(%w[value deposit ownershipsch mortgage mortgageused discount grant type])
end
end

44
spec/models/form/sales/pages/shared_ownership_deposit_value_check_spec.rb

@ -1,44 +0,0 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::SharedOwnershipDepositValueCheck, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
let(:page_id) { "shared_ownership_deposit_value_check" }
let(:page_definition) { nil }
let(:form) { instance_double(Form, start_date: Time.zone.local(2024, 4, 1)) }
let(:subsection) { instance_double(Form::Subsection, form:) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[shared_ownership_deposit_value_check])
end
it "has the correct id" do
expect(page.id).to eq("shared_ownership_deposit_value_check")
end
it "has correct depends_on" do
expect(page.depends_on).to eq([
{
"shared_ownership_deposit_invalid?" => true,
},
])
end
it "has the correct title_text" do
expect(page.title_text).to eq({
"translation" => "forms.2024.sales.soft_validations.shared_ownership_deposit_value_check.title_text",
"arguments" => [
{ "i18n_template" => "mortgage_deposit_and_discount_error_fields", "key" => "mortgage_deposit_and_discount_error_fields" },
{ "arguments_for_key" => "mortgage_deposit_and_discount_total", "i18n_template" => "mortgage_deposit_and_discount_total", "key" => "field_formatted_as_currency" },
],
})
end
it "has the correct interruption_screen_question_ids" do
expect(page.interruption_screen_question_ids).to eq(%w[mortgage mortgageused cashdis type deposit value equity])
end
end

45
spec/models/form/sales/questions/discounted_sale_value_check_spec.rb

@ -1,45 +0,0 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::DiscountedSaleValueCheck, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("discounted_sale_value_check")
end
it "has the correct type" do
expect(question.type).to eq("interruption_screen")
end
it "is not marked as derived" do
expect(question.derived?(nil)).to be false
end
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
})
end
it "has the correct hidden_in_check_answers" do
expect(question.hidden_in_check_answers).to eq({
"depends_on" => [
{
"discounted_sale_value_check" => 0,
},
{
"discounted_sale_value_check" => 1,
},
],
})
end
end

45
spec/models/form/sales/questions/shared_ownership_deposit_value_check_spec.rb

@ -1,45 +0,0 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::SharedOwnershipDepositValueCheck, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("shared_ownership_deposit_value_check")
end
it "has the correct type" do
expect(question.type).to eq("interruption_screen")
end
it "is not marked as derived" do
expect(question.derived?(nil)).to be false
end
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
})
end
it "has the correct hidden_in_check_answers" do
expect(question.hidden_in_check_answers).to eq({
"depends_on" => [
{
"shared_ownership_deposit_value_check" => 0,
},
{
"shared_ownership_deposit_value_check" => 1,
},
],
})
end
end

61
spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb

@ -52,51 +52,6 @@ RSpec.describe Form::Sales::Subsections::DiscountedOwnershipScheme, type: :model
end
end
context "when 2024", metadata: { year: 24 } do
let(:start_year_2025_or_later?) { false }
let(:start_year_2026_or_later?) { false }
it "has correct pages" do
expect(discounted_ownership_scheme.pages.map(&:id)).to eq(
%w[
living_before_purchase_discounted_ownership_joint_purchase
living_before_purchase_discounted_ownership
purchase_price
discount
extra_borrowing_price_value_check
percentage_discount_value_check
grant
grant_value_check
purchase_price_discounted_ownership
discounted_sale_grant_value_check
about_price_discounted_ownership_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_value_and_discount
mortgage_used_discounted_ownership
discounted_ownership_mortgage_used_mortgage_value_check
discounted_sale_mortgage_used_value_check
mortgage_amount_discounted_ownership
discounted_ownership_mortgage_amount_mortgage_value_check
discounted_sale_mortgage_value_check
extra_borrowing_mortgage_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_mortgage
mortgage_lender_discounted_ownership
mortgage_lender_other_discounted_ownership
mortgage_length_discounted_ownership
extra_borrowing_discounted_ownership
extra_borrowing_value_check
deposit_discounted_ownership
extra_borrowing_deposit_value_check
discounted_ownership_deposit_joint_purchase_value_check
discounted_ownership_deposit_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_deposit
discounted_sale_deposit_value_check
leasehold_charges_discounted_ownership
monthly_charges_discounted_ownership_value_check
],
)
end
end
context "when 2025", metadata: { year: 25 } do
let(:start_year_2026_or_later?) { false }
@ -107,31 +62,23 @@ RSpec.describe Form::Sales::Subsections::DiscountedOwnershipScheme, type: :model
living_before_purchase_discounted_ownership
purchase_price
discount
extra_borrowing_price_value_check
percentage_discount_value_check
grant
grant_value_check
purchase_price_discounted_ownership
discounted_sale_grant_value_check
about_price_discounted_ownership_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_value_and_discount
mortgage_used_discounted_ownership
discounted_ownership_mortgage_used_mortgage_value_check
discounted_sale_mortgage_used_value_check
mortgage_amount_discounted_ownership
discounted_ownership_mortgage_amount_mortgage_value_check
discounted_sale_mortgage_value_check
extra_borrowing_mortgage_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_mortgage
mortgage_length_discounted_ownership
extra_borrowing_discounted_ownership
extra_borrowing_value_check
deposit_discounted_ownership
extra_borrowing_deposit_value_check
discounted_ownership_deposit_joint_purchase_value_check
discounted_ownership_deposit_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_deposit
discounted_sale_deposit_value_check
leasehold_charges_discounted_ownership
monthly_charges_discounted_ownership_value_check
],
@ -147,32 +94,24 @@ RSpec.describe Form::Sales::Subsections::DiscountedOwnershipScheme, type: :model
living_before_purchase_discounted_ownership
purchase_price
discount
extra_borrowing_price_value_check
percentage_discount_value_check
grant
grant_value_check
purchase_price_discounted_ownership
discounted_sale_grant_value_check
about_price_discounted_ownership_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_value_and_discount
mortgage_used_discounted_ownership
discounted_ownership_mortgage_used_mortgage_value_check
discounted_sale_mortgage_used_value_check
mortgage_amount_discounted_ownership
discounted_ownership_mortgage_amount_mortgage_value_check
discounted_sale_mortgage_value_check
extra_borrowing_mortgage_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_mortgage
mortgage_length_discounted_ownership_not_interviewed
mortgage_length_discounted_ownership_interviewed
extra_borrowing_discounted_ownership
extra_borrowing_value_check
deposit_discounted_ownership
extra_borrowing_deposit_value_check
discounted_ownership_deposit_joint_purchase_value_check
discounted_ownership_deposit_value_check
discounted_ownership_deposit_and_mortgage_value_check_after_deposit
discounted_sale_deposit_value_check
leasehold_charges_discounted_ownership
monthly_charges_discounted_ownership_value_check
],

9
spec/models/form/sales/subsections/shared_ownership_initial_purchase_spec.rb

@ -43,11 +43,9 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipInitialPurchase, type: :
value_shared_ownership
about_price_shared_ownership_value_check
initial_equity
shared_ownership_equity_value_check
mortgage_used_shared_ownership
mortgage_used_mortgage_value_check
mortgage_amount_shared_ownership
shared_ownership_mortgage_amount_value_check
mortgage_amount_mortgage_value_check
mortgage_length_shared_ownership
deposit_shared_ownership
@ -56,7 +54,6 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipInitialPurchase, type: :
deposit_value_check
deposit_discount
deposit_discount_optional
shared_ownership_deposit_value_check
monthly_rent
service_charge
monthly_charges_initial_purchase_value_check
@ -86,11 +83,9 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipInitialPurchase, type: :
value_shared_ownership
about_price_shared_ownership_value_check
initial_equity
shared_ownership_equity_value_check
mortgage_used_shared_ownership
mortgage_used_mortgage_value_check
mortgage_amount_shared_ownership
shared_ownership_mortgage_amount_value_check
mortgage_amount_mortgage_value_check
mortgage_length_shared_ownership
deposit_shared_ownership
@ -99,7 +94,6 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipInitialPurchase, type: :
deposit_value_check
deposit_discount
deposit_discount_optional
shared_ownership_deposit_value_check
monthly_rent
service_charge
monthly_charges_initial_purchase_value_check
@ -128,11 +122,9 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipInitialPurchase, type: :
value_shared_ownership
about_price_shared_ownership_value_check
initial_equity
shared_ownership_equity_value_check
mortgage_used_shared_ownership
mortgage_used_mortgage_value_check
mortgage_amount_shared_ownership
shared_ownership_mortgage_amount_value_check
mortgage_amount_mortgage_value_check
mortgage_length_shared_ownership_not_interviewed
mortgage_length_shared_ownership_interviewed
@ -142,7 +134,6 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipInitialPurchase, type: :
deposit_value_check
deposit_discount
deposit_discount_optional
shared_ownership_deposit_value_check
monthly_rent
service_charge
monthly_charges_initial_purchase_value_check

3
spec/models/form/sales/subsections/shared_ownership_scheme_spec.rb

@ -39,11 +39,9 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipScheme, type: :model do
value_shared_ownership
about_price_shared_ownership_value_check
equity
shared_ownership_equity_value_check
mortgage_used_shared_ownership
mortgage_used_mortgage_value_check
mortgage_amount_shared_ownership
shared_ownership_mortgage_amount_value_check
mortgage_amount_mortgage_value_check
mortgage_lender_shared_ownership
mortgage_lender_other_shared_ownership
@ -53,7 +51,6 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipScheme, type: :model do
deposit_joint_purchase_value_check
deposit_value_check
deposit_discount
shared_ownership_deposit_value_check
monthly_rent
leasehold_charges_shared_ownership
monthly_charges_shared_ownership_value_check

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

@ -44,7 +44,6 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipStaircasingTransaction,
value_shared_ownership_staircase
about_price_shared_ownership_value_check_staircasing
staircase_equity
shared_ownership_equity_value_check_staircasing
staircase_mortgage_used_shared_ownership
monthly_rent_staircasing_owned
monthly_rent_staircasing
@ -72,7 +71,6 @@ RSpec.describe Form::Sales::Subsections::SharedOwnershipStaircasingTransaction,
value_shared_ownership_staircase
about_price_shared_ownership_value_check_staircasing
staircase_equity
shared_ownership_equity_value_check_staircasing
staircase_mortgage_used_shared_ownership
monthly_rent_staircasing_owned
monthly_rent_staircasing

12
spec/models/lettings_log_spec.rb

@ -90,22 +90,10 @@ RSpec.describe LettingsLog do
expect(validator).to receive(:validate_irproduct_other)
end
it "validates partner count" do
expect(validator).to receive(:validate_partner_count)
end
it "validates person age matches economic status" do
expect(validator).to receive(:validate_person_age_matches_economic_status)
end
it "validates person age matches relationship" do
expect(validator).to receive(:validate_person_age_matches_relationship)
end
it "validates person age and relationship matches economic status" do
expect(validator).to receive(:validate_person_age_and_relationship_matches_economic_status)
end
it "validates bedroom number" do
expect(validator).to receive(:validate_shared_housing_rooms)
end

16
spec/models/sales_log_spec.rb

@ -45,26 +45,10 @@ RSpec.describe SalesLog, type: :model do
sales_log.update(age1: 25)
end
it "validates partner count" do
expect(validator).to receive(:validate_partner_count)
end
it "validates person age matches economic status" do
expect(validator).to receive(:validate_person_age_matches_economic_status)
end
it "validates person age matches relationship" do
expect(validator).to receive(:validate_person_age_matches_relationship)
end
it "validates person age and relationship matches economic status" do
expect(validator).to receive(:validate_person_age_and_relationship_matches_economic_status)
end
it "validates child is over 12 years younger than lead tenant" do
expect(validator).to receive(:validate_child_12_years_younger)
end
it "calls the form to clear any invalid answers" do
expect(sales_log.form).to receive(:reset_not_routed_questions_and_invalid_answers)
end

91
spec/models/validations/household_validations_spec.rb

@ -269,92 +269,13 @@ RSpec.describe Validations::HouseholdValidations do
end
end
describe "#validate_person_age_matches_relationship" do
context "with 2024 logs" do
let(:startdate) { current_collection_start_date }
it "does not add an error is person under 16 is a partner" do
record.age2 = 14
record.relat2 = "P"
household_validator.validate_person_age_matches_relationship(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "does not add an error if person over 19 is child" do
record.age2 = 20
record.relat2 = "C"
household_validator.validate_person_age_matches_relationship(record)
expect(record.errors["age2"]).to be_empty
expect(record.errors["relat2"]).to be_empty
end
end
end
describe "#validate_person_age_matches_economic_status" do
context "with 2024 logs" do
let(:startdate) { current_collection_start_date }
it "does not run the validation" do
record.age2 = 14
record.ecstat2 = 1
household_validator.validate_person_age_matches_economic_status(record)
expect(record.errors["ecstat2"])
.not_to include(match I18n.t("validations.lettings.household.ecstat.child_under_16", person_num: 2))
expect(record.errors["age2"])
.not_to include(match I18n.t("validations.lettings.household.age.child_under_16_ecstat", person_num: 2))
end
end
end
describe "#validate_person_age_and_relationship_matches_economic_status" do
context "with 2024 logs" do
let(:startdate) { current_collection_start_date }
context "when the household contains a tenant’s child between the ages of 16 and 19" do
it "does not add an error" do
record.age2 = 17
record.relat2 = "C"
record.ecstat2 = 1
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["ecstat2"])
.to be_empty
expect(record.errors["age2"])
.to be_empty
expect(record.errors["relat2"])
.to be_empty
end
end
it "does not add an error for a person not aged 16-19 who is a student but not a child of the lead tenant" do
record.age2 = 20
record.ecstat2 = "7"
record.relat2 = "P"
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "does not add errors for a person who is a child of the lead tenant and a student but not aged 16-19" do
record.age2 = 14
record.ecstat2 = "7"
record.relat2 = "C"
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "does not add for a person who is a student and aged 16-19 but not child" do
record.age2 = 17
record.ecstat2 = "7"
record.relat2 = "X"
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "does not add errors when the person is under 16 but not marked as a child" do
record.age2 = 14
record.ecstat2 = 1
household_validator.validate_person_age_matches_economic_status(record)
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
end

294
spec/models/validations/property_validations_spec.rb

@ -210,71 +210,47 @@ RSpec.describe Validations::PropertyValidations do
end
describe "#validate_la_in_england" do
context "with a log on or after 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return true
end
context "and the local authority is not in England for general needs log" do
let(:log) { build(:lettings_log, la: "S12000019", needstype: 1) }
it "adds an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.not_in_england"))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.not_in_england"))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.not_in_england"))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.not_in_england"))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.postcode_not_in_england"))
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
end
end
context "and the local authority is not in England for general needs log" do
let(:log) { build(:lettings_log, la: "S12000019", needstype: 1) }
context "and the local authority is not in England for supported housing log" do
let(:location) { create(:location, location_code: "S12000019") }
let(:log) { build(:lettings_log, la: "S12000019", needstype: 2, location:) }
it "adds an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.not_in_england"))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.not_in_england"))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.location_not_in_england"))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.not_in_england"))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.not_in_england"))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.not_in_england"))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.not_in_england"))
end
it "adds an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.not_in_england"))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.not_in_england"))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.not_in_england"))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.not_in_england"))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.postcode_not_in_england"))
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
end
end
context "and the local authority is in England" do
let(:log) { build(:lettings_log, la: "E06000002") }
context "and the local authority is not in England for supported housing log" do
let(:location) { create(:location, location_code: "S12000019") }
let(:log) { build(:lettings_log, la: "S12000019", needstype: 2, location:) }
it "does not add an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["startdate"]).to be_empty
end
it "adds an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.not_in_england"))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.not_in_england"))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.location_not_in_england"))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.not_in_england"))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.not_in_england"))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.not_in_england"))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.not_in_england"))
end
end
context "with a log before 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return false
end
context "and the local authority is in England" do
let(:log) { build(:lettings_log, la: "E06000002") }
context "and the local authority is not in England" do
let(:log) { build(:lettings_log, la: "S12000019") }
it "does not add an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
end
it "does not add an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["startdate"]).to be_empty
end
end
end
@ -285,98 +261,77 @@ RSpec.describe Validations::PropertyValidations do
let(:local_authority_active) { LocalAuthority.find_by(code: la_ecode_active) }
let(:local_authority_inactive) { LocalAuthority.find_by(code: la_ecode_inactive) }
context "with a log on or after 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return true
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return true
end
context "and the local authority is active for general needs log" do
let(:log) { build(:lettings_log, :completed, la: la_ecode_active, needstype: 1) }
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["startdate"]).to be_empty
end
end
context "and the local authority is active for general needs log" do
let(:log) { build(:lettings_log, :completed, la: la_ecode_active, needstype: 1) }
context "and the local authority is inactive for general needs log" do
let(:log) { build(:lettings_log, :completed, la: la_ecode_inactive, needstype: 1) }
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["startdate"]).to be_empty
end
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
end
end
context "and the local authority is inactive for general needs log" do
let(:log) { build(:lettings_log, :completed, la: la_ecode_inactive, needstype: 1) }
context "when 2025", metadata: { year: 25 } do
let(:startdate) { collection_start_date_for_year(2025) }
it "adds an error" do
context "and the local authority is active for supported housing log" do
let(:location) { create(:location, location_code: la_ecode_active) }
let(:log) { build(:lettings_log, :completed, startdate:, needstype: 2, location:) }
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
expect(log.errors["startdate"]).to be_empty
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
end
end
context "when 2025", metadata: { year: 25 } do
let(:startdate) { collection_start_date_for_year(2025) }
context "and the local authority is active for supported housing log" do
let(:location) { create(:location, location_code: la_ecode_active) }
let(:log) { build(:lettings_log, :completed, startdate:, needstype: 2, location:) }
context "and the local authority is inactive for supported housing log" do
let(:location) { create(:location, location_code: la_ecode_inactive) }
let(:log) { build(:lettings_log, :completed, startdate:, needstype: 2, location:) }
it "does not add an error" do
context "and the inactive local authority is not linked to an active one" do
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
expect(log.errors["startdate"]).to be_empty
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
context "and the local authority is inactive for supported housing log" do
let(:location) { create(:location, location_code: la_ecode_inactive) }
let(:log) { build(:lettings_log, :completed, startdate:, needstype: 2, location:) }
context "and the inactive local authority is not linked to an active one" do
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
context "and the inactive local authority is linked to an active one" do
it "does not add an error" do
LocalAuthorityLink.create!(local_authority: local_authority_inactive, linked_local_authority: local_authority_active)
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
expect(log.errors["startdate"]).to be_empty
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
end
end
end
end
context "when 2026 or later", metadata: { year: 26 } do
let(:startdate) { collection_start_date_for_year_or_later(2026) }
context "and the local authority is active for supported housing log" do
let(:log) { build(:lettings_log, :completed, startdate:, la: la_ecode_active, needstype: 2) }
context "and the inactive local authority is linked to an active one" do
it "does not add an error" do
LocalAuthorityLink.create!(local_authority: local_authority_inactive, linked_local_authority: local_authority_active)
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
@ -387,57 +342,58 @@ RSpec.describe Validations::PropertyValidations do
expect(log.errors["uprn_selection"]).to be_empty
end
end
context "and the local authority is inactive for supported housing log" do
let(:log) { build(:lettings_log, :completed, startdate:, la: la_ecode_inactive, needstype: 2) }
context "and the inactive local authority is not linked to an active one" do
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
context "and the inactive local authority is linked to an active one" do
# the link code was only ever used if the LA was drawn from the location
it "adds an error" do
LocalAuthorityLink.create!(local_authority: local_authority_inactive, linked_local_authority: local_authority_active)
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
end
end
end
context "with a log before 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return false
end
context "when 2026 or later", metadata: { year: 26 } do
let(:startdate) { collection_start_date_for_year_or_later(2026) }
context "and the local authority is inactive" do
let(:log) { build(:lettings_log, :completed, la: la_ecode_inactive) }
context "and the local authority is active for supported housing log" do
let(:log) { build(:lettings_log, :completed, startdate:, la: la_ecode_active, needstype: 2) }
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
expect(log.errors["startdate"]).to be_empty
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
end
end
context "and the local authority is inactive for supported housing log" do
let(:log) { build(:lettings_log, :completed, startdate:, la: la_ecode_inactive, needstype: 2) }
context "and the inactive local authority is not linked to an active one" do
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
context "and the inactive local authority is linked to an active one" do
# the link code was only ever used if the LA was drawn from the location
it "adds an error" do
LocalAuthorityLink.create!(local_authority: local_authority_inactive, linked_local_authority: local_authority_active)
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
end
end
end
end

98
spec/models/validations/sales/household_validations_spec.rb

@ -9,39 +9,6 @@ RSpec.describe Validations::Sales::HouseholdValidations do
let(:record) { build(:sales_log, saledate:) }
let(:saledate) { Time.zone.now }
describe "#validate_partner_count" do
let(:saledate) { current_collection_start_date }
it "does not validate for years >= 2024" do
record.relat2 = "P"
record.relat3 = "P"
household_validator.validate_partner_count(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["relat3"]).to be_empty
expect(record.errors["relat4"]).to be_empty
end
end
describe "#validate_person_age_matches_relationship" do
let(:saledate) { current_collection_start_date }
it "does not add error if person under 16 is a partner" do
record.age2 = 14
record.relat2 = "P"
household_validator.validate_person_age_matches_relationship(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "does not add error if person over 19 is a child" do
record.age2 = 20
record.relat2 = "C"
household_validator.validate_person_age_matches_relationship(record)
expect(record.errors["age2"]).to be_empty
expect(record.errors["relat2"]).to be_empty
end
end
describe "#validate_person_age_matches_economic_status" do
let(:saledate) { current_collection_start_date }
@ -56,69 +23,6 @@ RSpec.describe Validations::Sales::HouseholdValidations do
end
end
describe "#validate_child_12_years_younger" do
let(:saledate) { current_collection_start_date }
it "does not validate that child is at least 12 year younger than buyer" do
record.age1 = 20
record.age2 = 17
record.relat2 = "C"
household_validator.validate_child_12_years_younger(record)
expect(record.errors["age1"]).to be_empty
expect(record.errors["age2"]).to be_empty
expect(record.errors["relat2"]).to be_empty
end
end
describe "#validate_person_age_and_relationship_matches_economic_status" do
let(:saledate) { current_collection_start_date }
context "when the household contains a tenant’s child between the ages of 16 and 19" do
it "does not add an error" do
record.age2 = 17
record.relat2 = "C"
record.ecstat2 = 1
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["ecstat2"])
.to be_empty
expect(record.errors["age2"])
.to be_empty
expect(record.errors["relat2"])
.to be_empty
end
end
it "does not add an error for a person not aged 16-19 who is a student but not a child of the buyer" do
record.age2 = 20
record.ecstat2 = "7"
record.relat2 = "P"
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "does not add errors" do
record.age2 = 14
record.ecstat2 = "7"
record.relat2 = "C"
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "does not add errors for a person who is a student and aged 16-19 but not child" do
record.age2 = 17
record.ecstat2 = "7"
record.relat2 = "X"
household_validator.validate_person_age_and_relationship_matches_economic_status(record)
expect(record.errors["relat2"]).to be_empty
expect(record.errors["ecstat2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
end
describe "validating fields about buyers living in the property" do
let(:sales_log) { build(:sales_log, :outright_sale_setup_complete, saledate:, noint: 1, companybuy: 2, buylivein:, jointpur:, jointmore:, buy1livein:) }
@ -224,8 +128,6 @@ RSpec.describe Validations::Sales::HouseholdValidations do
end
describe "#validate_buyer_not_child" do
let(:saledate) { current_collection_start_date }
it "validates buyer 1 isn't a child" do
record.ecstat1 = 9
household_validator.validate_buyer_not_child(record)

136
spec/models/validations/sales/property_validations_spec.rb

@ -7,18 +7,6 @@ RSpec.describe Validations::Sales::PropertyValidations do
let(:property_validator_class) { Class.new { include Validations::Sales::PropertyValidations } }
describe "#validate_postcodes_match_if_discounted_ownership" do
let(:record) { build(:sales_log, ownershipsch: 1, saledate: current_collection_start_date) }
it "is not validated for years >= 2024" do
record.postcode_full = "SW1A 1AA"
record.ppostcode_full = "SW1A 0AA"
property_validator.validate_postcodes_match_if_discounted_ownership(record)
expect(record.errors["postcode_full"]).to be_empty
end
end
describe "#validate_property_unit_type" do
context "when number of bedrooms is 1" do
let(:record) { build(:sales_log, beds: 1, proptype: 2) }
@ -85,54 +73,29 @@ RSpec.describe Validations::Sales::PropertyValidations do
end
describe "#validate_la_in_england" do
context "with a log on or after 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return true
end
context "and the local authority is not in England" do
let(:log) { build(:sales_log, la: "S12000019") }
it "adds an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to include(I18n.t("validations.sales.property_information.la.not_in_england"))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.sales.property_information.postcode_full.not_in_england"))
expect(log.errors["uprn"]).to include(I18n.t("validations.sales.property_information.uprn.not_in_england"))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.sales.property_information.uprn_selection.not_in_england"))
expect(log.errors["saledate"]).to include(I18n.t("validations.sales.property_information.saledate.postcode_not_in_england"))
end
end
context "and the local authority is not in England" do
let(:log) { build(:sales_log, la: "S12000019") }
context "and the local authority is in England" do
let(:log) { build(:sales_log, la: "E06000002") }
it "does not add an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["saledate"]).to be_empty
end
it "adds an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to include(I18n.t("validations.sales.property_information.la.not_in_england"))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.sales.property_information.postcode_full.not_in_england"))
expect(log.errors["uprn"]).to include(I18n.t("validations.sales.property_information.uprn.not_in_england"))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.sales.property_information.uprn_selection.not_in_england"))
expect(log.errors["saledate"]).to include(I18n.t("validations.sales.property_information.saledate.postcode_not_in_england"))
end
end
context "with a log before 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return false
end
context "and the local authority is in England" do
let(:log) { build(:sales_log, la: "E06000002") }
context "and the local authority is not in England" do
let(:log) { build(:sales_log, la: "S12000019") }
it "does not add an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["saledate"]).to be_empty
end
it "does not add an error" do
property_validator.validate_la_in_england(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["saledate"]).to be_empty
end
end
end
@ -143,54 +106,33 @@ RSpec.describe Validations::Sales::PropertyValidations do
let(:local_authority_active) { LocalAuthority.find_by(code: la_ecode_active) }
let(:local_authority_inactive) { LocalAuthority.find_by(code: la_ecode_inactive) }
context "with a log on or after 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return true
end
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return true
end
context "and the local authority is active" do
let(:log) { build(:sales_log, :completed, la: la_ecode_active) }
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["saledate"]).to be_empty
end
end
context "and the local authority is active" do
let(:log) { build(:sales_log, :completed, la: la_ecode_active) }
context "and the local authority is inactive" do
let(:log) { build(:sales_log, :completed, la: la_ecode_inactive) }
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to include(I18n.t("validations.sales.property_information.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.sales.property_information.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.sales.property_information.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.sales.property_information.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["saledate"]).to include(I18n.t("validations.sales.property_information.saledate.la_not_valid_for_date", la: local_authority_inactive.name))
end
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["saledate"]).to be_empty
end
end
context "with a log before 2025" do
before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return false
end
context "and the local authority is inactive" do
let(:log) { build(:sales_log, :completed, la: la_ecode_inactive) }
context "and the local authority is inactive" do
let(:log) { build(:sales_log, :completed, la: la_ecode_inactive) }
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
expect(log.errors["saledate"]).to be_empty
end
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["la"]).to include(I18n.t("validations.sales.property_information.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.sales.property_information.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.sales.property_information.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.sales.property_information.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["saledate"]).to include(I18n.t("validations.sales.property_information.saledate.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
end

30
spec/models/validations/sales/sale_information_validations_spec.rb

@ -49,8 +49,8 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end
end
context "when hodate less than 3 years before saledate" do
let(:record) { build(:sales_log, hodate: current_collection_start_date - 3.years + 1.day, saledate: current_collection_start_date) }
context "when hodate less than 5 years before saledate" do
let(:record) { build(:sales_log, hodate: current_collection_start_date - 5.years + 1.day, saledate: current_collection_start_date) }
it "does not add an error" do
sale_information_validator.validate_practical_completion_date(record)
@ -59,32 +59,6 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end
end
context "when hodate 3 or more years before saledate" do
let(:record) { build(:sales_log, hodate: saledate - 3.years, saledate:) }
context "and form year is 2024 or earlier" do
let(:saledate) { collection_start_date_for_year(2024) }
it "does add an error" do
sale_information_validator.validate_practical_completion_date(record)
expect(record.errors[:hodate]).to be_present
expect(record.errors[:saledate]).to be_present
end
end
context "and form year is 2025 or later" do
let(:saledate) { collection_start_date_for_year_or_later(2025) }
it "does not add an error" do
sale_information_validator.validate_practical_completion_date(record)
expect(record.errors[:hodate]).to be_empty
expect(record.errors[:saledate]).to be_empty
end
end
end
context "when hodate 5 or more years before saledate" do
let(:record) { build(:sales_log, hodate: current_collection_start_date - 5.years, saledate: current_collection_start_date) }

303
spec/models/validations/sales/soft_validations_spec.rb

@ -372,20 +372,6 @@ RSpec.describe Validations::Sales::SoftValidations do
end
end
end
context "when validating extra borrowing" do
let(:saledate) { collection_start_date_for_year_or_later(2024) }
it "returns false for logs from 2024 onwards" do
record.extrabor = 2
record.mortgage = 50_000
record.deposit = 40_000
record.value = 100_000
record.discount = 11
expect(record)
.not_to be_extra_borrowing_expected_but_not_reported
end
end
end
describe "savings amount validations" do
@ -479,149 +465,6 @@ RSpec.describe Validations::Sales::SoftValidations do
.not_to be_deposit_over_soft_max
end
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
record.cashdis = 1000
record.value = 3000
record.equity = 100
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns false if MORTGAGE + DEPOSIT + CASHDIS are within 1£ of VALUE * EQUITY/100" do
record.mortgage = 500
record.deposit = 500
record.cashdis = 500
record.value = 3001
record.equity = 50
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns false 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
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns true 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
expect(record)
.to be_shared_ownership_deposit_invalid
end
it "returns false if no deposit is given" do
record.mortgage = 1000
record.deposit = nil
record.cashdis = 1000
record.value = 3000
record.equity = 100
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns false 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
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns true if no cashdis is given and cashdis is not routed to" do
record.mortgage = 1000
record.deposit = 1000
record.type = 2
record.cashdis = nil
record.value = 3000
record.equity = 100
expect(record)
.to be_shared_ownership_deposit_invalid
end
it "returns false if no cashdis not routed to and MORTGAGE + DEPOSIT are within 1£ of VALUE * EQUITY/100" do
record.mortgage = 500
record.deposit = 500
record.type = 2
record.cashdis = nil
record.value = 1999
record.equity = 50
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns false if no value is given" do
record.mortgage = 1000
record.deposit = 1000
record.cashdis = 1000
record.value = nil
record.equity = 100
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns false if no equity is given" do
record.mortgage = 1000
record.deposit = 1000
record.cashdis = 1000
record.value = 3000
record.equity = nil
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns true 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
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
describe "hodate_more_than_3_years_before_saledate" do
@ -765,7 +608,7 @@ RSpec.describe Validations::Sales::SoftValidations do
it "returns true if grant is below 9000" do
record.grant = 1_000
record.type = 9
record.saledate = Time.zone.local(2024, 1, 1)
record.saledate = current_collection_start_date
expect(record).to be_grant_outside_common_range
end
@ -773,7 +616,7 @@ RSpec.describe Validations::Sales::SoftValidations do
it "returns true if grant is above 16000" do
record.grant = 100_000
record.type = 9
record.saledate = Time.zone.local(2024, 1, 1)
record.saledate = current_collection_start_date
expect(record).to be_grant_outside_common_range
end
@ -781,34 +624,26 @@ RSpec.describe Validations::Sales::SoftValidations do
it "returns false if grant is within expected range" do
record.grant = 10_000
record.type = 9
record.saledate = Time.zone.local(2024, 1, 1)
record.saledate = current_collection_start_date
expect(record).not_to be_grant_outside_common_range
end
it "returns false for logs after 2024 with RTA" do
it "returns false for logs with RTA" do
record.grant = 100_000
record.type = 8
record.saledate = Time.zone.local(2025, 1, 1)
record.saledate = current_collection_start_date
expect(record).not_to be_grant_outside_common_range
end
it "returns false for logs after 2024 with socialBuy" do
it "returns false for logs with socialBuy" do
record.grant = 100_000
record.type = 21
record.saledate = Time.zone.local(2025, 1, 1)
record.saledate = current_collection_start_date
expect(record).not_to be_grant_outside_common_range
end
it "returns true for logs after 2024 with other type" do
record.grant = 100_000
record.type = 9
record.saledate = Time.zone.local(2025, 1, 1)
expect(record).to be_grant_outside_common_range
end
end
describe "#staircase_bought_above_fifty" do
@ -961,130 +796,6 @@ RSpec.describe Validations::Sales::SoftValidations do
end
end
describe "#discounted_ownership_value_invalid?" do
context "when grant is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, deposit: 5_000, value: 30_000, ownershipsch: 2, type: 8, saledate: Time.zone.local(2023, 4, 3)) }
context "and not provided" do
before do
record.grant = nil
end
it "returns false" do
expect(record).not_to be_discounted_ownership_value_invalid
end
end
context "and is provided" do
it "returns true if mortgage, deposit and grant total does not equal market value" do
record.grant = 3_000
expect(record).to be_discounted_ownership_value_invalid
end
it "returns false if mortgage, deposit and grant total equals market value" do
record.grant = 15_000
expect(record).not_to be_discounted_ownership_value_invalid
end
end
end
context "when discount is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, deposit: 5_000, value: 30_000, ownershipsch: 2, type: 9, saledate: Time.zone.local(2023, 4, 3)) }
context "and not provided" do
before do
record.discount = nil
end
it "returns false" do
expect(record).not_to be_discounted_ownership_value_invalid
end
end
context "and is provided" do
it "returns true if mortgage and deposit total does not equal market value - discount" do
record.discount = 10
expect(record).to be_discounted_ownership_value_invalid
end
it "returns false if mortgage and deposit total equals market value - discount" do
record.discount = 50
expect(record).not_to be_discounted_ownership_value_invalid
end
end
end
context "when neither discount nor grant is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, value: 30_000, ownershipsch: 2, type: 29, saledate: Time.zone.local(2023, 4, 3)) }
it "returns true if mortgage and deposit total does not equal market value" do
record.deposit = 2_000
expect(record).to be_discounted_ownership_value_invalid
end
it "returns false if mortgage and deposit total equals market value" do
record.deposit = 20_000
expect(record).not_to be_discounted_ownership_value_invalid
end
end
context "when mortgage is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgageused: 1, deposit: 5_000, grant: 3_000, value: 20_000, discount: 10, ownershipsch: 2, saledate: Time.zone.local(2023, 4, 3)) }
context "and not provided" do
before do
record.mortgage = nil
end
it "returns false" do
expect(record).not_to be_discounted_ownership_value_invalid
end
end
context "and is provided" do
it "returns true if mortgage, grant and deposit total does not equal market value - discount" do
record.mortgage = 10
expect(record).to be_discounted_ownership_value_invalid
end
it "returns false if mortgage, grant and deposit total equals market value - discount" do
record.mortgage = 10_000
expect(record).not_to be_discounted_ownership_value_invalid
end
end
end
context "when mortgage is not routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgageused: 2, deposit: 5_000, grant: 3_000, value: 20_000, discount: 10, ownershipsch: 2, saledate: Time.zone.local(2023, 4, 3)) }
it "returns true if grant and deposit total does not equal market value - discount" do
expect(record).to be_discounted_ownership_value_invalid
end
it "returns false if mortgage, grant and deposit total equals market value - discount" do
record.grant = 13_000
expect(record).not_to be_discounted_ownership_value_invalid
end
end
context "when ownership is not discounted" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, deposit: 5_000, grant: 3_000, value: 20_000, discount: 10, ownershipsch: 1, saledate: Time.zone.local(2023, 4, 3)) }
it "returns false" do
expect(record).not_to be_discounted_ownership_value_invalid
end
end
context "when it is a 2024 log" do
let(:record) { FactoryBot.build(:sales_log, mortgageused: 1, deposit: 5_000, grant: 3_000, value: 20_000, discount: 10, ownershipsch: 2, saledate: Time.zone.local(2024, 4, 3)) }
it "returns true if mortgage, grant and deposit total does not equal market value - discount" do
record.mortgage = 10
expect(record).not_to be_discounted_ownership_value_invalid
end
end
end
describe "#buyer1_livein_wrong_for_ownership_type?" do
context "when it's a shared ownership" do
let(:record) { FactoryBot.build(:sales_log, ownershipsch: 1) }

226
spec/services/bulk_upload/lettings/year2023/csv_parser_spec.rb

@ -1,226 +0,0 @@
require "rails_helper"
RSpec.describe BulkUpload::Lettings::Year2023::CsvParser do
subject(:service) { described_class.new(path:) }
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:lettings_log, :completed) }
context "when parsing csv with headers" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2023))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2023))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with headers with extra rows" do
before do
file.write("Section\n")
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2023))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2023))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(8)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with headers in arbitrary order" do
let(:seed) { rand }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2023, seed:))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2023, seed:))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with extra invalid headers" do
let(:seed) { rand }
let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) }
let(:field_numbers) { log_to_csv.default_2023_field_numbers + %w[invalid_field_number] }
let(:field_values) { log_to_csv.to_2023_row + %w[value_for_invalid_field_number] }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(log_to_csv.custom_field_numbers_row(seed:, field_numbers:))
file.write(log_to_csv.to_custom_csv_row(seed:, field_values:))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
end
context "when parsing csv without headers" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(0)
expect(service.col_offset).to eq(0)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing with BOM aka byte order mark" do
let(:bom) { "\uFEFF" }
before do
file.write(bom)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when an invalid byte sequence" do
let(:invalid_sequence) { "\x81" }
before do
file.write(invalid_sequence)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with carriage returns" do
before do
file.write("Question\r\n")
file.write("Additional info\r")
file.write("Values\r\n")
file.write("Can be empty?\r")
file.write("Type of letting the question applies to\r\n")
file.write("Duplicate check field?\r")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2023))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2023))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
describe "#column_for_field", :aggregate_failures do
context "when with headers using default ordering" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2023))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2023))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_5")).to eql("B")
expect(service.column_for_field("field_22")).to eql("EL")
end
end
context "when without headers using default ordering" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_5")).to eql("A")
expect(service.column_for_field("field_22")).to eql("EK")
end
end
context "when with headers using custom ordering" do
let(:seed) { 123 }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2023, seed:))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2023, seed:))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_5")).to eql("N")
expect(service.column_for_field("field_22")).to eql("O")
expect(service.column_for_field("field_26")).to eql("B")
expect(service.column_for_field("field_25")).to eql("EF")
end
end
end
end

2875
spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb

File diff suppressed because it is too large Load Diff

254
spec/services/bulk_upload/lettings/year2024/csv_parser_spec.rb

@ -1,254 +0,0 @@
require "rails_helper"
RSpec.describe BulkUpload::Lettings::Year2024::CsvParser do
subject(:service) { described_class.new(path:) }
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:lettings_log, :completed) }
context "when parsing csv with headers" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2024))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when some csv headers are empty (and we don't care about them)" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2024))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with headers with extra rows" do
before do
file.write("Section\n")
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2024))
file.write("\n")
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(8)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
it "does not parse the last empty row" do
expect(service.row_parsers.count).to eq(1)
end
end
context "when parsing csv with headers in arbitrary order" do
let(:seed) { rand }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2024, seed:))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2024, seed:))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with extra invalid headers" do
let(:seed) { rand }
let(:log_to_csv) { BulkUpload::LettingsLogToCsv.new(log:) }
let(:field_numbers) { log_to_csv.default_2024_field_numbers + %w[invalid_field_number] }
let(:field_values) { log_to_csv.to_2024_row + %w[value_for_invalid_field_number] }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(log_to_csv.custom_field_numbers_row(seed:, field_numbers:))
file.write(log_to_csv.to_custom_csv_row(seed:, field_values:))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
end
context "when parsing csv without headers" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2024))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(0)
expect(service.col_offset).to eq(0)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing with BOM aka byte order mark" do
let(:bom) { "\uFEFF" }
before do
file.write(bom)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2024))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when an invalid byte sequence" do
let(:invalid_sequence) { "\x81" }
before do
file.write(invalid_sequence)
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2024))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with carriage returns" do
before do
file.write("Question\r\n")
file.write("Additional info\r")
file.write("Values\r\n")
file.write("Can be empty?\r")
file.write("Type of letting the question applies to\r\n")
file.write("Duplicate check field?\r")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2024))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
describe "#column_for_field", :aggregate_failures do
context "when with headers using default ordering" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2024))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_5")).to eql("F")
expect(service.column_for_field("field_22")).to eql("W")
end
end
context "when without headers using default ordering" do
before do
file.write(BulkUpload::LettingsLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2024))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_5")).to eql("E")
expect(service.column_for_field("field_22")).to eql("V")
end
end
context "when with headers using custom ordering" do
let(:seed) { 123 }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_field_numbers_row_for_year(2024, seed:))
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_year_csv_row(2024, seed:))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_5")).to eql("B")
expect(service.column_for_field("field_22")).to eql("AS")
expect(service.column_for_field("field_26")).to eql("DH")
expect(service.column_for_field("field_25")).to eql("I")
end
end
end
end

3157
spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb

File diff suppressed because it is too large Load Diff

170
spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb

@ -1,170 +0,0 @@
require "rails_helper"
RSpec.describe BulkUpload::Sales::Year2023::CsvParser do
subject(:service) { described_class.new(path:) }
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
context "when parsing csv with headers" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2023))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2023))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_19).to eql(log.uprn)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
end
context "when parsing csv with headers in arbitrary order" do
let(:seed) { rand }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2023, seed:))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2023, seed:))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_19).to eql(log.uprn)
end
end
context "when parsing csv without headers" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(0)
expect(service.col_offset).to eq(0)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_19).to eql(log.uprn)
end
end
context "when parsing with BOM aka byte order mark" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
let(:bom) { "\uFEFF" }
before do
file.write(bom)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.close
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_19).to eql(log.uprn)
end
end
context "when an invalid byte sequence" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
let(:invalid_sequence) { "\x81" }
before do
file.write(invalid_sequence)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.close
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_19).to eql(log.uprn)
end
end
describe "#column_for_field", :aggregate_failures do
context "when headers present" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2023))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2023))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("CO")
expect(service.column_for_field("field_99")).to eql("EK")
end
end
context "when no headers" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2023))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("CN")
expect(service.column_for_field("field_99")).to eql("EJ")
end
end
end
context "when parsing csv with carriage returns" do
before do
file.write("Question\r\n")
file.write("Additional info\r")
file.write("Values\r\n")
file.write("Can be empty?\r")
file.write("Type of letting the question applies to\r\n")
file.write("Duplicate check field?\r")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2023))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2023))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_19).to eql(log.uprn)
end
end
end

1454
spec/services/bulk_upload/sales/year2023/row_parser_spec.rb

File diff suppressed because it is too large Load Diff

191
spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb

@ -1,191 +0,0 @@
require "rails_helper"
RSpec.describe BulkUpload::Sales::Year2024::CsvParser do
subject(:service) { described_class.new(path:) }
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
context "when parsing csv with headers" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2024))
file.write("\n")
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
it "does not parse the last empty row" do
expect(service.row_parsers.count).to eq(1)
end
end
context "when some csv headers are empty (and we don't care about them)" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2024))
file.write("\n")
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
it "does not parse the last empty row" do
expect(service.row_parsers.count).to eq(1)
end
end
context "when parsing csv with headers in arbitrary order" do
let(:seed) { rand }
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2024, seed:))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2024, seed:))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
end
context "when parsing csv without headers" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
before do
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2024))
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(0)
expect(service.col_offset).to eq(0)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
end
context "when parsing with BOM aka byte order mark" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
let(:bom) { "\uFEFF" }
before do
file.write(bom)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2024))
file.close
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
end
context "when an invalid byte sequence" do
let(:file) { Tempfile.new }
let(:path) { file.path }
let(:log) { build(:sales_log, :completed, :with_uprn) }
let(:invalid_sequence) { "\x81" }
before do
file.write(invalid_sequence)
file.write(BulkUpload::SalesLogToCsv.new(log:, col_offset: 0).to_year_csv_row(2024))
file.close
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
end
describe "#column_for_field", :aggregate_failures do
context "when headers present" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("Can be empty?\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2024))
file.rewind
end
it "returns correct column" do
expect(service.column_for_field("field_1")).to eql("B")
expect(service.column_for_field("field_99")).to eql("CV")
end
end
end
context "when parsing csv with carriage returns" do
before do
file.write("Question\r\n")
file.write("Additional info\r")
file.write("Values\r\n")
file.write("Can be empty?\r")
file.write("Type of letting the question applies to\r\n")
file.write("Duplicate check field?\r")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2024))
file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2024))
file.rewind
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
end
end

2109
spec/services/bulk_upload/sales/year2024/row_parser_spec.rb

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save