From f57b93045d4e8cc947b0ee144d1949712aacca0e Mon Sep 17 00:00:00 2001 From: Arthur Campbell <51094020+arfacamble@users.noreply.github.com> Date: Tue, 18 Apr 2023 09:30:49 +0100 Subject: [PATCH] Revert "CLDC-1945 numeric questions decimal letter entry (#1442)" (#1555) This reverts commit c78f2ef5f97b79f3ad94f12ab6b0dab0ea65a28b. --- app/models/form/lettings/questions/beds.rb | 4 +- app/models/form/lettings/questions/offered.rb | 2 +- .../lettings/questions/offered_social_let.rb | 2 +- app/models/form/sales/questions/age1.rb | 1 - app/models/form/sales/questions/age2.rb | 1 - .../form/sales/questions/deposit_amount.rb | 3 +- .../form/sales/questions/deposit_discount.rb | 1 - app/models/form/sales/questions/discount.rb | 1 - app/models/form/sales/questions/equity.rb | 1 - app/models/form/sales/questions/grant.rb | 1 - .../form/sales/questions/leasehold_charges.rb | 1 - .../form/sales/questions/monthly_rent.rb | 1 - .../form/sales/questions/mortgage_amount.rb | 1 - .../form/sales/questions/mortgage_length.rb | 1 - .../questions/number_of_others_in_property.rb | 1 - app/models/form/sales/questions/person_age.rb | 1 - .../form/sales/questions/previous_bedrooms.rb | 1 - .../questions/property_number_of_bedrooms.rb | 1 - .../form/sales/questions/purchase_price.rb | 1 - app/models/form/sales/questions/savings.rb | 4 +- .../form/sales/questions/staircase_bought.rb | 1 - .../form/sales/questions/staircase_owned.rb | 1 - app/models/form/sales/questions/value.rb | 1 - .../validations/property_validations.rb | 26 +++ .../sales/sale_information_validations.rb | 2 +- app/models/validations/shared_validations.rb | 21 --- .../imports/lettings_logs_import_service.rb | 4 +- config/forms/2021_2022.json | 8 +- config/forms/2022_2023.json | 8 +- config/locales/en.yml | 9 +- spec/fixtures/forms/2021_2022.json | 26 ++- .../questions/offered_social_let_spec.rb | 8 +- .../form/sales/questions/savings_spec.rb | 4 +- spec/models/lettings_log_spec.rb | 8 +- spec/models/sales_log_spec.rb | 4 +- .../validations/property_validations_spec.rb | 49 ++++++ .../validations/shared_validations_spec.rb | 158 ++++++------------ .../requests/lettings_logs_controller_spec.rb | 2 +- .../lettings_logs_import_service_spec.rb | 4 +- 39 files changed, 174 insertions(+), 200 deletions(-) diff --git a/app/models/form/lettings/questions/beds.rb b/app/models/form/lettings/questions/beds.rb index 6fa6c7c2b..75d2a835d 100644 --- a/app/models/form/lettings/questions/beds.rb +++ b/app/models/form/lettings/questions/beds.rb @@ -7,8 +7,8 @@ class Form::Lettings::Questions::Beds < ::Form::Question @type = "numeric" @width = 2 @check_answers_card_number = 0 - @max = 12 - @min = 1 + @max = 150 + @min = 0 @hint_text = "If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom." @step = 1 @question_number = 22 diff --git a/app/models/form/lettings/questions/offered.rb b/app/models/form/lettings/questions/offered.rb index 2c9828d31..e41def301 100644 --- a/app/models/form/lettings/questions/offered.rb +++ b/app/models/form/lettings/questions/offered.rb @@ -7,7 +7,7 @@ class Form::Lettings::Questions::Offered < ::Form::Question @type = "numeric" @width = 2 @check_answers_card_number = 0 - @max = 20 + @max = 150 @min = 0 @hint_text = I18n.t("hints.offered") @step = 1 diff --git a/app/models/form/lettings/questions/offered_social_let.rb b/app/models/form/lettings/questions/offered_social_let.rb index dd57acbfe..d3ac29516 100644 --- a/app/models/form/lettings/questions/offered_social_let.rb +++ b/app/models/form/lettings/questions/offered_social_let.rb @@ -7,7 +7,7 @@ class Form::Lettings::Questions::OfferedSocialLet < ::Form::Question @type = "numeric" @width = 2 @check_answers_card_number = 0 - @max = 20 + @max = 150 @min = 0 @hint_text = I18n.t("hints.offered") @step = 1 diff --git a/app/models/form/sales/questions/age1.rb b/app/models/form/sales/questions/age1.rb index 0ae3bf682..d32083b53 100644 --- a/app/models/form/sales/questions/age1.rb +++ b/app/models/form/sales/questions/age1.rb @@ -19,7 +19,6 @@ class Form::Sales::Questions::Age1 < ::Form::Question @check_answers_card_number = 1 @min = 16 @max = 110 - @step = 1 @question_number = 20 end end diff --git a/app/models/form/sales/questions/age2.rb b/app/models/form/sales/questions/age2.rb index c003eb02e..c0dc567a1 100644 --- a/app/models/form/sales/questions/age2.rb +++ b/app/models/form/sales/questions/age2.rb @@ -13,7 +13,6 @@ class Form::Sales::Questions::Age2 < ::Form::Question @check_answers_card_number = 2 @max = 110 @min = 0 - @step = 1 @question_number = 28 end end diff --git a/app/models/form/sales/questions/deposit_amount.rb b/app/models/form/sales/questions/deposit_amount.rb index 784bb56a1..fb6c0e563 100644 --- a/app/models/form/sales/questions/deposit_amount.rb +++ b/app/models/form/sales/questions/deposit_amount.rb @@ -6,9 +6,8 @@ class Form::Sales::Questions::DepositAmount < ::Form::Question @header = "How much cash deposit was paid on the property?" @type = "numeric" @min = 0 - @max = 999_999 - @step = 1 @width = 5 + @max = 999_999 @prefix = "£" @hint_text = "Enter the total cash sum paid by the buyer towards the property that was not funded by the mortgage" @derived = true diff --git a/app/models/form/sales/questions/deposit_discount.rb b/app/models/form/sales/questions/deposit_discount.rb index ae6521392..577da5a91 100644 --- a/app/models/form/sales/questions/deposit_discount.rb +++ b/app/models/form/sales/questions/deposit_discount.rb @@ -7,7 +7,6 @@ class Form::Sales::Questions::DepositDiscount < ::Form::Question @type = "numeric" @min = 0 @max = 999_999 - @step = 1 @width = 5 @prefix = "£" @hint_text = "Enter the total cash discount given on the property being purchased through the Social HomeBuy scheme" diff --git a/app/models/form/sales/questions/discount.rb b/app/models/form/sales/questions/discount.rb index ee39b8916..8c5cf7132 100644 --- a/app/models/form/sales/questions/discount.rb +++ b/app/models/form/sales/questions/discount.rb @@ -7,7 +7,6 @@ class Form::Sales::Questions::Discount < ::Form::Question @type = "numeric" @min = 0 @max = 100 - @step = 1 @width = 5 @suffix = "%" @hint_text = "For Right to Buy (RTB), Preserved Right to Buy (PRTB), and Voluntary Right to Buy (VRTB)

diff --git a/app/models/form/sales/questions/equity.rb b/app/models/form/sales/questions/equity.rb index 4db09a31f..0119fea69 100644 --- a/app/models/form/sales/questions/equity.rb +++ b/app/models/form/sales/questions/equity.rb @@ -7,7 +7,6 @@ class Form::Sales::Questions::Equity < ::Form::Question @type = "numeric" @min = 0 @max = 100 - @step = 1 @width = 5 @suffix = "%" @hint_text = "Enter the amount of initial equity held by the purchaser (for example, 25% or 50%)" diff --git a/app/models/form/sales/questions/grant.rb b/app/models/form/sales/questions/grant.rb index e113be536..9b0fd3091 100644 --- a/app/models/form/sales/questions/grant.rb +++ b/app/models/form/sales/questions/grant.rb @@ -7,7 +7,6 @@ class Form::Sales::Questions::Grant < ::Form::Question @type = "numeric" @min = 0 @max = 999_999 - @step = 1 @width = 5 @prefix = "£" @hint_text = "For all schemes except Right to Buy (RTB), Preserved Right to Buy (PRTB), Voluntary Right to Buy (VRTB) and Rent to Buy" diff --git a/app/models/form/sales/questions/leasehold_charges.rb b/app/models/form/sales/questions/leasehold_charges.rb index 2b2afb3e4..22ed7246e 100644 --- a/app/models/form/sales/questions/leasehold_charges.rb +++ b/app/models/form/sales/questions/leasehold_charges.rb @@ -6,7 +6,6 @@ class Form::Sales::Questions::LeaseholdCharges < ::Form::Question @header = "Enter the total monthly charge" @type = "numeric" @min = 1 - @step = 0.01 @width = 5 @prefix = "£" @ownershipsch = ownershipsch diff --git a/app/models/form/sales/questions/monthly_rent.rb b/app/models/form/sales/questions/monthly_rent.rb index 75c4a7ce5..2a28bc691 100644 --- a/app/models/form/sales/questions/monthly_rent.rb +++ b/app/models/form/sales/questions/monthly_rent.rb @@ -6,7 +6,6 @@ class Form::Sales::Questions::MonthlyRent < ::Form::Question @header = "What is the basic monthly rent?" @type = "numeric" @min = 0 - @step = 0.01 @width = 5 @prefix = "£" @hint_text = "Amount paid before any charges" diff --git a/app/models/form/sales/questions/mortgage_amount.rb b/app/models/form/sales/questions/mortgage_amount.rb index ce4b548e1..9b199b2aa 100644 --- a/app/models/form/sales/questions/mortgage_amount.rb +++ b/app/models/form/sales/questions/mortgage_amount.rb @@ -6,7 +6,6 @@ class Form::Sales::Questions::MortgageAmount < ::Form::Question @header = "What is the mortgage amount?" @type = "numeric" @min = 1 - @step = 1 @width = 5 @prefix = "£" @hint_text = "Enter the amount of mortgage agreed with the mortgage lender. Exclude any deposits or cash payments. Numeric in pounds. Rounded to the nearest pound." diff --git a/app/models/form/sales/questions/mortgage_length.rb b/app/models/form/sales/questions/mortgage_length.rb index 218ea03a1..adaa94d01 100644 --- a/app/models/form/sales/questions/mortgage_length.rb +++ b/app/models/form/sales/questions/mortgage_length.rb @@ -7,7 +7,6 @@ class Form::Sales::Questions::MortgageLength < ::Form::Question @type = "numeric" @min = 0 @max = 60 - @step = 1 @width = 5 @suffix = " years" @hint_text = "You should round up to the nearest year. Value should not exceed 60 years." diff --git a/app/models/form/sales/questions/number_of_others_in_property.rb b/app/models/form/sales/questions/number_of_others_in_property.rb index 450b12eb0..556ddf837 100644 --- a/app/models/form/sales/questions/number_of_others_in_property.rb +++ b/app/models/form/sales/questions/number_of_others_in_property.rb @@ -9,7 +9,6 @@ class Form::Sales::Questions::NumberOfOthersInProperty < ::Form::Question @width = 2 @min = 0 @max = 15 - @step = 1 @question_number = 35 end diff --git a/app/models/form/sales/questions/person_age.rb b/app/models/form/sales/questions/person_age.rb index cdbc9f80b..779e09669 100644 --- a/app/models/form/sales/questions/person_age.rb +++ b/app/models/form/sales/questions/person_age.rb @@ -12,7 +12,6 @@ class Form::Sales::Questions::PersonAge < ::Form::Question @check_answers_card_number = person_index @min = 0 @max = 110 - @step = 1 @question_number = 29 + (4 * person_index) end end diff --git a/app/models/form/sales/questions/previous_bedrooms.rb b/app/models/form/sales/questions/previous_bedrooms.rb index 8f36a8485..d9f9aaddb 100644 --- a/app/models/form/sales/questions/previous_bedrooms.rb +++ b/app/models/form/sales/questions/previous_bedrooms.rb @@ -8,7 +8,6 @@ class Form::Sales::Questions::PreviousBedrooms < ::Form::Question @width = 5 @min = 1 @max = 6 - @step = 1 @hint_text = "For bedsits enter 1" @question_number = 85 end diff --git a/app/models/form/sales/questions/property_number_of_bedrooms.rb b/app/models/form/sales/questions/property_number_of_bedrooms.rb index b37253244..9dbdbf3e8 100644 --- a/app/models/form/sales/questions/property_number_of_bedrooms.rb +++ b/app/models/form/sales/questions/property_number_of_bedrooms.rb @@ -9,7 +9,6 @@ class Form::Sales::Questions::PropertyNumberOfBedrooms < ::Form::Question @width = 10 @min = 1 @max = 9 - @step = 1 @question_number = 11 end end diff --git a/app/models/form/sales/questions/purchase_price.rb b/app/models/form/sales/questions/purchase_price.rb index f88938777..c98a39ef3 100644 --- a/app/models/form/sales/questions/purchase_price.rb +++ b/app/models/form/sales/questions/purchase_price.rb @@ -6,7 +6,6 @@ class Form::Sales::Questions::PurchasePrice < ::Form::Question @header = "What is the full purchase price?" @type = "numeric" @min = 0 - @step = 0.01 @width = 5 @prefix = "£" @hint_text = "For all schemes, including Right to Acquire (RTA), Right to Buy (RTB), Voluntary Right to Buy (VRTB) or Preserved Right to Buy (PRTB) sales, enter the full price of the property without any discount" diff --git a/app/models/form/sales/questions/savings.rb b/app/models/form/sales/questions/savings.rb index 6c01ed2fd..086a0ec8d 100644 --- a/app/models/form/sales/questions/savings.rb +++ b/app/models/form/sales/questions/savings.rb @@ -2,12 +2,12 @@ class Form::Sales::Questions::Savings < ::Form::Question def initialize(id, hsh, page) super @id = "savings" - @check_answer_label = "Buyer’s total savings before any deposit paid" + @check_answer_label = "Buyer’s total savings (to nearest £10) before any deposit paid" @header = "Enter their total savings to the nearest £10" @type = "numeric" @width = 5 @prefix = "£" - @step = 10 + @step = 1 @min = 0 @question_number = 72 end diff --git a/app/models/form/sales/questions/staircase_bought.rb b/app/models/form/sales/questions/staircase_bought.rb index dfdb273f5..9e54e92d3 100644 --- a/app/models/form/sales/questions/staircase_bought.rb +++ b/app/models/form/sales/questions/staircase_bought.rb @@ -8,7 +8,6 @@ class Form::Sales::Questions::StaircaseBought < ::Form::Question @width = 5 @min = 0 @max = 100 - @step = 1 @suffix = "%" @question_number = 77 end diff --git a/app/models/form/sales/questions/staircase_owned.rb b/app/models/form/sales/questions/staircase_owned.rb index 2b4d89861..b8d5a65ec 100644 --- a/app/models/form/sales/questions/staircase_owned.rb +++ b/app/models/form/sales/questions/staircase_owned.rb @@ -8,7 +8,6 @@ class Form::Sales::Questions::StaircaseOwned < ::Form::Question @width = 5 @min = 0 @max = 100 - @step = 1 @suffix = "%" @question_number = 78 end diff --git a/app/models/form/sales/questions/value.rb b/app/models/form/sales/questions/value.rb index d349a99df..4736f37af 100644 --- a/app/models/form/sales/questions/value.rb +++ b/app/models/form/sales/questions/value.rb @@ -6,7 +6,6 @@ class Form::Sales::Questions::Value < ::Form::Question @header = "What was the full purchase price?" @type = "numeric" @min = 0 - @step = 1 @width = 5 @prefix = "£" @hint_text = "Enter the full purchase price of the property before any discounts are applied. For shared ownership, enter the full purchase price paid for 100% equity (this is equal to the value of the share owned by the PRP plus the value bought by the purchaser)" diff --git a/app/models/validations/property_validations.rb b/app/models/validations/property_validations.rb index e9680facf..d2b6d2a0b 100644 --- a/app/models/validations/property_validations.rb +++ b/app/models/validations/property_validations.rb @@ -2,6 +2,24 @@ module Validations::PropertyValidations # Validations methods need to be called 'validate_' to run on model save # or 'validate_' to run on submit as well + def validate_property_number_of_times_relet(record) + return unless record.offered + + # Since offered is an integer type ActiveRecord will automatically cast that for us + # but it's type casting is a little lax so "random" becomes 0. To make sure that doesn't pass + # validation and then get silently dropped we attempt strict type casting on the original value + # as part of our validation. + begin + Integer(record.offered_before_type_cast) + rescue ArgumentError + record.errors.add :offered, I18n.t("validations.property.offered.relet_number") + end + + if record.offered.negative? || record.offered > 20 + record.errors.add :offered, :over_20, message: I18n.t("validations.property.offered.relet_number") + end + end + REFERRAL_INVALID_TMP = [8, 10, 12, 13, 14, 15].freeze def validate_rsnvac(record) if !record.first_time_property_let_as_social_housing? && record.has_first_let_vacancy_reason? @@ -33,6 +51,10 @@ module Validations::PropertyValidations end def validate_shared_housing_rooms(record) + if record.beds.present? && record.beds <= 0 + record.errors.add :beds, I18n.t("validations.property.beds.non_positive") + end + unless record.unittype_gn.nil? if record.is_bedsit? && record.beds != 1 && record.beds.present? record.errors.add :unittype_gn, I18n.t("validations.property.unittype_gn.one_bedroom_bedsit") @@ -48,6 +70,10 @@ module Validations::PropertyValidations record.errors.add :beds, I18n.t("validations.property.unittype_gn.one_seven_bedroom_shared") end end + + if record.beds.present? && record.beds > 12 + record.errors.add :beds, :over_max, message: I18n.t("validations.property.beds.over_max") + end end def validate_uprn(record) diff --git a/app/models/validations/sales/sale_information_validations.rb b/app/models/validations/sales/sale_information_validations.rb index bf3c2af86..42dbde2a5 100644 --- a/app/models/validations/sales/sale_information_validations.rb +++ b/app/models/validations/sales/sale_information_validations.rb @@ -12,7 +12,7 @@ module Validations::Sales::SaleInformationValidations end def validate_years_living_in_property_before_purchase(record) - return unless record.proplen&.nonzero? + return unless record.proplen && record.proplen.nonzero? case record.type when 18 diff --git a/app/models/validations/shared_validations.rb b/app/models/validations/shared_validations.rb index 6a32563a7..f032a089c 100644 --- a/app/models/validations/shared_validations.rb +++ b/app/models/validations/shared_validations.rb @@ -35,27 +35,6 @@ module Validations::SharedValidations end end - def validate_numeric_step(record) - record.form.numeric_questions.each do |question| - next unless question.step - next unless record[question.id] && question.page.routed_to?(record, nil) - - value = record.public_send("#{question.id}_before_type_cast") - field = question.check_answer_label || question.id - incorrect_accuracy = (value.to_d * 100) % (question.step * 100) != 0 - - if question.step < 1 && incorrect_accuracy - record.errors.add question.id.to_sym, I18n.t("validations.numeric.nearest_hundredth", field:) - elsif incorrect_accuracy || value.to_d != value.to_i # if the user enters a value in exponent notation (eg '4e1') the to_i method does not convert this to the correct value - field = question.check_answer_label || question.id - case question.step - when 1 then record.errors.add question.id.to_sym, I18n.t("validations.numeric.whole_number", field:) - when 10 then record.errors.add question.id.to_sym, I18n.t("validations.numeric.nearest_ten", field:) - end - end - end - end - def validate_property_postcode(record) postcode = record.postcode_full if record.postcode_known? && (postcode.blank? || !postcode.match(POSTCODE_REGEXP)) diff --git a/app/services/imports/lettings_logs_import_service.rb b/app/services/imports/lettings_logs_import_service.rb index 56fb0c0d2..01c71faef 100644 --- a/app/services/imports/lettings_logs_import_service.rb +++ b/app/services/imports/lettings_logs_import_service.rb @@ -290,10 +290,10 @@ module Imports %i[prevten over_20_foster_care] => %w[prevten age1], %i[prevten non_temp_accommodation] => %w[prevten rsnvac], %i[joint not_joint_tenancy] => %w[joint], - %i[offered outside_the_range] => %w[offered], + %i[offered over_20] => %w[offered], %i[earnings over_hard_max] => %w[ecstat1], %i[tshortfall no_outstanding_charges] => %w[tshortfall hbrentshortfall], - %i[beds outside_the_range] => %w[beds], + %i[beds over_max] => %w[beds], %i[tcharge complete_1_of_3] => %w[brent scharge pscharge supcharg tcharge], %i[scharge under_min] => %w[brent scharge pscharge supcharg tcharge], %i[tshortfall must_be_positive] => %w[tshortfall tshortfall_known], diff --git a/config/forms/2021_2022.json b/config/forms/2021_2022.json index cf8ac4cd9..741195f01 100644 --- a/config/forms/2021_2022.json +++ b/config/forms/2021_2022.json @@ -566,7 +566,7 @@ "hint_text": "This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0.", "type": "numeric", "min": 0, - "max": 20, + "max": 150, "step": 1, "width": 2 } @@ -588,7 +588,7 @@ "hint_text": "If the property is being offered for let for the first time, enter 0.", "type": "numeric", "min": 0, - "max": 20, + "max": 150, "step": 1, "width": 2 } @@ -702,8 +702,8 @@ "header": "How many bedrooms does the property have?", "hint_text": "If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom.", "type": "numeric", - "min": 1, - "max": 12, + "min": 0, + "max": 150, "step": 1, "width": 2 } diff --git a/config/forms/2022_2023.json b/config/forms/2022_2023.json index 181d8a19c..9b5aa6bb8 100644 --- a/config/forms/2022_2023.json +++ b/config/forms/2022_2023.json @@ -561,7 +561,7 @@ "hint_text": "This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0.", "type": "numeric", "min": 0, - "max": 20, + "max": 150, "step": 1, "width": 2 } @@ -583,7 +583,7 @@ "hint_text": "If the property is being offered for let for the first time, enter 0.", "type": "numeric", "min": 0, - "max": 20, + "max": 150, "step": 1, "width": 2 } @@ -697,8 +697,8 @@ "header": "How many bedrooms does the property have?", "hint_text": "If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom.", "type": "numeric", - "min": 1, - "max": 12, + "min": 0, + "max": 150, "step": 1, "width": 2 } diff --git a/config/locales/en.yml b/config/locales/en.yml index 7b65a8cb2..eef342674 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -144,11 +144,6 @@ en: numeric: within_range: "%{field} must be between %{min} and %{max}" above_min: "%{field} must be at least %{min}" - whole_number: "%{field} must be a whole number" - nearest_ten: "%{field} must be given to the nearest ten" - nearest_hundredth: "%{field} must be given to the nearest hundredth" - normal_format: "Enter a number" - date: invalid_date: "Enter a date in the correct format, for example 31 1 2022" outside_collection_window: Enter a date within the 22/23 collection year, which is between 1st April 2022 and 31st March 2023 @@ -218,6 +213,8 @@ en: ten_years_before_tenancy_start: "Enter a void date no more than 10 years before the tenancy start date" before_tenancy_start: "Enter a void date that is before the tenancy start date" after_mrcdate: "Void date must be before the major repairs date if provided" + offered: + relet_number: "Enter a number between 0 and 20 for the amount of times the property has been re-let" la: la_invalid_for_org: "%{org_name} does not operate in %{la_name}" postcode_invalid_for_org: "Enter a postcode in an area covered by %{org_name}" @@ -233,6 +230,8 @@ en: one_seven_bedroom_shared: "A shared house must have 1 to 7 bedrooms" one_three_bedroom_single_tenant_shared: "A shared house with fewer than two tenants must have 1 to 3 bedrooms" beds: + non_positive: "Number of bedrooms has to be greater than 0" + over_max: "Number of bedrooms cannot be more than 12" bedsits_have_max_one_bedroom: "Number of bedrooms must be 1 if the property is a bedsit" proptype: bedsits_have_max_one_bedroom: "Answer cannot be 'Bedsit' if the property has 2 or more bedrooms" diff --git a/spec/fixtures/forms/2021_2022.json b/spec/fixtures/forms/2021_2022.json index d25b575cc..97999d8a3 100644 --- a/spec/fixtures/forms/2021_2022.json +++ b/spec/fixtures/forms/2021_2022.json @@ -908,7 +908,7 @@ "hint_text": "Eligible for housing benefit or Universal Credit", "type": "numeric", "min": 0, - "step": 0.01, + "step": 1, "width": 4, "fields-to-add": [ "brent", @@ -924,7 +924,7 @@ "hint_text": "Eligible for housing benefit or Universal Credit", "type": "numeric", "min": 0, - "step": 0.01, + "step": 1, "width": 4, "fields-to-add": [ "brent", @@ -940,7 +940,7 @@ "hint_text": "Not eligible for housing benefit or Universal Credit. For example, hot water excluding water rates.", "type": "numeric", "min": 0, - "step": 0.01, + "step": 1, "width": 4, "fields-to-add": [ "brent", @@ -957,7 +957,7 @@ "type": "numeric", "min": 0, "max": 300, - "step": 0.01, + "step": 1, "width": 4, "fields-to-add": [ "brent", @@ -973,7 +973,7 @@ "hint_text": "This is the total of rent and all charges", "type": "numeric_output", "min": 0, - "step": 0.01, + "step": 1, "width": 4, "readonly": true, "requires_js": true @@ -990,7 +990,7 @@ "hint_text": "", "type": "numeric", "min": 0, - "step": 1, + "step": "1", "width": 5, "prefix": "£", "suffix": " every week" @@ -1000,12 +1000,11 @@ "care_home_charge": { "questions": { "offered": { - "check_answer_label": "Times previously offered since becoming available", - "header": "Since becoming available for re-let, how many times has the property been previously offered?", - "hint_text": "This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0.", + "check_answer_label": "Basic Rent", + "header": "What is the basic rent?", + "hint_text": "Eligible for housing benefit or Universal Credit", "type": "numeric", "min": 0, - "max": 20, "step": 1, "width": 4 } @@ -1019,12 +1018,11 @@ "care_home_charge_bi_weekly": { "questions": { "offered": { - "check_answer_label": "Times previously offered since becoming available", - "header": "Since becoming available for re-let, how many times has the property been previously offered?", - "hint_text": "This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0.", + "check_answer_label": "Basic Rent", + "header": "What is the basic rent?", + "hint_text": "Eligible for housing benefit or Universal Credit", "type": "numeric", "min": 0, - "max": 20, "step": 1, "width": 4 } diff --git a/spec/models/form/lettings/questions/offered_social_let_spec.rb b/spec/models/form/lettings/questions/offered_social_let_spec.rb index ac1930495..6516c661b 100644 --- a/spec/models/form/lettings/questions/offered_social_let_spec.rb +++ b/spec/models/form/lettings/questions/offered_social_let_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Form::Lettings::Questions::OfferedSocialLet, type: :model do let(:page) { instance_double(Form::Page) } it "has correct page" do - expect(question.page).to be page + expect(question.page).to eq page end it "has the correct id" do @@ -26,12 +26,12 @@ RSpec.describe Form::Lettings::Questions::OfferedSocialLet, type: :model do end it "has the correct minimum and maximum values" do - expect(question.min).to be 0 - expect(question.max).to be 20 + expect(question.min).to eq 0 + expect(question.max).to eq 150 end it "has the correct step" do - expect(question.step).to be 1 + expect(question.step).to eq 1 end it "is not marked as derived" do diff --git a/spec/models/form/sales/questions/savings_spec.rb b/spec/models/form/sales/questions/savings_spec.rb index 8e9c4daa4..3f721d7ef 100644 --- a/spec/models/form/sales/questions/savings_spec.rb +++ b/spec/models/form/sales/questions/savings_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Form::Sales::Questions::Savings, type: :model do end it "has the correct check_answer_label" do - expect(question.check_answer_label).to eq("Buyer’s total savings before any deposit paid") + expect(question.check_answer_label).to eq("Buyer’s total savings (to nearest £10) before any deposit paid") end it "has the correct type" do @@ -40,7 +40,7 @@ RSpec.describe Form::Sales::Questions::Savings, type: :model do end it "has correct step" do - expect(question.step).to be 10 + expect(question.step).to eq(1) end it "has correct prefix" do diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb index 481f7fbbe..fb0f01be2 100644 --- a/spec/models/lettings_log_spec.rb +++ b/spec/models/lettings_log_spec.rb @@ -112,6 +112,10 @@ RSpec.describe LettingsLog do expect(validator).to receive(:validate_shared_housing_rooms) end + it "validates number of times the property has been relet" do + expect(validator).to receive(:validate_property_number_of_times_relet) + end + it "validates tenancy type" do expect(validator).to receive(:validate_fixed_term_tenancy) expect(validator).to receive(:validate_other_tenancy_type) @@ -3100,11 +3104,11 @@ RSpec.describe LettingsLog do end context "when a non setup field is invalid" do - subject(:model) { build(:lettings_log, :completed, offered: 234) } + subject(:model) { described_class.new(beds: 404) } it "blanks it" do model.valid? - expect { model.blank_invalid_non_setup_fields! }.to change(model, :offered) + expect { model.blank_invalid_non_setup_fields! }.to change(model, :beds) end end end diff --git a/spec/models/sales_log_spec.rb b/spec/models/sales_log_spec.rb index 1fc2cf73e..c008269ea 100644 --- a/spec/models/sales_log_spec.rb +++ b/spec/models/sales_log_spec.rb @@ -509,9 +509,9 @@ RSpec.describe SalesLog, type: :model do let(:completed_sales_log) { create(:sales_log, :completed) } it "returns small numbers correctly formatted as currency" do - completed_sales_log.update!(savings: 20) + completed_sales_log.update!(savings: 4) - expect(completed_sales_log.field_formatted_as_currency("savings")).to eq("£20.00") + expect(completed_sales_log.field_formatted_as_currency("savings")).to eq("£4.00") end it "returns quite large numbers correctly formatted as currency" do diff --git a/spec/models/validations/property_validations_spec.rb b/spec/models/validations/property_validations_spec.rb index e918e3405..3b3e42e9e 100644 --- a/spec/models/validations/property_validations_spec.rb +++ b/spec/models/validations/property_validations_spec.rb @@ -6,6 +6,39 @@ RSpec.describe Validations::PropertyValidations do let(:property_validator_class) { Class.new { include Validations::PropertyValidations } } let(:record) { FactoryBot.create(:lettings_log) } + describe "#validate_property_number_of_times_relet" do + let(:expected_error) { I18n.t("validations.property.offered.relet_number") } + + it "does not add an error if the record offered is missing" do + record.offered = nil + property_validator.validate_property_number_of_times_relet(record) + expect(record.errors).to be_empty + end + + it "does not add an error if offered is valid (number between 0 and 20)" do + record.offered = 0 + property_validator.validate_property_number_of_times_relet(record) + expect(record.errors).to be_empty + record.offered = 10 + property_validator.validate_property_number_of_times_relet(record) + expect(record.errors).to be_empty + record.offered = 20 + property_validator.validate_property_number_of_times_relet(record) + expect(record.errors).to be_empty + end + + it "does add an error when offered is invalid" do + record.offered = "invalid" + property_validator.validate_property_number_of_times_relet(record) + expect(record.errors).not_to be_empty + expect(record.errors["offered"]).to include(match(expected_error)) + record.offered = 21 + property_validator.validate_property_number_of_times_relet(record) + expect(record.errors).not_to be_empty + expect(record.errors["offered"]).to include(match(expected_error)) + end + end + describe "#validate_shared_housing_rooms" do context "when number of bedrooms has not been answered" do it "does not add an error" do @@ -96,6 +129,22 @@ RSpec.describe Validations::PropertyValidations do expect(record.errors["beds"]).to include(I18n.t("validations.property.unittype_gn.one_three_bedroom_single_tenant_shared")) end end + + context "when a negative number of bedrooms is entered" do + it "adds an error" do + record.beds = -4 + property_validator.validate_shared_housing_rooms(record) + expect(record.errors["beds"]).to include(I18n.t("validations.property.beds.non_positive")) + end + end + + context "when a room number higher than 12 has been entered" do + it "adds an error" do + record.beds = 13 + property_validator.validate_shared_housing_rooms(record) + expect(record.errors["beds"]).to include(I18n.t("validations.property.beds.over_max")) + end + end end describe "#validate_unitletas" do diff --git a/spec/models/validations/shared_validations_spec.rb b/spec/models/validations/shared_validations_spec.rb index fe3612c3c..8f5038c5d 100644 --- a/spec/models/validations/shared_validations_spec.rb +++ b/spec/models/validations/shared_validations_spec.rb @@ -4,8 +4,8 @@ RSpec.describe Validations::SharedValidations do subject(:shared_validator) { validator_class.new } let(:validator_class) { Class.new { include Validations::SharedValidations } } - let(:lettings_log) { FactoryBot.create(:lettings_log) } - let(:sales_log) { FactoryBot.create(:sales_log, :completed) } + let(:record) { FactoryBot.create(:lettings_log) } + let(:sales_record) { FactoryBot.create(:sales_log, :completed) } let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") } describe "numeric min max validations" do @@ -15,164 +15,102 @@ RSpec.describe Validations::SharedValidations do context "when validating age" do it "validates that person 1's age is a number" do - lettings_log.age1 = "random" - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age1"]) + record.age1 = "random" + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age1"]) .to include(match I18n.t("validations.numeric.within_range", field: "Lead tenant’s age", min: 16, max: 120)) end it "validates that other household member ages are a number" do - lettings_log.age2 = "random" - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age2"]) + record.age2 = "random" + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age2"]) .to include(match I18n.t("validations.numeric.within_range", field: "Person 2’s age", min: 1, max: 120)) end it "validates that person 1's age is greater than 16" do - lettings_log.age1 = 15 - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age1"]) + record.age1 = 15 + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age1"]) .to include(match I18n.t("validations.numeric.within_range", field: "Lead tenant’s age", min: 16, max: 120)) end it "validates that other household member ages are greater than 1" do - lettings_log.age2 = 0 - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age2"]) + record.age2 = 0 + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age2"]) .to include(match I18n.t("validations.numeric.within_range", field: "Person 2’s age", min: 1, max: 120)) end it "validates that person 1's age is less than 121" do - lettings_log.age1 = 121 - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age1"]) + record.age1 = 121 + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age1"]) .to include(match I18n.t("validations.numeric.within_range", field: "Lead tenant’s age", min: 16, max: 120)) end it "validates that other household member ages are greater than 121" do - lettings_log.age2 = 123 - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age2"]) + record.age2 = 123 + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age2"]) .to include(match I18n.t("validations.numeric.within_range", field: "Person 2’s age", min: 1, max: 120)) end it "validates that person 1's age is between 16 and 120" do - lettings_log.age1 = 63 - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age1"]).to be_empty + record.age1 = 63 + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age1"]).to be_empty end it "validates that other household member ages are between 1 and 120" do - lettings_log.age6 = 45 - shared_validator.validate_numeric_min_max(lettings_log) - expect(lettings_log.errors["age6"]).to be_empty + record.age6 = 45 + shared_validator.validate_numeric_min_max(record) + expect(record.errors["age6"]).to be_empty end context "with sales log" do it "validates that person 2's age is between 0 and 110 for non joint purchase" do - sales_log.jointpur = 2 - sales_log.hholdcount = 1 - sales_log.details_known_2 = 1 - sales_log.age2 = 130 - shared_validator.validate_numeric_min_max(sales_log) - expect(sales_log.errors["age2"].first).to eq("Person 2’s age must be between 0 and 110") + sales_record.jointpur = 2 + sales_record.hholdcount = 1 + sales_record.details_known_2 = 1 + sales_record.age2 = 130 + shared_validator.validate_numeric_min_max(sales_record) + expect(sales_record.errors["age2"].first).to eq("Person 2’s age must be between 0 and 110") end it "validates that buyer 2's age is between 0 and 110 for joint purchase" do - sales_log.jointpur = 1 - sales_log.age2 = 130 - shared_validator.validate_numeric_min_max(sales_log) - expect(sales_log.errors["age2"].first).to eq("Buyer 2’s age must be between 0 and 110") + sales_record.jointpur = 1 + sales_record.age2 = 130 + shared_validator.validate_numeric_min_max(sales_record) + expect(sales_record.errors["age2"].first).to eq("Buyer 2’s age must be between 0 and 110") end end end it "adds the correct validation text when a question has a min but not a max" do - sales_log.savings = -10 - shared_validator.validate_numeric_min_max(sales_log) - expect(sales_log.errors["savings"]).to include(match I18n.t("validations.numeric.above_min", field: "Buyer’s total savings before any deposit paid", min: "£0")) + sales_record.savings = -10 + shared_validator.validate_numeric_min_max(sales_record) + expect(sales_record.errors["savings"]).to include(match I18n.t("validations.numeric.above_min", field: "Buyer’s total savings (to nearest £10) before any deposit paid", min: "£0")) end context "when validating percent" do it "validates that suffixes are added in the error message" do - sales_log.ownershipsch = 1 - sales_log.staircase = 1 - sales_log.stairbought = 150 - shared_validator.validate_numeric_min_max(sales_log) - expect(sales_log.errors["stairbought"]) + sales_record.ownershipsch = 1 + sales_record.staircase = 1 + sales_record.stairbought = 150 + shared_validator.validate_numeric_min_max(sales_record) + expect(sales_record.errors["stairbought"]) .to include(match I18n.t("validations.numeric.within_range", field: "Percentage bought in this staircasing transaction", min: "0%", max: "100%")) end end context "when validating price" do - it "validates that prefix £ and delimeter ',' is added in the error message" do - sales_log.income1 = -5 - shared_validator.validate_numeric_min_max(sales_log) - expect(sales_log.errors["income1"]) + it "validates that £ prefix and , is added in the error message" do + sales_record.income1 = -5 + shared_validator.validate_numeric_min_max(sales_record) + expect(sales_record.errors["income1"]) .to include(match I18n.t("validations.numeric.within_range", field: "Buyer 1’s gross annual income", min: "£0", max: "£999,999")) end end end - - describe "validating level of accuracy or rounding for numeric questions" do - context "when validating a question with a step of 1" do - it "adds an error if input is a decimal" do - sales_log.income1 = 30_000.5 - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors[:income1]).to include I18n.t("validations.numeric.whole_number", field: "Buyer 1’s gross annual income") - end - - it "adds an error if the user attempts to input a number in exponent format" do - sales_log.income1 = "3e5" - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors[:income1]).to include I18n.t("validations.numeric.whole_number", field: "Buyer 1’s gross annual income") - end - - it "does not add an error if input is an integer" do - sales_log.income1 = 30_000 - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors).to be_empty - end - end - - context "when validating a question with a step of 10" do - it "adds an error if input is not a multiple of ten" do - sales_log.savings = 30_005 - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors[:savings]).to include I18n.t("validations.numeric.nearest_ten", field: "Buyer’s total savings before any deposit paid") - end - - it "adds an error if the user attempts to input a number in exponent format" do - sales_log.savings = "3e5" - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors[:savings]).to include I18n.t("validations.numeric.nearest_ten", field: "Buyer’s total savings before any deposit paid") - end - - it "does not add an error if input is a multiple of ten" do - sales_log.savings = 30_000 - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors).to be_empty - end - end - - context "when validating a question with a step of 0.01" do - it "adds an error if input has more than 2 decimal places" do - sales_log.mscharge = 30.7418 - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors[:mscharge]).to include I18n.t("validations.numeric.nearest_hundredth", field: "Monthly leasehold charges") - end - - it "does not add an error if the user attempts to input a number in exponent format" do - sales_log.mscharge = "3e1" - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors).to be_empty - end - - it "does not add an error if input has 2 or fewer decimal places" do - sales_log.mscharge = 30.74 - shared_validator.validate_numeric_step(sales_log) - expect(sales_log.errors).to be_empty - end - end - end end diff --git a/spec/requests/lettings_logs_controller_spec.rb b/spec/requests/lettings_logs_controller_spec.rb index 6de5c4db2..d95e0a3fd 100644 --- a/spec/requests/lettings_logs_controller_spec.rb +++ b/spec/requests/lettings_logs_controller_spec.rb @@ -82,7 +82,7 @@ RSpec.describe LettingsLogsController, type: :request do it "validates lettings log parameters" do json_response = JSON.parse(response.body) expect(response).to have_http_status(:unprocessable_entity) - expect(json_response["errors"]).to match_array([["offered", [I18n.t("validations.numeric.within_range", field: "Times previously offered since becoming available", min: 0, max: 20)]], ["age1", [I18n.t("validations.numeric.within_range", field: "Lead tenant’s age", min: 16, max: 120)]]]) + expect(json_response["errors"]).to match_array([["offered", [I18n.t("validations.property.offered.relet_number")]], ["age1", [I18n.t("validations.numeric.within_range", field: "Lead tenant’s age", min: 16, max: 120)]]]) end end diff --git a/spec/services/imports/lettings_logs_import_service_spec.rb b/spec/services/imports/lettings_logs_import_service_spec.rb index 11a25ff22..4621afb2f 100644 --- a/spec/services/imports/lettings_logs_import_service_spec.rb +++ b/spec/services/imports/lettings_logs_import_service_spec.rb @@ -434,7 +434,7 @@ RSpec.describe Imports::LettingsLogsImportService do end it "intercepts the relevant validation error" do - expect(logger).to receive(:warn).with(/Removing offered with error: Times previously offered since becoming available must be between 0 and 20/) + expect(logger).to receive(:warn).with(/Removing offered with error: Enter a number between 0 and 20 for the amount of times the property has been re-let/) expect { lettings_log_service.send(:create_log, lettings_log_xml) } .not_to raise_error end @@ -530,7 +530,7 @@ RSpec.describe Imports::LettingsLogsImportService do end it "intercepts the relevant validation error" do - expect(logger).to receive(:warn).with(/Removing beds with error: Number of bedrooms must be between 1 and 12/) + expect(logger).to receive(:warn).with(/Removing beds with error: Number of bedrooms cannot be more than 12/) expect { lettings_log_service.send(:create_log, lettings_log_xml) } .not_to raise_error end