diff --git a/app/models/form/sales/pages/handover_date_check.rb b/app/models/form/sales/pages/handover_date_check.rb index cc0ce9a9b..5d656200b 100644 --- a/app/models/form/sales/pages/handover_date_check.rb +++ b/app/models/form/sales/pages/handover_date_check.rb @@ -1,8 +1,14 @@ class Form::Sales::Pages::HandoverDateCheck < ::Form::Page def initialize(id, hsh, subsection) super - @depends_on = [{ "hodate_3_years_or_more_saledate?" => true }] + @id = "handover_date_check" + @depends_on = [{ "saledate_check" => nil, "hodate_3_years_or_more_saledate?" => true }, + { "saledate_check" => 1, "hodate_3_years_or_more_saledate?" => true }] @informative_text = {} + @title_text = { + "translation" => "validations.sale_information.hodate.must_be_less_than_3_years_from_saledate", + "arguments" => [], + } end def questions diff --git a/app/models/form/sales/pages/sale_date_check.rb b/app/models/form/sales/pages/sale_date_check.rb new file mode 100644 index 000000000..acb34589c --- /dev/null +++ b/app/models/form/sales/pages/sale_date_check.rb @@ -0,0 +1,19 @@ +class Form::Sales::Pages::SaleDateCheck < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "completion_date_check" + @depends_on = [{ "hodate_check" => nil, "hodate_3_years_or_more_saledate?" => true }, + { "hodate_check" => 1, "hodate_3_years_or_more_saledate?" => true }] + @informative_text = {} + @title_text = { + "translation" => "validations.sale_information.saledate.must_be_less_than_3_years_from_hodate", + "arguments" => [], + } + end + + def questions + @questions ||= [ + Form::Sales::Questions::SaleDateCheck.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/questions/handover_date_check.rb b/app/models/form/sales/questions/handover_date_check.rb index 03a516e55..f19ee0196 100644 --- a/app/models/form/sales/questions/handover_date_check.rb +++ b/app/models/form/sales/questions/handover_date_check.rb @@ -3,7 +3,7 @@ class Form::Sales::Questions::HandoverDateCheck < ::Form::Question super @id = "hodate_check" @check_answer_label = "Practical completion or handover date check" - @header = "Are you sure practical completion or handover date is more than 3 years before exchange date?" + @header = "Are you sure?" @type = "interruption_screen" @answer_options = { "0" => { "value" => "Yes" }, @@ -17,6 +17,12 @@ class Form::Sales::Questions::HandoverDateCheck < ::Form::Question { "hodate_check" => 1, }, + { + "saledate_check" => 0, + }, + { + "saledate_check" => 1, + }, ], } end diff --git a/app/models/form/sales/questions/sale_date_check.rb b/app/models/form/sales/questions/sale_date_check.rb new file mode 100644 index 000000000..b2947434b --- /dev/null +++ b/app/models/form/sales/questions/sale_date_check.rb @@ -0,0 +1,29 @@ +class Form::Sales::Questions::SaleDateCheck < ::Form::Question + def initialize(id, hsh, page) + super + @id = "saledate_check" + @check_answer_label = "Sale completion date check" + @header = "Are you sure?" + @type = "interruption_screen" + @answer_options = { + "0" => { "value" => "Yes" }, + "1" => { "value" => "No" }, + } + @hidden_in_check_answers = { + "depends_on" => [ + { + "hodate_check" => 0, + }, + { + "hodate_check" => 1, + }, + { + "saledate_check" => 0, + }, + { + "saledate_check" => 1, + }, + ], + } + end +end diff --git a/app/models/form/sales/subsections/setup.rb b/app/models/form/sales/subsections/setup.rb index 22dcda8b9..aa3c498fc 100644 --- a/app/models/form/sales/subsections/setup.rb +++ b/app/models/form/sales/subsections/setup.rb @@ -10,6 +10,7 @@ class Form::Sales::Subsections::Setup < ::Form::Subsection Form::Common::Pages::Organisation.new(nil, nil, self), Form::Common::Pages::CreatedBy.new(nil, nil, self), Form::Sales::Pages::SaleDate.new(nil, nil, self), + Form::Sales::Pages::SaleDateCheck.new(nil, nil, self), Form::Sales::Pages::PurchaserCode.new(nil, nil, self), Form::Sales::Pages::OwnershipScheme.new(nil, nil, self), Form::Sales::Pages::SharedOwnershipType.new(nil, nil, self), diff --git a/app/models/form/sales/subsections/shared_ownership_scheme.rb b/app/models/form/sales/subsections/shared_ownership_scheme.rb index d011d5429..04ff9b56e 100644 --- a/app/models/form/sales/subsections/shared_ownership_scheme.rb +++ b/app/models/form/sales/subsections/shared_ownership_scheme.rb @@ -15,7 +15,7 @@ class Form::Sales::Subsections::SharedOwnershipScheme < ::Form::Subsection Form::Sales::Pages::Resale.new(nil, nil, self), Form::Sales::Pages::ExchangeDate.new(nil, nil, self), Form::Sales::Pages::HandoverDate.new(nil, nil, self), - Form::Sales::Pages::HandoverDateCheck.new("handover_date_check", nil, self), + Form::Sales::Pages::HandoverDateCheck.new(nil, nil, self), Form::Sales::Pages::LaNominations.new(nil, nil, self), Form::Sales::Pages::BuyerPrevious.new(nil, nil, self), Form::Sales::Pages::PreviousBedrooms.new(nil, nil, self), diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index b217ff69c..8a99932bd 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -35,7 +35,7 @@ class SalesLog < Log scope :search_by, ->(param) { filter_by_id(param) } scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org) } - OPTIONAL_FIELDS = %w[purchid monthly_charges_value_check old_persons_shared_ownership_value_check].freeze + OPTIONAL_FIELDS = %w[saledate_check purchid monthly_charges_value_check old_persons_shared_ownership_value_check].freeze RETIREMENT_AGES = { "M" => 65, "F" => 60, "X" => 65 }.freeze def startdate diff --git a/app/models/validations/date_validations.rb b/app/models/validations/date_validations.rb index ceec8ed9a..3823b3dd2 100644 --- a/app/models/validations/date_validations.rb +++ b/app/models/validations/date_validations.rb @@ -84,15 +84,6 @@ private @second_collection_end_date ||= FormHandler.instance.forms.map { |_name, form| form.end_date }.compact.max end - def date_valid?(question, record) - if record[question].is_a?(ActiveSupport::TimeWithZone) && record[question].year.zero? - record.errors.add question, I18n.t("validations.date.invalid_date") - false - else - true - end - end - def is_rsnvac_first_let?(record) [15, 16, 17].include?(record["rsnvac"]) end diff --git a/app/models/validations/sales/sale_information_validations.rb b/app/models/validations/sales/sale_information_validations.rb index 24fdff3ea..e448b6aca 100644 --- a/app/models/validations/sales/sale_information_validations.rb +++ b/app/models/validations/sales/sale_information_validations.rb @@ -2,8 +2,9 @@ module Validations::Sales::SaleInformationValidations def validate_practical_completion_date_before_saledate(record) return if record.saledate.blank? || record.hodate.blank? - unless record.saledate > record.hodate - record.errors.add :hodate, I18n.t("validations.sale_information.hodate.must_be_before_exdate") + if record.hodate > record.saledate + record.errors.add :hodate, I18n.t("validations.sale_information.hodate.must_be_before_saledate") + record.errors.add :saledate, I18n.t("validations.sale_information.saledate.must_be_after_hodate") end end diff --git a/app/models/validations/sales/setup_validations.rb b/app/models/validations/sales/setup_validations.rb index 0e7a759ee..0ae1f43ea 100644 --- a/app/models/validations/sales/setup_validations.rb +++ b/app/models/validations/sales/setup_validations.rb @@ -1,6 +1,8 @@ module Validations::Sales::SetupValidations + include Validations::SharedValidations + def validate_saledate(record) - return unless record.saledate + return unless record.saledate && date_valid?("saledate", record) unless Time.zone.local(2022, 4, 1) <= record.saledate && record.saledate < Time.zone.local(2023, 4, 1) record.errors.add :saledate, I18n.t("validations.setup.saledate.financial_year") diff --git a/app/models/validations/sales/soft_validations.rb b/app/models/validations/sales/soft_validations.rb index e7b170e89..cba756ea3 100644 --- a/app/models/validations/sales/soft_validations.rb +++ b/app/models/validations/sales/soft_validations.rb @@ -67,7 +67,7 @@ module Validations::Sales::SoftValidations def hodate_3_years_or_more_saledate? return unless hodate && saledate - ((saledate.to_date - hodate.to_date).to_i / 365) >= 3 + saledate - hodate >= 3.years end def grant_outside_common_range? diff --git a/app/models/validations/shared_validations.rb b/app/models/validations/shared_validations.rb index 8452b9a52..3df46bc8b 100644 --- a/app/models/validations/shared_validations.rb +++ b/app/models/validations/shared_validations.rb @@ -99,6 +99,15 @@ module Validations::SharedValidations end end + def date_valid?(question, record) + if record[question].is_a?(ActiveSupport::TimeWithZone) && record[question].year.zero? + record.errors.add question, I18n.t("validations.date.invalid_date") + false + else + true + end + end + private def person_is_partner?(relationship) diff --git a/app/services/filter_service.rb b/app/services/filter_service.rb index affe31f02..71fc19a46 100644 --- a/app/services/filter_service.rb +++ b/app/services/filter_service.rb @@ -36,7 +36,7 @@ class FilterService end def bulk_upload - id = ((logs_filters["bulk_upload_id"] || []).reject(&:blank?))[0] + id = (logs_filters["bulk_upload_id"] || []).reject(&:blank?)[0] @bulk_upload ||= current_user.bulk_uploads.find_by(id:) end diff --git a/config/locales/en.yml b/config/locales/en.yml index 0f3bcc923..5da5974a4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -427,13 +427,16 @@ en: social_homebuy: "Social HomeBuy buyers should not have lived here before" rent_to_buy: "Rent to Buy buyers should not have lived here before" hodate: - must_be_before_exdate: "Practical completion or handover date must be before exchange date" + must_be_before_saledate: "Practical completion or handover date must be before exchange date" + must_be_less_than_3_years_from_saledate: "You told us practical completion or handover date is more than 3 years before completion date" exdate: - must_be_before_saledate: "Contract exchange date must be less than 1 year before completion date" + must_be_before_saledate: "Contract exchange date must be before completion date" must_be_less_than_1_year_from_saledate: "Contract exchange date must be less than 1 year before completion date" saledate: - must_be_after_exdate: "Completion date must be less than 1 year after contract exchange date" + must_be_after_exdate: "Completion date must be after contract exchange date" must_be_less_than_1_year_from_exdate: "Completion date must be less than 1 year after contract exchange date" + must_be_less_than_3_years_from_hodate: "You told us completion date is more than 3 years after practical completion or handover date" + must_be_after_hodate: "Completion date must be after practical completion or handover date" previous_property_beds: property_type_bedsit: "Bedsit bedroom maximum 1" discounted_ownership_value: "Mortgage, deposit, and grant total must equal £%{value_with_discount}" diff --git a/db/migrate/20230203104238_add_saledate_check_to_sales_log.rb b/db/migrate/20230203104238_add_saledate_check_to_sales_log.rb new file mode 100644 index 000000000..8ee7fdc65 --- /dev/null +++ b/db/migrate/20230203104238_add_saledate_check_to_sales_log.rb @@ -0,0 +1,5 @@ +class AddSaledateCheckToSalesLog < ActiveRecord::Migration[7.0] + def change + add_column :sales_logs, :saledate_check, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 95e7799a1..99aef7031 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_01_27_102334) do +ActiveRecord::Schema[7.0].define(version: 2023_02_03_104238) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -504,12 +504,13 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_27_102334) do t.integer "retirement_value_check" t.integer "hodate_check" t.integer "extrabor_value_check" - t.integer "grant_value_check" - t.integer "staircase_bought_value_check" t.integer "deposit_and_mortgage_value_check" t.integer "shared_ownership_deposit_value_check" + t.integer "grant_value_check" t.integer "old_persons_shared_ownership_value_check" + t.integer "staircase_bought_value_check" t.integer "monthly_charges_value_check" + t.integer "saledate_check" t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id" diff --git a/spec/models/form/sales/pages/handover_date_check_spec.rb b/spec/models/form/sales/pages/handover_date_check_spec.rb index 86c74fda6..6bd3f3874 100644 --- a/spec/models/form/sales/pages/handover_date_check_spec.rb +++ b/spec/models/form/sales/pages/handover_date_check_spec.rb @@ -16,18 +16,28 @@ RSpec.describe Form::Sales::Pages::HandoverDateCheck, type: :model do end it "has the correct id" do - expect(page.id).to eq("") + expect(page.id).to eq("handover_date_check") end it "has the correct header" do expect(page.header).to be_nil end + it "has the correct title_text" do + expect(page.title_text).to eq({ + "translation" => "validations.sale_information.hodate.must_be_less_than_3_years_from_saledate", + "arguments" => [], + }) + end + + it "has the correct informative_text" do + expect(page.informative_text).to eq({}) + end + it "has correct depends_on" do expect(page.depends_on).to eq([ - { - "hodate_3_years_or_more_saledate?" => true, - }, + { "hodate_3_years_or_more_saledate?" => true, "saledate_check" => nil }, + { "hodate_3_years_or_more_saledate?" => true, "saledate_check" => 1 }, ]) end diff --git a/spec/models/form/sales/pages/sale_date_check_spec.rb b/spec/models/form/sales/pages/sale_date_check_spec.rb new file mode 100644 index 000000000..f1e0b3e2b --- /dev/null +++ b/spec/models/form/sales/pages/sale_date_check_spec.rb @@ -0,0 +1,47 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::SaleDateCheck, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { "" } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + + 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[saledate_check]) + end + + it "has the correct id" do + expect(page.id).to eq("completion_date_check") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct title_text" do + expect(page.title_text).to eq({ + "translation" => "validations.sale_information.saledate.must_be_less_than_3_years_from_hodate", + "arguments" => [], + }) + end + + it "has the correct informative_text" do + expect(page.informative_text).to eq({}) + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([ + { "hodate_3_years_or_more_saledate?" => true, "hodate_check" => nil }, + { "hodate_3_years_or_more_saledate?" => true, "hodate_check" => 1 }, + ]) + end + + it "is interruption screen page" do + expect(page.interruption_screen?).to eq(true) + end +end diff --git a/spec/models/form/sales/questions/handover_date_check_spec.rb b/spec/models/form/sales/questions/handover_date_check_spec.rb index 0e57abf35..86a46436b 100644 --- a/spec/models/form/sales/questions/handover_date_check_spec.rb +++ b/spec/models/form/sales/questions/handover_date_check_spec.rb @@ -16,7 +16,7 @@ RSpec.describe Form::Sales::Questions::HandoverDateCheck, type: :model do end it "has the correct header" do - expect(question.header).to eq("Are you sure practical completion or handover date is more than 3 years before exchange date?") + expect(question.header).to eq("Are you sure?") end it "has the correct check_answer_label" do @@ -43,6 +43,6 @@ RSpec.describe Form::Sales::Questions::HandoverDateCheck, type: :model do end it "has the correct hidden_in_check_answers" do - expect(question.hidden_in_check_answers).to eq({ "depends_on" => [{ "hodate_check" => 0 }, { "hodate_check" => 1 }] }) + expect(question.hidden_in_check_answers).to eq({ "depends_on" => [{ "hodate_check" => 0 }, { "hodate_check" => 1 }, { "saledate_check" => 0 }, { "saledate_check" => 1 }] }) end end diff --git a/spec/models/form/sales/questions/sale_date_check_spec.rb b/spec/models/form/sales/questions/sale_date_check_spec.rb new file mode 100644 index 000000000..c37b2e870 --- /dev/null +++ b/spec/models/form/sales/questions/sale_date_check_spec.rb @@ -0,0 +1,48 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::SaleDateCheck, 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("saledate_check") + end + + it "has the correct header" do + expect(question.header).to eq("Are you sure?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Sale completion date 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?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + 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" => [{ "hodate_check" => 0 }, { "hodate_check" => 1 }, { "saledate_check" => 0 }, { "saledate_check" => 1 }] }) + end +end diff --git a/spec/models/form/sales/subsections/setup_spec.rb b/spec/models/form/sales/subsections/setup_spec.rb index ac4f0246c..779b9537e 100644 --- a/spec/models/form/sales/subsections/setup_spec.rb +++ b/spec/models/form/sales/subsections/setup_spec.rb @@ -17,6 +17,7 @@ RSpec.describe Form::Sales::Subsections::Setup, type: :model do organisation created_by completion_date + completion_date_check purchaser_code ownership_scheme shared_ownership_type diff --git a/spec/models/form_handler_spec.rb b/spec/models/form_handler_spec.rb index d332d2b21..9c02a5318 100644 --- a/spec/models/form_handler_spec.rb +++ b/spec/models/form_handler_spec.rb @@ -52,14 +52,14 @@ RSpec.describe FormHandler do it "is able to load a current sales form" do form = form_handler.get_form("current_sales") expect(form).to be_a(Form) - expect(form.pages.count).to eq(210) + expect(form.pages.count).to eq(211) expect(form.name).to eq("2022_2023_sales") end it "is able to load a previous sales form" do form = form_handler.get_form("previous_sales") expect(form).to be_a(Form) - expect(form.pages.count).to eq(210) + expect(form.pages.count).to eq(211) expect(form.name).to eq("2021_2022_sales") end end @@ -76,6 +76,10 @@ RSpec.describe FormHandler do context "when the date is after 1st of April" do let(:now) { Time.utc(2022, 8, 3) } + it "returns the same year as the current start year" do + expect(form_handler.current_collection_start_year).to eq(2022) + end + it "returns the correct current lettings form name" do expect(form_handler.form_name_from_start_year(2022, "lettings")).to eq("current_lettings") end @@ -99,11 +103,19 @@ RSpec.describe FormHandler do it "returns the correct next sales form name" do expect(form_handler.form_name_from_start_year(2023, "sales")).to eq("next_sales") end + + it "returns the correct current start date" do + expect(form_handler.current_collection_start_date).to eq(Time.zone.local(2022, 4, 1)) + end end context "with the date before 1st of April" do let(:now) { Time.utc(2022, 2, 3) } + it "returns the previous year as the current start year" do + expect(form_handler.current_collection_start_year).to eq(2021) + end + it "returns the correct current lettings form name" do expect(form_handler.form_name_from_start_year(2021, "lettings")).to eq("current_lettings") end diff --git a/spec/models/form_spec.rb b/spec/models/form_spec.rb index 71dfd4b60..72223c1b5 100644 --- a/spec/models/form_spec.rb +++ b/spec/models/form_spec.rb @@ -218,9 +218,9 @@ RSpec.describe Form, type: :model do expect(form.sections[0].class).to eq(Form::Sales::Sections::Setup) expect(form.subsections.count).to eq(1) expect(form.subsections.first.id).to eq("setup") - expect(form.pages.count).to eq(14) + expect(form.pages.count).to eq(15) expect(form.pages.first.id).to eq("organisation") - expect(form.questions.count).to eq(15) + expect(form.questions.count).to eq(16) expect(form.questions.first.id).to eq("owning_organisation_id") expect(form.start_date).to eq(Time.zone.parse("2022-04-01")) expect(form.end_date).to eq(Time.zone.parse("2023-07-01")) diff --git a/spec/models/sales_log_spec.rb b/spec/models/sales_log_spec.rb index 0b4fa4459..a5a57f36e 100644 --- a/spec/models/sales_log_spec.rb +++ b/spec/models/sales_log_spec.rb @@ -47,7 +47,7 @@ RSpec.describe SalesLog, type: :model do let(:sales_log) { build(:sales_log) } it "returns optional fields" do - expect(sales_log.optional_fields).to eq(%w[purchid monthly_charges_value_check old_persons_shared_ownership_value_check]) + expect(sales_log.optional_fields).to eq(%w[saledate_check purchid monthly_charges_value_check old_persons_shared_ownership_value_check]) end end diff --git a/spec/models/validations/sales/sale_information_validations_spec.rb b/spec/models/validations/sales/sale_information_validations_spec.rb index 7ca507c1d..055d749ae 100644 --- a/spec/models/validations/sales/sale_information_validations_spec.rb +++ b/spec/models/validations/sales/sale_information_validations_spec.rb @@ -62,7 +62,7 @@ RSpec.describe Validations::Sales::SaleInformationValidations do it "does not add an error" do sale_information_validator.validate_practical_completion_date_before_saledate(record) - expect(record.errors[:hodate]).to be_present + expect(record.errors[:hodate]).not_to be_present end end end @@ -130,10 +130,10 @@ RSpec.describe Validations::Sales::SaleInformationValidations do sale_information_validator.validate_exchange_date(record) expect(record.errors[:exdate]).to eq( - ["Contract exchange date must be less than 1 year before completion date"], + ["Contract exchange date must be before completion date"], ) expect(record.errors[:saledate]).to eq( - ["Completion date must be less than 1 year after contract exchange date"], + ["Completion date must be after contract exchange date"], ) end end