From 466d3fc2cfc379cea6ee609b3a3ad9cd06d76b39 Mon Sep 17 00:00:00 2001 From: Jack <113976590+bibblobcode@users.noreply.github.com> Date: Fri, 10 Feb 2023 14:42:55 +0000 Subject: [PATCH 01/25] CLDC-1809 Add prevshared question (#1269) * Add prevshared question * Update CYA * Add missing specs --- .../form/sales/pages/previous_shared.rb | 15 ++++ app/models/form/sales/questions/prevshared.rb | 17 +++++ .../income_benefits_and_savings.rb | 11 ++- ...20230203153051_add_prev_shared_to_sales.rb | 7 ++ db/schema.rb | 3 +- spec/factories/sales_log.rb | 1 + .../form/sales/pages/previous_shared_spec.rb | 29 ++++++++ .../form/sales/questions/prevshared_spec.rb | 49 +++++++++++++ .../discounted_ownership_scheme_spec.rb | 1 - .../income_benefits_and_savings_spec.rb | 72 ++++++++++++++----- spec/models/form_handler_spec.rb | 2 + 11 files changed, 185 insertions(+), 22 deletions(-) create mode 100644 app/models/form/sales/pages/previous_shared.rb create mode 100644 app/models/form/sales/questions/prevshared.rb create mode 100644 db/migrate/20230203153051_add_prev_shared_to_sales.rb create mode 100644 spec/models/form/sales/pages/previous_shared_spec.rb create mode 100644 spec/models/form/sales/questions/prevshared_spec.rb diff --git a/app/models/form/sales/pages/previous_shared.rb b/app/models/form/sales/pages/previous_shared.rb new file mode 100644 index 000000000..e733da266 --- /dev/null +++ b/app/models/form/sales/pages/previous_shared.rb @@ -0,0 +1,15 @@ +class Form::Sales::Pages::PreviousShared < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "previous_shared" + @depends_on = [ + { "prevown" => 1 }, + ] + end + + def questions + @questions ||= [ + Form::Sales::Questions::Prevshared.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/questions/prevshared.rb b/app/models/form/sales/questions/prevshared.rb new file mode 100644 index 000000000..2c09cf485 --- /dev/null +++ b/app/models/form/sales/questions/prevshared.rb @@ -0,0 +1,17 @@ +class Form::Sales::Questions::Prevshared < ::Form::Question + def initialize(id, hsh, page) + super + @id = "prevshared" + @check_answer_label = "Previous property shared ownership?" + @header = "Was the previous property a shared ownership property?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @hint = "For any buyer" + end + + ANSWER_OPTIONS = { + "1" => { "value" => "Yes" }, + "2" => { "value" => "No" }, + "3" => { "value" => "Don’t know" }, + }.freeze +end diff --git a/app/models/form/sales/subsections/income_benefits_and_savings.rb b/app/models/form/sales/subsections/income_benefits_and_savings.rb index 2df8a929b..fe95bfd8c 100644 --- a/app/models/form/sales/subsections/income_benefits_and_savings.rb +++ b/app/models/form/sales/subsections/income_benefits_and_savings.rb @@ -22,6 +22,15 @@ class Form::Sales::Subsections::IncomeBenefitsAndSavings < ::Form::Subsection Form::Sales::Pages::SavingsValueCheck.new("savings_value_check", nil, self), Form::Sales::Pages::DepositValueCheck.new("savings_deposit_value_check", nil, self), Form::Sales::Pages::PreviousOwnership.new(nil, nil, self), - ] + previous_shared_page, + ].compact + end + +private + + def previous_shared_page + if form.start_date.year >= 2023 + Form::Sales::Pages::PreviousShared.new(nil, nil, self) + end end end diff --git a/db/migrate/20230203153051_add_prev_shared_to_sales.rb b/db/migrate/20230203153051_add_prev_shared_to_sales.rb new file mode 100644 index 000000000..191112416 --- /dev/null +++ b/db/migrate/20230203153051_add_prev_shared_to_sales.rb @@ -0,0 +1,7 @@ +class AddPrevSharedToSales < ActiveRecord::Migration[7.0] + def change + change_table :sales_logs, bulk: true do |t| + t.column :prevshared, :integer + end + end +end diff --git a/db/schema.rb b/db/schema.rb index b9022d026..195315675 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -521,9 +521,10 @@ ActiveRecord::Schema[7.0].define(version: 2023_02_03_174815) do 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.integer "details_known_5" t.integer "details_known_6" + t.integer "saledate_check" + t.integer "prevshared" 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/factories/sales_log.rb b/spec/factories/sales_log.rb index bfce386c7..f1da841a4 100644 --- a/spec/factories/sales_log.rb +++ b/spec/factories/sales_log.rb @@ -60,6 +60,7 @@ FactoryBot.define do la { "E09000003" } savingsnk { 1 } prevown { 1 } + prevshared { 2 } sex3 { "X" } sex4 { "X" } sex5 { "X" } diff --git a/spec/models/form/sales/pages/previous_shared_spec.rb b/spec/models/form/sales/pages/previous_shared_spec.rb new file mode 100644 index 000000000..b93c0760e --- /dev/null +++ b/spec/models/form/sales/pages/previous_shared_spec.rb @@ -0,0 +1,29 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::PreviousShared, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + 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[prevshared]) + end + + it "has the correct id" do + expect(page.id).to eq("previous_shared") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end +end diff --git a/spec/models/form/sales/questions/prevshared_spec.rb b/spec/models/form/sales/questions/prevshared_spec.rb new file mode 100644 index 000000000..3806b9561 --- /dev/null +++ b/spec/models/form/sales/questions/prevshared_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Prevshared, 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("prevshared") + end + + it "has the correct header" do + expect(question.header).to eq("Was the previous property a shared ownership property?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Previous property shared ownership?") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "1" => { "value" => "Yes" }, + "2" => { "value" => "No" }, + "3" => { "value" => "Don’t know" }, + }) + end + + it "has correct conditional for" do + expect(question.conditional_for).to eq(nil) + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end +end 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 525ad06b4..5919abb24 100644 --- a/spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb +++ b/spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb @@ -12,7 +12,6 @@ RSpec.describe Form::Sales::Subsections::DiscountedOwnershipScheme, type: :model end it "has correct pages" do - puts discounted_ownership_scheme.pages.map(&:id) expect(discounted_ownership_scheme.pages.map(&:id)).to eq( %w[ living_before_purchase_discounted_ownership diff --git a/spec/models/form/sales/subsections/income_benefits_and_savings_spec.rb b/spec/models/form/sales/subsections/income_benefits_and_savings_spec.rb index edd03eb37..74002d5e0 100644 --- a/spec/models/form/sales/subsections/income_benefits_and_savings_spec.rb +++ b/spec/models/form/sales/subsections/income_benefits_and_savings_spec.rb @@ -11,25 +11,59 @@ RSpec.describe Form::Sales::Subsections::IncomeBenefitsAndSavings, type: :model expect(subsection.section).to eq(section) end - it "has correct pages" do - expect(subsection.pages.map(&:id)).to eq( - %w[ - buyer_1_income - buyer_1_income_value_check - buyer_1_income_mortgage_value_check - buyer_1_mortgage - buyer_1_mortgage_value_check - buyer_2_income - buyer_2_income_mortgage_value_check - buyer_2_mortgage - buyer_2_mortgage_value_check - housing_benefits - savings - savings_value_check - savings_deposit_value_check - previous_ownership - ], - ) + describe "pages" do + let(:section) { instance_double(Form::Sales::Sections::Household, form: instance_double(Form, start_date:)) } + + context "when 2022" do + let(:start_date) { Time.utc(2022, 2, 8) } + + it "has correct pages" do + expect(subsection.pages.compact.map(&:id)).to eq( + %w[ + buyer_1_income + buyer_1_income_value_check + buyer_1_income_mortgage_value_check + buyer_1_mortgage + buyer_1_mortgage_value_check + buyer_2_income + buyer_2_income_mortgage_value_check + buyer_2_mortgage + buyer_2_mortgage_value_check + housing_benefits + savings + savings_value_check + savings_deposit_value_check + previous_ownership + ], + ) + end + end + + context "when 2023" do + let(:start_date) { Time.utc(2023, 2, 8) } + + it "has correct pages" do + expect(subsection.pages.map(&:id)).to eq( + %w[ + buyer_1_income + buyer_1_income_value_check + buyer_1_income_mortgage_value_check + buyer_1_mortgage + buyer_1_mortgage_value_check + buyer_2_income + buyer_2_income_mortgage_value_check + buyer_2_mortgage + buyer_2_mortgage_value_check + housing_benefits + savings + savings_value_check + savings_deposit_value_check + previous_ownership + previous_shared + ], + ) + end + end end it "has the correct id" do diff --git a/spec/models/form_handler_spec.rb b/spec/models/form_handler_spec.rb index 9a533e6c1..9b4920198 100644 --- a/spec/models/form_handler_spec.rb +++ b/spec/models/form_handler_spec.rb @@ -41,12 +41,14 @@ RSpec.describe FormHandler do form = form_handler.get_form("current_lettings") expect(form).to be_a(Form) expect(form.pages.count).to eq(13) + expect(form.name).to eq("2022_2023_lettings") end it "is able to load a previous lettings form" do form = form_handler.get_form("previous_lettings") expect(form).to be_a(Form) expect(form.pages.count).to eq(46) + expect(form.name).to eq("2021_2022_lettings") end it "is able to load a current sales form" do From c481055f4dc6fb6a913f31499cf38ea6c3c9a79f Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Fri, 10 Feb 2023 16:46:00 +0000 Subject: [PATCH 02/25] CLDC-1965 Bulk upload correct again email (#1274) * tests for bulk upload mailer * bulk upload send upload again email --- app/mailers/bulk_upload_mailer.rb | 28 ++++++++--- app/models/bulk_upload.rb | 8 +++ app/services/bulk_upload/processor.rb | 5 ++ spec/mailers/bulk_upload_mailer_spec.rb | 54 ++++++++++++++++++++- spec/services/bulk_upload/processor_spec.rb | 11 +++++ 5 files changed, 97 insertions(+), 9 deletions(-) diff --git a/app/mailers/bulk_upload_mailer.rb b/app/mailers/bulk_upload_mailer.rb index 59d03ce9b..be0a71e05 100644 --- a/app/mailers/bulk_upload_mailer.rb +++ b/app/mailers/bulk_upload_mailer.rb @@ -33,17 +33,29 @@ class BulkUploadMailer < NotifyMailer ) end - def send_bulk_upload_failed_csv_errors_mail(user, bulk_upload) + def columns_with_errors(bulk_upload:) + array = bulk_upload.columns_with_errors + + if array.size > 3 + "#{array.take(3).join(', ')} and more" + else + array.join(", ") + end + end + + def send_correct_and_upload_again_mail(bulk_upload:) + error_description = "We noticed that you have a lot of similar errors in column #{columns_with_errors(bulk_upload:)}. Please correct your data export and upload again." + send_email( - user.email, + bulk_upload.user.email, BULK_UPLOAD_FAILED_CSV_ERRORS_TEMPLATE_ID, { - filename: "[#{bulk_upload} filename]", - upload_timestamp: "[#{bulk_upload} upload_timestamp]", - year_combo: "[#{bulk_upload} year_combo]", - lettings_or_sales: "[#{bulk_upload} lettings_or_sales]", - error_description: "[#{bulk_upload} error_description]", - summary_report_link: "[#{bulk_upload} summary_report_link]", + filename: bulk_upload.filename, + upload_timestamp: bulk_upload.created_at.to_fs(:govuk_date_and_time), + year_combo: bulk_upload.year_combo, + lettings_or_sales: bulk_upload.log_type, + error_description:, + summary_report_link: summary_bulk_upload_lettings_result_url(bulk_upload), }, ) end diff --git a/app/models/bulk_upload.rb b/app/models/bulk_upload.rb index cf2965446..8385b9ba4 100644 --- a/app/models/bulk_upload.rb +++ b/app/models/bulk_upload.rb @@ -30,6 +30,14 @@ class BulkUpload < ApplicationRecord end end + def columns_with_errors + bulk_upload_errors + .select(:col) + .distinct(:col) + .pluck(:col) + .sort_by { |col| col.rjust(2, "0") } + end + def general_needs? needstype == 1 end diff --git a/app/services/bulk_upload/processor.rb b/app/services/bulk_upload/processor.rb index d69f76243..bbf7e6cd1 100644 --- a/app/services/bulk_upload/processor.rb +++ b/app/services/bulk_upload/processor.rb @@ -13,6 +13,7 @@ class BulkUpload::Processor validator.call create_logs if validator.create_logs? + send_correct_and_upload_again_mail unless validator.create_logs? send_fix_errors_mail if created_logs_but_incompleted? send_success_mail if created_logs_and_all_completed? @@ -25,6 +26,10 @@ class BulkUpload::Processor private + def send_correct_and_upload_again_mail + BulkUploadMailer.send_correct_and_upload_again_mail(bulk_upload:).deliver_later + end + def send_fix_errors_mail BulkUploadMailer.send_bulk_upload_with_errors_mail(bulk_upload:).deliver_later end diff --git a/spec/mailers/bulk_upload_mailer_spec.rb b/spec/mailers/bulk_upload_mailer_spec.rb index a3706beb3..d0217bfaf 100644 --- a/spec/mailers/bulk_upload_mailer_spec.rb +++ b/spec/mailers/bulk_upload_mailer_spec.rb @@ -5,7 +5,7 @@ RSpec.describe BulkUploadMailer do let(:notify_client) { instance_double(Notifications::Client) } let(:user) { create(:user, email: "user@example.com") } - let(:bulk_upload) { build(:bulk_upload, :lettings, user:) } + let(:bulk_upload) { create(:bulk_upload, :lettings, user:) } before do allow(Notifications::Client).to receive(:new).and_return(notify_client) @@ -75,4 +75,56 @@ RSpec.describe BulkUploadMailer do end end end + + describe "#send_correct_and_upload_again_mail" do + context "when 2 columns with errors" do + before do + create(:bulk_upload_error, bulk_upload:, col: "A") + create(:bulk_upload_error, bulk_upload:, col: "B") + end + + it "sends correctly formed email with A, B" do + expect(notify_client).to receive(:send_email).with( + email_address: user.email, + template_id: described_class::BULK_UPLOAD_FAILED_CSV_ERRORS_TEMPLATE_ID, + personalisation: { + filename: bulk_upload.filename, + upload_timestamp: bulk_upload.created_at.to_fs(:govuk_date_and_time), + year_combo: bulk_upload.year_combo, + lettings_or_sales: bulk_upload.log_type, + error_description: "We noticed that you have a lot of similar errors in column A, B. Please correct your data export and upload again.", + summary_report_link: "http://localhost:3000/lettings-logs/bulk-upload-results/#{bulk_upload.id}/summary", + }, + ) + + mailer.send_correct_and_upload_again_mail(bulk_upload:) + end + end + + context "when 4 columns with errors" do + before do + create(:bulk_upload_error, bulk_upload:, col: "A") + create(:bulk_upload_error, bulk_upload:, col: "B") + create(:bulk_upload_error, bulk_upload:, col: "C") + create(:bulk_upload_error, bulk_upload:, col: "D") + end + + it "sends correctly formed email with A, B, C and more" do + expect(notify_client).to receive(:send_email).with( + email_address: user.email, + template_id: described_class::BULK_UPLOAD_FAILED_CSV_ERRORS_TEMPLATE_ID, + personalisation: { + filename: bulk_upload.filename, + upload_timestamp: bulk_upload.created_at.to_fs(:govuk_date_and_time), + year_combo: bulk_upload.year_combo, + lettings_or_sales: bulk_upload.log_type, + error_description: "We noticed that you have a lot of similar errors in column A, B, C and more. Please correct your data export and upload again.", + summary_report_link: "http://localhost:3000/lettings-logs/bulk-upload-results/#{bulk_upload.id}/summary", + }, + ) + + mailer.send_correct_and_upload_again_mail(bulk_upload:) + end + end + end end diff --git a/spec/services/bulk_upload/processor_spec.rb b/spec/services/bulk_upload/processor_spec.rb index b751e7dd7..d56b2ff4e 100644 --- a/spec/services/bulk_upload/processor_spec.rb +++ b/spec/services/bulk_upload/processor_spec.rb @@ -171,6 +171,17 @@ RSpec.describe BulkUpload::Processor do expect(mock_downloader).to have_received(:delete_local_file!) end + it "sends correct and upload again mail" do + mail_double = instance_double("ActionMailer::MessageDelivery", deliver_later: nil) + + allow(BulkUploadMailer).to receive(:send_correct_and_upload_again_mail).and_return(mail_double) + + processor.call + + expect(BulkUploadMailer).to have_received(:send_correct_and_upload_again_mail) + expect(mail_double).to have_received(:deliver_later) + end + it "does not send fix errors email" do allow(BulkUploadMailer).to receive(:send_bulk_upload_with_errors_mail).and_call_original From 0ff387ad84e83782ce9ab928ce95888f16b56cc1 Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Mon, 13 Feb 2023 08:47:21 +0000 Subject: [PATCH 03/25] Remove nils before adding up location units (#1290) --- app/services/exports/lettings_log_export_service.rb | 2 +- spec/services/exports/lettings_log_export_service_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/services/exports/lettings_log_export_service.rb b/app/services/exports/lettings_log_export_service.rb index 6cc5c1f52..aed3ea98a 100644 --- a/app/services/exports/lettings_log_export_service.rb +++ b/app/services/exports/lettings_log_export_service.rb @@ -214,7 +214,7 @@ module Exports attribute_hash["reghome"] = scheme.registered_under_care_act_before_type_cast attribute_hash["schtype"] = scheme.scheme_type_before_type_cast attribute_hash["support"] = scheme.support_type_before_type_cast - attribute_hash["units_scheme"] = scheme.locations.map(&:units).sum + attribute_hash["units_scheme"] = scheme.locations.map(&:units).compact.sum end def add_location_fields!(location, attribute_hash) diff --git a/spec/services/exports/lettings_log_export_service_spec.rb b/spec/services/exports/lettings_log_export_service_spec.rb index a8d626b98..36adda071 100644 --- a/spec/services/exports/lettings_log_export_service_spec.rb +++ b/spec/services/exports/lettings_log_export_service_spec.rb @@ -258,6 +258,10 @@ RSpec.describe Exports::LettingsLogExportService do let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, :export, :sh, scheme:, location:, created_by: user, owning_organisation: organisation, startdate: Time.utc(2022, 2, 2, 10, 36, 49), underoccupation_benefitcap: 4, sheltered: 1) } + before do + FactoryBot.create(:location, scheme:, startdate: Time.zone.local(2021, 4, 1), units: nil) + end + it "generates an XML export file with the expected content" do expected_content = replace_entity_ids(lettings_log, export_file.read) expect(storage_service).to receive(:write_file).with(expected_zip_filename, any_args) do |_, content| From f0a1e183252d2d78200942c611d43295da44992a Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Mon, 13 Feb 2023 15:40:20 +0000 Subject: [PATCH 04/25] CLDC-1885 Bulk upload type must match given needs type (#1288) * bulk upload type must match given needs type * refactor invert logic statement * tweak validation copy --- app/models/bulk_upload.rb | 4 ++ .../bulk_upload/lettings/row_parser.rb | 15 ++++++- config/locales/en.yml | 3 ++ .../bulk_upload/lettings/row_parser_spec.rb | 40 +++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/app/models/bulk_upload.rb b/app/models/bulk_upload.rb index 8385b9ba4..0adf0d84a 100644 --- a/app/models/bulk_upload.rb +++ b/app/models/bulk_upload.rb @@ -42,6 +42,10 @@ class BulkUpload < ApplicationRecord needstype == 1 end + def supported_housing? + needstype == 2 + end + private def generate_identifier diff --git a/app/services/bulk_upload/lettings/row_parser.rb b/app/services/bulk_upload/lettings/row_parser.rb index cee5fa319..42e762be1 100644 --- a/app/services/bulk_upload/lettings/row_parser.rb +++ b/app/services/bulk_upload/lettings/row_parser.rb @@ -148,7 +148,8 @@ class BulkUpload::Lettings::RowParser validate :validate_relevant_collection_window validate :validate_la_with_local_housing_referral validate :validate_cannot_be_la_referral_if_general_needs - validate :leaving_reason_for_renewal + validate :validate_leaving_reason_for_renewal + validate :validate_lettings_type_matches_bulk_upload def valid? errors.clear @@ -171,6 +172,16 @@ class BulkUpload::Lettings::RowParser private + def validate_lettings_type_matches_bulk_upload + if [1, 3, 5, 7, 9, 11].include?(field_1) && !bulk_upload.general_needs? + errors.add(:field_1, I18n.t("validations.setup.lettype.supported_housing_mismatch")) + end + + if [2, 4, 6, 8, 10, 12].include?(field_1) && !bulk_upload.supported_housing? + errors.add(:field_1, I18n.t("validations.setup.lettype.general_needs_mismatch")) + end + end + def validate_cannot_be_la_referral_if_general_needs if field_78 == 4 && bulk_upload.general_needs? errors.add :field_78, I18n.t("validations.household.referral.la_general_needs.prp_referred_by_la") @@ -183,7 +194,7 @@ private end end - def leaving_reason_for_renewal + def validate_leaving_reason_for_renewal if field_134 == 1 && ![40, 42].include?(field_52) errors.add(:field_52, I18n.t("validations.household.reason.renewal_reason_needed")) end diff --git a/config/locales/en.yml b/config/locales/en.yml index a97863c30..0a4ae34de 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -170,6 +170,9 @@ en: invalid: "Please select owning organisation or managing organisation that you belong to" created_by: invalid: "Please select owning organisation or managing organisation that you belong to" + lettype: + general_needs_mismatch: Lettings type must be a general needs type because you selected general needs when uploading the file + supported_housing_mismatch: Lettings type must be a supported housing type because you selected supported housing when uploading the file property: mrcdate: diff --git a/spec/services/bulk_upload/lettings/row_parser_spec.rb b/spec/services/bulk_upload/lettings/row_parser_spec.rb index 297b9fd46..29ce6efbb 100644 --- a/spec/services/bulk_upload/lettings/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/row_parser_spec.rb @@ -202,6 +202,46 @@ RSpec.describe BulkUpload::Lettings::RowParser do expect(parser.errors[:field_1]).to be_blank end end + + context "when bulk upload is for general needs" do + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: "1") } + + context "when general needs option selected" do + let(:attributes) { { bulk_upload:, field_1: "1" } } + + it "is permitted" do + expect(parser.errors[:field_1]).to be_blank + end + end + + context "when supported housing option selected" do + let(:attributes) { { bulk_upload:, field_1: "2" } } + + it "is not permitted" do + expect(parser.errors[:field_1]).to include("Lettings type must be a general needs type because you selected general needs when uploading the file") + end + end + end + + context "when bulk upload is for supported housing" do + let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: "2") } + + context "when general needs option selected" do + let(:attributes) { { bulk_upload:, field_1: "1" } } + + it "is not permitted" do + expect(parser.errors[:field_1]).to include("Lettings type must be a supported housing type because you selected supported housing when uploading the file") + end + end + + context "when supported housing option selected" do + let(:attributes) { { bulk_upload:, field_1: "2" } } + + it "is permitted" do + expect(parser.errors[:field_1]).to be_blank + end + end + end end describe "#field_4" do From ca8b7970127b8db56661d5515290298c200da349 Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Mon, 13 Feb 2023 15:40:39 +0000 Subject: [PATCH 05/25] bulk upload ignores blank rows in csv (#1295) --- .../bulk_upload/lettings/log_creator.rb | 2 ++ .../bulk_upload/lettings/row_parser.rb | 6 ++++ .../bulk_upload/lettings/log_creator_spec.rb | 17 +++++++++++ .../bulk_upload/lettings/row_parser_spec.rb | 30 +++++++++++++++++-- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/app/services/bulk_upload/lettings/log_creator.rb b/app/services/bulk_upload/lettings/log_creator.rb index 9dd4a2f66..625d53f43 100644 --- a/app/services/bulk_upload/lettings/log_creator.rb +++ b/app/services/bulk_upload/lettings/log_creator.rb @@ -10,6 +10,8 @@ class BulkUpload::Lettings::LogCreator row_parsers.each do |row_parser| row_parser.valid? + next if row_parser.blank_row? + row_parser.log.blank_invalid_non_setup_fields! row_parser.log.bulk_upload = bulk_upload diff --git a/app/services/bulk_upload/lettings/row_parser.rb b/app/services/bulk_upload/lettings/row_parser.rb index 42e762be1..9d5604587 100644 --- a/app/services/bulk_upload/lettings/row_parser.rb +++ b/app/services/bulk_upload/lettings/row_parser.rb @@ -154,6 +154,8 @@ class BulkUpload::Lettings::RowParser def valid? errors.clear + return true if blank_row? + super log.valid? @@ -166,6 +168,10 @@ class BulkUpload::Lettings::RowParser errors.blank? end + def blank_row? + attribute_set.to_hash.reject { |k, _| %w[bulk_upload].include?(k) }.values.compact.empty? + end + def log @log ||= LettingsLog.new(attributes_for_log) end diff --git a/spec/services/bulk_upload/lettings/log_creator_spec.rb b/spec/services/bulk_upload/lettings/log_creator_spec.rb index fc7d1cdc0..39dfd00fe 100644 --- a/spec/services/bulk_upload/lettings/log_creator_spec.rb +++ b/spec/services/bulk_upload/lettings/log_creator_spec.rb @@ -24,6 +24,23 @@ RSpec.describe BulkUpload::Lettings::LogCreator do end end + context "when a valid csv with several blank rows" do + let(:file) { Tempfile.new } + let(:path) { file.path } + let(:log) { LettingsLog.new } + + before do + file.write(BulkUpload::LogToCsv.new(log:, col_offset: 0).to_csv_row) + file.write(BulkUpload::LogToCsv.new(log:, col_offset: 0).to_csv_row) + file.write(BulkUpload::LogToCsv.new(log:, col_offset: 0).to_csv_row) + file.rewind + end + + it "ignores them and does not create the logs" do + expect { service.call }.not_to change(LettingsLog, :count) + end + end + context "when a valid csv with row with one invalid non setup field" do let(:file) { Tempfile.new } let(:path) { file.path } diff --git a/spec/services/bulk_upload/lettings/row_parser_spec.rb b/spec/services/bulk_upload/lettings/row_parser_spec.rb index 29ce6efbb..8f609838c 100644 --- a/spec/services/bulk_upload/lettings/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/row_parser_spec.rb @@ -31,6 +31,24 @@ RSpec.describe BulkUpload::Lettings::RowParser do FormHandler.instance.use_fake_forms! end + describe "#blank_row?" do + context "when a new object" do + it "returns true" do + expect(parser).to be_blank_row + end + end + + context "when any field is populated" do + before do + parser.field_1 = "1" + end + + it "returns false" do + expect(parser).not_to be_blank_row + end + end + end + describe "validations" do before do stub_request(:get, /api.postcodes.io/) @@ -40,6 +58,14 @@ RSpec.describe BulkUpload::Lettings::RowParser do end describe "#valid?" do + context "when the row is blank" do + let(:attributes) { { bulk_upload: } } + + it "returns true" do + expect(parser).to be_valid + end + end + context "when calling the method multiple times" do let(:attributes) { { bulk_upload:, field_134: 2 } } @@ -172,7 +198,7 @@ RSpec.describe BulkUpload::Lettings::RowParser do describe "#field_1" do context "when null" do - let(:attributes) { { bulk_upload:, field_1: nil } } + let(:attributes) { { bulk_upload:, field_1: nil, field_4: "1" } } it "returns an error" do expect(parser.errors[:field_1]).to be_present @@ -347,7 +373,7 @@ RSpec.describe BulkUpload::Lettings::RowParser do describe "fields 96, 97, 98 => startdate" do context "when any one of these fields is blank" do - let(:attributes) { { bulk_upload:, field_96: nil, field_97: nil, field_98: nil } } + let(:attributes) { { bulk_upload:, field_1: "1", field_96: nil, field_97: nil, field_98: nil } } it "returns an error" do parser.valid? From 6c0780291b6ff7f6d253f5b0a24936f6ae167dd5 Mon Sep 17 00:00:00 2001 From: natdeanlewissoftwire <94526761+natdeanlewissoftwire@users.noreply.github.com> Date: Mon, 13 Feb 2023 17:01:54 +0000 Subject: [PATCH 06/25] CLDC-1810 new staircasing followup (#1286) * feat: behaviour * feat: conditional year behaviour and test * refactor: linting * db: update --- .../form/sales/pages/about_staircase.rb | 9 +++- .../form/sales/questions/staircase_sale.rb | 16 ++++++ ...0122037_add_staircasesale_to_sales_logs.rb | 5 ++ db/schema.rb | 3 +- .../form/sales/pages/about_staircase_spec.rb | 20 +++++++- .../sales/questions/staircase_sale_spec.rb | 49 +++++++++++++++++++ 6 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 app/models/form/sales/questions/staircase_sale.rb create mode 100644 db/migrate/20230210122037_add_staircasesale_to_sales_logs.rb create mode 100644 spec/models/form/sales/questions/staircase_sale_spec.rb diff --git a/app/models/form/sales/pages/about_staircase.rb b/app/models/form/sales/pages/about_staircase.rb index fd740c10e..2d1a17db4 100644 --- a/app/models/form/sales/pages/about_staircase.rb +++ b/app/models/form/sales/pages/about_staircase.rb @@ -12,6 +12,13 @@ class Form::Sales::Pages::AboutStaircase < ::Form::Page @questions ||= [ Form::Sales::Questions::StaircaseBought.new(nil, nil, self), Form::Sales::Questions::StaircaseOwned.new(nil, nil, self), - ] + staircase_sale_question, + ].compact + end + + def staircase_sale_question + if form.start_date.year >= 2023 + Form::Sales::Questions::StaircaseSale.new(nil, nil, self) + end end end diff --git a/app/models/form/sales/questions/staircase_sale.rb b/app/models/form/sales/questions/staircase_sale.rb new file mode 100644 index 000000000..fb56572cf --- /dev/null +++ b/app/models/form/sales/questions/staircase_sale.rb @@ -0,0 +1,16 @@ +class Form::Sales::Questions::StaircaseSale < ::Form::Question + def initialize(id, hsh, page) + super + @id = "staircasesale" + @check_answer_label = "Part of a back-to-back staircasing transaction" + @header = "Is this transaction part of a back-to-back staircasing transaction to facilitate sale of the home on the open market?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + end + + ANSWER_OPTIONS = { + "1" => { "value" => "Yes" }, + "2" => { "value" => "No" }, + "3" => { "value" => "Don't know" }, + }.freeze +end diff --git a/db/migrate/20230210122037_add_staircasesale_to_sales_logs.rb b/db/migrate/20230210122037_add_staircasesale_to_sales_logs.rb new file mode 100644 index 000000000..824549cff --- /dev/null +++ b/db/migrate/20230210122037_add_staircasesale_to_sales_logs.rb @@ -0,0 +1,5 @@ +class AddStaircasesaleToSalesLogs < ActiveRecord::Migration[7.0] + def change + add_column :sales_logs, :staircasesale, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 195315675..679b582c1 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_02_03_174815) do +ActiveRecord::Schema[7.0].define(version: 2023_02_10_122037) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -524,6 +524,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_02_03_174815) do t.integer "details_known_5" t.integer "details_known_6" t.integer "saledate_check" + t.integer "staircasesale" t.integer "prevshared" 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" diff --git a/spec/models/form/sales/pages/about_staircase_spec.rb b/spec/models/form/sales/pages/about_staircase_spec.rb index a2fba103e..3828f52e4 100644 --- a/spec/models/form/sales/pages/about_staircase_spec.rb +++ b/spec/models/form/sales/pages/about_staircase_spec.rb @@ -11,8 +11,24 @@ RSpec.describe Form::Sales::Pages::AboutStaircase, type: :model do expect(page.subsection).to eq(subsection) end - it "has correct questions" do - expect(page.questions.map(&:id)).to eq(%w[stairbought stairowned]) + describe "questions" do + let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date:)) } + + context "when 2022" do + let(:start_date) { Time.utc(2022, 2, 8) } + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[stairbought stairowned]) + end + end + + context "when 2023" do + let(:start_date) { Time.utc(2023, 2, 8) } + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[stairbought stairowned staircasesale]) + end + end end it "has the correct id" do diff --git a/spec/models/form/sales/questions/staircase_sale_spec.rb b/spec/models/form/sales/questions/staircase_sale_spec.rb new file mode 100644 index 000000000..39927c967 --- /dev/null +++ b/spec/models/form/sales/questions/staircase_sale_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::StaircaseSale, 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("staircasesale") + end + + it "has the correct header" do + expect(question.header).to eq("Is this transaction part of a back-to-back staircasing transaction to facilitate sale of the home on the open market?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Part of a back-to-back staircasing transaction") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "1" => { "value" => "Yes" }, + "2" => { "value" => "No" }, + "3" => { "value" => "Don't know" }, + }) + end + + it "has correct conditional for" do + expect(question.conditional_for).to eq(nil) + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end +end From 92029ea2a09d135b84e843ac3ec2fe97c6ec3233 Mon Sep 17 00:00:00 2001 From: SamSeed-Softwire <63662292+SamSeed-Softwire@users.noreply.github.com> Date: Tue, 14 Feb 2023 10:41:40 +0000 Subject: [PATCH 07/25] CLDC-859 Sales validation - bedsits cannot have more than 1 bed (#1188) * feat: add sales validation to check bedsits have <=1 beds * test: sales validation to check bedsits have <=1 beds * fix: typo in property validation method name * feat: add same bedsit validation to number of bedrooms question * test: fix typo propert -> property in property validations tests * test: add test for validate_property_number_of_bedrooms (sales) * feat: update wording for 'number of bedrooms' validation when bedsit * test: condense sales property validations tests * test: strengthen sales property validations error addition test * refactor: simplify sales property validations into one method * fix: update error message content to match Beth's choices * chore: lint * test: add requests test for invalid sales log params when posting * refactor: use if rather than unless... not in property validation * refactor: write method is_bedsit? on SalesLog * test: check bedsit error not added if proptype or beds is nil * lint: use update! not update * feat: update validation messages to improve readability * fix: provide valid date in request test for invalid proptype/beds * feat: make is_bedsit and validate_bedsit_number_of_beds more readable --- app/models/sales_log.rb | 4 +++ .../validations/sales/property_validations.rb | 9 +++++ config/locales/en.yml | 3 ++ .../sales/property_validations_spec.rb | 36 +++++++++++++++++++ spec/requests/sales_logs_controller_spec.rb | 25 +++++++++++++ 5 files changed, 77 insertions(+) diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index 463381559..add706f7c 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -223,6 +223,10 @@ class SalesLog < Log type == 24 end + def is_bedsit? + proptype == 2 + end + def shared_ownership_scheme? ownershipsch == 1 end diff --git a/app/models/validations/sales/property_validations.rb b/app/models/validations/sales/property_validations.rb index 879e37ff1..83f86ec8f 100644 --- a/app/models/validations/sales/property_validations.rb +++ b/app/models/validations/sales/property_validations.rb @@ -7,4 +7,13 @@ module Validations::Sales::PropertyValidations record.errors.add :ppostcode_full, I18n.t("validations.property.postcode.must_match_previous") end end + + def validate_bedsit_number_of_beds(record) + return unless record.proptype.present? && record.beds.present? + + if record.is_bedsit? && record.beds > 1 + record.errors.add :proptype, I18n.t("validations.property.proptype.bedsits_have_max_one_bedroom") + record.errors.add :beds, I18n.t("validations.property.beds.bedsits_have_max_one_bedroom") + end + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 0a4ae34de..98e40dfb3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -202,6 +202,9 @@ en: 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" postcode: must_match_previous: "Buyer's last accommodation and discounted ownership postcodes must match" diff --git a/spec/models/validations/sales/property_validations_spec.rb b/spec/models/validations/sales/property_validations_spec.rb index fc3fdd1a8..180f16021 100644 --- a/spec/models/validations/sales/property_validations_spec.rb +++ b/spec/models/validations/sales/property_validations_spec.rb @@ -48,4 +48,40 @@ RSpec.describe Validations::Sales::PropertyValidations do end end end + + describe "#validate_property_unit_type" do + context "when number of bedrooms is 1" do + let(:record) { FactoryBot.build(:sales_log, beds: 1, proptype: 2) } + + it "does not add an error if it's a bedsit" do + property_validator.validate_bedsit_number_of_beds(record) + expect(record.errors).not_to be_present + end + end + + context "when number of bedrooms is > 1" do + let(:record) { FactoryBot.build(:sales_log, beds: 2, proptype: 2) } + + it "does add an error if it's a bedsit" do + property_validator.validate_bedsit_number_of_beds(record) + expect(record.errors.added?(:proptype, "Answer cannot be 'Bedsit' if the property has 2 or more bedrooms")).to be true + expect(record.errors.added?(:beds, "Number of bedrooms must be 1 if the property is a bedsit")).to be true + end + + it "does not add an error if proptype is undefined" do + record.update!(proptype: nil) + property_validator.validate_bedsit_number_of_beds(record) + expect(record.errors).not_to be_present + end + end + + context "when number of bedrooms is undefined" do + let(:record) { FactoryBot.build(:sales_log, beds: nil, proptype: 2) } + + it "does not add an error if it's a bedsit" do + property_validator.validate_bedsit_number_of_beds(record) + expect(record.errors).not_to be_present + end + end + end end diff --git a/spec/requests/sales_logs_controller_spec.rb b/spec/requests/sales_logs_controller_spec.rb index 925e3f1f3..e45fee440 100644 --- a/spec/requests/sales_logs_controller_spec.rb +++ b/spec/requests/sales_logs_controller_spec.rb @@ -61,6 +61,31 @@ RSpec.describe SalesLogsController, type: :request do expect(response).to have_http_status(:unauthorized) end end + + context "with a request containing invalid json parameters" do + let(:params) do + { + "saledate": Date.new(2022, 4, 1), + "purchid": "1", + "ownershipsch": 1, + "type": 2, + "jointpur": 1, + "jointmore": 1, + "beds": 2, + "proptype": 2, + } + end + + before do + post "/sales-logs", headers:, params: params.to_json + end + + it "validates sales log parameters" do + json_response = JSON.parse(response.body) + expect(response).to have_http_status(:unprocessable_entity) + expect(json_response["errors"]).to match_array([["beds", ["Number of bedrooms must be 1 if the property is a bedsit"]], ["proptype", ["Answer cannot be 'Bedsit' if the property has 2 or more bedrooms"]]]) + end + end end context "when UI" do From 8879748f823b0017d2646f27603dd03706954a60 Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Tue, 14 Feb 2023 15:39:49 +0000 Subject: [PATCH 08/25] only load session fiters when getting or exporting the logs (#1301) --- app/controllers/lettings_logs_controller.rb | 4 ++-- app/controllers/organisations_controller.rb | 4 ++-- app/controllers/sales_logs_controller.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/lettings_logs_controller.rb b/app/controllers/lettings_logs_controller.rb index 5181d21ca..f86a55a27 100644 --- a/app/controllers/lettings_logs_controller.rb +++ b/app/controllers/lettings_logs_controller.rb @@ -1,7 +1,7 @@ class LettingsLogsController < LogsController before_action :find_resource, except: %i[create index edit] - before_action :session_filters, if: :current_user - before_action :set_session_filters, if: :current_user + before_action :session_filters, if: :current_user, only: %i[index email_csv download_csv] + before_action :set_session_filters, if: :current_user, only: %i[index email_csv download_csv] before_action :extract_bulk_upload_from_session_filters, only: [:index] before_action :redirect_if_bulk_upload_resolved, only: [:index] diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb index 0c8c4a172..211283ffe 100644 --- a/app/controllers/organisations_controller.rb +++ b/app/controllers/organisations_controller.rb @@ -6,8 +6,8 @@ class OrganisationsController < ApplicationController before_action :authenticate_user! before_action :find_resource, except: %i[index new create] before_action :authenticate_scope!, except: [:index] - before_action -> { session_filters(specific_org: true) }, if: -> { current_user.support? || current_user.organisation.has_managing_agents? } - before_action :set_session_filters, if: -> { current_user.support? || current_user.organisation.has_managing_agents? } + before_action -> { session_filters(specific_org: true) }, if: -> { current_user.support? || current_user.organisation.has_managing_agents? }, only: %i[lettings_logs sales_logs email_csv download_csv] + before_action :set_session_filters, if: -> { current_user.support? || current_user.organisation.has_managing_agents? }, only: %i[lettings_logs sales_logs email_csv download_csv] def index redirect_to organisation_path(current_user.organisation) unless current_user.support? diff --git a/app/controllers/sales_logs_controller.rb b/app/controllers/sales_logs_controller.rb index 8a6c9937f..ecfeabcad 100644 --- a/app/controllers/sales_logs_controller.rb +++ b/app/controllers/sales_logs_controller.rb @@ -1,6 +1,6 @@ class SalesLogsController < LogsController - before_action :session_filters, if: :current_user - before_action :set_session_filters, if: :current_user + before_action :session_filters, if: :current_user, only: %i[index email_csv download_csv] + before_action :set_session_filters, if: :current_user, only: %i[index email_csv download_csv] def create super { SalesLog.new(log_params) } From 00cb2347978cb55850e2b1ab01a96e11719187b4 Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Wed, 15 Feb 2023 09:01:15 +0000 Subject: [PATCH 09/25] CLDC-1811 Add buyer 2 ethnicity question for 23/24 form (#1287) * Add buyer 2 ethnic questions and pages * Add ethnic fields for buyer 2 * Add the new questions to the correct year --- .../pages/buyer2_ethnic_background_arab.rb | 15 ++ .../pages/buyer2_ethnic_background_asian.rb | 15 ++ .../pages/buyer2_ethnic_background_black.rb | 15 ++ .../pages/buyer2_ethnic_background_mixed.rb | 15 ++ .../pages/buyer2_ethnic_background_white.rb | 15 ++ .../form/sales/pages/buyer2_ethnic_group.rb | 22 ++ .../buyer2_ethnic_background_arab.rb | 16 ++ .../buyer2_ethnic_background_asian.rb | 19 ++ .../buyer2_ethnic_background_black.rb | 17 ++ .../buyer2_ethnic_background_mixed.rb | 18 ++ .../buyer2_ethnic_background_white.rb | 18 ++ .../sales/questions/buyer2_ethnic_group.rb | 27 +++ .../subsections/household_characteristics.rb | 14 +- ...0210143120_add_ethnic_fields_for_buyer2.rb | 8 + db/schema.rb | 4 +- .../buyer2_ethnic_background_arab_spec.rb | 33 +++ .../buyer2_ethnic_background_asian_spec.rb | 33 +++ .../buyer2_ethnic_background_black_spec.rb | 33 +++ .../buyer2_ethnic_background_mixed_spec.rb | 33 +++ .../buyer2_ethnic_background_white_spec.rb | 33 +++ .../sales/pages/buyer2_ethnic_group_spec.rb | 42 ++++ .../buyer2_ethnic_background_arab_spec.rb | 48 ++++ .../buyer2_ethnic_background_asian_spec.rb | 51 ++++ .../buyer2_ethnic_background_black_spec.rb | 49 ++++ .../buyer2_ethnic_background_mixed_spec.rb | 50 ++++ .../buyer2_ethnic_background_white_spec.rb | 50 ++++ .../questions/buyer2_ethnic_group_spec.rb | 62 +++++ .../household_characteristics_spec.rb | 218 ++++++++++++------ 28 files changed, 906 insertions(+), 67 deletions(-) create mode 100644 app/models/form/sales/pages/buyer2_ethnic_background_arab.rb create mode 100644 app/models/form/sales/pages/buyer2_ethnic_background_asian.rb create mode 100644 app/models/form/sales/pages/buyer2_ethnic_background_black.rb create mode 100644 app/models/form/sales/pages/buyer2_ethnic_background_mixed.rb create mode 100644 app/models/form/sales/pages/buyer2_ethnic_background_white.rb create mode 100644 app/models/form/sales/pages/buyer2_ethnic_group.rb create mode 100644 app/models/form/sales/questions/buyer2_ethnic_background_arab.rb create mode 100644 app/models/form/sales/questions/buyer2_ethnic_background_asian.rb create mode 100644 app/models/form/sales/questions/buyer2_ethnic_background_black.rb create mode 100644 app/models/form/sales/questions/buyer2_ethnic_background_mixed.rb create mode 100644 app/models/form/sales/questions/buyer2_ethnic_background_white.rb create mode 100644 app/models/form/sales/questions/buyer2_ethnic_group.rb create mode 100644 db/migrate/20230210143120_add_ethnic_fields_for_buyer2.rb create mode 100644 spec/models/form/sales/pages/buyer2_ethnic_background_arab_spec.rb create mode 100644 spec/models/form/sales/pages/buyer2_ethnic_background_asian_spec.rb create mode 100644 spec/models/form/sales/pages/buyer2_ethnic_background_black_spec.rb create mode 100644 spec/models/form/sales/pages/buyer2_ethnic_background_mixed_spec.rb create mode 100644 spec/models/form/sales/pages/buyer2_ethnic_background_white_spec.rb create mode 100644 spec/models/form/sales/pages/buyer2_ethnic_group_spec.rb create mode 100644 spec/models/form/sales/questions/buyer2_ethnic_background_arab_spec.rb create mode 100644 spec/models/form/sales/questions/buyer2_ethnic_background_asian_spec.rb create mode 100644 spec/models/form/sales/questions/buyer2_ethnic_background_black_spec.rb create mode 100644 spec/models/form/sales/questions/buyer2_ethnic_background_mixed_spec.rb create mode 100644 spec/models/form/sales/questions/buyer2_ethnic_background_white_spec.rb create mode 100644 spec/models/form/sales/questions/buyer2_ethnic_group_spec.rb diff --git a/app/models/form/sales/pages/buyer2_ethnic_background_arab.rb b/app/models/form/sales/pages/buyer2_ethnic_background_arab.rb new file mode 100644 index 000000000..593e43ebc --- /dev/null +++ b/app/models/form/sales/pages/buyer2_ethnic_background_arab.rb @@ -0,0 +1,15 @@ +class Form::Sales::Pages::Buyer2EthnicBackgroundArab < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_2_ethnic_background_arab" + @depends_on = [{ + "ethnic_group2" => 4, + }] + end + + def questions + @questions ||= [ + Form::Sales::Questions::Buyer2EthnicBackgroundArab.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/buyer2_ethnic_background_asian.rb b/app/models/form/sales/pages/buyer2_ethnic_background_asian.rb new file mode 100644 index 000000000..98a36476e --- /dev/null +++ b/app/models/form/sales/pages/buyer2_ethnic_background_asian.rb @@ -0,0 +1,15 @@ +class Form::Sales::Pages::Buyer2EthnicBackgroundAsian < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_2_ethnic_background_asian" + @depends_on = [{ + "ethnic_group2" => 2, + }] + end + + def questions + @questions ||= [ + Form::Sales::Questions::Buyer2EthnicBackgroundAsian.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/buyer2_ethnic_background_black.rb b/app/models/form/sales/pages/buyer2_ethnic_background_black.rb new file mode 100644 index 000000000..a772f46ac --- /dev/null +++ b/app/models/form/sales/pages/buyer2_ethnic_background_black.rb @@ -0,0 +1,15 @@ +class Form::Sales::Pages::Buyer2EthnicBackgroundBlack < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_2_ethnic_background_black" + @depends_on = [{ + "ethnic_group2" => 3, + }] + end + + def questions + @questions ||= [ + Form::Sales::Questions::Buyer2EthnicBackgroundBlack.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/buyer2_ethnic_background_mixed.rb b/app/models/form/sales/pages/buyer2_ethnic_background_mixed.rb new file mode 100644 index 000000000..f02165dfc --- /dev/null +++ b/app/models/form/sales/pages/buyer2_ethnic_background_mixed.rb @@ -0,0 +1,15 @@ +class Form::Sales::Pages::Buyer2EthnicBackgroundMixed < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_2_ethnic_background_mixed" + @depends_on = [{ + "ethnic_group2" => 1, + }] + end + + def questions + @questions ||= [ + Form::Sales::Questions::Buyer2EthnicBackgroundMixed.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/buyer2_ethnic_background_white.rb b/app/models/form/sales/pages/buyer2_ethnic_background_white.rb new file mode 100644 index 000000000..2013c8682 --- /dev/null +++ b/app/models/form/sales/pages/buyer2_ethnic_background_white.rb @@ -0,0 +1,15 @@ +class Form::Sales::Pages::Buyer2EthnicBackgroundWhite < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_2_ethnic_background_white" + @depends_on = [{ + "ethnic_group2" => 0, + }] + end + + def questions + @questions ||= [ + Form::Sales::Questions::Buyer2EthnicBackgroundWhite.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/buyer2_ethnic_group.rb b/app/models/form/sales/pages/buyer2_ethnic_group.rb new file mode 100644 index 000000000..1b815996e --- /dev/null +++ b/app/models/form/sales/pages/buyer2_ethnic_group.rb @@ -0,0 +1,22 @@ +class Form::Sales::Pages::Buyer2EthnicGroup < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_2_ethnic_group" + @depends_on = [ + { + "jointpur" => 1, + "privacynotice" => 1, + }, + { + "jointpur" => 1, + "noint" => 1, + }, + ] + end + + def questions + @questions ||= [ + Form::Sales::Questions::Buyer2EthnicGroup.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/questions/buyer2_ethnic_background_arab.rb b/app/models/form/sales/questions/buyer2_ethnic_background_arab.rb new file mode 100644 index 000000000..1766780b7 --- /dev/null +++ b/app/models/form/sales/questions/buyer2_ethnic_background_arab.rb @@ -0,0 +1,16 @@ +class Form::Sales::Questions::Buyer2EthnicBackgroundArab < ::Form::Question + def initialize(id, hsh, page) + super + @id = "ethnicbuy2" + @check_answer_label = "Buyer 2’s ethnic background" + @header = "Which of the following best describes the buyer 2’s Arab background?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @check_answers_card_number = 2 + end + + ANSWER_OPTIONS = { + "19" => { "value" => "Arab" }, + "16" => { "value" => "Other ethnic group" }, + }.freeze +end diff --git a/app/models/form/sales/questions/buyer2_ethnic_background_asian.rb b/app/models/form/sales/questions/buyer2_ethnic_background_asian.rb new file mode 100644 index 000000000..2578d220a --- /dev/null +++ b/app/models/form/sales/questions/buyer2_ethnic_background_asian.rb @@ -0,0 +1,19 @@ +class Form::Sales::Questions::Buyer2EthnicBackgroundAsian < ::Form::Question + def initialize(id, hsh, page) + super + @id = "ethnicbuy2" + @check_answer_label = "Buyer 2’s ethnic background" + @header = "Which of the following best describes the buyer 2’s Asian or Asian British background?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @check_answers_card_number = 2 + end + + ANSWER_OPTIONS = { + "10" => { "value" => "Bangladeshi" }, + "15" => { "value" => "Chinese" }, + "8" => { "value" => "Indian" }, + "9" => { "value" => "Pakistani" }, + "11" => { "value" => "Any other Asian or Asian British background" }, + }.freeze +end diff --git a/app/models/form/sales/questions/buyer2_ethnic_background_black.rb b/app/models/form/sales/questions/buyer2_ethnic_background_black.rb new file mode 100644 index 000000000..11d47790c --- /dev/null +++ b/app/models/form/sales/questions/buyer2_ethnic_background_black.rb @@ -0,0 +1,17 @@ +class Form::Sales::Questions::Buyer2EthnicBackgroundBlack < ::Form::Question + def initialize(id, hsh, page) + super + @id = "ethnicbuy2" + @check_answer_label = "Buyer 2’s ethnic background" + @header = "Which of the following best describes the buyer 2’s Black, African, Caribbean or Black British background?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @check_answers_card_number = 2 + end + + ANSWER_OPTIONS = { + "13" => { "value" => "African" }, + "12" => { "value" => "Caribbean" }, + "14" => { "value" => "Any other Black, African or Caribbean background" }, + }.freeze +end diff --git a/app/models/form/sales/questions/buyer2_ethnic_background_mixed.rb b/app/models/form/sales/questions/buyer2_ethnic_background_mixed.rb new file mode 100644 index 000000000..78600af34 --- /dev/null +++ b/app/models/form/sales/questions/buyer2_ethnic_background_mixed.rb @@ -0,0 +1,18 @@ +class Form::Sales::Questions::Buyer2EthnicBackgroundMixed < ::Form::Question + def initialize(id, hsh, page) + super + @id = "ethnicbuy2" + @check_answer_label = "Buyer 2’s ethnic background" + @header = "Which of the following best describes the buyer 2’s Mixed or Multiple ethnic groups background?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @check_answers_card_number = 2 + end + + ANSWER_OPTIONS = { + "4" => { "value" => "White and Black Caribbean" }, + "5" => { "value" => "White and Black African" }, + "6" => { "value" => "White and Asian" }, + "7" => { "value" => "Any other Mixed or Multiple ethnic background" }, + }.freeze +end diff --git a/app/models/form/sales/questions/buyer2_ethnic_background_white.rb b/app/models/form/sales/questions/buyer2_ethnic_background_white.rb new file mode 100644 index 000000000..5b5fc8e2c --- /dev/null +++ b/app/models/form/sales/questions/buyer2_ethnic_background_white.rb @@ -0,0 +1,18 @@ +class Form::Sales::Questions::Buyer2EthnicBackgroundWhite < ::Form::Question + def initialize(id, hsh, page) + super + @id = "ethnicbuy2" + @check_answer_label = "Buyer 2’s ethnic background" + @header = "Which of the following best describes the buyer 2’s White background?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @check_answers_card_number = 2 + end + + ANSWER_OPTIONS = { + "1" => { "value" => "English, Welsh, Northern Irish, Scottish or British" }, + "2" => { "value" => "Irish" }, + "18" => { "value" => "Gypsy or Irish Traveller" }, + "3" => { "value" => "Any other White background" }, + }.freeze +end diff --git a/app/models/form/sales/questions/buyer2_ethnic_group.rb b/app/models/form/sales/questions/buyer2_ethnic_group.rb new file mode 100644 index 000000000..5366910fe --- /dev/null +++ b/app/models/form/sales/questions/buyer2_ethnic_group.rb @@ -0,0 +1,27 @@ +class Form::Sales::Questions::Buyer2EthnicGroup < ::Form::Question + def initialize(id, hsh, page) + super + @id = "ethnic_group2" + @check_answer_label = "Buyer 2’s ethnic group" + @header = "What is buyer 2’s ethnic group?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @inferred_check_answers_value = [{ + "condition" => { + "ethnic_group2" => 17, + }, + "value" => "Prefers not to say", + }] + @check_answers_card_number = 2 + end + + ANSWER_OPTIONS = { + "0" => { "value" => "White" }, + "1" => { "value" => "Mixed or Multiple ethnic groups" }, + "2" => { "value" => "Asian or Asian British" }, + "3" => { "value" => "Black, African, Caribbean or Black British" }, + "4" => { "value" => "Arab or other ethnic group" }, + "divider" => { "value" => true }, + "17" => { "value" => "Buyer 1 prefers not to say" }, + }.freeze +end diff --git a/app/models/form/sales/subsections/household_characteristics.rb b/app/models/form/sales/subsections/household_characteristics.rb index 7e342499e..55ec0b137 100644 --- a/app/models/form/sales/subsections/household_characteristics.rb +++ b/app/models/form/sales/subsections/household_characteristics.rb @@ -32,6 +32,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection Form::Sales::Pages::RetirementValueCheck.new("age_2_buyer_retirement_value_check", nil, self, person_index: 2), Form::Sales::Pages::GenderIdentity2.new(nil, nil, self), Form::Sales::Pages::RetirementValueCheck.new("gender_2_buyer_retirement_value_check", nil, self, person_index: 2), + ethnic_pages_for_buyer_2, Form::Sales::Pages::Buyer2WorkingSituation.new(nil, nil, self), Form::Sales::Pages::RetirementValueCheck.new("working_situation_2_buyer_retirement_value_check", nil, self, person_index: 2), Form::Sales::Pages::Buyer2LiveInProperty.new(nil, nil, self), @@ -68,6 +69,17 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection Form::Sales::Pages::RetirementValueCheck.new("gender_5_retirement_value_check", nil, self, person_index: 5), Form::Sales::Pages::PersonWorkingSituation.new("person_5_working_situation", nil, self, person_index: 5), Form::Sales::Pages::RetirementValueCheck.new("working_situation_5_retirement_value_check", nil, self, person_index: 5), - ] + ].flatten.compact + end + + def ethnic_pages_for_buyer_2 + if form.start_date.year >= 2023 + [Form::Sales::Pages::Buyer2EthnicGroup.new(nil, nil, self), + Form::Sales::Pages::Buyer2EthnicBackgroundBlack.new(nil, nil, self), + Form::Sales::Pages::Buyer2EthnicBackgroundAsian.new(nil, nil, self), + Form::Sales::Pages::Buyer2EthnicBackgroundArab.new(nil, nil, self), + Form::Sales::Pages::Buyer2EthnicBackgroundMixed.new(nil, nil, self), + Form::Sales::Pages::Buyer2EthnicBackgroundWhite.new(nil, nil, self)] + end end end diff --git a/db/migrate/20230210143120_add_ethnic_fields_for_buyer2.rb b/db/migrate/20230210143120_add_ethnic_fields_for_buyer2.rb new file mode 100644 index 000000000..c545a0539 --- /dev/null +++ b/db/migrate/20230210143120_add_ethnic_fields_for_buyer2.rb @@ -0,0 +1,8 @@ +class AddEthnicFieldsForBuyer2 < ActiveRecord::Migration[7.0] + def change + change_table :sales_logs, bulk: true do |t| + t.column :ethnic_group2, :integer + t.column :ethnicbuy2, :integer + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 679b582c1..ffea32c01 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_02_10_122037) do +ActiveRecord::Schema[7.0].define(version: 2023_02_10_143120) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -526,6 +526,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_02_10_122037) do t.integer "saledate_check" t.integer "staircasesale" t.integer "prevshared" + t.integer "ethnic_group2" + t.integer "ethnicbuy2" 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/buyer2_ethnic_background_arab_spec.rb b/spec/models/form/sales/pages/buyer2_ethnic_background_arab_spec.rb new file mode 100644 index 000000000..1fbbe3bc8 --- /dev/null +++ b/spec/models/form/sales/pages/buyer2_ethnic_background_arab_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::Buyer2EthnicBackgroundArab, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + 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[ethnicbuy2]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_2_ethnic_background_arab") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "ethnic_group2" => 4 }]) + end +end diff --git a/spec/models/form/sales/pages/buyer2_ethnic_background_asian_spec.rb b/spec/models/form/sales/pages/buyer2_ethnic_background_asian_spec.rb new file mode 100644 index 000000000..60878f99a --- /dev/null +++ b/spec/models/form/sales/pages/buyer2_ethnic_background_asian_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::Buyer2EthnicBackgroundAsian, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + 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[ethnicbuy2]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_2_ethnic_background_asian") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "ethnic_group2" => 2 }]) + end +end diff --git a/spec/models/form/sales/pages/buyer2_ethnic_background_black_spec.rb b/spec/models/form/sales/pages/buyer2_ethnic_background_black_spec.rb new file mode 100644 index 000000000..2643f460b --- /dev/null +++ b/spec/models/form/sales/pages/buyer2_ethnic_background_black_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::Buyer2EthnicBackgroundBlack, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + 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[ethnicbuy2]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_2_ethnic_background_black") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "ethnic_group2" => 3 }]) + end +end diff --git a/spec/models/form/sales/pages/buyer2_ethnic_background_mixed_spec.rb b/spec/models/form/sales/pages/buyer2_ethnic_background_mixed_spec.rb new file mode 100644 index 000000000..4505ce08b --- /dev/null +++ b/spec/models/form/sales/pages/buyer2_ethnic_background_mixed_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::Buyer2EthnicBackgroundMixed, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + 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[ethnicbuy2]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_2_ethnic_background_mixed") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "ethnic_group2" => 1 }]) + end +end diff --git a/spec/models/form/sales/pages/buyer2_ethnic_background_white_spec.rb b/spec/models/form/sales/pages/buyer2_ethnic_background_white_spec.rb new file mode 100644 index 000000000..7647f35af --- /dev/null +++ b/spec/models/form/sales/pages/buyer2_ethnic_background_white_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::Buyer2EthnicBackgroundWhite, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + 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[ethnicbuy2]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_2_ethnic_background_white") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "ethnic_group2" => 0 }]) + end +end diff --git a/spec/models/form/sales/pages/buyer2_ethnic_group_spec.rb b/spec/models/form/sales/pages/buyer2_ethnic_group_spec.rb new file mode 100644 index 000000000..2767a2168 --- /dev/null +++ b/spec/models/form/sales/pages/buyer2_ethnic_group_spec.rb @@ -0,0 +1,42 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::Buyer2EthnicGroup, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + 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[ethnic_group2]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_2_ethnic_group") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([ + { + "jointpur" => 1, + "privacynotice" => 1, + }, + { + "jointpur" => 1, + "noint" => 1, + }, + ]) + end +end diff --git a/spec/models/form/sales/questions/buyer2_ethnic_background_arab_spec.rb b/spec/models/form/sales/questions/buyer2_ethnic_background_arab_spec.rb new file mode 100644 index 000000000..9fd408db9 --- /dev/null +++ b/spec/models/form/sales/questions/buyer2_ethnic_background_arab_spec.rb @@ -0,0 +1,48 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer2EthnicBackgroundArab, 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("ethnicbuy2") + end + + it "has the correct header" do + expect(question.header).to eq("Which of the following best describes the buyer 2’s Arab background?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 2’s ethnic background") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint_text" do + expect(question.hint_text).to be nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "16" => { "value" => "Other ethnic group" }, + "19" => { "value" => "Arab" }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(2) + end +end diff --git a/spec/models/form/sales/questions/buyer2_ethnic_background_asian_spec.rb b/spec/models/form/sales/questions/buyer2_ethnic_background_asian_spec.rb new file mode 100644 index 000000000..67ce60e43 --- /dev/null +++ b/spec/models/form/sales/questions/buyer2_ethnic_background_asian_spec.rb @@ -0,0 +1,51 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer2EthnicBackgroundAsian, 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("ethnicbuy2") + end + + it "has the correct header" do + expect(question.header).to eq("Which of the following best describes the buyer 2’s Asian or Asian British background?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 2’s ethnic background") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint_text" do + expect(question.hint_text).to be nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "10" => { "value" => "Bangladeshi" }, + "11" => { "value" => "Any other Asian or Asian British background" }, + "15" => { "value" => "Chinese" }, + "8" => { "value" => "Indian" }, + "9" => { "value" => "Pakistani" }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(2) + end +end diff --git a/spec/models/form/sales/questions/buyer2_ethnic_background_black_spec.rb b/spec/models/form/sales/questions/buyer2_ethnic_background_black_spec.rb new file mode 100644 index 000000000..8e772f870 --- /dev/null +++ b/spec/models/form/sales/questions/buyer2_ethnic_background_black_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer2EthnicBackgroundBlack, 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("ethnicbuy2") + end + + it "has the correct header" do + expect(question.header).to eq("Which of the following best describes the buyer 2’s Black, African, Caribbean or Black British background?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 2’s ethnic background") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint_text" do + expect(question.hint_text).to be nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "12" => { "value" => "Caribbean" }, + "13" => { "value" => "African" }, + "14" => { "value" => "Any other Black, African or Caribbean background" }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(2) + end +end diff --git a/spec/models/form/sales/questions/buyer2_ethnic_background_mixed_spec.rb b/spec/models/form/sales/questions/buyer2_ethnic_background_mixed_spec.rb new file mode 100644 index 000000000..6c1b12865 --- /dev/null +++ b/spec/models/form/sales/questions/buyer2_ethnic_background_mixed_spec.rb @@ -0,0 +1,50 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer2EthnicBackgroundMixed, 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("ethnicbuy2") + end + + it "has the correct header" do + expect(question.header).to eq("Which of the following best describes the buyer 2’s Mixed or Multiple ethnic groups background?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 2’s ethnic background") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint_text" do + expect(question.hint_text).to be nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "4" => { "value" => "White and Black Caribbean" }, + "5" => { "value" => "White and Black African" }, + "6" => { "value" => "White and Asian" }, + "7" => { "value" => "Any other Mixed or Multiple ethnic background" }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(2) + end +end diff --git a/spec/models/form/sales/questions/buyer2_ethnic_background_white_spec.rb b/spec/models/form/sales/questions/buyer2_ethnic_background_white_spec.rb new file mode 100644 index 000000000..d3f2da508 --- /dev/null +++ b/spec/models/form/sales/questions/buyer2_ethnic_background_white_spec.rb @@ -0,0 +1,50 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer2EthnicBackgroundWhite, 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("ethnicbuy2") + end + + it "has the correct header" do + expect(question.header).to eq("Which of the following best describes the buyer 2’s White background?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 2’s ethnic background") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint_text" do + expect(question.hint_text).to be nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "1" => { "value" => "English, Welsh, Northern Irish, Scottish or British" }, + "18" => { "value" => "Gypsy or Irish Traveller" }, + "2" => { "value" => "Irish" }, + "3" => { "value" => "Any other White background" }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(2) + end +end diff --git a/spec/models/form/sales/questions/buyer2_ethnic_group_spec.rb b/spec/models/form/sales/questions/buyer2_ethnic_group_spec.rb new file mode 100644 index 000000000..2e9e0c28c --- /dev/null +++ b/spec/models/form/sales/questions/buyer2_ethnic_group_spec.rb @@ -0,0 +1,62 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer2EthnicGroup, 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("ethnic_group2") + end + + it "has the correct header" do + expect(question.header).to eq("What is buyer 2’s ethnic group?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 2’s ethnic group") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint_text" do + expect(question.hint_text).to be nil + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "0" => { "value" => "White" }, + "1" => { "value" => "Mixed or Multiple ethnic groups" }, + "17" => { "value" => "Buyer 1 prefers not to say" }, + "2" => { "value" => "Asian or Asian British" }, + "3" => { "value" => "Black, African, Caribbean or Black British" }, + "4" => { "value" => "Arab or other ethnic group" }, + "divider" => { "value" => true }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(2) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to eq([{ + "condition" => { + "ethnic_group2" => 17, + }, + "value" => "Prefers not to say", + }]) + end +end diff --git a/spec/models/form/sales/subsections/household_characteristics_spec.rb b/spec/models/form/sales/subsections/household_characteristics_spec.rb index 681b4b50b..76109b7f4 100644 --- a/spec/models/form/sales/subsections/household_characteristics_spec.rb +++ b/spec/models/form/sales/subsections/household_characteristics_spec.rb @@ -6,76 +6,164 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model let(:subsection_id) { nil } let(:subsection_definition) { nil } let(:section) { instance_double(Form::Sales::Sections::Household) } + let(:form) { instance_double(Form) } it "has correct section" do expect(household_characteristics.section).to eq(section) end - it "has correct pages" do - expect(household_characteristics.pages.map(&:id)).to eq( - %w[ - buyer_interview - privacy_notice - buyer_1_age - age_1_retirement_value_check - age_1_old_persons_shared_ownership_value_check - buyer_1_gender_identity - gender_1_retirement_value_check - buyer_1_ethnic_group - buyer_1_ethnic_background_black - buyer_1_ethnic_background_asian - buyer_1_ethnic_background_arab - buyer_1_ethnic_background_mixed - buyer_1_ethnic_background_white - buyer_1_nationality - buyer_1_working_situation - working_situation_1_retirement_value_check - working_situation_buyer_1_income_value_check - buyer_1_live_in_property - buyer_2_relationship_to_buyer_1 - buyer_2_age - age_2_old_persons_shared_ownership_value_check - age_2_buyer_retirement_value_check - buyer_2_gender_identity - gender_2_buyer_retirement_value_check - buyer_2_working_situation - working_situation_2_buyer_retirement_value_check - buyer_2_live_in_property - number_of_others_in_property - person_2_known - person_2_relationship_to_buyer_1 - person_2_age - age_2_retirement_value_check - person_2_gender_identity - gender_2_retirement_value_check - person_2_working_situation - working_situation_2_retirement_value_check - person_3_known - person_3_relationship_to_buyer_1 - person_3_age - age_3_retirement_value_check - person_3_gender_identity - gender_3_retirement_value_check - person_3_working_situation - working_situation_3_retirement_value_check - person_4_known - person_4_relationship_to_buyer_1 - person_4_age - age_4_retirement_value_check - person_4_gender_identity - gender_4_retirement_value_check - person_4_working_situation - working_situation_4_retirement_value_check - person_5_known - person_5_relationship_to_buyer_1 - person_5_age - age_5_retirement_value_check - person_5_gender_identity - gender_5_retirement_value_check - person_5_working_situation - working_situation_5_retirement_value_check - ], - ) + context "with 2022/23 form" do + before do + allow(form).to receive(:start_date).and_return(Time.zone.local(2022, 4, 1)) + allow(section).to receive(:form).and_return(form) + end + + it "has correct pages" do + expect(household_characteristics.pages.map(&:id)).to eq( + %w[ + buyer_interview + privacy_notice + buyer_1_age + age_1_retirement_value_check + age_1_old_persons_shared_ownership_value_check + buyer_1_gender_identity + gender_1_retirement_value_check + buyer_1_ethnic_group + buyer_1_ethnic_background_black + buyer_1_ethnic_background_asian + buyer_1_ethnic_background_arab + buyer_1_ethnic_background_mixed + buyer_1_ethnic_background_white + buyer_1_nationality + buyer_1_working_situation + working_situation_1_retirement_value_check + working_situation_buyer_1_income_value_check + buyer_1_live_in_property + buyer_2_relationship_to_buyer_1 + buyer_2_age + age_2_old_persons_shared_ownership_value_check + age_2_buyer_retirement_value_check + buyer_2_gender_identity + gender_2_buyer_retirement_value_check + buyer_2_working_situation + working_situation_2_buyer_retirement_value_check + buyer_2_live_in_property + number_of_others_in_property + person_2_known + person_2_relationship_to_buyer_1 + person_2_age + age_2_retirement_value_check + person_2_gender_identity + gender_2_retirement_value_check + person_2_working_situation + working_situation_2_retirement_value_check + person_3_known + person_3_relationship_to_buyer_1 + person_3_age + age_3_retirement_value_check + person_3_gender_identity + gender_3_retirement_value_check + person_3_working_situation + working_situation_3_retirement_value_check + person_4_known + person_4_relationship_to_buyer_1 + person_4_age + age_4_retirement_value_check + person_4_gender_identity + gender_4_retirement_value_check + person_4_working_situation + working_situation_4_retirement_value_check + person_5_known + person_5_relationship_to_buyer_1 + person_5_age + age_5_retirement_value_check + person_5_gender_identity + gender_5_retirement_value_check + person_5_working_situation + working_situation_5_retirement_value_check + ], + ) + end + end + + context "with 2023/24 form" do + before do + allow(form).to receive(:start_date).and_return(Time.zone.local(2023, 4, 1)) + allow(section).to receive(:form).and_return(form) + end + + it "has correct pages" do + expect(household_characteristics.pages.map(&:id)).to eq( + %w[ + buyer_interview + privacy_notice + buyer_1_age + age_1_retirement_value_check + age_1_old_persons_shared_ownership_value_check + buyer_1_gender_identity + gender_1_retirement_value_check + buyer_1_ethnic_group + buyer_1_ethnic_background_black + buyer_1_ethnic_background_asian + buyer_1_ethnic_background_arab + buyer_1_ethnic_background_mixed + buyer_1_ethnic_background_white + buyer_1_nationality + buyer_1_working_situation + working_situation_1_retirement_value_check + working_situation_buyer_1_income_value_check + buyer_1_live_in_property + buyer_2_relationship_to_buyer_1 + buyer_2_age + age_2_old_persons_shared_ownership_value_check + age_2_buyer_retirement_value_check + buyer_2_gender_identity + gender_2_buyer_retirement_value_check + buyer_2_ethnic_group + buyer_2_ethnic_background_black + buyer_2_ethnic_background_asian + buyer_2_ethnic_background_arab + buyer_2_ethnic_background_mixed + buyer_2_ethnic_background_white + buyer_2_working_situation + working_situation_2_buyer_retirement_value_check + buyer_2_live_in_property + number_of_others_in_property + person_2_known + person_2_relationship_to_buyer_1 + person_2_age + age_2_retirement_value_check + person_2_gender_identity + gender_2_retirement_value_check + person_2_working_situation + working_situation_2_retirement_value_check + person_3_known + person_3_relationship_to_buyer_1 + person_3_age + age_3_retirement_value_check + person_3_gender_identity + gender_3_retirement_value_check + person_3_working_situation + working_situation_3_retirement_value_check + person_4_known + person_4_relationship_to_buyer_1 + person_4_age + age_4_retirement_value_check + person_4_gender_identity + gender_4_retirement_value_check + person_4_working_situation + working_situation_4_retirement_value_check + person_5_known + person_5_relationship_to_buyer_1 + person_5_age + age_5_retirement_value_check + person_5_gender_identity + gender_5_retirement_value_check + person_5_working_situation + working_situation_5_retirement_value_check + ], + ) + end end it "has the correct id" do From 02f04fde60948154f812919e51bce8bef0d3728a Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Wed, 15 Feb 2023 13:45:36 +0000 Subject: [PATCH 10/25] CLDC-1884 Bulk upload disability access fields and validations (#1299) * bulk upload considers housing needs fields * bulk upload only permits one housing needs type * add bulk upload validation - no disabled needs cannot be selected in conjunction with a disabled need * add bulk upload validation - dont know disabled needs cannot be selected in conjunction with a disabled need * add bulk upload validation - no and don't know disabled access needs cannot be selected together --- .../bulk_upload/lettings/row_parser.rb | 49 +++++++++- config/locales/en.yml | 6 ++ .../bulk_upload/lettings/row_parser_spec.rb | 97 +++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/app/services/bulk_upload/lettings/row_parser.rb b/app/services/bulk_upload/lettings/row_parser.rb index 9d5604587..bf1f62eba 100644 --- a/app/services/bulk_upload/lettings/row_parser.rb +++ b/app/services/bulk_upload/lettings/row_parser.rb @@ -150,6 +150,10 @@ class BulkUpload::Lettings::RowParser validate :validate_cannot_be_la_referral_if_general_needs validate :validate_leaving_reason_for_renewal validate :validate_lettings_type_matches_bulk_upload + validate :validate_only_one_housing_needs_type + validate :validate_no_disabled_needs_conjunction + validate :validate_dont_know_disabled_needs_conjunction + validate :validate_no_and_dont_know_disabled_needs_conjunction def valid? errors.clear @@ -178,6 +182,33 @@ class BulkUpload::Lettings::RowParser private + def validate_no_and_dont_know_disabled_needs_conjunction + if field_59 == 1 && field_60 == 1 + errors.add(:field_59, I18n.t("validations.household.housingneeds.no_and_dont_know_disabled_needs_conjunction")) + errors.add(:field_60, I18n.t("validations.household.housingneeds.no_and_dont_know_disabled_needs_conjunction")) + end + end + + def validate_dont_know_disabled_needs_conjunction + if field_60 == 1 && [field_55, field_56, field_57, field_58].compact.count.positive? + errors.add(:field_60, I18n.t("validations.household.housingneeds.dont_know_disabled_needs_conjunction")) + end + end + + def validate_no_disabled_needs_conjunction + if field_59 == 1 && [field_55, field_56, field_57, field_58].compact.count.positive? + errors.add(:field_59, I18n.t("validations.household.housingneeds.no_disabled_needs_conjunction")) + end + end + + def validate_only_one_housing_needs_type + if [field_55, field_56, field_57].compact.count.positive? + errors.add(:field_55, I18n.t("validations.household.housingneeds_type.only_one_option_permitted")) + errors.add(:field_56, I18n.t("validations.household.housingneeds_type.only_one_option_permitted")) + errors.add(:field_57, I18n.t("validations.household.housingneeds_type.only_one_option_permitted")) + end + end + def validate_lettings_type_matches_bulk_upload if [1, 3, 5, 7, 9, 11].include?(field_1) && !bulk_upload.general_needs? errors.add(:field_1, I18n.t("validations.setup.lettype.supported_housing_mismatch")) @@ -552,6 +583,8 @@ private attributes["preg_occ"] = field_47 attributes["housingneeds"] = housingneeds + attributes["housingneeds_type"] = housingneeds_type + attributes["housingneeds_other"] = housingneeds_other attributes["illness"] = field_118 @@ -808,7 +841,7 @@ private def housingneeds if field_59 == 1 - 1 + 2 elsif field_60 == 1 3 else @@ -816,6 +849,20 @@ private end end + def housingneeds_type + if field_55 == 1 + 0 + elsif field_56 == 1 + 1 + elsif field_57 == 1 + 2 + end + end + + def housingneeds_other + return 1 if field_58 == 1 + end + def ethnic_group_from_ethnic return nil if field_43.blank? diff --git a/config/locales/en.yml b/config/locales/en.yml index 98e40dfb3..23d39bbe8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -347,6 +347,12 @@ en: must_be_child: "Answer must be ‘child’ if the person is aged 16-19 and a student" housingneeds_a: one_or_two_choices: "You can only select one option or ‘other disabled access needs’ plus ‘wheelchair-accessible housing’, ‘wheelchair access to essential rooms’ or ‘level access housing’" + housingneeds_type: + only_one_option_permitted: "Only one disabled access need: fully wheelchair-accessible housing, wheelchair access to essential rooms or level access housing, can be selected" + housingneeds: + no_disabled_needs_conjunction: "No disabled access needs can’t be selected if you have selected fully wheelchair-accessible housing, wheelchair access to essential rooms, level access housing or other disabled access needs" + dont_know_disabled_needs_conjunction: "Don’t know disabled access needs can’t be selected if you have selected fully wheelchair-accessible housing, wheelchair access to essential rooms, level access housing or other disabled access needs" + no_and_dont_know_disabled_needs_conjunction: "No disabled access needs and don’t know disabled access needs cannot be selected together" prevten: non_temp_accommodation: "Answer cannot be non-temporary accommodation as this is a re-let to a tenant who occupied the same property as temporary accommodation" over_20_foster_care: "Answer cannot be a children’s home or foster care as the lead tenant is 20 or older" diff --git a/spec/services/bulk_upload/lettings/row_parser_spec.rb b/spec/services/bulk_upload/lettings/row_parser_spec.rb index 8f609838c..1bebd6444 100644 --- a/spec/services/bulk_upload/lettings/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/row_parser_spec.rb @@ -344,6 +344,49 @@ RSpec.describe BulkUpload::Lettings::RowParser do end end + describe "#field_55, #field_56, #field_57" do + context "when more than one item selected" do + let(:attributes) { { bulk_upload:, field_55: "1", field_56: "1" } } + + it "is not permitted" do + expect(parser.errors[:field_55]).to be_present + expect(parser.errors[:field_56]).to be_present + expect(parser.errors[:field_57]).to be_present + end + end + end + + describe "#field_59" do + context "when 1 and another disability field selected" do + let(:attributes) { { bulk_upload:, field_59: "1", field_58: "1" } } + + it "is not permitted" do + expect(parser.errors[:field_59]).to be_present + end + end + end + + describe "#field_60" do + context "when 1 and another disability field selected" do + let(:attributes) { { bulk_upload:, field_60: "1", field_58: "1" } } + + it "is not permitted" do + expect(parser.errors[:field_60]).to be_present + end + end + end + + describe "#field_59, #field_60" do + context "when both 1" do + let(:attributes) { { bulk_upload:, field_59: "1", field_60: "1" } } + + it "is not permitted" do + expect(parser.errors[:field_59]).to be_present + expect(parser.errors[:field_60]).to be_present + end + end + end + describe "#field_78" do # referral context "when 3 ie PRP nominated by LA and owning org is LA" do let(:attributes) { { bulk_upload:, field_78: "3", field_111: owning_org.old_visible_id } } @@ -894,6 +937,60 @@ RSpec.describe BulkUpload::Lettings::RowParser do end end end + + describe "#housingneeds" do + context "when no disabled needs" do + let(:attributes) { { bulk_upload:, field_59: "1" } } + + it "sets to 2" do + expect(parser.log.housingneeds).to eq(2) + end + end + + context "when dont know about disabled needs" do + let(:attributes) { { bulk_upload:, field_60: "1" } } + + it "sets to 3" do + expect(parser.log.housingneeds).to eq(3) + end + end + end + + describe "#housingneeds_type" do + context "when field_55 is 1" do + let(:attributes) { { bulk_upload:, field_55: "1" } } + + it "set to 0" do + expect(parser.log.housingneeds_type).to eq(0) + end + end + + context "when field_56 is 1" do + let(:attributes) { { bulk_upload:, field_56: "1" } } + + it "set to 1" do + expect(parser.log.housingneeds_type).to eq(1) + end + end + + context "when field_57 is 1" do + let(:attributes) { { bulk_upload:, field_57: "1" } } + + it "set to 2" do + expect(parser.log.housingneeds_type).to eq(2) + end + end + end + + describe "#housingneeds_other" do + context "when field_58 is 1" do + let(:attributes) { { bulk_upload:, field_58: "1" } } + + it "sets to 1" do + expect(parser.log.housingneeds_other).to eq(1) + end + end + end end describe "#start_date" do From 2b918a09d7a2baee05f6caaef05810546086c5cd Mon Sep 17 00:00:00 2001 From: James Rose Date: Thu, 16 Feb 2023 08:55:01 +0000 Subject: [PATCH 11/25] Rename lettings log export field `form` to `formid` (#1306) --- app/services/exports/lettings_log_export_constants.rb | 2 +- app/services/exports/lettings_log_export_service.rb | 2 +- spec/fixtures/exports/general_needs_log.csv | 2 +- spec/fixtures/exports/general_needs_log.xml | 2 +- spec/fixtures/exports/supported_housing_logs.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/services/exports/lettings_log_export_constants.rb b/app/services/exports/lettings_log_export_constants.rb index 9184efb25..332f22550 100644 --- a/app/services/exports/lettings_log_export_constants.rb +++ b/app/services/exports/lettings_log_export_constants.rb @@ -30,7 +30,7 @@ module Exports::LettingsLogExportConstants "confidential", "earnings", "ethnic", - "form", + "formid", "has_benefits", "hb", "hbrentshortfall", diff --git a/app/services/exports/lettings_log_export_service.rb b/app/services/exports/lettings_log_export_service.rb index aed3ea98a..fb985f931 100644 --- a/app/services/exports/lettings_log_export_service.rb +++ b/app/services/exports/lettings_log_export_service.rb @@ -152,7 +152,7 @@ module Exports def apply_cds_transformation(lettings_log, export_mode) attribute_hash = lettings_log.attributes_before_type_cast - attribute_hash["form"] = attribute_hash["old_form_id"] || (attribute_hash["id"] + LOG_ID_OFFSET) + attribute_hash["formid"] = attribute_hash["old_form_id"] || (attribute_hash["id"] + LOG_ID_OFFSET) # We can't have a variable number of columns in CSV unless export_mode == EXPORT_MODE[:csv] diff --git a/spec/fixtures/exports/general_needs_log.csv b/spec/fixtures/exports/general_needs_log.csv index afaa9e745..8cc656f19 100644 --- a/spec/fixtures/exports/general_needs_log.csv +++ b/spec/fixtures/exports/general_needs_log.csv @@ -1,2 +1,2 @@ -status,tenancycode,age1,sex1,ethnic,national,prevten,ecstat1,hhmemb,age2,sex2,ecstat2,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,leftreg,reservist,illness,preg_occ,startertenancy,tenancylength,tenancy,ppostcode_full,rsnvac,unittype_gn,beds,offered,wchair,earnings,incfreq,benefits,period,layear,waityear,postcode_full,reasonpref,cbl,chr,cap,reasonother,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,illness_type_1,illness_type_2,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,irproduct_other,reason,propcode,la,prevloc,hb,hbrentshortfall,mrcdate,incref,startdate,armedforces,unitletas,builtype,voiddate,renttype,needstype,lettype,totchild,totelder,totadult,nocharge,referral,brent,scharge,pscharge,supcharg,tcharge,tshortfall,chcharge,ppcodenk,has_benefits,renewal,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat2,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,hhtype,new_old,vacdays,form,owningorgid,owningorgname,hcnum,maningorgid,maningorgname,manhcnum,createddate,uploaddate +status,tenancycode,age1,sex1,ethnic,national,prevten,ecstat1,hhmemb,age2,sex2,ecstat2,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,leftreg,reservist,illness,preg_occ,startertenancy,tenancylength,tenancy,ppostcode_full,rsnvac,unittype_gn,beds,offered,wchair,earnings,incfreq,benefits,period,layear,waityear,postcode_full,reasonpref,cbl,chr,cap,reasonother,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,illness_type_1,illness_type_2,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,irproduct_other,reason,propcode,la,prevloc,hb,hbrentshortfall,mrcdate,incref,startdate,armedforces,unitletas,builtype,voiddate,renttype,needstype,lettype,totchild,totelder,totadult,nocharge,referral,brent,scharge,pscharge,supcharg,tcharge,tshortfall,chcharge,ppcodenk,has_benefits,renewal,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat2,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,hhtype,new_old,vacdays,formid,owningorgid,owningorgname,hcnum,maningorgid,maningorgname,manhcnum,createddate,uploaddate 2,BZ737,35,F,2,4,6,0,2,32,M,6,,,,,,,,,,,,,,,,,,,1,4,1,1,1,2,1,5,1,SE2 6RT,6,7,3,2,1,68,1,1,2,2,1,NW1 5TY,1,2,1,2,,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,,,4,123,E09000003,E07000105,6,1,2020-05-05T10:36:49+01:00,0,2022-02-02T10:36:49+00:00,1,2,1,2019-11-03T00:00:00+00:00,2,1,7,0,0,2,0,2,200.0,50.0,40.0,35.0,325.0,12.0,,1,1,0,100.0,25.0,20.0,17.5,162.5,6.0,0,1,,2,P,,,,,,,,,,,4,2,638,{id},{owning_org_id},DLUHC,1234,{managing_org_id},DLUHC,1234,2022-02-08T16:52:15+00:00,2022-02-08T16:52:15+00:00 diff --git a/spec/fixtures/exports/general_needs_log.xml b/spec/fixtures/exports/general_needs_log.xml index 1e60333dc..62542af54 100644 --- a/spec/fixtures/exports/general_needs_log.xml +++ b/spec/fixtures/exports/general_needs_log.xml @@ -135,7 +135,7 @@ 4 2 638 -
{id}
+ {id} {owning_org_id} DLUHC 1234 diff --git a/spec/fixtures/exports/supported_housing_logs.xml b/spec/fixtures/exports/supported_housing_logs.xml index 7674984b4..69f52161c 100644 --- a/spec/fixtures/exports/supported_housing_logs.xml +++ b/spec/fixtures/exports/supported_housing_logs.xml @@ -134,7 +134,7 @@ 4 2 638 -
{id}
+ {id} {owning_org_id} DLUHC 1234 From be3e782a0eb77854de6ee639651d674ba346c32c Mon Sep 17 00:00:00 2001 From: Jack <113976590+bibblobcode@users.noreply.github.com> Date: Thu, 16 Feb 2023 09:41:56 +0000 Subject: [PATCH 12/25] Add 2023 sales validations (#1305) --- config/sale_range_data/2023.csv | 1185 +++++++++++++++++++++++++++++++ 1 file changed, 1185 insertions(+) create mode 100644 config/sale_range_data/2023.csv diff --git a/config/sale_range_data/2023.csv b/config/sale_range_data/2023.csv new file mode 100644 index 000000000..ebe873c07 --- /dev/null +++ b/config/sale_range_data/2023.csv @@ -0,0 +1,1185 @@ +la_name,la,bedrooms,soft_min,soft_max +Adur,E07000223,1,126000,447000 +Adur,E07000223,2,220000,480000 +Adur,E07000223,3,312000,658000 +Adur,E07000223,4,383000,938000 +Amber Valley,E07000032,1,99000,306000 +Amber Valley,E07000032,2,99000,306000 +Amber Valley,E07000032,3,123000,407000 +Amber Valley,E07000032,4,236000,842000 +Arun,E07000224,1,102000,486000 +Arun,E07000224,2,182000,486000 +Arun,E07000224,3,248000,569000 +Arun,E07000224,4,351000,966000 +Ashfield,E07000170,1,77000,250000 +Ashfield,E07000170,2,87000,250000 +Ashfield,E07000170,3,103000,298000 +Ashfield,E07000170,4,198000,547000 +Ashford,E07000105,1,102000,435000 +Ashford,E07000105,2,105000,435000 +Ashford,E07000105,3,239000,543000 +Ashford,E07000105,4,340000,1120000 +Babergh,E07000200,1,113000,428000 +Babergh,E07000200,2,149000,428000 +Babergh,E07000200,3,215000,557000 +Babergh,E07000200,4,341000,1230000 +Barking and Dagenham,E09000002,1,88000,383000 +Barking and Dagenham,E09000002,2,103000,401000 +Barking and Dagenham,E09000002,3,220000,506000 +Barking and Dagenham,E09000002,4,308000,661000 +Barnet,E09000003,1,142000,538000 +Barnet,E09000003,2,205000,696000 +Barnet,E09000003,3,416000,1071000 +Barnet,E09000003,4,654000,2254000 +Barnsley,E08000016,1,70000,225000 +Barnsley,E08000016,2,70000,225000 +Barnsley,E08000016,3,93000,289000 +Barnsley,E08000016,4,175000,574000 +Basildon,E07000066,1,96000,457000 +Basildon,E07000066,2,145000,457000 +Basildon,E07000066,3,273000,567000 +Basildon,E07000066,4,376000,1118000 +Basingstoke and Deane,E07000084,1,113000,448000 +Basingstoke and Deane,E07000084,2,139000,448000 +Basingstoke and Deane,E07000084,3,275000,578000 +Basingstoke and Deane,E07000084,4,394000,1115000 +Bassetlaw,E07000171,1,92000,313000 +Bassetlaw,E07000171,2,92000,313000 +Bassetlaw,E07000171,3,105000,356000 +Bassetlaw,E07000171,4,186000,627000 +Bath and North East Somerset,E06000022,1,119000,609000 +Bath and North East Somerset,E06000022,2,154000,609000 +Bath and North East Somerset,E06000022,3,249000,762000 +Bath and North East Somerset,E06000022,4,380000,1604000 +Bedford,E06000055,1,96000,349000 +Bedford,E06000055,2,120000,349000 +Bedford,E06000055,3,210000,467000 +Bedford,E06000055,4,371000,946000 +Bexley,E09000004,1,109000,449000 +Bexley,E09000004,2,142000,449000 +Bexley,E09000004,3,312000,581000 +Bexley,E09000004,4,412000,972000 +Birmingham,E08000025,1,79000,373000 +Birmingham,E08000025,2,107000,373000 +Birmingham,E08000025,3,137000,452000 +Birmingham,E08000025,4,198000,1006000 +Blaby,E07000129,1,111000,357000 +Blaby,E07000129,2,111000,357000 +Blaby,E07000129,3,194000,389000 +Blaby,E07000129,4,285000,723000 +Blackburn with Darwen,E06000008,1,61000,234000 +Blackburn with Darwen,E06000008,2,74000,234000 +Blackburn with Darwen,E06000008,3,92000,310000 +Blackburn with Darwen,E06000008,4,148000,608000 +Blackpool,E06000009,1,59000,228000 +Blackpool,E06000009,2,83000,228000 +Blackpool,E06000009,3,100000,265000 +Blackpool,E06000009,4,114000,450000 +Bolsover,E07000033,1,81000,222000 +Bolsover,E07000033,2,81000,222000 +Bolsover,E07000033,3,87000,279000 +Bolsover,E07000033,4,169000,543000 +Bolton,E08000001,1,77000,251000 +Bolton,E08000001,2,84000,251000 +Bolton,E08000001,3,104000,340000 +Bolton,E08000001,4,175000,762000 +Boston,E07000136,1,58000,258000 +Boston,E07000136,2,58000,258000 +Boston,E07000136,3,111000,308000 +Boston,E07000136,4,212000,510000 +Bournemouth, Christchurch and Poole,E06000058,1,140000,500000 +Bournemouth, Christchurch and Poole,E06000058,2,197000,500000 +Bournemouth, Christchurch and Poole,E06000058,3,285000,657000 +Bournemouth, Christchurch and Poole,E06000058,4,370000,1321000 +Bracknell Forest,E06000036,1,95000,488000 +Bracknell Forest,E06000036,2,157000,488000 +Bracknell Forest,E06000036,3,341000,654000 +Bracknell Forest,E06000036,4,417000,1185000 +Bradford,E08000032,1,65000,291000 +Bradford,E08000032,2,77000,291000 +Bradford,E08000032,3,96000,365000 +Bradford,E08000032,4,124000,799000 +Braintree,E07000067,1,126000,425000 +Braintree,E07000067,2,166000,425000 +Braintree,E07000067,3,273000,534000 +Braintree,E07000067,4,370000,1177000 +Breckland,E07000143,1,105000,315000 +Breckland,E07000143,2,130000,315000 +Breckland,E07000143,3,173000,415000 +Breckland,E07000143,4,262000,795000 +Brent,E09000005,1,109000,625000 +Brent,E09000005,2,160000,817000 +Brent,E09000005,3,387000,1319000 +Brent,E09000005,4,555000,2717000 +Brentwood,E07000068,1,146000,530000 +Brentwood,E07000068,2,244000,703000 +Brentwood,E07000068,3,402000,897000 +Brentwood,E07000068,4,508000,1851000 +Brighton and Hove,E06000043,1,185000,526000 +Brighton and Hove,E06000043,2,270000,610000 +Brighton and Hove,E06000043,3,350000,846000 +Brighton and Hove,E06000043,4,458000,1487000 +Bristol, City of,E06000023,1,145000,417000 +Bristol, City of,E06000023,2,184000,562000 +Bristol, City of,E06000023,3,242000,685000 +Bristol, City of,E06000023,4,331000,1394000 +Broadland,E07000144,1,126000,334000 +Broadland,E07000144,2,140000,334000 +Broadland,E07000144,3,225000,433000 +Broadland,E07000144,4,302000,749000 +Bromley,E09000006,1,198000,559000 +Bromley,E09000006,2,276000,629000 +Bromley,E09000006,3,352000,824000 +Bromley,E09000006,4,499000,1553000 +Bromsgrove,E07000234,1,119000,485000 +Bromsgrove,E07000234,2,121000,485000 +Bromsgrove,E07000234,3,195000,556000 +Bromsgrove,E07000234,4,347000,1090000 +Broxbourne,E07000095,1,170000,480000 +Broxbourne,E07000095,2,252000,480000 +Broxbourne,E07000095,3,371000,658000 +Broxbourne,E07000095,4,485000,1428000 +Broxtowe,E07000172,1,99000,297000 +Broxtowe,E07000172,2,109000,297000 +Broxtowe,E07000172,3,151000,381000 +Broxtowe,E07000172,4,235000,789000 +Buckinghamshire,E06000060,1,157000,650000 +Buckinghamshire,E06000060,2,171000,650000 +Buckinghamshire,E06000060,3,314000,867000 +Buckinghamshire,E06000060,4,459000,1926000 +Burnley,E07000117,1,52000,225000 +Burnley,E07000117,2,62000,225000 +Burnley,E07000117,3,83000,283000 +Burnley,E07000117,4,147000,475000 +Bury,E08000002,1,89000,319000 +Bury,E08000002,2,99000,319000 +Bury,E08000002,3,136000,390000 +Bury,E08000002,4,224000,792000 +Calderdale,E08000033,1,74000,283000 +Calderdale,E08000033,2,79000,283000 +Calderdale,E08000033,3,103000,393000 +Calderdale,E08000033,4,163000,749000 +Cambridge,E07000008,1,139000,603000 +Cambridge,E07000008,2,174000,663000 +Cambridge,E07000008,3,339000,870000 +Cambridge,E07000008,4,530000,1952000 +Camden,E09000007,1,256000,806000 +Camden,E09000007,2,449000,1468000 +Camden,E09000007,3,559000,2535000 +Camden,E09000007,4,1009000,6026000 +Cannock Chase,E07000192,1,75000,248000 +Cannock Chase,E07000192,2,111000,248000 +Cannock Chase,E07000192,3,147000,326000 +Cannock Chase,E07000192,4,228000,511000 +Canterbury,E07000106,1,96000,465000 +Canterbury,E07000106,2,167000,465000 +Canterbury,E07000106,3,239000,591000 +Canterbury,E07000106,4,356000,1076000 +Castle Point,E07000069,1,155000,465000 +Castle Point,E07000069,2,219000,465000 +Castle Point,E07000069,3,283000,543000 +Castle Point,E07000069,4,378000,1017000 +Central Bedfordshire,E06000056,1,106000,418000 +Central Bedfordshire,E06000056,2,134000,418000 +Central Bedfordshire,E06000056,3,255000,537000 +Central Bedfordshire,E06000056,4,395000,942000 +Charnwood,E07000130,1,95000,338000 +Charnwood,E07000130,2,110000,338000 +Charnwood,E07000130,3,168000,397000 +Charnwood,E07000130,4,286000,803000 +Chelmsford,E07000070,1,89000,498000 +Chelmsford,E07000070,2,125000,498000 +Chelmsford,E07000070,3,330000,675000 +Chelmsford,E07000070,4,449000,1189000 +Cheltenham,E07000078,1,118000,487000 +Cheltenham,E07000078,2,175000,511000 +Cheltenham,E07000078,3,226000,638000 +Cheltenham,E07000078,4,328000,1280000 +Cherwell,E07000177,1,114000,432000 +Cherwell,E07000177,2,114000,432000 +Cherwell,E07000177,3,235000,543000 +Cherwell,E07000177,4,359000,999000 +Cheshire East,E06000049,1,98000,454000 +Cheshire East,E06000049,2,98000,454000 +Cheshire East,E06000049,3,132000,566000 +Cheshire East,E06000049,4,288000,1199000 +Cheshire West and Chester,E06000050,1,84000,375000 +Cheshire West and Chester,E06000050,2,94000,375000 +Cheshire West and Chester,E06000050,3,122000,450000 +Cheshire West and Chester,E06000050,4,253000,975000 +Chesterfield,E07000034,1,73000,240000 +Chesterfield,E07000034,2,95000,240000 +Chesterfield,E07000034,3,117000,353000 +Chesterfield,E07000034,4,194000,629000 +Chichester,E07000225,1,101000,610000 +Chichester,E07000225,2,115000,610000 +Chichester,E07000225,3,282000,787000 +Chichester,E07000225,4,410000,2095000 +Chorley,E07000118,1,73000,333000 +Chorley,E07000118,2,100000,333000 +Chorley,E07000118,3,123000,393000 +Chorley,E07000118,4,234000,716000 +City of London,E09000001,1,467000,1026000 +City of London,E09000001,2,681000,2732000 +City of London,E09000001,3,1741000,5775000 +City of London,E09000001,4,1932000,2288000 +Colchester,E07000071,1,114000,383000 +Colchester,E07000071,2,164000,383000 +Colchester,E07000071,3,256000,490000 +Colchester,E07000071,4,364000,928000 +Cornwall,E06000052,1,98000,406000 +Cornwall,E06000052,2,102000,406000 +Cornwall,E06000052,3,161000,524000 +Cornwall,E06000052,4,250000,864000 +Cotswold,E07000079,1,74000,659000 +Cotswold,E07000079,2,121000,659000 +Cotswold,E07000079,3,181000,812000 +Cotswold,E07000079,4,408000,1603000 +County Durham,E06000047,1,55000,232000 +County Durham,E06000047,2,55000,232000 +County Durham,E06000047,3,72000,299000 +County Durham,E06000047,4,148000,593000 +Coventry,E08000026,1,88000,277000 +Coventry,E08000026,2,118000,277000 +Coventry,E08000026,3,165000,396000 +Coventry,E08000026,4,237000,783000 +Crawley,E07000226,1,159000,387000 +Crawley,E07000226,2,230000,416000 +Crawley,E07000226,3,315000,528000 +Crawley,E07000226,4,378000,794000 +Croydon,E09000008,1,115000,444000 +Croydon,E09000008,2,183000,553000 +Croydon,E09000008,3,341000,692000 +Croydon,E09000008,4,464000,1215000 +Cumberland,E06000063,1,67000,271000 +Cumberland,E06000063,2,81000,271000 +Cumberland,E06000063,3,96000,349000 +Cumberland,E06000063,4,153000,577000 +Dacorum,E07000096,1,174000,618000 +Dacorum,E07000096,2,234000,621000 +Dacorum,E07000096,3,354000,839000 +Dacorum,E07000096,4,478000,1765000 +Darlington,E06000005,1,56000,240000 +Darlington,E06000005,2,69000,240000 +Darlington,E06000005,3,91000,310000 +Darlington,E06000005,4,185000,614000 +Dartford,E07000107,1,117000,431000 +Dartford,E07000107,2,117000,431000 +Dartford,E07000107,3,307000,559000 +Dartford,E07000107,4,426000,963000 +Derby,E06000015,1,67000,258000 +Derby,E06000015,2,94000,258000 +Derby,E06000015,3,117000,352000 +Derby,E06000015,4,237000,646000 +Derbyshire Dales,E07000035,1,73000,474000 +Derbyshire Dales,E07000035,2,88000,474000 +Derbyshire Dales,E07000035,3,181000,601000 +Derbyshire Dales,E07000035,4,300000,973000 +Doncaster,E08000017,1,77000,233000 +Doncaster,E08000017,2,78000,233000 +Doncaster,E08000017,3,93000,286000 +Doncaster,E08000017,4,173000,582000 +Dorset,E06000059,1,112000,471000 +Dorset,E06000059,2,159000,471000 +Dorset,E06000059,3,231000,615000 +Dorset,E06000059,4,328000,1150000 +Dover,E07000108,1,109000,384000 +Dover,E07000108,2,120000,384000 +Dover,E07000108,3,190000,501000 +Dover,E07000108,4,265000,956000 +Dudley,E08000027,1,76000,281000 +Dudley,E08000027,2,102000,281000 +Dudley,E08000027,3,137000,371000 +Dudley,E08000027,4,209000,650000 +Ealing,E09000009,1,129000,574000 +Ealing,E09000009,2,195000,760000 +Ealing,E09000009,3,338000,1095000 +Ealing,E09000009,4,523000,2198000 +East Cambridgeshire,E07000009,1,120000,385000 +East Cambridgeshire,E07000009,2,128000,385000 +East Cambridgeshire,E07000009,3,227000,499000 +East Cambridgeshire,E07000009,4,331000,916000 +East Devon,E07000040,1,91000,459000 +East Devon,E07000040,2,114000,459000 +East Devon,E07000040,3,181000,593000 +East Devon,E07000040,4,324000,1123000 +East Hampshire,E07000085,1,122000,577000 +East Hampshire,E07000085,2,152000,577000 +East Hampshire,E07000085,3,288000,727000 +East Hampshire,E07000085,4,438000,1371000 +East Hertfordshire,E07000242,1,143000,578000 +East Hertfordshire,E07000242,2,170000,578000 +East Hertfordshire,E07000242,3,349000,816000 +East Hertfordshire,E07000242,4,512000,1582000 +East Lindsey,E07000137,1,68000,320000 +East Lindsey,E07000137,2,85000,320000 +East Lindsey,E07000137,3,112000,359000 +East Lindsey,E07000137,4,199000,699000 +East Riding of Yorkshire,E06000011,1,79000,322000 +East Riding of Yorkshire,E06000011,2,101000,322000 +East Riding of Yorkshire,E06000011,3,133000,376000 +East Riding of Yorkshire,E06000011,4,205000,717000 +East Staffordshire,E07000193,1,80000,330000 +East Staffordshire,E07000193,2,100000,330000 +East Staffordshire,E07000193,3,128000,379000 +East Staffordshire,E07000193,4,236000,753000 +East Suffolk,E07000244,1,94000,414000 +East Suffolk,E07000244,2,125000,414000 +East Suffolk,E07000244,3,147000,481000 +East Suffolk,E07000244,4,247000,913000 +Eastbourne,E07000061,1,121000,371000 +Eastbourne,E07000061,2,169000,371000 +Eastbourne,E07000061,3,238000,496000 +Eastbourne,E07000061,4,307000,870000 +Eastleigh,E07000086,1,113000,389000 +Eastleigh,E07000086,2,117000,389000 +Eastleigh,E07000086,3,202000,514000 +Eastleigh,E07000086,4,369000,936000 +Elmbridge,E07000207,1,145000,857000 +Elmbridge,E07000207,2,265000,857000 +Elmbridge,E07000207,3,462000,1175000 +Elmbridge,E07000207,4,668000,2805000 +Enfield,E09000010,1,126000,507000 +Enfield,E09000010,2,175000,600000 +Enfield,E09000010,3,336000,858000 +Enfield,E09000010,4,498000,1612000 +Epping Forest,E07000072,1,131000,697000 +Epping Forest,E07000072,2,287000,697000 +Epping Forest,E07000072,3,391000,923000 +Epping Forest,E07000072,4,545000,2007000 +Epsom and Ewell,E07000208,1,183000,693000 +Epsom and Ewell,E07000208,2,270000,693000 +Epsom and Ewell,E07000208,3,430000,929000 +Epsom and Ewell,E07000208,4,627000,1574000 +Erewash,E07000036,1,90000,270000 +Erewash,E07000036,2,99000,270000 +Erewash,E07000036,3,133000,362000 +Erewash,E07000036,4,211000,701000 +Exeter,E07000041,1,112000,402000 +Exeter,E07000041,2,130000,402000 +Exeter,E07000041,3,226000,500000 +Exeter,E07000041,4,329000,1005000 +Fareham,E07000087,1,127000,418000 +Fareham,E07000087,2,190000,418000 +Fareham,E07000087,3,265000,520000 +Fareham,E07000087,4,356000,943000 +Fenland,E07000010,1,85000,268000 +Fenland,E07000010,2,120000,268000 +Fenland,E07000010,3,154000,348000 +Fenland,E07000010,4,230000,594000 +Folkestone and Hythe,E07000112,1,106000,406000 +Folkestone and Hythe,E07000112,2,115000,406000 +Folkestone and Hythe,E07000112,3,208000,549000 +Folkestone and Hythe,E07000112,4,287000,883000 +Forest of Dean,E07000080,1,101000,439000 +Forest of Dean,E07000080,2,119000,439000 +Forest of Dean,E07000080,3,176000,522000 +Forest of Dean,E07000080,4,262000,872000 +Fylde,E07000119,1,87000,394000 +Fylde,E07000119,2,109000,407000 +Fylde,E07000119,3,127000,407000 +Fylde,E07000119,4,240000,763000 +Gateshead,E08000037,1,59000,229000 +Gateshead,E08000037,2,71000,229000 +Gateshead,E08000037,3,94000,337000 +Gateshead,E08000037,4,151000,583000 +Gedling,E07000173,1,77000,288000 +Gedling,E07000173,2,102000,288000 +Gedling,E07000173,3,147000,376000 +Gedling,E07000173,4,232000,747000 +Gloucester,E07000081,1,80000,302000 +Gloucester,E07000081,2,126000,302000 +Gloucester,E07000081,3,181000,397000 +Gloucester,E07000081,4,286000,619000 +Gosport,E07000088,1,107000,369000 +Gosport,E07000088,2,139000,370000 +Gosport,E07000088,3,201000,425000 +Gosport,E07000088,4,270000,791000 +Gravesham,E07000109,1,85000,432000 +Gravesham,E07000109,2,124000,432000 +Gravesham,E07000109,3,272000,549000 +Gravesham,E07000109,4,365000,1107000 +Great Yarmouth,E07000145,1,89000,287000 +Great Yarmouth,E07000145,2,93000,287000 +Great Yarmouth,E07000145,3,116000,352000 +Great Yarmouth,E07000145,4,178000,586000 +Greenwich,E09000011,1,115000,592000 +Greenwich,E09000011,2,158000,705000 +Greenwich,E09000011,3,283000,888000 +Greenwich,E09000011,4,410000,1778000 +Guildford,E07000209,1,124000,629000 +Guildford,E07000209,2,240000,738000 +Guildford,E07000209,3,387000,946000 +Guildford,E07000209,4,525000,2156000 +Hackney,E09000012,1,181000,698000 +Hackney,E09000012,2,236000,935000 +Hackney,E09000012,3,423000,1443000 +Hackney,E09000012,4,732000,2120000 +Halton,E06000006,1,76000,255000 +Halton,E06000006,2,87000,255000 +Halton,E06000006,3,102000,327000 +Halton,E06000006,4,174000,581000 +Hammersmith and Fulham,E09000013,1,206000,790000 +Hammersmith and Fulham,E09000013,2,395000,1248000 +Hammersmith and Fulham,E09000013,3,484000,1767000 +Hammersmith and Fulham,E09000013,4,1058000,3462000 +Harborough,E07000131,1,65000,458000 +Harborough,E07000131,2,65000,458000 +Harborough,E07000131,3,154000,535000 +Harborough,E07000131,4,352000,1070000 +Haringey,E09000014,1,155000,589000 +Haringey,E09000014,2,251000,862000 +Haringey,E09000014,3,406000,1279000 +Haringey,E09000014,4,644000,2638000 +Harlow,E07000073,1,128000,369000 +Harlow,E07000073,2,166000,422000 +Harlow,E07000073,3,283000,536000 +Harlow,E07000073,4,384000,920000 +Harrow,E09000015,1,129000,536000 +Harrow,E09000015,2,282000,623000 +Harrow,E09000015,3,418000,836000 +Harrow,E09000015,4,570000,1607000 +Hart,E07000089,1,108000,576000 +Hart,E07000089,2,150000,576000 +Hart,E07000089,3,351000,705000 +Hart,E07000089,4,508000,1431000 +Hartlepool,E06000001,1,56000,242000 +Hartlepool,E06000001,2,56000,242000 +Hartlepool,E06000001,3,77000,261000 +Hartlepool,E06000001,4,133000,559000 +Hastings,E07000062,1,106000,340000 +Hastings,E07000062,2,155000,381000 +Hastings,E07000062,3,214000,437000 +Hastings,E07000062,4,282000,727000 +Havant,E07000090,1,98000,414000 +Havant,E07000090,2,144000,414000 +Havant,E07000090,3,229000,501000 +Havant,E07000090,4,309000,855000 +Havering,E09000016,1,137000,472000 +Havering,E09000016,2,204000,481000 +Havering,E09000016,3,336000,657000 +Havering,E09000016,4,412000,1232000 +Herefordshire, County of,E06000019,1,98000,419000 +Herefordshire, County of,E06000019,2,105000,419000 +Herefordshire, County of,E06000019,3,162000,499000 +Herefordshire, County of,E06000019,4,283000,885000 +Hertsmere,E07000098,1,178000,666000 +Hertsmere,E07000098,2,316000,666000 +Hertsmere,E07000098,3,440000,918000 +Hertsmere,E07000098,4,591000,2232000 +High Peak,E07000037,1,110000,322000 +High Peak,E07000037,2,126000,322000 +High Peak,E07000037,3,161000,433000 +High Peak,E07000037,4,247000,804000 +Hillingdon,E09000017,1,132000,502000 +Hillingdon,E09000017,2,196000,577000 +Hillingdon,E09000017,3,401000,788000 +Hillingdon,E09000017,4,507000,1414000 +Hinckley and Bosworth,E07000132,1,99000,328000 +Hinckley and Bosworth,E07000132,2,110000,328000 +Hinckley and Bosworth,E07000132,3,164000,418000 +Hinckley and Bosworth,E07000132,4,270000,840000 +Horsham,E07000227,1,140000,529000 +Horsham,E07000227,2,140000,529000 +Horsham,E07000227,3,297000,745000 +Horsham,E07000227,4,496000,1513000 +Hounslow,E09000018,1,119000,563000 +Hounslow,E09000018,2,154000,733000 +Hounslow,E09000018,3,330000,1036000 +Hounslow,E09000018,4,475000,2743000 +Huntingdonshire,E07000011,1,91000,389000 +Huntingdonshire,E07000011,2,107000,389000 +Huntingdonshire,E07000011,3,208000,478000 +Huntingdonshire,E07000011,4,318000,814000 +Hyndburn,E07000120,1,66000,214000 +Hyndburn,E07000120,2,66000,214000 +Hyndburn,E07000120,3,87000,307000 +Hyndburn,E07000120,4,168000,587000 +Ipswich,E07000202,1,97000,309000 +Ipswich,E07000202,2,125000,309000 +Ipswich,E07000202,3,182000,399000 +Ipswich,E07000202,4,253000,851000 +Isle of Wight,E06000046,1,96000,352000 +Isle of Wight,E06000046,2,131000,352000 +Isle of Wight,E06000046,3,185000,452000 +Isle of Wight,E06000046,4,239000,827000 +Islington,E09000019,1,203000,741000 +Islington,E09000019,2,398000,1223000 +Islington,E09000019,3,490000,1891000 +Islington,E09000019,4,762000,2824000 +Kensington and Chelsea,E09000020,1,234000,1261000 +Kensington and Chelsea,E09000020,2,599000,2368000 +Kensington and Chelsea,E09000020,3,706000,4202000 +Kensington and Chelsea,E09000020,4,1405000,13278000 +King's Lynn and West Norfolk,E07000146,1,77000,346000 +King's Lynn and West Norfolk,E07000146,2,123000,346000 +King's Lynn and West Norfolk,E07000146,3,161000,408000 +King's Lynn and West Norfolk,E07000146,4,243000,778000 +Kingston upon Hull, City of,E06000010,1,63000,189000 +Kingston upon Hull, City of,E06000010,2,67000,189000 +Kingston upon Hull, City of,E06000010,3,84000,259000 +Kingston upon Hull, City of,E06000010,4,110000,415000 +Kingston upon Thames,E09000021,1,156000,649000 +Kingston upon Thames,E09000021,2,325000,708000 +Kingston upon Thames,E09000021,3,398000,935000 +Kingston upon Thames,E09000021,4,549000,1957000 +Kirklees,E08000034,1,70000,261000 +Kirklees,E08000034,2,85000,261000 +Kirklees,E08000034,3,115000,356000 +Kirklees,E08000034,4,198000,752000 +Knowsley,E08000011,1,74000,223000 +Knowsley,E08000011,2,74000,223000 +Knowsley,E08000011,3,94000,302000 +Knowsley,E08000011,4,134000,481000 +Lambeth,E09000022,1,166000,639000 +Lambeth,E09000022,2,242000,842000 +Lambeth,E09000022,3,392000,1259000 +Lambeth,E09000022,4,573000,2054000 +Lancaster,E07000121,1,79000,312000 +Lancaster,E07000121,2,93000,312000 +Lancaster,E07000121,3,126000,378000 +Lancaster,E07000121,4,147000,699000 +Leeds,E08000035,1,87000,323000 +Leeds,E08000035,2,101000,323000 +Leeds,E08000035,3,126000,435000 +Leeds,E08000035,4,181000,878000 +Leicester,E06000016,1,47000,282000 +Leicester,E06000016,2,82000,282000 +Leicester,E06000016,3,102000,364000 +Leicester,E06000016,4,235000,728000 +Lewes,E07000063,1,140000,528000 +Lewes,E07000063,2,204000,528000 +Lewes,E07000063,3,251000,725000 +Lewes,E07000063,4,363000,1374000 +Lewisham,E09000023,1,169000,506000 +Lewisham,E09000023,2,238000,675000 +Lewisham,E09000023,3,357000,881000 +Lewisham,E09000023,4,486000,1540000 +Lichfield,E07000194,1,100000,433000 +Lichfield,E07000194,2,100000,433000 +Lichfield,E07000194,3,176000,528000 +Lichfield,E07000194,4,296000,990000 +Lincoln,E07000138,1,63000,258000 +Lincoln,E07000138,2,85000,258000 +Lincoln,E07000138,3,132000,335000 +Lincoln,E07000138,4,195000,563000 +Liverpool,E08000012,1,76000,323000 +Liverpool,E08000012,2,76000,323000 +Liverpool,E08000012,3,95000,381000 +Liverpool,E08000012,4,138000,790000 +Luton,E06000032,1,123000,349000 +Luton,E06000032,2,154000,349000 +Luton,E06000032,3,253000,462000 +Luton,E06000032,4,310000,755000 +Maidstone,E07000110,1,75000,455000 +Maidstone,E07000110,2,121000,455000 +Maidstone,E07000110,3,217000,566000 +Maidstone,E07000110,4,402000,1099000 +Maldon,E07000074,1,127000,516000 +Maldon,E07000074,2,127000,516000 +Maldon,E07000074,3,293000,612000 +Maldon,E07000074,4,400000,1389000 +Malvern Hills,E07000235,1,103000,448000 +Malvern Hills,E07000235,2,103000,448000 +Malvern Hills,E07000235,3,201000,588000 +Malvern Hills,E07000235,4,330000,942000 +Manchester,E08000003,1,106000,348000 +Manchester,E08000003,2,106000,438000 +Manchester,E08000003,3,109000,517000 +Manchester,E08000003,4,165000,1108000 +Mansfield,E07000174,1,77000,270000 +Mansfield,E07000174,2,80000,270000 +Mansfield,E07000174,3,103000,305000 +Mansfield,E07000174,4,184000,544000 +Medway,E06000035,1,72000,375000 +Medway,E06000035,2,148000,375000 +Medway,E06000035,3,226000,484000 +Medway,E06000035,4,309000,758000 +Melton,E07000133,1,62000,393000 +Melton,E07000133,2,62000,393000 +Melton,E07000133,3,173000,464000 +Melton,E07000133,4,264000,1049000 +Mendip,E07000187,1,110000,417000 +Mendip,E07000187,2,121000,417000 +Mendip,E07000187,3,222000,525000 +Mendip,E07000187,4,320000,1134000 +Merton,E09000024,1,205000,696000 +Merton,E09000024,2,263000,792000 +Merton,E09000024,3,370000,1016000 +Merton,E09000024,4,508000,2679000 +Mid Devon,E07000042,1,100000,412000 +Mid Devon,E07000042,2,115000,412000 +Mid Devon,E07000042,3,189000,526000 +Mid Devon,E07000042,4,292000,931000 +Mid Suffolk,E07000203,1,111000,389000 +Mid Suffolk,E07000203,2,124000,389000 +Mid Suffolk,E07000203,3,218000,502000 +Mid Suffolk,E07000203,4,315000,962000 +Mid Sussex,E07000228,1,187000,548000 +Mid Sussex,E07000228,2,245000,548000 +Mid Sussex,E07000228,3,352000,713000 +Mid Sussex,E07000228,4,471000,1406000 +Middlesbrough,E06000002,1,54000,228000 +Middlesbrough,E06000002,2,63000,228000 +Middlesbrough,E06000002,3,80000,272000 +Middlesbrough,E06000002,4,183000,533000 +Milton Keynes,E06000042,1,67000,377000 +Milton Keynes,E06000042,2,93000,377000 +Milton Keynes,E06000042,3,207000,495000 +Milton Keynes,E06000042,4,354000,921000 +Mole Valley,E07000210,1,173000,743000 +Mole Valley,E07000210,2,261000,753000 +Mole Valley,E07000210,3,429000,981000 +Mole Valley,E07000210,4,617000,1913000 +New Forest,E07000091,1,127000,505000 +New Forest,E07000091,2,199000,556000 +New Forest,E07000091,3,272000,756000 +New Forest,E07000091,4,378000,1262000 +Newark and Sherwood,E07000175,1,92000,353000 +Newark and Sherwood,E07000175,2,92000,353000 +Newark and Sherwood,E07000175,3,122000,402000 +Newark and Sherwood,E07000175,4,233000,829000 +Newcastle upon Tyne,E08000021,1,58000,293000 +Newcastle upon Tyne,E08000021,2,69000,293000 +Newcastle upon Tyne,E08000021,3,88000,381000 +Newcastle upon Tyne,E08000021,4,170000,828000 +Newcastle-under-Lyme,E07000195,1,92000,245000 +Newcastle-under-Lyme,E07000195,2,92000,245000 +Newcastle-under-Lyme,E07000195,3,121000,348000 +Newcastle-under-Lyme,E07000195,4,205000,684000 +Newham,E09000025,1,111000,515000 +Newham,E09000025,2,149000,665000 +Newham,E09000025,3,246000,794000 +Newham,E09000025,4,425000,1108000 +North Devon,E07000043,1,92000,415000 +North Devon,E07000043,2,110000,415000 +North Devon,E07000043,3,170000,468000 +North Devon,E07000043,4,255000,831000 +North East Derbyshire,E07000038,1,79000,322000 +North East Derbyshire,E07000038,2,79000,322000 +North East Derbyshire,E07000038,3,117000,424000 +North East Derbyshire,E07000038,4,230000,882000 +North East Lincolnshire,E06000012,1,53000,255000 +North East Lincolnshire,E06000012,2,69000,255000 +North East Lincolnshire,E06000012,3,87000,283000 +North East Lincolnshire,E06000012,4,161000,562000 +North Hertfordshire,E07000099,1,108000,528000 +North Hertfordshire,E07000099,2,157000,528000 +North Hertfordshire,E07000099,3,318000,752000 +North Hertfordshire,E07000099,4,453000,1558000 +North Kesteven,E07000139,1,85000,339000 +North Kesteven,E07000139,2,85000,339000 +North Kesteven,E07000139,3,149000,367000 +North Kesteven,E07000139,4,250000,634000 +North Lincolnshire,E06000013,1,71000,291000 +North Lincolnshire,E06000013,2,84000,291000 +North Lincolnshire,E06000013,3,100000,305000 +North Lincolnshire,E06000013,4,186000,560000 +North Norfolk,E07000147,1,106000,403000 +North Norfolk,E07000147,2,136000,403000 +North Norfolk,E07000147,3,176000,507000 +North Norfolk,E07000147,4,251000,1072000 +North Northamptonshire,E06000061,1,79000,330000 +North Northamptonshire,E06000061,2,95000,330000 +North Northamptonshire,E06000061,3,170000,407000 +North Northamptonshire,E06000061,4,270000,782000 +North Somerset,E06000024,1,108000,430000 +North Somerset,E06000024,2,145000,430000 +North Somerset,E06000024,3,222000,588000 +North Somerset,E06000024,4,306000,1105000 +North Tyneside,E08000022,1,69000,263000 +North Tyneside,E08000022,2,69000,263000 +North Tyneside,E08000022,3,91000,373000 +North Tyneside,E08000022,4,205000,619000 +North Warwickshire,E07000218,1,112000,369000 +North Warwickshire,E07000218,2,118000,369000 +North Warwickshire,E07000218,3,153000,434000 +North Warwickshire,E07000218,4,260000,968000 +North West Leicestershire,E07000134,1,103000,315000 +North West Leicestershire,E07000134,2,103000,315000 +North West Leicestershire,E07000134,3,130000,398000 +North West Leicestershire,E07000134,4,271000,733000 +North Yorkshire,E06000065,1,81000,384000 +North Yorkshire,E06000065,2,108000,384000 +North Yorkshire,E06000065,3,143000,496000 +North Yorkshire,E06000065,4,234000,1005000 +Northumberland,E06000057,1,62000,333000 +Northumberland,E06000057,2,64000,333000 +Northumberland,E06000057,3,95000,376000 +Northumberland,E06000057,4,188000,790000 +Norwich,E07000148,1,83000,263000 +Norwich,E07000148,2,83000,346000 +Norwich,E07000148,3,149000,466000 +Norwich,E07000148,4,230000,960000 +Nottingham,E06000018,1,72000,304000 +Nottingham,E06000018,2,79000,304000 +Nottingham,E06000018,3,89000,350000 +Nottingham,E06000018,4,165000,761000 +Nuneaton and Bedworth,E07000219,1,95000,266000 +Nuneaton and Bedworth,E07000219,2,98000,266000 +Nuneaton and Bedworth,E07000219,3,142000,356000 +Nuneaton and Bedworth,E07000219,4,225000,637000 +Oadby and Wigston,E07000135,1,90000,303000 +Oadby and Wigston,E07000135,2,125000,303000 +Oadby and Wigston,E07000135,3,188000,401000 +Oadby and Wigston,E07000135,4,295000,911000 +Oldham,E08000004,1,85000,262000 +Oldham,E08000004,2,85000,262000 +Oldham,E08000004,3,107000,357000 +Oldham,E08000004,4,160000,789000 +Oxford,E07000178,1,126000,656000 +Oxford,E07000178,2,198000,707000 +Oxford,E07000178,3,328000,794000 +Oxford,E07000178,4,440000,2267000 +Pendle,E07000122,1,59000,251000 +Pendle,E07000122,2,60000,251000 +Pendle,E07000122,3,81000,366000 +Pendle,E07000122,4,155000,700000 +Peterborough,E06000031,1,75000,282000 +Peterborough,E06000031,2,89000,282000 +Peterborough,E06000031,3,152000,337000 +Peterborough,E06000031,4,223000,697000 +Plymouth,E06000026,1,91000,320000 +Plymouth,E06000026,2,95000,320000 +Plymouth,E06000026,3,148000,370000 +Plymouth,E06000026,4,218000,635000 +Portsmouth,E06000044,1,107000,332000 +Portsmouth,E06000044,2,145000,341000 +Portsmouth,E06000044,3,202000,451000 +Portsmouth,E06000044,4,276000,875000 +Preston,E07000123,1,47000,253000 +Preston,E07000123,2,82000,253000 +Preston,E07000123,3,106000,329000 +Preston,E07000123,4,197000,649000 +Reading,E06000038,1,141000,434000 +Reading,E06000038,2,228000,471000 +Reading,E06000038,3,319000,662000 +Reading,E06000038,4,428000,1149000 +Redbridge,E09000026,1,102000,497000 +Redbridge,E09000026,2,162000,639000 +Redbridge,E09000026,3,355000,826000 +Redbridge,E09000026,4,488000,1329000 +Redcar and Cleveland,E06000003,1,62000,244000 +Redcar and Cleveland,E06000003,2,62000,244000 +Redcar and Cleveland,E06000003,3,82000,273000 +Redcar and Cleveland,E06000003,4,158000,482000 +Redditch,E07000236,1,57000,296000 +Redditch,E07000236,2,102000,296000 +Redditch,E07000236,3,157000,389000 +Redditch,E07000236,4,258000,627000 +Reigate and Banstead,E07000211,1,154000,574000 +Reigate and Banstead,E07000211,2,154000,574000 +Reigate and Banstead,E07000211,3,383000,864000 +Reigate and Banstead,E07000211,4,522000,1872000 +Ribble Valley,E07000124,1,116000,350000 +Ribble Valley,E07000124,2,116000,350000 +Ribble Valley,E07000124,3,131000,483000 +Ribble Valley,E07000124,4,282000,935000 +Richmond upon Thames,E09000027,1,218000,798000 +Richmond upon Thames,E09000027,2,346000,978000 +Richmond upon Thames,E09000027,3,481000,1355000 +Richmond upon Thames,E09000027,4,686000,2642000 +Rochdale,E08000005,1,73000,224000 +Rochdale,E08000005,2,75000,224000 +Rochdale,E08000005,3,102000,316000 +Rochdale,E08000005,4,174000,594000 +Rochford,E07000075,1,147000,494000 +Rochford,E07000075,2,237000,494000 +Rochford,E07000075,3,320000,585000 +Rochford,E07000075,4,406000,1011000 +Rossendale,E07000125,1,64000,283000 +Rossendale,E07000125,2,77000,283000 +Rossendale,E07000125,3,108000,383000 +Rossendale,E07000125,4,188000,736000 +Rother,E07000064,1,104000,406000 +Rother,E07000064,2,151000,456000 +Rother,E07000064,3,233000,628000 +Rother,E07000064,4,350000,1165000 +Rotherham,E08000018,1,69000,246000 +Rotherham,E08000018,2,73000,246000 +Rotherham,E08000018,3,90000,305000 +Rotherham,E08000018,4,174000,574000 +Rugby,E07000220,1,109000,343000 +Rugby,E07000220,2,109000,343000 +Rugby,E07000220,3,184000,441000 +Rugby,E07000220,4,314000,835000 +Runnymede,E07000212,1,143000,543000 +Runnymede,E07000212,2,177000,582000 +Runnymede,E07000212,3,398000,819000 +Runnymede,E07000212,4,537000,1644000 +Rushcliffe,E07000176,1,99000,512000 +Rushcliffe,E07000176,2,99000,512000 +Rushcliffe,E07000176,3,178000,528000 +Rushcliffe,E07000176,4,329000,950000 +Rushmoor,E07000092,1,107000,413000 +Rushmoor,E07000092,2,183000,413000 +Rushmoor,E07000092,3,317000,555000 +Rushmoor,E07000092,4,433000,831000 +Rutland,E06000017,1,89000,390000 +Rutland,E06000017,2,89000,452000 +Rutland,E06000017,3,191000,615000 +Rutland,E06000017,4,333000,1262000 +Salford,E08000006,1,94000,355000 +Salford,E08000006,2,105000,355000 +Salford,E08000006,3,131000,396000 +Salford,E08000006,4,210000,784000 +Sandwell,E08000028,1,72000,241000 +Sandwell,E08000028,2,96000,241000 +Sandwell,E08000028,3,125000,323000 +Sandwell,E08000028,4,185000,465000 +Sefton,E08000014,1,78000,361000 +Sefton,E08000014,2,86000,361000 +Sefton,E08000014,3,105000,376000 +Sefton,E08000014,4,182000,841000 +Sevenoaks,E07000111,1,186000,677000 +Sevenoaks,E07000111,2,186000,677000 +Sevenoaks,E07000111,3,327000,940000 +Sevenoaks,E07000111,4,470000,2260000 +Sheffield,E08000019,1,76000,318000 +Sheffield,E08000019,2,79000,318000 +Sheffield,E08000019,3,108000,423000 +Sheffield,E08000019,4,211000,921000 +Shropshire,E06000051,1,85000,407000 +Shropshire,E06000051,2,108000,407000 +Shropshire,E06000051,3,164000,465000 +Shropshire,E06000051,4,252000,849000 +Slough,E06000039,1,163000,446000 +Slough,E06000039,2,224000,462000 +Slough,E06000039,3,352000,685000 +Slough,E06000039,4,432000,1004000 +Solihull,E08000029,1,93000,516000 +Solihull,E08000029,2,124000,516000 +Solihull,E08000029,3,162000,571000 +Solihull,E08000029,4,343000,1276000 +Somerset,E06000066,1,97000,376000 +Somerset,E06000066,2,120000,376000 +Somerset,E06000066,3,181000,469000 +Somerset,E06000066,4,278000,917000 +South Cambridgeshire,E07000012,1,137000,510000 +South Cambridgeshire,E07000012,2,164000,510000 +South Cambridgeshire,E07000012,3,271000,685000 +South Cambridgeshire,E07000012,4,403000,1219000 +South Derbyshire,E07000039,1,93000,330000 +South Derbyshire,E07000039,2,93000,330000 +South Derbyshire,E07000039,3,150000,380000 +South Derbyshire,E07000039,4,257000,747000 +South Gloucestershire,E06000025,1,95000,395000 +South Gloucestershire,E06000025,2,143000,395000 +South Gloucestershire,E06000025,3,263000,510000 +South Gloucestershire,E06000025,4,387000,890000 +South Hams,E07000044,1,106000,503000 +South Hams,E07000044,2,106000,503000 +South Hams,E07000044,3,207000,696000 +South Hams,E07000044,4,335000,1182000 +South Holland,E07000140,1,69000,278000 +South Holland,E07000140,2,69000,278000 +South Holland,E07000140,3,138000,367000 +South Holland,E07000140,4,238000,622000 +South Kesteven,E07000141,1,85000,358000 +South Kesteven,E07000141,2,92000,358000 +South Kesteven,E07000141,3,143000,448000 +South Kesteven,E07000141,4,250000,903000 +South Norfolk,E07000149,1,107000,364000 +South Norfolk,E07000149,2,107000,364000 +South Norfolk,E07000149,3,214000,482000 +South Norfolk,E07000149,4,295000,810000 +South Oxfordshire,E07000179,1,152000,615000 +South Oxfordshire,E07000179,2,152000,615000 +South Oxfordshire,E07000179,3,290000,784000 +South Oxfordshire,E07000179,4,440000,1898000 +South Ribble,E07000126,1,96000,282000 +South Ribble,E07000126,2,96000,282000 +South Ribble,E07000126,3,136000,337000 +South Ribble,E07000126,4,226000,640000 +South Staffordshire,E07000196,1,90000,369000 +South Staffordshire,E07000196,2,98000,369000 +South Staffordshire,E07000196,3,169000,475000 +South Staffordshire,E07000196,4,258000,850000 +South Tyneside,E08000023,1,58000,248000 +South Tyneside,E08000023,2,67000,248000 +South Tyneside,E08000023,3,80000,324000 +South Tyneside,E08000023,4,162000,624000 +Southampton,E06000045,1,80000,254000 +Southampton,E06000045,2,149000,348000 +Southampton,E06000045,3,216000,449000 +Southampton,E06000045,4,265000,794000 +Southend-on-Sea,E06000033,1,128000,451000 +Southend-on-Sea,E06000033,2,154000,503000 +Southend-on-Sea,E06000033,3,277000,658000 +Southend-on-Sea,E06000033,4,376000,1133000 +Southwark,E09000028,1,144000,676000 +Southwark,E09000028,2,185000,928000 +Southwark,E09000028,3,342000,1257000 +Southwark,E09000028,4,574000,2501000 +Spelthorne,E07000213,1,227000,560000 +Spelthorne,E07000213,2,293000,580000 +Spelthorne,E07000213,3,392000,768000 +Spelthorne,E07000213,4,524000,1262000 +St Albans,E07000240,1,194000,818000 +St Albans,E07000240,2,303000,818000 +St Albans,E07000240,3,443000,1077000 +St Albans,E07000240,4,679000,2067000 +St. Helens,E08000013,1,76000,226000 +St. Helens,E08000013,2,78000,226000 +St. Helens,E08000013,3,97000,315000 +St. Helens,E08000013,4,174000,628000 +Stafford,E07000197,1,76000,360000 +Stafford,E07000197,2,87000,360000 +Stafford,E07000197,3,150000,432000 +Stafford,E07000197,4,257000,736000 +Staffordshire Moorlands,E07000198,1,96000,347000 +Staffordshire Moorlands,E07000198,2,109000,347000 +Staffordshire Moorlands,E07000198,3,141000,442000 +Staffordshire Moorlands,E07000198,4,216000,826000 +Stevenage,E07000243,1,88000,392000 +Stevenage,E07000243,2,109000,392000 +Stevenage,E07000243,3,297000,504000 +Stevenage,E07000243,4,328000,848000 +Stockport,E08000007,1,95000,396000 +Stockport,E08000007,2,100000,396000 +Stockport,E08000007,3,174000,527000 +Stockport,E08000007,4,302000,1084000 +Stockton-on-Tees,E06000004,1,59000,245000 +Stockton-on-Tees,E06000004,2,59000,245000 +Stockton-on-Tees,E06000004,3,86000,302000 +Stockton-on-Tees,E06000004,4,178000,643000 +Stoke-on-Trent,E06000021,1,71000,197000 +Stoke-on-Trent,E06000021,2,72000,197000 +Stoke-on-Trent,E06000021,3,85000,287000 +Stoke-on-Trent,E06000021,4,178000,540000 +Stratford-on-Avon,E07000221,1,112000,487000 +Stratford-on-Avon,E07000221,2,112000,487000 +Stratford-on-Avon,E07000221,3,198000,649000 +Stratford-on-Avon,E07000221,4,384000,1338000 +Stroud,E07000082,1,99000,436000 +Stroud,E07000082,2,121000,436000 +Stroud,E07000082,3,220000,589000 +Stroud,E07000082,4,330000,1123000 +Sunderland,E08000024,1,60000,213000 +Sunderland,E08000024,2,66000,213000 +Sunderland,E08000024,3,81000,282000 +Sunderland,E08000024,4,139000,514000 +Surrey Heath,E07000214,1,160000,574000 +Surrey Heath,E07000214,2,160000,574000 +Surrey Heath,E07000214,3,366000,731000 +Surrey Heath,E07000214,4,528000,1387000 +Sutton,E09000029,1,128000,443000 +Sutton,E09000029,2,236000,495000 +Sutton,E09000029,3,362000,692000 +Sutton,E09000029,4,506000,1252000 +Swale,E07000113,1,116000,371000 +Swale,E07000113,2,121000,371000 +Swale,E07000113,3,207000,487000 +Swale,E07000113,4,318000,943000 +Swindon,E06000030,1,114000,317000 +Swindon,E06000030,2,118000,317000 +Swindon,E06000030,3,208000,433000 +Swindon,E06000030,4,322000,768000 +Tameside,E08000008,1,98000,237000 +Tameside,E08000008,2,110000,237000 +Tameside,E08000008,3,139000,336000 +Tameside,E08000008,4,209000,679000 +Tamworth,E07000199,1,102000,269000 +Tamworth,E07000199,2,116000,269000 +Tamworth,E07000199,3,159000,381000 +Tamworth,E07000199,4,243000,609000 +Tandridge,E07000215,1,189000,601000 +Tandridge,E07000215,2,225000,601000 +Tandridge,E07000215,3,392000,876000 +Tandridge,E07000215,4,532000,1958000 +Teignbridge,E07000045,1,98000,419000 +Teignbridge,E07000045,2,112000,419000 +Teignbridge,E07000045,3,208000,511000 +Teignbridge,E07000045,4,302000,952000 +Telford and Wrekin,E06000020,1,86000,260000 +Telford and Wrekin,E06000020,2,96000,260000 +Telford and Wrekin,E06000020,3,118000,332000 +Telford and Wrekin,E06000020,4,210000,618000 +Tendring,E07000076,1,82000,360000 +Tendring,E07000076,2,137000,360000 +Tendring,E07000076,3,184000,471000 +Tendring,E07000076,4,281000,915000 +Test Valley,E07000093,1,112000,503000 +Test Valley,E07000093,2,114000,511000 +Test Valley,E07000093,3,216000,577000 +Test Valley,E07000093,4,357000,1156000 +Tewkesbury,E07000083,1,72000,365000 +Tewkesbury,E07000083,2,102000,365000 +Tewkesbury,E07000083,3,155000,510000 +Tewkesbury,E07000083,4,352000,928000 +Thanet,E07000114,1,101000,377000 +Thanet,E07000114,2,153000,377000 +Thanet,E07000114,3,217000,484000 +Thanet,E07000114,4,292000,814000 +Three Rivers,E07000102,1,215000,574000 +Three Rivers,E07000102,2,287000,772000 +Three Rivers,E07000102,3,423000,1000000 +Three Rivers,E07000102,4,612000,2138000 +Thurrock,E06000034,1,134000,400000 +Thurrock,E06000034,2,176000,400000 +Thurrock,E06000034,3,277000,513000 +Thurrock,E06000034,4,377000,804000 +Tonbridge and Malling,E07000115,1,123000,472000 +Tonbridge and Malling,E07000115,2,133000,472000 +Tonbridge and Malling,E07000115,3,293000,691000 +Tonbridge and Malling,E07000115,4,439000,1315000 +Torbay,E06000027,1,92000,383000 +Torbay,E06000027,2,120000,383000 +Torbay,E06000027,3,174000,443000 +Torbay,E06000027,4,235000,779000 +Torridge,E07000046,1,110000,372000 +Torridge,E07000046,2,136000,372000 +Torridge,E07000046,3,181000,513000 +Torridge,E07000046,4,249000,807000 +Tower Hamlets,E09000030,1,153000,616000 +Tower Hamlets,E09000030,2,204000,872000 +Tower Hamlets,E09000030,3,261000,1335000 +Tower Hamlets,E09000030,4,448000,1896000 +Trafford,E08000009,1,102000,518000 +Trafford,E08000009,2,151000,518000 +Trafford,E08000009,3,212000,619000 +Trafford,E08000009,4,346000,1630000 +Tunbridge Wells,E07000116,1,102000,578000 +Tunbridge Wells,E07000116,2,143000,578000 +Tunbridge Wells,E07000116,3,326000,843000 +Tunbridge Wells,E07000116,4,490000,1729000 +Uttlesford,E07000077,1,83000,543000 +Uttlesford,E07000077,2,141000,543000 +Uttlesford,E07000077,3,266000,687000 +Uttlesford,E07000077,4,476000,1497000 +Vale of White Horse,E07000180,1,98000,473000 +Vale of White Horse,E07000180,2,132000,473000 +Vale of White Horse,E07000180,3,274000,585000 +Vale of White Horse,E07000180,4,409000,1157000 +Wakefield,E08000036,1,74000,233000 +Wakefield,E08000036,2,88000,233000 +Wakefield,E08000036,3,107000,322000 +Wakefield,E08000036,4,192000,605000 +Walsall,E08000030,1,79000,275000 +Walsall,E08000030,2,99000,275000 +Walsall,E08000030,3,121000,383000 +Walsall,E08000030,4,204000,853000 +Waltham Forest,E09000031,1,146000,538000 +Waltham Forest,E09000031,2,256000,643000 +Waltham Forest,E09000031,3,401000,821000 +Waltham Forest,E09000031,4,510000,1068000 +Wandsworth,E09000032,1,172000,715000 +Wandsworth,E09000032,2,284000,973000 +Wandsworth,E09000032,3,459000,1399000 +Wandsworth,E09000032,4,802000,2725000 +Warrington,E06000007,1,92000,361000 +Warrington,E06000007,2,108000,361000 +Warrington,E06000007,3,134000,449000 +Warrington,E06000007,4,251000,946000 +Warwick,E07000222,1,104000,473000 +Warwick,E07000222,2,139000,473000 +Warwick,E07000222,3,265000,647000 +Warwick,E07000222,4,421000,1253000 +Watford,E07000103,1,198000,516000 +Watford,E07000103,2,281000,547000 +Watford,E07000103,3,402000,849000 +Watford,E07000103,4,520000,1495000 +Waverley,E07000216,1,162000,723000 +Waverley,E07000216,2,206000,723000 +Waverley,E07000216,3,382000,929000 +Waverley,E07000216,4,565000,2204000 +Wealden,E07000065,1,129000,521000 +Wealden,E07000065,2,174000,521000 +Wealden,E07000065,3,264000,691000 +Wealden,E07000065,4,390000,1515000 +Welwyn Hatfield,E07000241,1,104000,482000 +Welwyn Hatfield,E07000241,2,149000,590000 +Welwyn Hatfield,E07000241,3,331000,824000 +Welwyn Hatfield,E07000241,4,493000,1714000 +West Berkshire,E06000037,1,97000,515000 +West Berkshire,E06000037,2,136000,515000 +West Berkshire,E06000037,3,312000,696000 +West Berkshire,E06000037,4,452000,1531000 +West Devon,E07000047,1,95000,421000 +West Devon,E07000047,2,145000,421000 +West Devon,E07000047,3,205000,527000 +West Devon,E07000047,4,259000,1018000 +West Lancashire,E07000127,1,57000,411000 +West Lancashire,E07000127,2,81000,411000 +West Lancashire,E07000127,3,81000,432000 +West Lancashire,E07000127,4,133000,880000 +West Lindsey,E07000142,1,78000,319000 +West Lindsey,E07000142,2,78000,319000 +West Lindsey,E07000142,3,110000,372000 +West Lindsey,E07000142,4,195000,691000 +West Northamptonshire,E06000062,1,59000,371000 +West Northamptonshire,E06000062,2,99000,371000 +West Northamptonshire,E06000062,3,185000,477000 +West Northamptonshire,E06000062,4,320000,947000 +West Oxfordshire,E07000181,1,119000,483000 +West Oxfordshire,E07000181,2,122000,483000 +West Oxfordshire,E07000181,3,279000,636000 +West Oxfordshire,E07000181,4,377000,1202000 +West Suffolk,E07000245,1,104000,367000 +West Suffolk,E07000245,2,126000,367000 +West Suffolk,E07000245,3,192000,475000 +West Suffolk,E07000245,4,278000,893000 +Westminster,E09000033,1,281000,1026000 +Westminster,E09000033,2,478000,2045000 +Westminster,E09000033,3,560000,3377000 +Westminster,E09000033,4,869000,11513000 +Westmorland,E06000064,1,81000,346000 +Westmorland,E06000064,2,81000,346000 +Westmorland,E06000064,3,114000,458000 +Westmorland,E06000064,4,195000,770000 +Wigan,E08000010,1,81000,243000 +Wigan,E08000010,2,81000,243000 +Wigan,E08000010,3,99000,318000 +Wigan,E08000010,4,197000,530000 +Wiltshire,E06000054,1,105000,438000 +Wiltshire,E06000054,2,120000,438000 +Wiltshire,E06000054,3,225000,565000 +Wiltshire,E06000054,4,341000,1139000 +Winchester,E07000094,1,124000,624000 +Winchester,E07000094,2,138000,660000 +Winchester,E07000094,3,298000,893000 +Winchester,E07000094,4,458000,1615000 +Windsor and Maidenhead,E06000040,1,228000,695000 +Windsor and Maidenhead,E06000040,2,307000,695000 +Windsor and Maidenhead,E06000040,3,422000,974000 +Windsor and Maidenhead,E06000040,4,597000,2059000 +Wirral,E08000015,1,77000,350000 +Wirral,E08000015,2,89000,350000 +Wirral,E08000015,3,112000,375000 +Wirral,E08000015,4,161000,818000 +Woking,E07000217,1,191000,570000 +Woking,E07000217,2,279000,570000 +Woking,E07000217,3,393000,875000 +Woking,E07000217,4,538000,1750000 +Wokingham,E06000041,1,140000,546000 +Wokingham,E06000041,2,151000,546000 +Wokingham,E06000041,3,290000,686000 +Wokingham,E06000041,4,518000,1299000 +Wolverhampton,E08000031,1,43000,249000 +Wolverhampton,E08000031,2,69000,249000 +Wolverhampton,E08000031,3,101000,327000 +Wolverhampton,E08000031,4,170000,703000 +Worcester,E07000237,1,90000,309000 +Worcester,E07000237,2,138000,309000 +Worcester,E07000237,3,190000,423000 +Worcester,E07000237,4,290000,793000 +Worthing,E07000229,1,148000,460000 +Worthing,E07000229,2,188000,465000 +Worthing,E07000229,3,297000,586000 +Worthing,E07000229,4,393000,864000 +Wychavon,E07000238,1,100000,432000 +Wychavon,E07000238,2,100000,452000 +Wychavon,E07000238,3,167000,546000 +Wychavon,E07000238,4,320000,969000 +Wyre,E07000128,1,72000,328000 +Wyre,E07000128,2,87000,328000 +Wyre,E07000128,3,114000,381000 +Wyre,E07000128,4,199000,648000 +Wyre Forest,E07000239,1,93000,358000 +Wyre Forest,E07000239,2,100000,358000 +Wyre Forest,E07000239,3,146000,398000 +Wyre Forest,E07000239,4,231000,825000 +York,E06000014,1,105000,414000 +York,E06000014,2,173000,414000 +York,E06000014,3,220000,529000 +York,E06000014,4,322000,983000 From ef0fc992e79d5712ea8ebc13a2e159747e9497c6 Mon Sep 17 00:00:00 2001 From: natdeanlewissoftwire <94526761+natdeanlewissoftwire@users.noreply.github.com> Date: Thu, 16 Feb 2023 10:18:37 +0000 Subject: [PATCH 13/25] CLDC-1906 infer offered (#1298) * feat: infer offered if renewal * feat: update test * db:update --- app/models/derived_variables/lettings_log_variables.rb | 1 + db/schema.rb | 2 +- spec/models/lettings_log_spec.rb | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/models/derived_variables/lettings_log_variables.rb b/app/models/derived_variables/lettings_log_variables.rb index 96b937ab4..526963d9c 100644 --- a/app/models/derived_variables/lettings_log_variables.rb +++ b/app/models/derived_variables/lettings_log_variables.rb @@ -45,6 +45,7 @@ module DerivedVariables::LettingsLogVariables self.underoccupation_benefitcap = 2 if collection_start_year == 2021 self.referral = 1 self.waityear = 2 + self.offered = 0 if is_general_needs? # fixed term self.prevten = 32 if managing_organisation&.provider_type == "PRP" diff --git a/db/schema.rb b/db/schema.rb index ffea32c01..2c1ff7692 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -524,8 +524,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_02_10_143120) do t.integer "details_known_5" t.integer "details_known_6" t.integer "saledate_check" - t.integer "staircasesale" t.integer "prevshared" + t.integer "staircasesale" t.integer "ethnic_group2" t.integer "ethnicbuy2" t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id" diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb index c8cdc466e..abe3057a6 100644 --- a/spec/models/lettings_log_spec.rb +++ b/spec/models/lettings_log_spec.rb @@ -1946,12 +1946,12 @@ RSpec.describe LettingsLog do end context "when a non select question associated with several pages is routed to" do - let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, period: 2) } + let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, period: 2, needstype: 1) } it "does not clear the answer value" do - lettings_log.update!({ offered: 4 }) + lettings_log.update!({ unitletas: 1 }) lettings_log.reload - expect(lettings_log.offered).to eq(4) + expect(lettings_log.unitletas).to eq(1) end end From b973e8348e4e013350186264eb2778a919cbdf5d Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Thu, 16 Feb 2023 12:16:39 +0000 Subject: [PATCH 14/25] CLDC-1861 Update options order for lead tenant's working situation (#1289) * Switch the first two options so Full time comes before Part time * Enable dates validations on staging --- app/models/form/lettings/questions/working_situation1.rb | 2 +- config/initializers/feature_toggle.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/form/lettings/questions/working_situation1.rb b/app/models/form/lettings/questions/working_situation1.rb index 866271f4d..20f5dc984 100644 --- a/app/models/form/lettings/questions/working_situation1.rb +++ b/app/models/form/lettings/questions/working_situation1.rb @@ -11,8 +11,8 @@ class Form::Lettings::Questions::WorkingSituation1 < ::Form::Question end ANSWER_OPTIONS = { - "2" => { "value" => "Part-time – Less than 30 hours" }, "1" => { "value" => "Full-time – 30 hours or more" }, + "2" => { "value" => "Part-time – Less than 30 hours" }, "7" => { "value" => "Full-time student" }, "3" => { "value" => "In government training into work, such as New Deal" }, "4" => { "value" => "Jobseeker" }, diff --git a/config/initializers/feature_toggle.rb b/config/initializers/feature_toggle.rb index 37f6aa653..d31ee184b 100644 --- a/config/initializers/feature_toggle.rb +++ b/config/initializers/feature_toggle.rb @@ -1,14 +1,14 @@ class FeatureToggle def self.startdate_two_week_validation_enabled? - Rails.env.production? || Rails.env.test? + Rails.env.production? || Rails.env.test? || Rails.env.staging? end def self.startdate_collection_window_validation_enabled? - Rails.env.production? || Rails.env.test? + Rails.env.production? || Rails.env.test? || Rails.env.staging? end def self.saledate_collection_window_validation_enabled? - Rails.env.production? || Rails.env.test? + Rails.env.production? || Rails.env.test? || Rails.env.staging? end def self.sales_log_enabled? From 293077695ca5e10077915681664c6f61a2e5ebd8 Mon Sep 17 00:00:00 2001 From: James Rose Date: Thu, 16 Feb 2023 12:32:19 +0000 Subject: [PATCH 15/25] Allow issues/pull-request write permissions for GitHub token (#1310) --- .github/workflows/review_pipeline.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/review_pipeline.yml b/.github/workflows/review_pipeline.yml index 1e7ae0efb..5656898bc 100644 --- a/.github/workflows/review_pipeline.yml +++ b/.github/workflows/review_pipeline.yml @@ -72,6 +72,9 @@ jobs: runs-on: ubuntu-latest environment: staging needs: [postgres, redis] + permissions: + issues: write + pull-requests: write steps: - name: Checkout code From d8689c30a2bc493167602ce5c5cbf755b336d758 Mon Sep 17 00:00:00 2001 From: Jack <113976590+bibblobcode@users.noreply.github.com> Date: Thu, 16 Feb 2023 12:33:58 +0000 Subject: [PATCH 16/25] CLDC-1968 Add review page for Sales logs (#1292) * CLDC-1968 Add review page for Sales logs * use log#sales? * Do not use type checking --- Gemfile | 2 +- app/helpers/tasklist_helper.rb | 4 ++- app/models/lettings_log.rb | 12 +++++--- app/models/log.rb | 4 +++ app/models/sales_log.rb | 8 ++++++ app/views/form/review.html.erb | 40 ++++++++++++++++----------- config/routes.rb | 4 +++ spec/helpers/tasklist_helper_spec.rb | 2 +- spec/models/lettings_log_spec.rb | 5 ++++ spec/models/sales_log_spec.rb | 7 ++++- spec/requests/form_controller_spec.rb | 6 ++++ 11 files changed, 70 insertions(+), 24 deletions(-) diff --git a/Gemfile b/Gemfile index b20b7fe97..f77a70899 100644 --- a/Gemfile +++ b/Gemfile @@ -68,6 +68,7 @@ group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem "byebug", platforms: %i[mri mingw x64_mingw] gem "dotenv-rails" + gem "factory_bot_rails" gem "pry-byebug" gem "parallel_tests" @@ -90,7 +91,6 @@ end group :test do gem "capybara", require: false gem "capybara-lockstep" - gem "factory_bot_rails" gem "faker" gem "rspec-rails", require: false gem "selenium-webdriver", require: false diff --git a/app/helpers/tasklist_helper.rb b/app/helpers/tasklist_helper.rb index f297de2ff..f4f1d51dd 100644 --- a/app/helpers/tasklist_helper.rb +++ b/app/helpers/tasklist_helper.rb @@ -39,7 +39,9 @@ module TasklistHelper def review_log_text(log) if log.collection_period_open? - "You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(log)} until #{log.form.end_date.to_formatted_s(:govuk_date)}.".html_safe + link = log.sales? ? review_sales_log_path(id: log, sales_log: true) : review_lettings_log_path(log) + + "You can #{govuk_link_to 'review and make changes to this log', link} until #{log.form.end_date.to_formatted_s(:govuk_date)}.".html_safe else "This log is from the #{log.form.start_date.year}/#{log.form.start_date.year + 1} collection window, which is now closed." end diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index 66f622270..02236f70b 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -70,6 +70,14 @@ class LettingsLog < Log collection_start_year end + def lettings? + true + end + + def sales? + false + end + def form_name return unless startdate @@ -481,10 +489,6 @@ class LettingsLog < Log location.type_of_unit_before_type_cast if location end - def lettings? - true - end - def rent_type_detail form.get_question("rent_type", self)&.label_from_value(rent_type) end diff --git a/app/models/log.rb b/app/models/log.rb index 1b43fd1cb..0cd3add92 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -43,6 +43,10 @@ class Log < ApplicationRecord false end + def sales? + false + end + def ethnic_refused? ethnic_group == 17 end diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index add706f7c..6ed653955 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -38,6 +38,14 @@ class SalesLog < Log 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 lettings? + false + end + + def sales? + true + end + def startdate saledate end diff --git a/app/views/form/review.html.erb b/app/views/form/review.html.erb index a95b577bd..bc46c89d8 100644 --- a/app/views/form/review.html.erb +++ b/app/views/form/review.html.erb @@ -1,9 +1,18 @@ -<% content_for :title, "Review lettings log" %> -<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { - "Logs" => "/logs", - "Log #{@log.id}" => "/lettings-logs/#{@log.id}", - "Review lettings log" => "", -}) %> +<% if @log.sales? %> + <% content_for :title, "Review sales log" %> + <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { + "Logs" => "/logs", + "Log #{@log.id}" => "/sales-logs/#{@log.id}", + "Review sales log" => "", + }) %> +<% else %> + <% content_for :title, "Review lettings log" %> + <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { + "Logs" => "/logs", + "Log #{@log.id}" => "/lettings-logs/#{@log.id}", + "Review lettings log" => "", + }) %> +<% end %>
@@ -16,17 +25,16 @@ <% @log.form.sections.map do |section| %>

<%= section.label %>

<% section.subsections.map do |subsection| %> -
-
-

<%= subsection.label %>

+ <% if total_applicable_questions(subsection, @log, current_user).any? %> +
+
+

<%= subsection.label %>

+
+
+ <%= render partial: "form/check_answers_summary_list", locals: { subsection: } %> +
-
- <%= render partial: "form/check_answers_summary_list", locals: { - subsection:, - lettings_log: @log, - } %> -
-
+ <% end %> <% end %> <% end %>
diff --git a/config/routes.rb b/config/routes.rb index be765c8c0..74b613989 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -171,6 +171,10 @@ Rails.application.routes.draw do resources :bulk_upload_sales_results, path: "bulk-upload-results", only: [:show] end + member do + get "review", to: "form#review" + end + FormHandler.instance.sales_forms.each do |_key, form| form.pages.map do |page| get page.id.to_s.dasherize, to: "form#show_page" diff --git a/spec/helpers/tasklist_helper_spec.rb b/spec/helpers/tasklist_helper_spec.rb index f7726745d..e14e06ea4 100644 --- a/spec/helpers/tasklist_helper_spec.rb +++ b/spec/helpers/tasklist_helper_spec.rb @@ -136,7 +136,7 @@ RSpec.describe TasklistHelper do it "returns relevant text" do expect(review_log_text(sales_log)).to eq( - "You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(sales_log)} until 1 July 2023.".html_safe, + "You can #{govuk_link_to 'review and make changes to this log', review_sales_log_path(id: sales_log, sales_log: true)} until 1 July 2023.".html_safe, ) end end diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb index abe3057a6..2aee5ddcf 100644 --- a/spec/models/lettings_log_spec.rb +++ b/spec/models/lettings_log_spec.rb @@ -18,6 +18,11 @@ RSpec.describe LettingsLog do expect(described_class).to be < ApplicationRecord end + it "is a not a sales log" do + lettings_log = FactoryBot.build(:lettings_log, created_by: created_by_user) + expect(lettings_log.sales?).to be false + end + it "is a lettings log" do lettings_log = FactoryBot.build(:lettings_log, created_by: created_by_user) expect(lettings_log).to be_lettings diff --git a/spec/models/sales_log_spec.rb b/spec/models/sales_log_spec.rb index 42bf9d4cd..523c2924b 100644 --- a/spec/models/sales_log_spec.rb +++ b/spec/models/sales_log_spec.rb @@ -12,11 +12,16 @@ RSpec.describe SalesLog, type: :model do expect(described_class).to be < ApplicationRecord end - it "is a sales log" do + it "is a not a lettings log" do sales_log = build(:sales_log, created_by: created_by_user) expect(sales_log.lettings?).to be false end + it "is a sales log" do + sales_log = build(:sales_log, created_by: created_by_user) + expect(sales_log.sales?).to be true + end + describe "#new" do context "when creating a record" do let(:sales_log) do diff --git a/spec/requests/form_controller_spec.rb b/spec/requests/form_controller_spec.rb index dcf67cb71..d5a8dbcf8 100644 --- a/spec/requests/form_controller_spec.rb +++ b/spec/requests/form_controller_spec.rb @@ -314,6 +314,12 @@ RSpec.describe FormController, type: :request do get "/lettings-logs/#{setup_complete_lettings_log.id}/review", headers: headers, params: {} expect(response.body).to match("Review lettings log") end + + it "renders the review page for the sales log" do + log = create(:sales_log, :completed, created_by: user) + get "/sales-logs/#{log.id}/review", headers: headers, params: { sales_log: true } + expect(response.body).to match("Review sales log") + end end context "when viewing a user dependent page" do From 65bde2b7f55a2f56f7442642f68f033a261e000f Mon Sep 17 00:00:00 2001 From: Jack <113976590+bibblobcode@users.noreply.github.com> Date: Thu, 16 Feb 2023 12:34:22 +0000 Subject: [PATCH 17/25] CLDC-1903 Infer first time property let question (#1300) --- .../lettings_log_variables.rb | 3 ++- lib/tasks/data_export.rake | 18 ------------------ spec/models/lettings_log_spec.rb | 9 +++++++++ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/app/models/derived_variables/lettings_log_variables.rb b/app/models/derived_variables/lettings_log_variables.rb index 526963d9c..7d664e48f 100644 --- a/app/models/derived_variables/lettings_log_variables.rb +++ b/app/models/derived_variables/lettings_log_variables.rb @@ -46,6 +46,8 @@ module DerivedVariables::LettingsLogVariables self.referral = 1 self.waityear = 2 self.offered = 0 + self.voiddate = startdate + self.first_time_property_let_as_social_housing = 0 if is_general_needs? # fixed term self.prevten = 32 if managing_organisation&.provider_type == "PRP" @@ -61,7 +63,6 @@ module DerivedVariables::LettingsLogVariables if is_supported_housing? && location self.wchair = location.mobility_type_before_type_cast == "W" ? 1 : 2 end - self.voiddate = startdate if is_renewal? self.vacdays = property_vacant_days set_housingneeds_fields if housingneeds? diff --git a/lib/tasks/data_export.rake b/lib/tasks/data_export.rake index 17f258293..a86712d83 100644 --- a/lib/tasks/data_export.rake +++ b/lib/tasks/data_export.rake @@ -11,21 +11,3 @@ namespace :core do DataExportXmlJob.perform_later(full_update:) end end - -namespace :illness_type_0 do - desc "Export log data where illness_type_0 == 1" - task export: :environment do |_task| - logs = LettingsLog.where(illness_type_0: 1, status: "completed").includes(created_by: :organisation) - puts "log_id,created_by_id,organisation_id,organisation_name,startdate" - - logs.each do |log| - puts [ - log.id, - log.created_by_id, - log.created_by.organisation.id, - log.created_by.organisation.name, - log.startdate&.strftime("%d/%m/%Y"), - ].join(",") - end - end -end diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb index 2aee5ddcf..d4bbd8378 100644 --- a/spec/models/lettings_log_spec.rb +++ b/spec/models/lettings_log_spec.rb @@ -1459,6 +1459,15 @@ RSpec.describe LettingsLog do expect(record_from_db["vacdays"]).to eq(0) expect(lettings_log["vacdays"]).to eq(0) end + + it "correctly derives and saves first_time_property_let_as_social_housing" do + record_from_db = ActiveRecord::Base.connection.execute( + "select first_time_property_let_as_social_housing" \ + " from lettings_logs where id=#{lettings_log.id}", + ).to_a[0] + expect(record_from_db["first_time_property_let_as_social_housing"]).to eq(0) + expect(lettings_log["first_time_property_let_as_social_housing"]).to eq(0) + end end context "when answering the household characteristics questions" do From b6ff8bf896ed93df4769651e01c721b8e93f45b2 Mon Sep 17 00:00:00 2001 From: Jack <113976590+bibblobcode@users.noreply.github.com> Date: Fri, 17 Feb 2023 09:38:25 +0000 Subject: [PATCH 18/25] CLDC-1909 Add 2023-2024 collection year filter (#1314) --- app/helpers/filters_helper.rb | 8 ++++++++ app/views/logs/_log_filters.erb | 3 +-- config/initializers/feature_toggle.rb | 4 ++++ spec/helpers/filters_helper_spec.rb | 26 ++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index a1875081c..7f906b4ea 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -27,4 +27,12 @@ module FiltersHelper organisation_options = user.support? ? Organisation.all : [user.organisation] + user.organisation.managing_agents [OpenStruct.new(id: "", name: "Select an option")] + organisation_options.map { |org| OpenStruct.new(id: org.id, name: org.name) } end + + def collection_year_options + if FeatureToggle.collection_2023_2024_year_enabled? + { "2023": "2023/24", "2022": "2022/23", "2021": "2021/22" } + else + { "2022": "2022/23", "2021": "2021/22" } + end + end end diff --git a/app/views/logs/_log_filters.erb b/app/views/logs/_log_filters.erb index 8fb4f2ba4..a1aa752c3 100644 --- a/app/views/logs/_log_filters.erb +++ b/app/views/logs/_log_filters.erb @@ -6,7 +6,6 @@
<%= form_with html: { method: :get } do |f| %> - <% years = { "2021": "2021/22", "2022": "2022/23" } %> <% all_or_yours = { "all": { label: "All" }, "yours": { label: "Yours" } } %> <% if bulk_upload_options(@bulk_upload).present? %> @@ -23,7 +22,7 @@ <%= render partial: "filters/checkbox_filter", locals: { f: f, - options: years, + options: collection_year_options, label: "Collection year", category: "years", } %> diff --git a/config/initializers/feature_toggle.rb b/config/initializers/feature_toggle.rb index d31ee184b..60a97c95c 100644 --- a/config/initializers/feature_toggle.rb +++ b/config/initializers/feature_toggle.rb @@ -42,4 +42,8 @@ class FeatureToggle def self.validate_valid_radio_options? !(Rails.env.production? || Rails.env.staging?) end + + def self.collection_2023_2024_year_enabled? + !Rails.env.production? + end end diff --git a/spec/helpers/filters_helper_spec.rb b/spec/helpers/filters_helper_spec.rb index 656578326..3eccac743 100644 --- a/spec/helpers/filters_helper_spec.rb +++ b/spec/helpers/filters_helper_spec.rb @@ -116,4 +116,30 @@ RSpec.describe FiltersHelper do end end end + + describe "#collection_year_options" do + context "when not production" do + it "includes 2023/2024 option" do + expect(collection_year_options).to eq( + { + "2021": "2021/22", "2022": "2022/23", "2023": "2023/24" + }, + ) + end + end + + context "when production" do + before do + allow(Rails.env).to receive(:production?).and_return(true) + end + + it "includes 2023/2024 option" do + expect(collection_year_options).to eq( + { + "2021": "2021/22", "2022": "2022/23" + }, + ) + end + end + end end From 26aa5244bb003c829d281457f45775724abbe03f Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Fri, 17 Feb 2023 09:42:58 +0000 Subject: [PATCH 19/25] mass update gems used by docs (#1313) --- docs/Gemfile.lock | 63 ++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 8d38e2e0a..c8a433b8f 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,12 +1,11 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.6) + activesupport (7.0.4.2) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) addressable (2.8.1) public_suffix (>= 2.0.2, < 6.0) coffee-script (2.4.1) @@ -14,30 +13,30 @@ GEM execjs coffee-script-source (1.11.1) colorator (1.1.0) - commonmarker (0.23.6) - concurrent-ruby (1.1.10) + commonmarker (0.23.8) + concurrent-ruby (1.2.0) dnsruby (1.61.9) simpleidn (~> 0.1) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) - ethon (0.15.0) + ethon (0.16.0) ffi (>= 1.15.0) eventmachine (1.2.7) execjs (2.8.1) - faraday (2.5.2) + faraday (2.7.4) faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.0) + faraday-net_http (3.0.2) ffi (1.15.5) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (227) + github-pages (228) github-pages-health-check (= 1.17.9) - jekyll (= 3.9.2) + jekyll (= 3.9.3) jekyll-avatar (= 0.7.0) jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.2.0) + jekyll-commonmark-ghpages (= 0.4.0) jekyll-default-layout (= 0.1.4) jekyll-feed (= 0.15.1) jekyll-gist (= 1.5.0) @@ -71,7 +70,7 @@ GEM jemoji (= 0.12.0) kramdown (= 2.3.2) kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.3) + liquid (= 4.0.4) mercenary (~> 0.3) minima (= 2.5.1) nokogiri (>= 1.13.6, < 2.0) @@ -83,17 +82,17 @@ GEM octokit (~> 4.0) public_suffix (>= 3.0, < 5.0) typhoeus (~> 1.3) - html-pipeline (2.14.2) + html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.8.0) - i18n (0.9.5) + i18n (1.12.0) concurrent-ruby (~> 1.0) - jekyll (3.9.2) + jekyll (3.9.3) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) - i18n (~> 0.7) + i18n (>= 0.7, < 2) jekyll-sass-converter (~> 1.0) jekyll-watch (~> 2.0) kramdown (>= 1.17, < 3) @@ -109,11 +108,11 @@ GEM coffee-script-source (~> 1.11.1) jekyll-commonmark (1.4.0) commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.2.0) - commonmarker (~> 0.23.4) + jekyll-commonmark-ghpages (0.4.0) + commonmarker (~> 0.23.7) jekyll (~> 3.9.0) jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 4.0) + rouge (>= 2.0, < 5.0) jekyll-default-layout (0.1.4) jekyll (~> 3.0) jekyll-feed (0.15.1) @@ -201,8 +200,8 @@ GEM rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - liquid (4.0.3) - listen (3.7.1) + liquid (4.0.4) + listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.3.6) @@ -210,12 +209,12 @@ GEM jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.16.3) - nokogiri (1.13.10-arm64-darwin) + minitest (5.17.0) + nokogiri (1.14.2-arm64-darwin) racc (~> 1.4) - nokogiri (1.13.10-x86_64-darwin) + nokogiri (1.14.2-x86_64-darwin) racc (~> 1.4) - nokogiri (1.13.10-x86_64-linux) + nokogiri (1.14.2-x86_64-linux) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) @@ -223,7 +222,7 @@ GEM pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.7) - racc (1.6.1) + racc (1.6.2) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) @@ -244,17 +243,15 @@ GEM unf (~> 0.1.4) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - thread_safe (0.3.6) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.10) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unf (0.1.4) unf_ext unf_ext (0.0.8.2) unicode-display_width (1.8.0) - webrick (1.7.0) - zeitwerk (2.6.0) + webrick (1.8.1) PLATFORMS arm64-darwin-21 From c19b200e84bfeb4989b9d9a1081c91277c170c87 Mon Sep 17 00:00:00 2001 From: James Rose Date: Fri, 17 Feb 2023 09:46:47 +0000 Subject: [PATCH 20/25] Add arcturus.net to whitelisted delivery domains (#1316) - We whitelist domains that we will deliver to in non-production environments - This adds arcturus.net so that they can conduct their pentest --- config/credentials.yml.enc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index 69dad9f7a..c9d564782 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc @@ -1 +1 @@ -PWC9A1AmalyFv4A63MG9jCm2YtwE1Eyu1BJKodtbmq2nW7FD9svZZ3V4yC0JO9J8sLfCS6UrxQC4TOKKYWP5iYpOr5TKPi9MqNCVueLsoErN+nMAPhCJVpl8+eJ4BOvNYGlmle4bcwbAvHLq6IoANTBjktFh5/tgJS+IHBWK1FwPzK1eAhgQ1fE1jluWslee4iYesmh+ufHIMZAkoWuGJVky4i4uN5nKnwQfaPN5MUxBlvGiDH+s+yex4pcIaJ6hxYWAQRZXJRQVpZcf/agwU0Tk/S/fuDMm8zVeHCQkkmsCYzH5czB8b8IWYwyslqFBZNCix7YnbgwgYk8MUh7wPBuF8CFoPKVyteqic9HgUp9KY8kkt/RcWJ4zpv+Vwz3cre+iZ3S1bxFcSxXqO0MGRug2H9iwhAnBQDLl3vXLNNRYEL5LhNv0Z9Cy7at1fnYe1FcvF+3DR9kG/RAYzR8S2eEDdzBl797+DG81yhfkjP3/gfWxD+J+Mx0F4SDEOaGK5c/MqNTdiRRbnhzuRaQFMg6itoJbZybe+EOQScNft1QLqC4QwPd4Qevhj/A=--QffpsNB1u+1Lk/tD--spkCqBIGHl8g6HGwd89yCg== \ No newline at end of file +EZNV2LiNWzf52erbQ41Dz3Bh+2f3Uih8liEyhXp5XzHCLzAbmN6/IJqr7b9cTZiCiroFo4n/dFoG3yYrospp3frKsDXxF1K2/MTCJWjpgnn7wc+HiPQWG0W3HRtQCNkyyrHes0YKcYyDWIP6kztYv1I/Me3p0pGEx6t3CpSTg1v46eRnOlDWiUz3rVxPauwq9IYZ75gmnThqvg/Z8wcYsWLx0arago0SXtRPASCNj4uO/lbqTcAfyIXOTSiOlcAIjoPFRSQY7UqY0o2p8jRR/1L16SmGDsk8ijm+UygNmMexa3Khy5WcKctpQICakHs4NRjHNflqgXpXKL9dVBmNc9d7h+gbhbGJQ53Y0d+a35UbhPRMiv4SRH98FwB+WEsLCDdGSHvdmM6ArfOLljTrqrsmSRf0JfUrvzyVYmMCxjv4xgJwUS/TD5lQD1yPwkp2ss00kQJqzNmB7qwFhA8a3e2iNzV8qtAV/Nj+tMlr99Hb7vZZs98/38G2p5RAsE/5Xl9taKhc/ACnVc/bwJND4JWaBB7duCa08xVB8nkjlt5cCwMurzAcy1ZT+e8JepR+g6s8fpScMEWVJXE0hd8=--rZ41rY9TMXmiBUJw--QiLRVNVXZzTW446s7cec1g== \ No newline at end of file From 02d8247f59cf29a57627a69b79a5721b7ff329c9 Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Fri, 17 Feb 2023 09:53:28 +0000 Subject: [PATCH 21/25] tweak bulk upload validation (#1302) - LA referral not permitted if general needs and now also if owning org is an LA --- app/services/bulk_upload/lettings/row_parser.rb | 6 +++--- spec/factories/organisation.rb | 4 ++++ .../bulk_upload/lettings/row_parser_spec.rb | 14 ++++++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/services/bulk_upload/lettings/row_parser.rb b/app/services/bulk_upload/lettings/row_parser.rb index bf1f62eba..005d5caf9 100644 --- a/app/services/bulk_upload/lettings/row_parser.rb +++ b/app/services/bulk_upload/lettings/row_parser.rb @@ -147,7 +147,7 @@ class BulkUpload::Lettings::RowParser validate :validate_nulls validate :validate_relevant_collection_window validate :validate_la_with_local_housing_referral - validate :validate_cannot_be_la_referral_if_general_needs + validate :validate_cannot_be_la_referral_if_general_needs_and_la validate :validate_leaving_reason_for_renewal validate :validate_lettings_type_matches_bulk_upload validate :validate_only_one_housing_needs_type @@ -219,8 +219,8 @@ private end end - def validate_cannot_be_la_referral_if_general_needs - if field_78 == 4 && bulk_upload.general_needs? + def validate_cannot_be_la_referral_if_general_needs_and_la + if field_78 == 4 && bulk_upload.general_needs? && owning_organisation && owning_organisation.la? errors.add :field_78, I18n.t("validations.household.referral.la_general_needs.prp_referred_by_la") end end diff --git a/spec/factories/organisation.rb b/spec/factories/organisation.rb index 147f847d6..7aee3ad66 100644 --- a/spec/factories/organisation.rb +++ b/spec/factories/organisation.rb @@ -13,6 +13,10 @@ FactoryBot.define do trait :with_old_visible_id do old_visible_id { rand(9_999_999).to_s } end + + trait :prp do + provider_type { "PRP" } + end end factory :organisation_rent_period do diff --git a/spec/services/bulk_upload/lettings/row_parser_spec.rb b/spec/services/bulk_upload/lettings/row_parser_spec.rb index 1bebd6444..4c0788033 100644 --- a/spec/services/bulk_upload/lettings/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/row_parser_spec.rb @@ -396,14 +396,24 @@ RSpec.describe BulkUpload::Lettings::RowParser do end end - context "when 4 ie referred by LA and is general needs" do - let(:attributes) { { bulk_upload:, field_78: "4" } } + context "when 4 ie referred by LA and is general needs and owning org is LA" do + let(:attributes) { { bulk_upload:, field_78: "4", field_111: owning_org.old_visible_id.to_s } } it "is not permitted" do expect(parser.errors[:field_78]).to be_present end end + context "when 4 ie referred by LA and is general needs and owning org is PRP" do + let(:owning_org) { create(:organisation, :prp, :with_old_visible_id) } + + let(:attributes) { { bulk_upload:, field_78: "4", field_111: owning_org.old_visible_id.to_s } } + + it "is permitted" do + expect(parser.errors[:field_78]).to be_blank + end + end + context "when 4 ie referred by LA and is not general needs" do let(:bulk_upload) { create(:bulk_upload, :lettings, user:, needstype: 2) } let(:attributes) { { bulk_upload:, field_78: "4" } } From 7c62d8b4a6445812d8d5f407195272053659010a Mon Sep 17 00:00:00 2001 From: James Rose Date: Fri, 17 Feb 2023 09:54:44 +0000 Subject: [PATCH 22/25] Change CDS export archive names from quarter to financial year (#1309) - We previously pushed logs into archives categorised by the quarter that they were created for. - CDS requested that instead we push everything into a larger bucket seperated by FY. --- app/helpers/collection_time_helper.rb | 20 ++++++-- .../exports/lettings_log_export_constants.rb | 7 --- .../exports/lettings_log_export_service.rb | 7 +-- spec/helpers/collection_time_helper_spec.rb | 46 +++++++++++++++++++ .../lettings_log_export_service_spec.rb | 8 ++-- 5 files changed, 69 insertions(+), 19 deletions(-) diff --git a/app/helpers/collection_time_helper.rb b/app/helpers/collection_time_helper.rb index 8478d06e7..be0abae20 100644 --- a/app/helpers/collection_time_helper.rb +++ b/app/helpers/collection_time_helper.rb @@ -1,16 +1,26 @@ module CollectionTimeHelper + def collection_start_year(date) + window_end_date = Time.zone.local(date.year, 4, 1) + date < window_end_date ? date.year - 1 : date.year + end + def current_collection_start_year - today = Time.zone.now - window_end_date = Time.zone.local(today.year, 4, 1) - today < window_end_date ? today.year - 1 : today.year + collection_start_year(Time.zone.now) end def collection_start_date(date) - window_end_date = Time.zone.local(date.year, 4, 1) - date < window_end_date ? Time.zone.local(date.year - 1, 4, 1) : Time.zone.local(date.year, 4, 1) + Time.zone.local(collection_start_year(date), 4, 1) end def current_collection_start_date Time.zone.local(current_collection_start_year, 4, 1) end + + def collection_end_date(date) + Time.zone.local(collection_start_year(date) + 1, 3, 31) + end + + def current_collection_end_date + Time.zone.local(current_collection_start_year + 1, 3, 31) + end end diff --git a/app/services/exports/lettings_log_export_constants.rb b/app/services/exports/lettings_log_export_constants.rb index 332f22550..3ae7d71fa 100644 --- a/app/services/exports/lettings_log_export_constants.rb +++ b/app/services/exports/lettings_log_export_constants.rb @@ -7,13 +7,6 @@ module Exports::LettingsLogExportConstants csv: 2, }.freeze - QUARTERS = { - 0 => "jan_mar", - 1 => "apr_jun", - 2 => "jul_sep", - 3 => "oct_dec", - }.freeze - EXPORT_FIELDS = Set[ "armedforces", "beds", diff --git a/app/services/exports/lettings_log_export_service.rb b/app/services/exports/lettings_log_export_service.rb index fb985f931..197e0ed4b 100644 --- a/app/services/exports/lettings_log_export_service.rb +++ b/app/services/exports/lettings_log_export_service.rb @@ -1,6 +1,7 @@ module Exports class LettingsLogExportService include Exports::LettingsLogExportConstants + include CollectionTimeHelper def initialize(storage_service, logger = Rails.logger) @storage_service = storage_service @@ -66,11 +67,11 @@ module Exports return unless lettings_log.startdate collection_start = lettings_log.collection_start_year - month = lettings_log.startdate.month - quarter = QUARTERS[(month - 1) / 3] + start_month = collection_start_date(lettings_log.startdate).strftime("%b") + end_month = collection_end_date(lettings_log.startdate).strftime("%b") base_number_str = "f#{base_number.to_s.rjust(4, '0')}" increment_str = "inc#{increment.to_s.rjust(4, '0')}" - "core_#{collection_start}_#{collection_start + 1}_#{quarter}_#{base_number_str}_#{increment_str}" + "core_#{collection_start}_#{collection_start + 1}_#{start_month}_#{end_month}_#{base_number_str}_#{increment_str}".downcase end def write_export_archive(export, lettings_logs) diff --git a/spec/helpers/collection_time_helper_spec.rb b/spec/helpers/collection_time_helper_spec.rb index 3b02802f2..c2eb2fedb 100644 --- a/spec/helpers/collection_time_helper_spec.rb +++ b/spec/helpers/collection_time_helper_spec.rb @@ -21,6 +21,10 @@ RSpec.describe CollectionTimeHelper do it "returns the correct current start date" do expect(current_collection_start_date).to eq(Time.zone.local(2022, 4, 1)) end + + it "returns the correct current end date" do + expect(current_collection_end_date).to eq(Time.zone.local(2023, 3, 31)) + end end context "with the date before 1st of April" do @@ -29,6 +33,48 @@ RSpec.describe CollectionTimeHelper do it "returns the previous year as the current start year" do expect(current_collection_start_year).to eq(2021) end + + it "returns the correct current start date" do + expect(current_collection_start_date).to eq(Time.zone.local(2021, 4, 1)) + end + + it "returns the correct current end date" do + expect(current_collection_end_date).to eq(Time.zone.local(2022, 3, 31)) + end + end + end + + describe "Any collection year" 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(collection_start_year(now)).to eq(2022) + end + + it "returns the correct current start date" do + expect(collection_start_date(now)).to eq(Time.zone.local(2022, 4, 1)) + end + + it "returns the correct current end date" do + expect(collection_end_date(now)).to eq(Time.zone.local(2023, 3, 31)) + 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(collection_start_year(now)).to eq(2021) + end + + it "returns the correct current start date" do + expect(collection_start_date(now)).to eq(Time.zone.local(2021, 4, 1)) + end + + it "returns the correct current end date" do + expect(collection_end_date(now)).to eq(Time.zone.local(2022, 3, 31)) + end end end end diff --git a/spec/services/exports/lettings_log_export_service_spec.rb b/spec/services/exports/lettings_log_export_service_spec.rb index 36adda071..55897c354 100644 --- a/spec/services/exports/lettings_log_export_service_spec.rb +++ b/spec/services/exports/lettings_log_export_service_spec.rb @@ -13,8 +13,8 @@ RSpec.describe Exports::LettingsLogExportService do let(:expected_master_manifest_filename) { "Manifest_2022_05_01_0001.csv" } let(:expected_master_manifest_rerun) { "Manifest_2022_05_01_0002.csv" } - let(:expected_zip_filename) { "core_2021_2022_jan_mar_f0001_inc0001.zip" } - let(:expected_data_filename) { "core_2021_2022_jan_mar_f0001_inc0001_pt001.xml" } + let(:expected_zip_filename) { "core_2021_2022_apr_mar_f0001_inc0001.zip" } + let(:expected_data_filename) { "core_2021_2022_apr_mar_f0001_inc0001_pt001.xml" } let(:expected_manifest_filename) { "manifest.xml" } let(:start_time) { Time.zone.local(2022, 5, 1) } @@ -108,7 +108,7 @@ RSpec.describe Exports::LettingsLogExportService do end context "and multiple lettings logs are available for export on different periods" do - let(:expected_zip_filename2) { "core_2022_2023_apr_jun_f0001_inc0001.zip" } + let(:expected_zip_filename2) { "core_2022_2023_apr_mar_f0001_inc0001.zip" } before do FactoryBot.create(:lettings_log, startdate: Time.zone.local(2022, 2, 1)) @@ -206,7 +206,7 @@ RSpec.describe Exports::LettingsLogExportService do end it "generates a ZIP export file with the expected filename" do - expect(storage_service).to receive(:write_file).with("core_2021_2022_jan_mar_f0002_inc0001.zip", any_args) + expect(storage_service).to receive(:write_file).with("core_2021_2022_apr_mar_f0002_inc0001.zip", any_args) export_service.export_xml_lettings_logs(full_update: true) end end From 5490e2ecb037cb75ec5eac323631c6b2d1eeef27 Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Fri, 17 Feb 2023 10:20:39 +0000 Subject: [PATCH 23/25] CLDC-1892 Bulk upload validation for managing organisation (#1315) * bulk upload validation for owning org * block log creation at row parser level * bubble up block_log_creation so it blocks logs * owning org id looks up serveral fields * validate bulk upload managing org --- app/models/organisation.rb | 27 ++++++ .../bulk_upload/lettings/row_parser.rb | 67 ++++++++++++-- .../bulk_upload/lettings/validator.rb | 1 + spec/factories/organisation.rb | 4 + .../bulk_upload/lettings/row_parser_spec.rb | 88 +++++++++++++++++++ .../bulk_upload/lettings/validator_spec.rb | 20 ++++- 6 files changed, 199 insertions(+), 8 deletions(-) diff --git a/app/models/organisation.rb b/app/models/organisation.rb index 89d7d1f34..32d3540d1 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -17,8 +17,21 @@ class Organisation < ApplicationRecord has_many :managing_agent_relationships, foreign_key: :parent_organisation_id, class_name: "OrganisationRelationship" has_many :managing_agents, through: :managing_agent_relationships, source: :child_organisation + def affiliated_stock_owners + ids = [] + + if holds_own_stock? && persisted? + ids << id + end + + ids.concat(stock_owners.pluck(:id)) + + Organisation.where(id: ids) + end + scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") } scope :search_by, ->(param) { search_by_name(param) } + has_paper_trail auto_strip_attributes :name @@ -35,6 +48,20 @@ class Organisation < ApplicationRecord validates :name, presence: { message: I18n.t("validations.organisation.name_missing") } validates :provider_type, presence: { message: I18n.t("validations.organisation.provider_type_missing") } + def self.find_by_id_on_mulitple_fields(id) + return if id.nil? + + if id.start_with?("ORG") + where(id: id[3..]).first + else + where(old_visible_id: id).first + end + end + + def can_be_managed_by?(organisation:) + organisation == self || managing_agents.include?(organisation) + end + def lettings_logs LettingsLog.filter_by_organisation(self) end diff --git a/app/services/bulk_upload/lettings/row_parser.rb b/app/services/bulk_upload/lettings/row_parser.rb index 005d5caf9..bdb35dbc6 100644 --- a/app/services/bulk_upload/lettings/row_parser.rb +++ b/app/services/bulk_upload/lettings/row_parser.rb @@ -3,6 +3,7 @@ class BulkUpload::Lettings::RowParser include ActiveModel::Attributes attribute :bulk_upload + attribute :block_log_creation, :boolean, default: -> { false } attribute :field_1, :integer attribute :field_2 @@ -114,9 +115,9 @@ class BulkUpload::Lettings::RowParser attribute :field_108, :string attribute :field_109, :string attribute :field_110 - attribute :field_111, :integer + attribute :field_111, :string attribute :field_112, :string - attribute :field_113, :integer + attribute :field_113, :string attribute :field_114, :integer attribute :field_115 attribute :field_116, :integer @@ -155,6 +156,13 @@ class BulkUpload::Lettings::RowParser validate :validate_dont_know_disabled_needs_conjunction validate :validate_no_and_dont_know_disabled_needs_conjunction + validate :validate_owning_org_permitted + validate :validate_owning_org_owns_stock + validate :validate_owning_org_exists + + validate :validate_managing_org_related + validate :validate_managing_org_exists + def valid? errors.clear @@ -173,15 +181,60 @@ class BulkUpload::Lettings::RowParser end def blank_row? - attribute_set.to_hash.reject { |k, _| %w[bulk_upload].include?(k) }.values.compact.empty? + attribute_set.to_hash.reject { |k, _| %w[bulk_upload block_log_creation].include?(k) }.values.compact.empty? end def log @log ||= LettingsLog.new(attributes_for_log) end + def block_log_creation! + self.block_log_creation = true + end + + def block_log_creation? + block_log_creation + end + private + def validate_managing_org_related + if owning_organisation && managing_organisation && !owning_organisation.can_be_managed_by?(organisation: managing_organisation) + block_log_creation! + errors.add(:field_113, "This managing organisation does not have a relationship with the owning organisation") + end + end + + def validate_managing_org_exists + if managing_organisation.nil? + errors.delete(:field_113) + errors.add(:field_113, "The managing organisation code is incorrect") + end + end + + def validate_owning_org_owns_stock + if owning_organisation && !owning_organisation.holds_own_stock? + block_log_creation! + errors.delete(:field_111) + errors.add(:field_111, "The owning organisation code provided is for an organisation that does not own stock") + end + end + + def validate_owning_org_exists + if owning_organisation.nil? + errors.delete(:field_111) + errors.add(:field_111, "The owning organisation code is incorrect") + end + end + + def validate_owning_org_permitted + if owning_organisation && !bulk_upload.user.organisation.affiliated_stock_owners.include?(owning_organisation) + block_log_creation! + errors.delete(:field_111) + errors.add(:field_111, "You do not have permission to add logs for this owning organisation") + end + end + def validate_no_and_dont_know_disabled_needs_conjunction if field_59 == 1 && field_60 == 1 errors.add(:field_59, I18n.t("validations.household.housingneeds.no_and_dont_know_disabled_needs_conjunction")) @@ -483,15 +536,19 @@ private end def owning_organisation - Organisation.find_by(old_visible_id: field_111) + Organisation.find_by_id_on_mulitple_fields(field_111) end def owning_organisation_id owning_organisation&.id end + def managing_organisation + Organisation.find_by_id_on_mulitple_fields(field_113) + end + def managing_organisation_id - Organisation.find_by(old_visible_id: field_113)&.id + managing_organisation&.id end def attributes_for_log diff --git a/app/services/bulk_upload/lettings/validator.rb b/app/services/bulk_upload/lettings/validator.rb index 6f37c0f3a..992f06196 100644 --- a/app/services/bulk_upload/lettings/validator.rb +++ b/app/services/bulk_upload/lettings/validator.rb @@ -176,6 +176,7 @@ class BulkUpload::Lettings::Validator def create_logs? return false if any_setup_sections_incomplete? return false if over_column_error_threshold? + return false if row_parsers.any?(&:block_log_creation?) row_parsers.all? { |row_parser| row_parser.log.valid? } end diff --git a/spec/factories/organisation.rb b/spec/factories/organisation.rb index 7aee3ad66..fa2650eb5 100644 --- a/spec/factories/organisation.rb +++ b/spec/factories/organisation.rb @@ -17,6 +17,10 @@ FactoryBot.define do trait :prp do provider_type { "PRP" } end + + trait :does_not_own_stock do + holds_own_stock { false } + end end factory :organisation_rent_period do diff --git a/spec/services/bulk_upload/lettings/row_parser_spec.rb b/spec/services/bulk_upload/lettings/row_parser_spec.rb index 4c0788033..36f145a5e 100644 --- a/spec/services/bulk_upload/lettings/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/row_parser_spec.rb @@ -8,8 +8,10 @@ RSpec.describe BulkUpload::Lettings::RowParser do let(:attributes) { { bulk_upload: } } let(:bulk_upload) { create(:bulk_upload, :lettings, user:) } let(:user) { create(:user, organisation: owning_org) } + let(:owning_org) { create(:organisation, :with_old_visible_id) } let(:managing_org) { create(:organisation, :with_old_visible_id) } + let(:setup_section_params) do { bulk_upload:, @@ -23,6 +25,10 @@ RSpec.describe BulkUpload::Lettings::RowParser do } end + before do + create(:organisation_relationship, parent_organisation: owning_org, child_organisation: managing_org) + end + around do |example| FormHandler.instance.use_real_forms! @@ -472,6 +478,68 @@ RSpec.describe BulkUpload::Lettings::RowParser do end end + describe "#field_111" do # owning org + context "when cannot find owning org" do + let(:attributes) { { bulk_upload:, field_111: "donotexist" } } + + it "is not permitted" do + expect(parser.errors[:field_111]).to eql(["The owning organisation code is incorrect"]) + end + end + + context "when org is not stock owning" do + let(:owning_org) { create(:organisation, :with_old_visible_id, :does_not_own_stock) } + + let(:attributes) { { bulk_upload:, field_111: owning_org.old_visible_id } } + + it "is not permitted" do + expect(parser.errors[:field_111]).to eql(["The owning organisation code provided is for an organisation that does not own stock"]) + end + + it "blocks log creation" do + expect(parser).to be_block_log_creation + end + end + + context "when not affiliated with owning org" do + let(:unaffiliated_org) { create(:organisation, :with_old_visible_id) } + + let(:attributes) { { bulk_upload:, field_111: unaffiliated_org.old_visible_id } } + + it "is not permitted" do + expect(parser.errors[:field_111]).to eql(["You do not have permission to add logs for this owning organisation"]) + end + + it "blocks log creation" do + expect(parser).to be_block_log_creation + end + end + end + + describe "#field_113" do # managing org + context "when cannot find managing org" do + let(:attributes) { { bulk_upload:, field_113: "donotexist" } } + + it "is not permitted" do + expect(parser.errors[:field_113]).to eql(["The managing organisation code is incorrect"]) + end + end + + context "when not affiliated with managing org" do + let(:unaffiliated_org) { create(:organisation, :with_old_visible_id) } + + let(:attributes) { { bulk_upload:, field_111: owning_org.old_visible_id, field_113: unaffiliated_org.old_visible_id } } + + it "is not permitted" do + expect(parser.errors[:field_113]).to eql(["This managing organisation does not have a relationship with the owning organisation"]) + end + + it "blocks log creation" do + expect(parser).to be_block_log_creation + end + end + end + describe "#field_134" do context "when an unpermitted value" do let(:attributes) { { bulk_upload:, field_134: 3 } } @@ -506,6 +574,26 @@ RSpec.describe BulkUpload::Lettings::RowParser do end describe "#log" do + describe "#owning_organisation" do + context "when lookup is via id prefixed with ORG" do + let(:attributes) { { bulk_upload:, field_111: "ORG#{owning_org.id}" } } + + it "assigns the correct org" do + expect(parser.log.owning_organisation).to eql(owning_org) + end + end + end + + describe "#managing_organisation" do + context "when lookup is via id prefixed with ORG" do + let(:attributes) { { bulk_upload:, field_113: "ORG#{managing_org.id}" } } + + it "assigns the correct org" do + expect(parser.log.managing_organisation).to eql(managing_org) + end + end + end + describe "#cbl" do context "when field_75 is yes ie 1" do let(:attributes) { { bulk_upload:, field_75: 1 } } diff --git a/spec/services/bulk_upload/lettings/validator_spec.rb b/spec/services/bulk_upload/lettings/validator_spec.rb index 263c83163..0aaeaac78 100644 --- a/spec/services/bulk_upload/lettings/validator_spec.rb +++ b/spec/services/bulk_upload/lettings/validator_spec.rb @@ -87,7 +87,7 @@ RSpec.describe BulkUpload::Lettings::Validator do end end - describe "#should_create_logs?" do + describe "#create_logs?" do context "when all logs are valid" do let(:target_path) { file_fixture("2022_23_lettings_bulk_upload.csv") } @@ -111,9 +111,7 @@ RSpec.describe BulkUpload::Lettings::Validator do expect(validator).not_to be_create_logs end end - end - describe "#create_logs?" do context "when a log is not valid?" do let(:log_1) { build(:lettings_log, :completed, created_by: user) } let(:log_2) { build(:lettings_log, :completed, created_by: user) } @@ -146,6 +144,22 @@ RSpec.describe BulkUpload::Lettings::Validator do end end + context "when a single log wants to block log creation" do + let(:unaffiliated_org) { create(:organisation) } + + let(:log_1) { build(:lettings_log, :completed, renttype: 1, created_by: user, owning_organisation: unaffiliated_org) } + + before do + file.write(BulkUpload::LogToCsv.new(log: log_1, line_ending: "\r\n", col_offset: 0).to_csv_row) + file.close + end + + it "will not create logs" do + validator.call + expect(validator).not_to be_create_logs + end + end + context "when a log has incomplete setup secion" do let(:log) { build(:lettings_log, :in_progress, created_by: user, startdate: Time.zone.local(2022, 5, 1)) } From b24ab538ce4ec8888fd7376e0ff52d6600b171d2 Mon Sep 17 00:00:00 2001 From: James Rose Date: Fri, 17 Feb 2023 12:07:14 +0000 Subject: [PATCH 24/25] Update collection year end dates for 2022 onwards (#1312) The source of truth for this update is: https://digital.dclg.gov.uk/confluence/pages/viewpage.action?spaceKey=MC&title=CORE+And+Collection+Years --- app/models/form.rb | 6 +++++- config/forms/2022_2023.json | 2 +- spec/helpers/tasklist_helper_spec.rb | 4 ++-- spec/models/form_spec.rb | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/models/form.rb b/app/models/form.rb index 3da85d52e..f9959959e 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -6,7 +6,11 @@ class Form def initialize(form_path, start_year = "", sections_in_form = [], type = "lettings") if sales_or_start_year_after_2022?(type, start_year) @start_date = Time.zone.local(start_year, 4, 1) - @end_date = Time.zone.local(start_year + 1, 7, 1) + @end_date = if start_year && start_year.to_i > 2022 + Time.zone.local(start_year + 1, 7, 9) + else + Time.zone.local(start_year + 1, 7, 7) + end @setup_sections = type == "sales" ? [Form::Sales::Sections::Setup.new(nil, nil, self)] : [Form::Lettings::Sections::Setup.new(nil, nil, self)] @form_sections = sections_in_form.map { |sec| sec.new(nil, nil, self) } @type = type diff --git a/config/forms/2022_2023.json b/config/forms/2022_2023.json index ebd1bd594..e0ef19198 100644 --- a/config/forms/2022_2023.json +++ b/config/forms/2022_2023.json @@ -1,7 +1,7 @@ { "form_type": "lettings", "start_date": "2022-04-01T00:00:00.000+01:00", - "end_date": "2023-07-01T00:00:00.000+01:00", + "end_date": "2023-07-09T00:00:00.000+01:00", "unresolved_log_redirect_page_id": "tenancy_start_date", "sections": { "tenancy_and_property": { diff --git a/spec/helpers/tasklist_helper_spec.rb b/spec/helpers/tasklist_helper_spec.rb index e14e06ea4..1ac6cf738 100644 --- a/spec/helpers/tasklist_helper_spec.rb +++ b/spec/helpers/tasklist_helper_spec.rb @@ -113,7 +113,7 @@ RSpec.describe TasklistHelper do it "returns relevant text" do expect(review_log_text(lettings_log)).to eq( - "You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(lettings_log)} until 1 July 2024.".html_safe, + "You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(lettings_log)} until 9 July 2024.".html_safe, ) end end @@ -136,7 +136,7 @@ RSpec.describe TasklistHelper do it "returns relevant text" do expect(review_log_text(sales_log)).to eq( - "You can #{govuk_link_to 'review and make changes to this log', review_sales_log_path(id: sales_log, sales_log: true)} until 1 July 2023.".html_safe, + "You can #{govuk_link_to 'review and make changes to this log', review_sales_log_path(id: sales_log, sales_log: true)} until 7 July 2023.".html_safe, ) end end diff --git a/spec/models/form_spec.rb b/spec/models/form_spec.rb index 72223c1b5..cd58587dc 100644 --- a/spec/models/form_spec.rb +++ b/spec/models/form_spec.rb @@ -223,7 +223,7 @@ RSpec.describe Form, type: :model do 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")) + expect(form.end_date).to eq(Time.zone.parse("2023-07-07")) expect(form.unresolved_log_redirect_page_id).to eq(nil) end From 01b957cc1093c6e9578062dc4fe57f1c165d4e65 Mon Sep 17 00:00:00 2001 From: Phil Lee Date: Fri, 17 Feb 2023 12:17:33 +0000 Subject: [PATCH 25/25] better validation on bulk upload start year (#1319) --- .../bulk_upload/lettings/row_parser.rb | 3 +++ config/locales/en.yml | 1 + .../bulk_upload/lettings/row_parser_spec.rb | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/app/services/bulk_upload/lettings/row_parser.rb b/app/services/bulk_upload/lettings/row_parser.rb index bdb35dbc6..9cb3edb78 100644 --- a/app/services/bulk_upload/lettings/row_parser.rb +++ b/app/services/bulk_upload/lettings/row_parser.rb @@ -143,6 +143,7 @@ class BulkUpload::Lettings::RowParser validates :field_1, presence: { message: I18n.t("validations.not_answered", question: "letting type") }, inclusion: { in: (1..12).to_a, message: I18n.t("validations.invalid_option", question: "letting type") } validates :field_4, presence: { if: proc { [2, 4, 6, 8, 10, 12].include?(field_1) } } + validates :field_98, format: { with: /\A\d{2}\z/, message: I18n.t("validations.setup.startdate.year_not_two_digits") } validate :validate_data_types validate :validate_nulls @@ -500,6 +501,8 @@ private def startdate Date.new(field_98 + 2000, field_97, field_96) if field_98.present? && field_97.present? && field_96.present? + rescue Date::Error + Date.new end def renttype diff --git a/config/locales/en.yml b/config/locales/en.yml index 23d39bbe8..747ed4414 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -156,6 +156,7 @@ en: before_scheme_end_date: "The tenancy start date must be before the end date for this supported housing scheme" after_void_date: "Enter a tenancy start date that is after the void date" after_major_repair_date: "Enter a tenancy start date that is after the major repair date" + year_not_two_digits: Tenancy start year must be 2 digits location: deactivated: "The location %{postcode} was deactivated on %{date} and was not available on the day you entered." reactivating_soon: "The location %{postcode} is not available until %{date}. Select another location or edit the tenancy start date" diff --git a/spec/services/bulk_upload/lettings/row_parser_spec.rb b/spec/services/bulk_upload/lettings/row_parser_spec.rb index 36f145a5e..d1792e9df 100644 --- a/spec/services/bulk_upload/lettings/row_parser_spec.rb +++ b/spec/services/bulk_upload/lettings/row_parser_spec.rb @@ -443,6 +443,24 @@ RSpec.describe BulkUpload::Lettings::RowParser do end end + context "when field 98 is 4 digits instead of 2" do + let(:attributes) { { bulk_upload:, field_98: "2022" } } + + it "returns an error" do + parser.valid? + + expect(parser.errors[:field_98]).to include("Tenancy start year must be 2 digits") + end + end + + context "when invalid date given" do + let(:attributes) { { bulk_upload:, field_1: "1", field_96: "a", field_97: "12", field_98: "2022" } } + + it "does not raise an error" do + expect { parser.valid? }.not_to raise_error + end + end + context "when inside of collection year" do let(:attributes) { { bulk_upload:, field_96: "1", field_97: "10", field_98: "22" } }