From 4659a3efcf240fc9a6904e1c8ebfc46f409c42e1 Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Thu, 26 Jan 2023 16:49:33 +0000 Subject: [PATCH 1/9] CLDC-1899 Add discounted ownership value validation (#1229) * Add validation for discounted ownership value * Fix tests * Update validations to work with different routing * update error message --- .../sales/sale_information_validations.rb | 16 ++ config/locales/en.yml | 1 + spec/factories/sales_log.rb | 4 +- .../sale_information_validations_spec.rb | 153 ++++++++++++++++++ 4 files changed, 172 insertions(+), 2 deletions(-) diff --git a/app/models/validations/sales/sale_information_validations.rb b/app/models/validations/sales/sale_information_validations.rb index be0295f2c..c42c42ccc 100644 --- a/app/models/validations/sales/sale_information_validations.rb +++ b/app/models/validations/sales/sale_information_validations.rb @@ -38,4 +38,20 @@ module Validations::Sales::SaleInformationValidations record.errors.add :fromprop, I18n.t("validations.sale_information.previous_property_type.property_type_bedsit") end end + + def validate_discounted_ownership_value(record) + return unless record.value && record.deposit && record.ownershipsch + return unless record.mortgage || record.mortgageused == 2 + return unless record.discount || record.grant || record.type == 29 + + discount_amount = record.discount ? record.value * record.discount / 100 : 0 + grant_amount = record.grant || 0 + mortgage_amount = record.mortgage || 0 + value_with_discount = (record.value - discount_amount) + if mortgage_amount + record.deposit + grant_amount != value_with_discount && record.discounted_ownership_sale? + %i[mortgage deposit grant value discount ownershipsch].each do |field| + record.errors.add field, I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: sprintf("%.2f", value_with_discount)) + end + end + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 0be594420..3dd612e8e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -425,6 +425,7 @@ en: property_type_bedsit: "Bedsit bedroom maximum 1" previous_property_type: property_type_bedsit: "A bedsit can not have more than 1 bedroom" + discounted_ownership_value: "Mortgage, deposit, and grant total must equal £%{value_with_discount}" soft_validations: net_income: diff --git a/spec/factories/sales_log.rb b/spec/factories/sales_log.rb index 003b11144..f83d102d3 100644 --- a/spec/factories/sales_log.rb +++ b/spec/factories/sales_log.rb @@ -70,10 +70,10 @@ FactoryBot.define do ecstat5 { 2 } ecstat6 { 1 } disabled { 1 } - deposit { 10_000 } + deposit { 80_000 } cashdis { 1_000 } value { 110_000 } - grant { 1_000 } + grant { 10_000 } proplen { 10 } pregyrha { 1 } pregla { 1 } diff --git a/spec/models/validations/sales/sale_information_validations_spec.rb b/spec/models/validations/sales/sale_information_validations_spec.rb index fb3aea06c..d2921e8f0 100644 --- a/spec/models/validations/sales/sale_information_validations_spec.rb +++ b/spec/models/validations/sales/sale_information_validations_spec.rb @@ -218,4 +218,157 @@ RSpec.describe Validations::Sales::SaleInformationValidations do end end end + + describe "#validate_discounted_ownership_value" 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) } + + context "and not provided" do + before do + record.grant = nil + end + + it "does not add an error" do + sale_information_validator.validate_discounted_ownership_value(record) + + expect(record.errors).to be_empty + end + end + + context "and is provided" do + it "adds an error if mortgage, deposit and grant total does not equal market value" do + record.grant = 3_000 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + end + + it "does not add an error if mortgage, deposit and grant total equals market value" do + record.grant = 15_000 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors).to be_empty + 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) } + + context "and not provided" do + before do + record.discount = nil + end + + it "does not add an error" do + sale_information_validator.validate_discounted_ownership_value(record) + + expect(record.errors).to be_empty + end + end + + context "and is provided" do + it "adds an error if mortgage and deposit total does not equal market value - discount" do + record.discount = 10 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00")) + expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00")) + expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00")) + expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00")) + expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00")) + end + + it "does not add an error if mortgage and deposit total equals market value - discount" do + record.discount = 50 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors).to be_empty + 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) } + + it "adds an error if mortgage and deposit total does not equal market value" do + record.deposit = 2_000 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00")) + end + + it "does not add an error if mortgage and deposit total equals market value" do + record.deposit = 20_000 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors).to be_empty + 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) } + + context "and not provided" do + before do + record.mortgage = nil + end + + it "does not add an error" do + sale_information_validator.validate_discounted_ownership_value(record) + + expect(record.errors).to be_empty + end + end + + context "and is provided" do + it "adds an error if mortgage, grant and deposit total does not equal market value - discount" do + record.mortgage = 10 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + end + + it "does not add an error if mortgage, grant and deposit total equals market value - discount" do + record.mortgage = 10_000 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors).to be_empty + 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) } + + it "adds an error if grant and deposit total does not equal market value - discount" do + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00")) + end + + it "does not add an error if mortgage, grant and deposit total equals market value - discount" do + record.grant = 13_000 + sale_information_validator.validate_discounted_ownership_value(record) + expect(record.errors).to be_empty + end + end + + context "when owhership 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) } + + it "does not add an error" do + sale_information_validator.validate_discounted_ownership_value(record) + + expect(record.errors).to be_empty + end + end + end end From 0f17eab3fedf1b4cc7d650481c0d473d9716572d Mon Sep 17 00:00:00 2001 From: Arthur Campbell <51094020+arfacamble@users.noreply.github.com> Date: Thu, 26 Jan 2023 17:22:41 +0000 Subject: [PATCH 2/9] CLDC 882 add validation against grant (#1220) * fix rebase conflicts * fix rebase conflicts * fix rebase conflicts * implement soft validation of grant value * fix rebase conflicts * fix rebase conflicts * fix rebase conflicts * fix rebase conflicts * fix final test from added page * update test after rebase --- .../form/sales/pages/grant_value_check.rb | 18 +++++++++++++++ app/models/form/sales/questions/grant.rb | 1 + .../form/sales/questions/grant_value_check.rb | 23 +++++++++++++++++++ .../discounted_ownership_scheme.rb | 1 + .../validations/sales/soft_validations.rb | 6 +++++ ...0741_add_grant_value_check_to_sales_log.rb | 5 ++++ db/schema.rb | 6 +++-- .../discounted_ownership_scheme_spec.rb | 1 + spec/models/form_handler_spec.rb | 4 ++-- .../sales/soft_validations_spec.rb | 20 ++++++++++++++++ 10 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 app/models/form/sales/pages/grant_value_check.rb create mode 100644 app/models/form/sales/questions/grant_value_check.rb create mode 100644 db/migrate/20230123160741_add_grant_value_check_to_sales_log.rb diff --git a/app/models/form/sales/pages/grant_value_check.rb b/app/models/form/sales/pages/grant_value_check.rb new file mode 100644 index 000000000..a739a1654 --- /dev/null +++ b/app/models/form/sales/pages/grant_value_check.rb @@ -0,0 +1,18 @@ +class Form::Sales::Pages::GrantValueCheck < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "grant_value_check" + @depends_on = [ + { + "grant_outside_common_range?" => true, + }, + ] + @informative_text = {} + end + + def questions + @questions ||= [ + Form::Sales::Questions::GrantValueCheck.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/questions/grant.rb b/app/models/form/sales/questions/grant.rb index 181e2281d..beef93c58 100644 --- a/app/models/form/sales/questions/grant.rb +++ b/app/models/form/sales/questions/grant.rb @@ -6,6 +6,7 @@ class Form::Sales::Questions::Grant < ::Form::Question @header = "What was the amount of any loan, grant, discount or subsidy given?" @type = "numeric" @min = 0 + @max = 999_999 @width = 5 @prefix = "£" @hint_text = "For all schemes except Right to Buy (RTB), Preserved Right to Buy (PRTB), Voluntary Right to Buy (VRTB)" diff --git a/app/models/form/sales/questions/grant_value_check.rb b/app/models/form/sales/questions/grant_value_check.rb new file mode 100644 index 000000000..a7efdbaee --- /dev/null +++ b/app/models/form/sales/questions/grant_value_check.rb @@ -0,0 +1,23 @@ +class Form::Sales::Questions::GrantValueCheck < ::Form::Question + def initialize(id, hsh, page) + super + @id = "grant_value_check" + @check_answer_label = "Grant value confirmation" + @header = "Are you sure? Grants are usually £9,000 - £16,000" + @type = "interruption_screen" + @answer_options = { + "0" => { "value" => "Yes" }, + "1" => { "value" => "No" }, + } + @hidden_in_check_answers = { + "depends_on" => [ + { + "grant_value_check" => 0, + }, + { + "grant_value_check" => 1, + }, + ], + } + end +end diff --git a/app/models/form/sales/subsections/discounted_ownership_scheme.rb b/app/models/form/sales/subsections/discounted_ownership_scheme.rb index 3b994d931..2ab47e729 100644 --- a/app/models/form/sales/subsections/discounted_ownership_scheme.rb +++ b/app/models/form/sales/subsections/discounted_ownership_scheme.rb @@ -12,6 +12,7 @@ class Form::Sales::Subsections::DiscountedOwnershipScheme < ::Form::Subsection Form::Sales::Pages::AboutPriceRtb.new(nil, nil, self), Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_price_value_check", nil, self), Form::Sales::Pages::AboutPriceNotRtb.new(nil, nil, self), + Form::Sales::Pages::GrantValueCheck.new(nil, nil, self), Form::Sales::Pages::PurchasePrice.new("purchase_price_discounted_ownership", nil, self), Form::Sales::Pages::Mortgageused.new("mortgage_used_discounted_ownership", nil, self), Form::Sales::Pages::MortgageAmount.new("mortgage_amount_discounted_ownership", nil, self), diff --git a/app/models/validations/sales/soft_validations.rb b/app/models/validations/sales/soft_validations.rb index e39b5e9d9..742e505a5 100644 --- a/app/models/validations/sales/soft_validations.rb +++ b/app/models/validations/sales/soft_validations.rb @@ -48,4 +48,10 @@ module Validations::Sales::SoftValidations ((saledate.to_date - hodate.to_date).to_i / 365) >= 3 end + + def grant_outside_common_range? + return unless grant + + !grant.between?(9_000, 16_000) + end end diff --git a/db/migrate/20230123160741_add_grant_value_check_to_sales_log.rb b/db/migrate/20230123160741_add_grant_value_check_to_sales_log.rb new file mode 100644 index 000000000..9a9cfb8ea --- /dev/null +++ b/db/migrate/20230123160741_add_grant_value_check_to_sales_log.rb @@ -0,0 +1,5 @@ +class AddGrantValueCheckToSalesLog < ActiveRecord::Migration[7.0] + def change + add_column :sales_logs, :grant_value_check, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 55cb24599..8722ec6a4 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_18_170602) do +ActiveRecord::Schema[7.0].define(version: 2023_01_23_160741) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -486,9 +486,9 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_18_170602) do t.integer "hoyear" t.integer "fromprop" t.integer "socprevten" + t.integer "mortlen" t.integer "mortgagelender" t.string "mortgagelenderother" - t.integer "mortlen" t.integer "extrabor" t.integer "hhmemb" t.integer "totadult" @@ -501,6 +501,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_18_170602) do t.boolean "is_la_inferred" t.bigint "bulk_upload_id" t.integer "retirement_value_check" + t.integer "deposit_and_mortgage_value_check" + t.integer "grant_value_check" t.integer "hodate_check" t.integer "extrabor_value_check" t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id" diff --git a/spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb b/spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb index 44896a0f9..7df741091 100644 --- a/spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb +++ b/spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb @@ -18,6 +18,7 @@ RSpec.describe Form::Sales::Subsections::DiscountedOwnershipScheme, type: :model about_price_rtb extra_borrowing_price_value_check about_price_not_rtb + grant_value_check purchase_price_discounted_ownership mortgage_used_discounted_ownership mortgage_amount_discounted_ownership diff --git a/spec/models/form_handler_spec.rb b/spec/models/form_handler_spec.rb index 8f9a88f7f..c7bfdc85b 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(187) + expect(form.pages.count).to eq(188) 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(187) + expect(form.pages.count).to eq(188) expect(form.name).to eq("2021_2022_sales") end end diff --git a/spec/models/validations/sales/soft_validations_spec.rb b/spec/models/validations/sales/soft_validations_spec.rb index 17bd87d96..da0ab8ed9 100644 --- a/spec/models/validations/sales/soft_validations_spec.rb +++ b/spec/models/validations/sales/soft_validations_spec.rb @@ -396,4 +396,24 @@ RSpec.describe Validations::Sales::SoftValidations do expect(record).not_to be_wheelchair_when_not_disabled end end + + describe "#grant_outside_common_range?" do + it "returns true if grant is below 9000" do + record.grant = 1_000 + + expect(record).to be_grant_outside_common_range + end + + it "returns true if grant is above 16000" do + record.grant = 100_000 + + expect(record).to be_grant_outside_common_range + end + + it "returns false if grant is within expected range" do + record.grant = 10_000 + + expect(record).not_to be_grant_outside_common_range + end + end end From 740f4cbdd429ee2a955510bbcdd4a256c319e200 Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Fri, 27 Jan 2023 08:09:08 +0000 Subject: [PATCH 3/9] CLDC-1843 Hide download csv link for sales logs (#1230) * Hide download csv link for sales logs * refactor --- app/views/logs/_log_list.html.erb | 4 +++- spec/requests/lettings_logs_controller_spec.rb | 1 + spec/requests/organisations_controller_spec.rb | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/views/logs/_log_list.html.erb b/app/views/logs/_log_list.html.erb index 702cd7d1f..1aeaa03f2 100644 --- a/app/views/logs/_log_list.html.erb +++ b/app/views/logs/_log_list.html.erb @@ -1,6 +1,8 @@
+ You’ve completed all the logs that had errors from your bulk upload. +
+ +<%= govuk_button_link_to "Back to all logs", lettings_logs_path, button: true %> diff --git a/app/views/logs/_log_filters.erb b/app/views/logs/_log_filters.erb index d2a327d99..8fb4f2ba4 100644 --- a/app/views/logs/_log_filters.erb +++ b/app/views/logs/_log_filters.erb @@ -3,13 +3,48 @@