diff --git a/Gemfile b/Gemfile index aae99d51e..d80a159dd 100644 --- a/Gemfile +++ b/Gemfile @@ -18,7 +18,7 @@ gem "jsbundling-rails" # Reduces boot times through caching; required in config/boot.rb gem "bootsnap", ">= 1.4.4", require: false # GOV UK frontend components -gem "govuk-components", "~> 5.0" +gem "govuk-components", "~> 5.1" # GOV UK component form builder DSL gem "govuk_design_system_formbuilder", "~> 5.0" # Convert Markdown into GOV.UK frontend-styled HTML diff --git a/Gemfile.lock b/Gemfile.lock index 0970a7721..74e787baf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,10 +171,10 @@ GEM raabro (~> 1.4) globalid (1.1.0) activesupport (>= 5.0) - govuk-components (5.0.2) + govuk-components (5.1.0) html-attributes-utils (~> 1.0.0, >= 1.0.0) pagy (~> 6.0) - view_component (>= 3.9, < 3.10) + view_component (>= 3.9, < 3.11) govuk_design_system_formbuilder (5.0.0) actionview (>= 6.1) activemodel (>= 6.1) @@ -237,7 +237,7 @@ GEM childprocess (>= 0.6.3, < 5) iniparse (~> 1.4) rexml (~> 3.2) - pagy (6.2.0) + pagy (6.5.0) paper_trail (14.0.0) activerecord (>= 6.0) request_store (~> 1.4) @@ -458,7 +458,7 @@ DEPENDENCIES erb_lint factory_bot_rails faker - govuk-components (~> 5.0) + govuk-components (~> 5.1) govuk_design_system_formbuilder (~> 5.0) govuk_markdown jsbundling-rails diff --git a/app/components/sales_log_summary_component.html.erb b/app/components/sales_log_summary_component.html.erb index 82acc6e14..5c0668301 100644 --- a/app/components/sales_log_summary_component.html.erb +++ b/app/components/sales_log_summary_component.html.erb @@ -32,7 +32,7 @@
<%= log.owning_organisation&.name %>
<% end %> - <% if log.managing_organisation && FeatureToggle.sales_managing_organisation_enabled? %> + <% if log.managing_organisation %>
Reported by
<%= log.managing_organisation&.name %>
diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb index 0952d12ac..4612e6bc9 100644 --- a/app/controllers/organisations_controller.rb +++ b/app/controllers/organisations_controller.rb @@ -33,7 +33,7 @@ class OrganisationsController < ApplicationController organisation_schemes = Scheme.where(owning_organisation: [@organisation] + @organisation.parent_organisations) unpaginated_filtered_schemes = filter_manager.filtered_schemes(organisation_schemes, search_term, session_filters) - render "schemes/download_csv", locals: { search_term:, post_path: email_csv_schemes_path, download_type: params[:download_type], schemes: unpaginated_filtered_schemes } + render "schemes/download_csv", locals: { search_term:, post_path: schemes_email_csv_organisation_path, download_type: params[:download_type], schemes: unpaginated_filtered_schemes } end def email_schemes_csv diff --git a/app/helpers/collection_time_helper.rb b/app/helpers/collection_time_helper.rb index 6f8ef62fc..4381aa43a 100644 --- a/app/helpers/collection_time_helper.rb +++ b/app/helpers/collection_time_helper.rb @@ -46,6 +46,10 @@ module CollectionTimeHelper current_collection_start_date - 1.year end + def archived_collection_start_year + current_collection_start_year - 2 + end + def quarter_for_date(date: Time.zone.now) quarters = [ { quarter: "Q3", cutoff_date: Time.zone.local(2024, 1, 12), start_date: Time.zone.local(2023, 10, 1), end_date: Time.zone.local(2023, 12, 31) }, diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb index f35caf31f..8841a0d36 100644 --- a/app/helpers/filters_helper.rb +++ b/app/helpers/filters_helper.rb @@ -1,4 +1,6 @@ module FiltersHelper + include CollectionTimeHelper + def filter_selected?(filter, value, filter_type) return false unless session[session_name_for(filter_type)] @@ -93,7 +95,11 @@ module FiltersHelper end def collection_year_options - { "2023": "2023/24", "2022": "2022/23", "2021": "2021/22" } + { + current_collection_start_year.to_s => year_combo(current_collection_start_year), + previous_collection_start_year.to_s => year_combo(previous_collection_start_year), + archived_collection_start_year.to_s => year_combo(archived_collection_start_year), + } end def filters_applied_text(filter_type) @@ -174,4 +180,8 @@ private end end end + + def year_combo(year) + "#{year}/#{year - 2000 + 1}" + end end diff --git a/app/jobs/scheme_email_csv_job.rb b/app/jobs/scheme_email_csv_job.rb index 1dad752c5..9c3060cb9 100644 --- a/app/jobs/scheme_email_csv_job.rb +++ b/app/jobs/scheme_email_csv_job.rb @@ -6,7 +6,11 @@ class SchemeEmailCsvJob < ApplicationJob EXPIRATION_TIME = 24.hours.to_i def perform(user, search_term = nil, filters = {}, all_orgs = false, organisation = nil, download_type = "combined") # rubocop:disable Style/OptionalBooleanParameter - sidekiq can't serialise named params - unfiltered_schemes = organisation.present? && user.support? ? Scheme.where(owning_organisation_id: organisation.id) : user.schemes + unfiltered_schemes = if organisation.present? && user.support? + Scheme.where(owning_organisation: [organisation] + organisation.parent_organisations) + else + user.schemes + end filtered_schemes = FilterManager.filter_schemes(unfiltered_schemes, search_term, filters, all_orgs, user) csv_string = Csv::SchemeCsvService.new(download_type:).prepare_csv(filtered_schemes) diff --git a/app/models/form/lettings/pages/reasonother_value_check.rb b/app/models/form/lettings/pages/reasonother_value_check.rb new file mode 100644 index 000000000..ccda997a7 --- /dev/null +++ b/app/models/form/lettings/pages/reasonother_value_check.rb @@ -0,0 +1,23 @@ +class Form::Lettings::Pages::ReasonotherValueCheck < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "reasonother_value_check" + @depends_on = [{ "reasonother_might_be_existing_category?" => true }] + @title_text = { + "translation" => "soft_validations.reasonother.title_text", + "arguments" => [{ "key" => "reasonother", "i18n_template" => "reasonother" }], + } + @informative_text = { + "translation" => "soft_validations.reasonother.informative_text", + "arguments" => [], + } + end + + def questions + @questions ||= [Form::Lettings::Questions::ReasonotherValueCheck.new(nil, nil, self)] + end + + def interruption_screen_question_ids + %w[reason reasonother] + end +end diff --git a/app/models/form/lettings/pages/stock_owner.rb b/app/models/form/lettings/pages/stock_owner.rb index 07fe01327..a653e7fe2 100644 --- a/app/models/form/lettings/pages/stock_owner.rb +++ b/app/models/form/lettings/pages/stock_owner.rb @@ -14,16 +14,10 @@ class Form::Lettings::Pages::StockOwner < ::Form::Page return false unless current_user return true if current_user.support? - stock_owners = if FeatureToggle.merge_organisations_enabled? - current_user.organisation.stock_owners + current_user.organisation.absorbed_organisations.where(holds_own_stock: true) - else - current_user.organisation.stock_owners - end + stock_owners = current_user.organisation.stock_owners + current_user.organisation.absorbed_organisations.where(holds_own_stock: true) if current_user.organisation.holds_own_stock? - if FeatureToggle.merge_organisations_enabled? && current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?) - return true - end + return true if current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?) return true if stock_owners.count >= 1 log.update!(owning_organisation: current_user.organisation) diff --git a/app/models/form/lettings/questions/reasonother_value_check.rb b/app/models/form/lettings/questions/reasonother_value_check.rb new file mode 100644 index 000000000..865f38764 --- /dev/null +++ b/app/models/form/lettings/questions/reasonother_value_check.rb @@ -0,0 +1,14 @@ +class Form::Lettings::Questions::ReasonotherValueCheck < ::Form::Question + def initialize(id, hsh, page) + super + @id = "reasonother_value_check" + @check_answer_label = "Reason other confirmation" + @header = "Are you sure this doesn’t fit an existing category?" + @type = "interruption_screen" + @check_answers_card_number = 0 + @answer_options = ANSWER_OPTIONS + @hidden_in_check_answers = { "depends_on" => [{ "reasonother_value_check" => 0 }, { "reasonother_value_check" => 1 }] } + end + + ANSWER_OPTIONS = { "0" => { "value" => "Yes" }, "1" => { "value" => "No" } }.freeze +end diff --git a/app/models/form/lettings/questions/stock_owner.rb b/app/models/form/lettings/questions/stock_owner.rb index c78c4a080..6b5e77c6d 100644 --- a/app/models/form/lettings/questions/stock_owner.rb +++ b/app/models/form/lettings/questions/stock_owner.rb @@ -67,11 +67,7 @@ class Form::Lettings::Questions::StockOwner < ::Form::Question def hidden_in_check_answers?(_log, user = nil) return false if user.support? - stock_owners = if FeatureToggle.merge_organisations_enabled? - user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true) - else - user.organisation.stock_owners - end + stock_owners = user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true) if user.organisation.holds_own_stock? stock_owners.count.zero? diff --git a/app/models/form/lettings/subsections/household_situation.rb b/app/models/form/lettings/subsections/household_situation.rb index 9db7c1f04..6646d7230 100644 --- a/app/models/form/lettings/subsections/household_situation.rb +++ b/app/models/form/lettings/subsections/household_situation.rb @@ -12,6 +12,7 @@ class Form::Lettings::Subsections::HouseholdSituation < ::Form::Subsection Form::Lettings::Pages::TimeOnWaitingList.new(nil, nil, self), Form::Lettings::Pages::ReasonForLeavingLastSettledHome.new(nil, nil, self), Form::Lettings::Pages::ReasonForLeavingLastSettledHomeRenewal.new(nil, nil, self), + (Form::Lettings::Pages::ReasonotherValueCheck.new(nil, nil, self) if form.start_year_after_2024?), Form::Lettings::Pages::PreviousHousingSituation.new(nil, nil, self), Form::Lettings::Pages::PreviousHousingSituationRenewal.new(nil, nil, self), Form::Lettings::Pages::Homelessness.new("homelessness", nil, self), diff --git a/app/models/form/sales/pages/managing_organisation.rb b/app/models/form/sales/pages/managing_organisation.rb index 0c9ed7337..3d8e59383 100644 --- a/app/models/form/sales/pages/managing_organisation.rb +++ b/app/models/form/sales/pages/managing_organisation.rb @@ -12,10 +12,20 @@ class Form::Sales::Pages::ManagingOrganisation < ::Form::Page def routed_to?(log, current_user) return false unless current_user - return false unless current_user.support? - return false unless FeatureToggle.sales_managing_organisation_enabled? - return false unless log.owning_organisation - log.owning_organisation.managing_agents.count >= 1 + if form.start_year_after_2024? + organisation = current_user.support? ? log.owning_organisation : current_user.organisation + + return false unless organisation + return false if log.owning_organisation != organisation && !organisation.holds_own_stock? + return true unless organisation.holds_own_stock? + + organisation.managing_agents.count >= 1 + else + return false unless current_user.support? + return false unless log.owning_organisation + + log.owning_organisation.managing_agents.count >= 1 + end end end diff --git a/app/models/form/sales/pages/owning_organisation.rb b/app/models/form/sales/pages/owning_organisation.rb index d8787a456..f0c9e4e68 100644 --- a/app/models/form/sales/pages/owning_organisation.rb +++ b/app/models/form/sales/pages/owning_organisation.rb @@ -13,19 +13,12 @@ class Form::Sales::Pages::OwningOrganisation < ::Form::Page def routed_to?(log, current_user) return false unless current_user return true if current_user.support? - return false unless FeatureToggle.sales_managing_organisation_enabled? return true if has_multiple_stock_owners_with_own_stock?(current_user) - stock_owners = if FeatureToggle.merge_organisations_enabled? - current_user.organisation.stock_owners.where(holds_own_stock: true) + current_user.organisation.absorbed_organisations.where(holds_own_stock: true) - else - current_user.organisation.stock_owners.where(holds_own_stock: true) - end + stock_owners = current_user.organisation.stock_owners.where(holds_own_stock: true) + current_user.organisation.absorbed_organisations.where(holds_own_stock: true) if current_user.organisation.holds_own_stock? - if FeatureToggle.merge_organisations_enabled? && current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?) - return true - end + return true if current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?) return true if stock_owners.count >= 1 log.update!(owning_organisation: current_user.organisation) diff --git a/app/models/form/sales/questions/owning_organisation_id.rb b/app/models/form/sales/questions/owning_organisation_id.rb index 47a10993d..a4c700e05 100644 --- a/app/models/form/sales/questions/owning_organisation_id.rb +++ b/app/models/form/sales/questions/owning_organisation_id.rb @@ -14,7 +14,7 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question return answer_opts unless user return answer_opts unless log - if FeatureToggle.sales_managing_organisation_enabled? && !user.support? + unless user.support? if log.owning_organisation_id.present? answer_opts[log.owning_organisation.id] = log.owning_organisation.name end @@ -28,43 +28,36 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question end end - if FeatureToggle.merge_organisations_enabled? - if log.owning_organisation_id.present? - answer_opts[log.owning_organisation.id] = log.owning_organisation.name - end + if log.owning_organisation_id.present? + answer_opts[log.owning_organisation.id] = log.owning_organisation.name + end - recently_absorbed_organisations = user.organisation.absorbed_organisations.merged_during_open_collection_period - if !user.support? && user.organisation.holds_own_stock? - answer_opts[user.organisation.id] = if recently_absorbed_organisations.exists? && user.organisation.available_from.present? - "#{user.organisation.name} (Your organisation, active as of #{user.organisation.available_from.to_fs(:govuk_date)})" - else - "#{user.organisation.name} (Your organisation)" - end - end + recently_absorbed_organisations = user.organisation.absorbed_organisations.merged_during_open_collection_period + if !user.support? && user.organisation.holds_own_stock? + answer_opts[user.organisation.id] = if recently_absorbed_organisations.exists? && user.organisation.available_from.present? + "#{user.organisation.name} (Your organisation, active as of #{user.organisation.available_from.to_fs(:govuk_date)})" + else + "#{user.organisation.name} (Your organisation)" + end + end - if user.support? - Organisation.where(holds_own_stock: true).find_each do |org| - if org.merge_date.present? - answer_opts[org.id] = "#{org.name} (inactive as of #{org.merge_date.to_fs(:govuk_date)})" if org.merge_date >= FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period - elsif org.absorbed_organisations.merged_during_open_collection_period.exists? && org.available_from.present? - answer_opts[org.id] = "#{org.name} (active as of #{org.available_from.to_fs(:govuk_date)})" - else - answer_opts[org.id] = org.name - end - end - else - recently_absorbed_organisations.each do |absorbed_org| - answer_opts[absorbed_org.id] = merged_organisation_label(absorbed_org.name, absorbed_org.merge_date) if absorbed_org.holds_own_stock? + if user.support? + Organisation.where(holds_own_stock: true).find_each do |org| + if org.merge_date.present? + answer_opts[org.id] = "#{org.name} (inactive as of #{org.merge_date.to_fs(:govuk_date)})" if org.merge_date >= FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period + elsif org.absorbed_organisations.merged_during_open_collection_period.exists? && org.available_from.present? + answer_opts[org.id] = "#{org.name} (active as of #{org.available_from.to_fs(:govuk_date)})" + else + answer_opts[org.id] = org.name end end - - answer_opts else - Organisation.select(:id, :name).each_with_object(answer_opts) do |organisation, hsh| - hsh[organisation.id] = organisation.name - hsh + recently_absorbed_organisations.each do |absorbed_org| + answer_opts[absorbed_org.id] = merged_organisation_label(absorbed_org.name, absorbed_org.merge_date) if absorbed_org.holds_own_stock? end end + + answer_opts end def displayed_answer_options(log, user = nil) @@ -82,18 +75,14 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question end def hidden_in_check_answers?(_log, user = nil) - if FeatureToggle.merge_organisations_enabled? - return false if user.support? + return false if user.support? - stock_owners = user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true) + stock_owners = user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true) - if user.organisation.holds_own_stock? - stock_owners.count.zero? - else - stock_owners.count <= 1 - end + if user.organisation.holds_own_stock? + stock_owners.count.zero? else - !current_user.support? + stock_owners.count <= 1 end end @@ -104,11 +93,7 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question private def selected_answer_option_is_derived?(_log) - if FeatureToggle.merge_organisations_enabled? - true - else - false - end + true end def merged_organisation_label(name, merge_date) diff --git a/app/models/user.rb b/app/models/user.rb index aba948425..0fc21172a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -113,7 +113,7 @@ class User < ApplicationRecord if support? Scheme.all else - Scheme.filter_by_owning_organisation(organisation.absorbed_organisations + [organisation]) + Scheme.filter_by_owning_organisation(organisation.absorbed_organisations + [organisation] + organisation.parent_organisations) end end diff --git a/app/models/validations/household_validations.rb b/app/models/validations/household_validations.rb index cd15d09cf..c7e034e94 100644 --- a/app/models/validations/household_validations.rb +++ b/app/models/validations/household_validations.rb @@ -9,6 +9,20 @@ module Validations::HouseholdValidations end end + PHRASES_INDICATING_HOMELESSNESS = [ + "Homeless", + "Homelessness", + "Temporary accommodation", + "Temp accommodation", + "TA", + "Sleeping rough", + "Rough sleeping", + ].freeze + + PHRASES_INDICATING_HOMELESSNESS_REGEX = Regexp.union( + PHRASES_INDICATING_HOMELESSNESS.map { |phrase| Regexp.new("\\A[^[:alpha:]]*#{phrase}[^[:alpha:]]*\\Z", Regexp::IGNORECASE) }, + ) + def validate_reason_for_leaving_last_settled_home(record) if record.reason == 32 && record.underoccupation_benefitcap != 4 record.errors.add :underoccupation_benefitcap, I18n.t("validations.household.underoccupation_benefitcap.dont_know_required") @@ -20,6 +34,12 @@ module Validations::HouseholdValidations record.errors.add :referral, I18n.t("validations.household.referral.reason_permanently_decanted") record.errors.add :reason, I18n.t("validations.household.reason.not_internal_transfer") end + + return unless record.form.start_year_after_2024? + + if record.reason == 20 && PHRASES_INDICATING_HOMELESSNESS_REGEX.match?(record.reasonother) + record.errors.add :reason, I18n.t("validations.household.reason.other_not_settled") + end end def validate_armed_forces(record) diff --git a/app/models/validations/soft_validations.rb b/app/models/validations/soft_validations.rb index 92685afe0..74afef27d 100644 --- a/app/models/validations/soft_validations.rb +++ b/app/models/validations/soft_validations.rb @@ -133,6 +133,44 @@ module Validations::SoftValidations weekly_value(supcharg) > max end + PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY = [ + "Decant", + "Decanted", + "Refugee", + "Asylum", + "Ukraine", + "Ukrainian", + "Army", + "Military", + "Domestic Abuse", + "Domestic Violence", + "DA", + "DV", + "Relationship breakdown", + "Overcrowding", + "Overcrowded", + "Too small", + "More space", + "Bigger property", + "Damp", + "Mould", + "Fire", + "Repossession", + "Death", + "Deceased", + "Passed away", + "Prison", + "Hospital", + ].freeze + + PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY_REGEX = Regexp.union( + PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY.map { |phrase| Regexp.new("\\b[^[:alpha]]*#{phrase}[^[:alpha:]]*\\b", Regexp::IGNORECASE) }, + ) + + def reasonother_might_be_existing_category? + PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY_REGEX.match?(reasonother) + end + private def details_known_or_lead_tenant?(tenant_number) diff --git a/app/services/bulk_upload/sales/validator.rb b/app/services/bulk_upload/sales/validator.rb index 91fa50096..32e9f7533 100644 --- a/app/services/bulk_upload/sales/validator.rb +++ b/app/services/bulk_upload/sales/validator.rb @@ -5,6 +5,7 @@ class BulkUpload::Sales::Validator attr_reader :bulk_upload, :path validate :validate_file_not_empty + validate :validate_field_numbers_count validate :validate_max_columns validate :validate_missing_required_headers validate :validate_correct_template @@ -166,6 +167,14 @@ private if csv_parser.missing_required_headers? errors.add :base, I18n.t("activemodel.errors.models.bulk_upload/sales/validator.attributes.base.no_headers", guidance_link: bulk_upload_sales_log_url(id: "guidance", form: { year: bulk_upload.year }, host: ENV["APP_HOST"], anchor: "using-the-bulk-upload-template")) + end + end + + def validate_field_numbers_count + return if halt_validations? + + unless csv_parser.correct_field_count? + errors.add(:base, :wrong_field_numbers_count) halt_validations! end end diff --git a/app/services/bulk_upload/sales/year2023/csv_parser.rb b/app/services/bulk_upload/sales/year2023/csv_parser.rb index 42b0764d9..c6c07e1d5 100644 --- a/app/services/bulk_upload/sales/year2023/csv_parser.rb +++ b/app/services/bulk_upload/sales/year2023/csv_parser.rb @@ -4,6 +4,7 @@ class BulkUpload::Sales::Year2023::CsvParser include CollectionTimeHelper MAX_COLUMNS = 142 + FIELDS = 135 FORM_YEAR = 2023 attr_reader :path @@ -59,6 +60,12 @@ class BulkUpload::Sales::Year2023::CsvParser false end + def correct_field_count? + valid_field_numbers_count = field_numbers.count { |f| f != "field_blank" } + + valid_field_numbers_count == FIELDS + end + private def default_field_numbers diff --git a/app/services/bulk_upload/sales/year2023/row_parser.rb b/app/services/bulk_upload/sales/year2023/row_parser.rb index 5ea5af787..a8f322828 100644 --- a/app/services/bulk_upload/sales/year2023/row_parser.rb +++ b/app/services/bulk_upload/sales/year2023/row_parser.rb @@ -455,12 +455,12 @@ class BulkUpload::Sales::Year2023::RowParser validate :validate_owning_org_data_given, on: :after_log validate :validate_owning_org_exists, on: :after_log - validate :validate_owning_org_owns_stock, on: :after_log if FeatureToggle.sales_managing_organisation_enabled? + validate :validate_owning_org_owns_stock, on: :after_log validate :validate_owning_org_permitted, on: :after_log validate :validate_created_by_exists, on: :after_log validate :validate_created_by_related, on: :after_log - validate :validate_managing_org_related, on: :after_log if FeatureToggle.sales_managing_organisation_enabled? + validate :validate_managing_org_related, on: :after_log validate :validate_relevant_collection_window, on: :after_log validate :validate_incomplete_soft_validations, on: :after_log diff --git a/app/services/bulk_upload/sales/year2024/csv_parser.rb b/app/services/bulk_upload/sales/year2024/csv_parser.rb index e53f0ec28..2dc9d38a1 100644 --- a/app/services/bulk_upload/sales/year2024/csv_parser.rb +++ b/app/services/bulk_upload/sales/year2024/csv_parser.rb @@ -3,6 +3,7 @@ require "csv" class BulkUpload::Sales::Year2024::CsvParser include CollectionTimeHelper + FIELDS = 131 MAX_COLUMNS = 142 FORM_YEAR = 2024 @@ -59,6 +60,12 @@ class BulkUpload::Sales::Year2024::CsvParser !with_headers? end + def correct_field_count? + valid_field_numbers_count = field_numbers.count { |f| f != "field_blank" } + + valid_field_numbers_count == FIELDS + end + private def default_field_numbers diff --git a/app/services/bulk_upload/sales/year2024/row_parser.rb b/app/services/bulk_upload/sales/year2024/row_parser.rb index decbb0aaa..2c1b6089a 100644 --- a/app/services/bulk_upload/sales/year2024/row_parser.rb +++ b/app/services/bulk_upload/sales/year2024/row_parser.rb @@ -455,12 +455,12 @@ class BulkUpload::Sales::Year2024::RowParser validate :validate_owning_org_data_given, on: :after_log validate :validate_owning_org_exists, on: :after_log - validate :validate_owning_org_owns_stock, on: :after_log if FeatureToggle.sales_managing_organisation_enabled? + validate :validate_owning_org_owns_stock, on: :after_log validate :validate_owning_org_permitted, on: :after_log validate :validate_created_by_exists, on: :after_log validate :validate_created_by_related, on: :after_log - validate :validate_managing_org_related, on: :after_log if FeatureToggle.sales_managing_organisation_enabled? + validate :validate_managing_org_related, on: :after_log validate :validate_relevant_collection_window, on: :after_log validate :validate_incomplete_soft_validations, on: :after_log @@ -732,6 +732,7 @@ private discount: %i[field_116], othtype: %i[field_12], owning_organisation_id: %i[field_1], + managing_organisation_id: [:field_2], created_by: %i[field_3], hhregres: %i[field_72], hhregresstill: %i[field_73], @@ -1211,9 +1212,7 @@ private end def managing_organisation - return owning_organisation if created_by&.organisation&.absorbed_organisations&.include?(owning_organisation) - - created_by&.organisation || bulk_upload.user.organisation + Organisation.find_by_id_on_multiple_fields(field_2) end def nationality_group(nationality_value) @@ -1228,8 +1227,8 @@ private if owning_organisation && managing_organisation && !owning_organisation.can_be_managed_by?(organisation: managing_organisation) block_log_creation! - if errors[:field_3].blank? - errors.add(:field_3, "This user belongs to an organisation that does not have a relationship with the owning organisation", category: :setup) + if errors[:field_2].blank? + errors.add(:field_2, "This organisation does not have a relationship with the owning organisation", category: :setup) end end end diff --git a/app/services/csv/lettings_log_csv_service.rb b/app/services/csv/lettings_log_csv_service.rb index e9ebd875a..e67363188 100644 --- a/app/services/csv/lettings_log_csv_service.rb +++ b/app/services/csv/lettings_log_csv_service.rb @@ -296,7 +296,7 @@ module Csv "letting_allocation_unknown" => %w[letting_allocation_none], }.freeze - SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed].freeze + SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed reasonother_value_check].freeze def lettings_log_attributes ordered_questions = FormHandler.instance.ordered_lettings_questions_for_all_years diff --git a/app/services/feature_toggle.rb b/app/services/feature_toggle.rb index 38c1372e1..e00e89b90 100644 --- a/app/services/feature_toggle.rb +++ b/app/services/feature_toggle.rb @@ -28,10 +28,6 @@ class FeatureToggle false end - def self.merge_organisations_enabled? - true - end - def self.deduplication_flow_enabled? true end @@ -47,8 +43,4 @@ class FeatureToggle def self.service_moved? false end - - def self.sales_managing_organisation_enabled? - true - end end diff --git a/app/views/logs/_log_filters.html.erb b/app/views/logs/_log_filters.html.erb index 16053c805..ea7496bdd 100644 --- a/app/views/logs/_log_filters.html.erb +++ b/app/views/logs/_log_filters.html.erb @@ -93,7 +93,7 @@ } %> <% end %> - <% if (current_user.support? || non_support_with_managing_orgs?) && (user_or_org_lettings_path? || FeatureToggle.sales_managing_organisation_enabled?) %> + <% if current_user.support? || non_support_with_managing_orgs? %> <%= render partial: "filters/radio_filter", locals: { f:, options: { diff --git a/app/views/organisations/show.html.erb b/app/views/organisations/show.html.erb index 21f722920..e2e07e28c 100644 --- a/app/views/organisations/show.html.erb +++ b/app/views/organisations/show.html.erb @@ -36,9 +36,7 @@ <% end %> <%= data_sharing_agreement_row(organisation: @organisation, user: current_user, summary_list:) %> <% end %> - <% if FeatureToggle.merge_organisations_enabled? %> -

To report a merge or update your organisation details, <%= govuk_link_to "contact the helpdesk", GlobalConstants::HELPDESK_URL %>.

- <% end %> +

To report a merge or update your organisation details, <%= govuk_link_to "contact the helpdesk", GlobalConstants::HELPDESK_URL %>.

<%= render partial: "organisations/merged_organisation_details" %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 90962e08d..b322f9759 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -543,6 +543,7 @@ en: reason: not_internal_transfer: "Answer cannot be ‘permanently decanted from another property owned by this landlord’ as you told us the source of referral for this tenancy was not an internal transfer" renewal_reason_needed: 'The reason for leaving must be "End of assured shorthold tenancy - no fault" or "End of fixed term tenancy - no fault" if the letting is a renewal' + other_not_settled: "Please give the reason for the tenant leaving their last settled home. This is where they were living before they became homeless, were living in temporary accommodation or sleeping rough" condition_effects: no_choices: "You cannot answer this question as you told us nobody in the household has a physical or mental health condition (or other illness) expected to last 12 months or more" postcode: @@ -740,6 +741,11 @@ Make sure these answers are correct." deposit_and_mortgage: title_text: "You told us the mortgage amount was %{mortgage}, the cash deposit was %{deposit} and the discount was %{discount}." hint_text: "We would expect the mortgage amount and the deposit added together to be the same as the purchase price minus the discount." + reasonother: + title_text: "You told us that the tenant’s main reason for leaving their last settled home was %{reasonother}" + informative_text: "The reason you have entered looks very similar to one of the existing response categories. + Please check the categories and select the appropriate one. + If the existing categories are not suitable, please confirm here to move onto the next question." devise: email: diff --git a/db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb b/db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb new file mode 100644 index 000000000..54486b3ae --- /dev/null +++ b/db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb @@ -0,0 +1,5 @@ +class AddReasonotherValueCheckToLettingsLogs < ActiveRecord::Migration[7.0] + def change + add_column :lettings_logs, :reasonother_value_check, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index a8e39d12f..b5b9c9fc0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -306,6 +306,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_02_16_163519) do t.integer "duplicate_set_id" t.integer "nationality_all" t.integer "nationality_all_group" + t.integer "reasonother_value_check" t.integer "accessible_register" t.index ["bulk_upload_id"], name: "index_lettings_logs_on_bulk_upload_id" t.index ["created_by_id"], name: "index_lettings_logs_on_created_by_id" diff --git a/package.json b/package.json index 5b34103fe..dedf7b6b7 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "css-loader": "^6.7.1", "custom-event-polyfill": "^1.0.7", "file-loader": "^6.2.0", - "govuk-frontend": "5.0.0", + "govuk-frontend": "5.1.0", "html5shiv": "^3.7.3", "intersection-observer": "^0.12.0", "mini-css-extract-plugin": "^2.6.0", diff --git a/spec/factories/lettings_log.rb b/spec/factories/lettings_log.rb index 23ba06bf1..6f4cf951c 100644 --- a/spec/factories/lettings_log.rb +++ b/spec/factories/lettings_log.rb @@ -10,6 +10,7 @@ FactoryBot.define do renewal { 0 } needstype { 1 } rent_type { 1 } + declaration { 1 } end trait :in_progress do status { 1 } diff --git a/spec/features/organisation_spec.rb b/spec/features/organisation_spec.rb index 43c0a9d8e..598be9e05 100644 --- a/spec/features/organisation_spec.rb +++ b/spec/features/organisation_spec.rb @@ -196,9 +196,9 @@ RSpec.describe "User Features" do end it "can filter lettings logs by year" do - check("years-2021-field") + check("years-2022-field") click_button("Apply filters") - expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&years[]=2021&status[]=&needstypes[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=") + expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&years[]=2022&status[]=&needstypes[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=") expect(page).not_to have_link first_log.id.to_s, href: "/lettings-logs/#{first_log.id}" end @@ -241,9 +241,9 @@ RSpec.describe "User Features" do organisation.sales_logs.map(&:id).each do |sales_log_id| expect(page).to have_link sales_log_id.to_s, href: "/sales-logs/#{sales_log_id}" end - check("years-2021-field") + check("years-2022-field") click_button("Apply filters") - expect(page).to have_current_path("/organisations/#{org_id}/sales-logs?years[]=&years[]=2021&status[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=") + expect(page).to have_current_path("/organisations/#{org_id}/sales-logs?years[]=&years[]=2022&status[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=") expect(page).not_to have_link first_log.id.to_s, href: "/sales-logs/#{first_log.id}" end end @@ -327,6 +327,19 @@ RSpec.describe "User Features" do end end + context "when viewing schemes for specific organisation" do + before do + create(:scheme, owning_organisation: organisation) + visit("/organisations/#{org_id}/schemes") + end + + it "allows downloading schemes csv for the specific org" do + click_link("Download schemes (CSV)") + click_button("Send email") + expect(page).to have_current_path("/organisations/#{org_id}/schemes/csv-confirmation") + end + end + context "and the organisation does not hold housing stock" do before do organisation.update!(holds_own_stock: false) diff --git a/spec/fixtures/files/lettings_log_csv_export_codes_23.csv b/spec/fixtures/files/lettings_log_csv_export_codes_23.csv index 873c703b0..086f250e0 100644 --- a/spec/fixtures/files/lettings_log_csv_export_codes_23.csv +++ b/spec/fixtures/files/lettings_log_csv_export_codes_23.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_codes_24.csv b/spec/fixtures/files/lettings_log_csv_export_codes_24.csv index 832ceed45..e752f4237 100644 --- a/spec/fixtures/files/lettings_log_csv_export_codes_24.csv +++ b/spec/fixtures/files/lettings_log_csv_export_codes_24.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_23.csv b/spec/fixtures/files/lettings_log_csv_export_labels_23.csv index a9c491ed9..4f2c43d5d 100644 --- a/spec/fixtures/files/lettings_log_csv_export_labels_23.csv +++ b/spec/fixtures/files/lettings_log_csv_export_labels_23.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv index 0e345b837..2d15ea4b3 100644 --- a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv +++ b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv @@ -1,2 +1,2 @@ -id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/helpers/filters_helper_spec.rb b/spec/helpers/filters_helper_spec.rb index f60cc483e..52a9595fc 100644 --- a/spec/helpers/filters_helper_spec.rb +++ b/spec/helpers/filters_helper_spec.rb @@ -240,12 +240,38 @@ RSpec.describe FiltersHelper do end describe "#collection_year_options" do - it "includes 2023/2024 option" do - expect(collection_year_options).to eq( - { - "2021": "2021/22", "2022": "2022/23", "2023": "2023/24" - }, - ) + context "with 23/24 as the current collection year" do + around do |example| + Timecop.freeze(Time.zone.local(2023, 5, 1)) do + example.run + end + Timecop.return + end + + it "has the correct options" do + expect(collection_year_options).to eq( + { + "2023" => "2023/24", "2022" => "2022/23", "2021" => "2021/22" + }, + ) + end + end + + context "with 24/25 as the current collection year" do + around do |example| + Timecop.freeze(Time.zone.local(2024, 5, 1)) do + example.run + end + Timecop.return + end + + it "has the correct options" do + expect(collection_year_options).to eq( + { + "2024" => "2024/25", "2023" => "2023/24", "2022" => "2022/23" + }, + ) + end end end diff --git a/spec/jobs/scheme_email_csv_job_spec.rb b/spec/jobs/scheme_email_csv_job_spec.rb index d23177ab3..5ddaa91a6 100644 --- a/spec/jobs/scheme_email_csv_job_spec.rb +++ b/spec/jobs/scheme_email_csv_job_spec.rb @@ -6,41 +6,52 @@ describe SchemeEmailCsvJob do test_url = :test_url let(:job) { described_class.new } + let(:storage_service) { instance_double(Storage::S3Service, write_file: nil, get_presigned_url: test_url) } + let(:mailer) { instance_double(CsvDownloadMailer, send_csv_download_mail: nil) } let(:user) { FactoryBot.create(:user) } - let(:storage_service) { instance_double(Storage::S3Service) } - let(:mailer) { instance_double(CsvDownloadMailer) } - let(:scheme_csv_service) { instance_double(Csv::SchemeCsvService) } - let(:search_term) { "meaning" } - let(:filters) { { "owning_organisation" => organisation.id, "status" => %w[active] } } - let(:all_orgs) { false } - let(:organisation) { build(:organisation) } - let(:download_type) { "combined" } - let(:schemes) { build_list(:scheme, 5, owning_organisation: organisation) } - let(:locations) { build_list(:location, 5, scheme: schemes.first) } before do allow(Storage::S3Service).to receive(:new).and_return(storage_service) - allow(storage_service).to receive(:write_file) - allow(storage_service).to receive(:get_presigned_url).and_return(test_url) - - allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service) - allow(scheme_csv_service).to receive(:prepare_csv).and_return("") - allow(CsvDownloadMailer).to receive(:new).and_return(mailer) - allow(mailer).to receive(:send_csv_download_mail) end context "when exporting" do + let(:scheme_csv_service) { instance_double(Csv::SchemeCsvService) } + let(:organisation) { user.organisation } + let(:download_type) { "combined" } + let(:schemes) { create_list(:scheme, 1, owning_organisation: organisation) } + before do - allow(FilterManager).to receive(:filter_schemes).and_return(schemes) + create_list(:location, 2, scheme: schemes.first) end context "when download type schemes" do let(:download_type) { "schemes" } - it "uses an appropriate filename in S3" do - expect(storage_service).to receive(:write_file).with(/schemes-.*\.csv/, anything) - job.perform(user) + it "uses an appropriate filename in S3 and exports the correct schemes" do + expect(storage_service).to receive(:write_file).with(/schemes-.*\.csv/, anything) do |_, content| + expect(content).not_to be_nil + expect(content).not_to be_nil + expect(CSV.parse(content).count).to eq(2) + end + job.perform(user, nil, {}, nil, nil, download_type) + end + + context "and there are stock owner schemes" do + let(:parent_organisation) { create(:organisation) } + + before do + create(:scheme, owning_organisation: parent_organisation) + create(:organisation_relationship, parent_organisation:, child_organisation: organisation) + end + + it "exports the correct number of schemes" do + expect(storage_service).to receive(:write_file).with(/schemes-.*\.csv/, anything) do |_, content| + expect(content).not_to be_nil + expect(CSV.parse(content).count).to eq(3) + end + job.perform(user, nil, {}, nil, nil, download_type) + end end end @@ -49,7 +60,7 @@ describe SchemeEmailCsvJob do it "uses an appropriate filename in S3" do expect(storage_service).to receive(:write_file).with(/locations-.*\.csv/, anything) - job.perform(user) + job.perform(user, nil, {}, nil, nil, download_type) end end @@ -58,7 +69,7 @@ describe SchemeEmailCsvJob do it "uses an appropriate filename in S3" do expect(storage_service).to receive(:write_file).with(/schemes-and-locations.*\.csv/, anything) - job.perform(user) + job.perform(user, nil, {}, nil, nil, download_type) end end @@ -67,12 +78,27 @@ describe SchemeEmailCsvJob do job.perform(user, nil, {}, nil, organisation, "combined") end - it "calls the filter manager with the arguments provided" do - expect(FilterManager).to receive(:filter_schemes).with(a_kind_of(ActiveRecord::Relation), search_term, filters, all_orgs, user) - job.perform(user, search_term, filters, all_orgs, organisation, "combined") + context "when resources are filtered" do + let(:search_term) { "meaning" } + let(:filters) { { "owning_organisation" => organisation.id, "status" => %w[active] } } + let(:all_orgs) { false } + + before do + allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service) + allow(scheme_csv_service).to receive(:prepare_csv).and_return("") + allow(FilterManager).to receive(:filter_schemes).and_return(schemes) + end + + it "calls the filter manager with the arguments provided" do + expect(FilterManager).to receive(:filter_schemes).with(a_kind_of(ActiveRecord::Relation), search_term, filters, all_orgs, user) + job.perform(user, search_term, filters, all_orgs, organisation, "combined") + end end it "creates a SchemeCsvService with the correct download type" do + allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service) + allow(scheme_csv_service).to receive(:prepare_csv).and_return("") + expect(Csv::SchemeCsvService).to receive(:new).with(download_type: "schemes") job.perform(user, nil, {}, nil, nil, "schemes") expect(Csv::SchemeCsvService).to receive(:new).with(download_type: "locations") @@ -82,6 +108,9 @@ describe SchemeEmailCsvJob do end it "passes the schemes returned by the filter manager to the csv service" do + allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service) + allow(scheme_csv_service).to receive(:prepare_csv).and_return("") + expect(scheme_csv_service).to receive(:prepare_csv).with(schemes) job.perform(user, nil, {}, nil, nil, "combined") end diff --git a/spec/models/form/lettings/subsections/household_situation_spec.rb b/spec/models/form/lettings/subsections/household_situation_spec.rb index 803f873f8..dd6f20d89 100644 --- a/spec/models/form/lettings/subsections/household_situation_spec.rb +++ b/spec/models/form/lettings/subsections/household_situation_spec.rb @@ -6,33 +6,75 @@ RSpec.describe Form::Lettings::Subsections::HouseholdSituation, type: :model do let(:subsection_id) { nil } let(:subsection_definition) { nil } let(:section) { instance_double(Form::Lettings::Sections::Household) } + let(:form) { instance_double(Form) } + + before do + allow(section).to receive(:form).and_return(form) + end it "has correct section" do expect(household_situation.section).to eq(section) end - it "has correct pages" do - expect(household_situation.pages.map(&:id)).to eq( - %w[ - time_lived_in_local_authority - time_on_waiting_list - reason_for_leaving_last_settled_home - reason_for_leaving_last_settled_home_renewal - previous_housing_situation - previous_housing_situation_renewal - homelessness - previous_postcode - previous_local_authority - reasonable_preference - reasonable_preference_reason - allocation_system - referral - referral_prp - referral_supported_housing - referral_supported_housing_prp - referral_value_check - ], - ) + context "with form year before 2024" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + end + + it "has correct pages" do + expect(household_situation.pages.map(&:id)).to eq( + %w[ + time_lived_in_local_authority + time_on_waiting_list + reason_for_leaving_last_settled_home + reason_for_leaving_last_settled_home_renewal + previous_housing_situation + previous_housing_situation_renewal + homelessness + previous_postcode + previous_local_authority + reasonable_preference + reasonable_preference_reason + allocation_system + referral + referral_prp + referral_supported_housing + referral_supported_housing_prp + referral_value_check + ], + ) + end + end + + context "with form year >= 2024" do + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + + it "has correct pages" do + expect(household_situation.pages.map(&:id)).to eq( + %w[ + time_lived_in_local_authority + time_on_waiting_list + reason_for_leaving_last_settled_home + reason_for_leaving_last_settled_home_renewal + reasonother_value_check + previous_housing_situation + previous_housing_situation_renewal + homelessness + previous_postcode + previous_local_authority + reasonable_preference + reasonable_preference_reason + allocation_system + referral + referral_prp + referral_supported_housing + referral_supported_housing_prp + referral_value_check + ], + ) + end end it "has the correct id" do diff --git a/spec/models/form/sales/pages/managing_organisation_spec.rb b/spec/models/form/sales/pages/managing_organisation_spec.rb index 0a34554cb..8c411401d 100644 --- a/spec/models/form/sales/pages/managing_organisation_spec.rb +++ b/spec/models/form/sales/pages/managing_organisation_spec.rb @@ -5,9 +5,13 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do let(:page_id) { nil } let(:page_definition) { nil } - let(:subsection) { instance_double(Form::Subsection) } + let(:subsection) { instance_double(Form::Subsection, form:) } let(:form) { instance_double(Form) } + before do + allow(form).to receive(:start_year_after_2024?).and_return(false) + end + it "has correct subsection" do expect(page.subsection).to eq(subsection) end @@ -32,8 +36,8 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do expect(page.depends_on).to be nil end - describe "#routed_to?" do - let(:log) { create(:lettings_log) } + describe "#routed_to? with 2023 logs" do + let(:log) { create(:sales_log) } let(:organisation) { create(:organisation) } context "when user nil" do @@ -54,7 +58,7 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do let(:user) { create(:user, :support) } context "when owning_organisation not set" do - let(:log) { create(:lettings_log, owning_organisation: nil) } + let(:log) { create(:sales_log, owning_organisation: nil) } it "is not shown" do expect(page.routed_to?(log, user)).to eq(false) @@ -103,4 +107,146 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do end end end + + describe "#routed_to? with 2024 logs" do + let(:log) { create(:sales_log) } + let(:organisation) { create(:organisation) } + + before do + allow(form).to receive(:start_year_after_2024?).and_return(true) + end + + context "when user nil" do + it "is not shown" do + expect(page.routed_to?(log, nil)).to eq(false) + end + end + + context "when support" do + context "when does not hold own stock" do + let(:user) do + create(:user, :support, organisation: create(:organisation, holds_own_stock: false)) + end + let(:log) { create(:sales_log, owning_organisation: user.organisation) } + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + + context "when owning_organisation not set" do + let(:user) { create(:user, :support) } + let(:log) { create(:sales_log, owning_organisation: nil) } + + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + end + + context "when holds own stock" do + let(:user) do + create(:user, :support, organisation: create(:organisation, holds_own_stock: true)) + end + + context "with 0 managing_agents" do + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + end + + context "with >1 managing_agents" do + before do + create(:organisation_relationship, parent_organisation: log.owning_organisation) + create(:organisation_relationship, parent_organisation: log.owning_organisation) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + + context "with 1 managing_agents" do + let(:managing_agent) { create(:organisation) } + + before do + create( + :organisation_relationship, + child_organisation: managing_agent, + parent_organisation: log.owning_organisation, + ) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + end + end + + context "when not support" do + context "when does not hold own stock" do + let(:user) { create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: false)) } + + context "and the user's organisation is selected as owning organisation" do + let(:log) { create(:sales_log, owning_organisation: user.organisation) } + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + + context "and a different than the user's organisation is selected as owning organisation" do + let(:stock_owner) { create(:organisation, holds_own_stock: true) } + let(:log) { create(:sales_log, owning_organisation: stock_owner) } + + before do + create(:organisation_relationship, parent_organisation: stock_owner, child_organisation: user.organisation) + end + + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + end + end + + context "when holds own stock" do + let(:user) do + create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: true)) + end + + context "with 0 managing_agents" do + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + end + + context "with >1 managing_agents" do + before do + create(:organisation_relationship, parent_organisation: user.organisation) + create(:organisation_relationship, parent_organisation: user.organisation) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + + context "with 1 managing_agents" do + let(:managing_agent) { create(:organisation) } + + before do + create( + :organisation_relationship, + child_organisation: managing_agent, + parent_organisation: user.organisation, + ) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + end + end + end end diff --git a/spec/models/validations/household_validations_spec.rb b/spec/models/validations/household_validations_spec.rb index 849046c65..5a48d4b3f 100644 --- a/spec/models/validations/household_validations_spec.rb +++ b/spec/models/validations/household_validations_spec.rb @@ -4,11 +4,15 @@ RSpec.describe Validations::HouseholdValidations do subject(:household_validator) { validator_class.new } let(:validator_class) { Class.new { include Validations::HouseholdValidations } } - let(:record) { FactoryBot.create(:lettings_log) } - let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") } + let(:log_date) { Time.zone.now } + let(:record) { FactoryBot.create(:lettings_log, :setup_completed, startdate: log_date) } before do - allow(FormHandler.instance).to receive(:current_lettings_form).and_return(fake_2021_2022_form) + Timecop.freeze(log_date + 1) + end + + after do + Timecop.return end describe "reasonable preference validations" do @@ -53,6 +57,44 @@ RSpec.describe Validations::HouseholdValidations do household_validator.validate_reason_for_leaving_last_settled_home(record) expect(record.errors["reasonother"]).to be_empty end + + context "when form year is before 2024" do + let(:log_date) { Time.zone.local(2024, 1, 1) } + + it "does not validate the content of reasonother for phrases indicating homelessness" do + record.reason = 20 + record.reasonother = "Temp accommodation" + household_validator.validate_reason_for_leaving_last_settled_home(record) + expect(record.errors["reason"]).to be_empty + end + end + + context "when form year is >= 2024" do + let(:log_date) { Time.zone.local(2024, 4, 1) } + + context "when checking the content of reasonother" do + it "validates that the reason doesn't match phrase indicating homelessness" do + record.reason = 20 + record.reasonother = "Temp accommodation" + household_validator.validate_reason_for_leaving_last_settled_home(record) + expect(record.errors["reason"]).to include(I18n.t("validations.household.reason.other_not_settled")) + end + + it "allows reasons that don't exactly match a phrase indicating homelessness" do + record.reason = 20 + record.reasonother = "Not quite homeless but some other reason" + household_validator.validate_reason_for_leaving_last_settled_home(record) + expect(record.errors["reason"]).to be_empty + end + + it "ignores surrounding non-alphabet characters and casing when determining a match" do + record.reason = 20 + record.reasonother = " 0homelessness ! " + household_validator.validate_reason_for_leaving_last_settled_home(record) + expect(record.errors["reason"]).to include(I18n.t("validations.household.reason.other_not_settled")) + end + end + end end context "when reason is not other" do @@ -231,6 +273,26 @@ RSpec.describe Validations::HouseholdValidations do end describe "household member validations" do + it "validates that the number of household members cannot be less than 1" do + record.hhmemb = 0 + household_validator.validate_numeric_min_max(record) + expect(record.errors["hhmemb"]) + .to include(match I18n.t("validations.numeric.within_range", field: "Number of household members", min: 1, max: 8)) + end + + it "validates that the number of household members cannot be more than 8" do + record.hhmemb = 9 + household_validator.validate_numeric_min_max(record) + expect(record.errors["hhmemb"]) + .to include(match I18n.t("validations.numeric.within_range", field: "Number of household members", min: 1, max: 8)) + end + + it "expects that the number of other household members is between the min and max" do + record.hhmemb = 5 + household_validator.validate_numeric_min_max(record) + expect(record.errors["hhmemb"]).to be_empty + end + it "validates that only 1 partner exists" do record.relat2 = "P" record.relat3 = "P" @@ -394,26 +456,6 @@ RSpec.describe Validations::HouseholdValidations do expect(record.errors["sex2"]).to be_empty expect(record.errors["age2"]).to be_empty end - - it "validates that the number of household members cannot be less than 0" do - record.hhmemb = -1 - household_validator.validate_numeric_min_max(record) - expect(record.errors["hhmemb"]) - .to include(match I18n.t("validations.numeric.within_range", field: "Number of Household Members", min: 0, max: 8)) - end - - it "validates that the number of household members cannot be more than 8" do - record.hhmemb = 9 - household_validator.validate_numeric_min_max(record) - expect(record.errors["hhmemb"]) - .to include(match I18n.t("validations.numeric.within_range", field: "Number of Household Members", min: 0, max: 8)) - end - - it "expects that the number of other household members is between the min and max" do - record.hhmemb = 5 - household_validator.validate_numeric_min_max(record) - expect(record.errors["hhmemb"]).to be_empty - end end context "when the household contains a retired female" do @@ -651,24 +693,30 @@ RSpec.describe Validations::HouseholdValidations do .to be_empty end - it "prevten cannot be 3" do - record.referral = 1 - record.prevten = 3 - household_validator.validate_previous_housing_situation(record) - expect(record.errors["prevten"]) - .to include(match I18n.t("validations.household.prevten.internal_transfer", prevten: "")) - expect(record.errors["referral"]) - .to include(match I18n.t("validations.household.referral.prevten_invalid", prevten: "")) - end - - it "prevten cannot be 4, 10, 13, 19, 23, 24, 25, 26, 28, 29" do - record.referral = 1 - record.prevten = 4 - household_validator.validate_previous_housing_situation(record) - expect(record.errors["prevten"]) - .to include(match I18n.t("validations.household.prevten.internal_transfer", prevten: "")) - expect(record.errors["referral"]) - .to include(match I18n.t("validations.household.referral.prevten_invalid", prevten: "")) + [ + { code: 3, label: "Private sector tenancy" }, + { code: 4, label: "Tied housing or rented with job" }, + { code: 7, label: "Direct access hostel" }, + { code: 10, label: "Hospital" }, + { code: 13, label: "Children’s home or foster care" }, + { code: 14, label: "Bed and breakfast" }, + { code: 19, label: "Rough sleeping" }, + { code: 23, label: "Mobile home or caravan" }, + { code: 24, label: "Home Office Asylum Support" }, + { code: 25, label: "Any other accommodation" }, + { code: 26, label: "Owner occupation (private)" }, + { code: 28, label: "Living with friends or family" }, + { code: 29, label: "Prison or approved probation hostel" }, + ].each do |prevten| + it "prevten cannot be #{prevten[:code]}" do + record.referral = 1 + record.prevten = prevten[:code] + household_validator.validate_previous_housing_situation(record) + expect(record.errors["prevten"]) + .to include(match I18n.t("validations.household.prevten.internal_transfer", prevten: prevten[:label])) + expect(record.errors["referral"]) + .to include(match I18n.t("validations.household.referral.prevten_invalid", prevten: "")) + end end end end diff --git a/spec/models/validations/soft_validations_spec.rb b/spec/models/validations/soft_validations_spec.rb index 8f00799ff..ad87b3c5b 100644 --- a/spec/models/validations/soft_validations_spec.rb +++ b/spec/models/validations/soft_validations_spec.rb @@ -1017,4 +1017,42 @@ RSpec.describe Validations::SoftValidations do end end end + + describe "reasonother_might_be_existing_category?" do + it "returns true if reasonother is exactly in the 'likely existing category' list" do + record.reasonother = "Domestic Abuse" + + expect(record).to be_reasonother_might_be_existing_category + end + + it "returns true if any word of reasonother is exactly in the 'likely existing category' list" do + record.reasonother = "Was decanted from somewhere" + + expect(record).to be_reasonother_might_be_existing_category + end + + it "is not case sensitive when matching" do + record.reasonother = "domestic abuse" + + expect(record).to be_reasonother_might_be_existing_category + end + + it "returns false if no part of reasonother is in the 'likely existing category' list" do + record.reasonother = "other" + + expect(record).not_to be_reasonother_might_be_existing_category + end + + it "returns false if match to the 'likely existing category' list is only part of a word" do + record.reasonother = "wasdecanted" + + expect(record).not_to be_reasonother_might_be_existing_category + end + + it "ignores neighbouring non-alphabet for matching" do + record.reasonother = "1Domestic abuse." + + expect(record).to be_reasonother_might_be_existing_category + end + end end diff --git a/spec/requests/sales_logs_controller_spec.rb b/spec/requests/sales_logs_controller_spec.rb index a9bf07883..6ad991934 100644 --- a/spec/requests/sales_logs_controller_spec.rb +++ b/spec/requests/sales_logs_controller_spec.rb @@ -161,30 +161,6 @@ RSpec.describe SalesLogsController, type: :request do expect(sales_log.managing_organisation.name).to eq("User org") end end - - context "when the user's org doesn't hold stock and merge_organisations_enabled is false" do - let(:organisation) { FactoryBot.create(:organisation, name: "User org", holds_own_stock: false) } - let(:user) { FactoryBot.create(:user, :data_coordinator, organisation:) } - - before do - RequestHelper.stub_http_requests - sign_in user - allow(FeatureToggle).to receive(:merge_organisations_enabled?).and_return(false) - post "/sales-logs", headers: - end - - it "does not set owning organisation" do - created_id = response.location.match(/[0-9]+/)[0] - sales_log = SalesLog.find_by(id: created_id) - expect(sales_log.owning_organisation).to be_nil - end - - it "sets managing organisation as the user organisation" do - created_id = response.location.match(/[0-9]+/)[0] - sales_log = SalesLog.find_by(id: created_id) - expect(sales_log.managing_organisation.name).to eq("User org") - end - end end end end diff --git a/spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb b/spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb index 72c19e5d1..6738eb3f3 100644 --- a/spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb @@ -28,6 +28,10 @@ RSpec.describe BulkUpload::Sales::Year2023::CsvParser do it "parses csv correctly" do expect(service.row_parsers[0].field_19).to eql(log.uprn) end + + it "counts the number of valid field numbers correctly" do + expect(service).to be_correct_field_count + end end context "when parsing csv with headers in arbitrary order" do diff --git a/spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb b/spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb index e4391212a..ef90bd834 100644 --- a/spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb @@ -28,6 +28,10 @@ RSpec.describe BulkUpload::Sales::Year2024::CsvParser do it "parses csv correctly" do expect(service.row_parsers[0].field_22).to eql(log.uprn) end + + it "counts the number of valid field numbers correctly" do + expect(service).to be_correct_field_count + end end context "when parsing csv with headers in arbitrary order" do diff --git a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb index 460cd8622..5a1a9e4df 100644 --- a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb @@ -9,11 +9,13 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do let(:bulk_upload) { create(:bulk_upload, :sales, user:, year: 2024) } 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:, field_1: owning_org.old_visible_id, # organisation - field_2: owning_org.old_visible_id, # organisation + field_2: managing_org.old_visible_id, # organisation field_3: user.email, # user field_4: now.day.to_s, # sale day field_5: now.month.to_s, # sale month @@ -31,7 +33,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do { bulk_upload:, field_1: owning_org.old_visible_id, - field_2: owning_org.old_visible_id, + field_2: managing_org.old_visible_id, field_4: "12", field_5: "5", @@ -114,6 +116,8 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do end around do |example| + create(:organisation_relationship, parent_organisation: owning_org, child_organisation: managing_org) + Timecop.freeze(Time.zone.local(2025, 2, 22)) do Singleton.__init__(FormHandler) example.run @@ -287,7 +291,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do it "has errors on correct setup fields" do errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort - expect(errors).to eql(%i[field_1 field_17 field_18 field_4 field_5 field_6 field_8]) + expect(errors).to eql(%i[field_1 field_17 field_18 field_2 field_4 field_5 field_6 field_8]) end end @@ -303,7 +307,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do it "has errors on correct setup fields" do errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort - expect(errors).to eql(%i[field_1 field_15 field_17 field_18 field_4 field_5 field_6 field_9]) + expect(errors).to eql(%i[field_1 field_15 field_17 field_18 field_2 field_4 field_5 field_6 field_9]) end end @@ -321,7 +325,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do it "has errors on correct setup fields" do errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort - expect(errors).to eql(%i[field_1 field_16 field_17 field_18 field_4 field_5 field_6]) + expect(errors).to eql(%i[field_1 field_16 field_17 field_18 field_2 field_4 field_5 field_6]) end end @@ -338,7 +342,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do it "has errors on correct setup fields" do errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort - expect(errors).to eql(%i[field_1 field_10 field_15 field_17 field_18 field_4 field_5 field_6]) + expect(errors).to eql(%i[field_1 field_10 field_15 field_17 field_18 field_2 field_4 field_5 field_6]) end end @@ -355,7 +359,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do it "has errors on correct setup fields" do errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort - expect(errors).to eql(%i[field_1 field_17 field_18 field_4 field_5 field_6 field_8]) + expect(errors).to eql(%i[field_1 field_17 field_18 field_2 field_4 field_5 field_6 field_8]) end end @@ -371,7 +375,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do it "has errors on correct setup fields" do errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort - expect(errors).to eql(%i[field_1 field_11 field_13 field_14 field_17 field_18 field_4 field_5 field_6]) + expect(errors).to eql(%i[field_1 field_11 field_13 field_14 field_17 field_18 field_2 field_4 field_5 field_6]) end end @@ -389,7 +393,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do it "has errors on correct setup fields" do errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort - expect(errors).to eql(%i[field_1 field_12 field_14 field_15 field_17 field_18 field_4 field_5 field_6]) + expect(errors).to eql(%i[field_1 field_12 field_14 field_15 field_17 field_18 field_2 field_4 field_5 field_6]) end end @@ -1463,39 +1467,55 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do let(:attributes) { setup_section_params } context "when user is part of the owning organisation" do - it "sets managing organisation to the users organisation" do + it "sets managing organisation to the correct organisation" do parser.valid? expect(parser.log.owning_organisation_id).to be(owning_org.id) - expect(parser.log.managing_organisation_id).to be(owning_org.id) + expect(parser.log.managing_organisation_id).to be(managing_org.id) end end - context "when user is part of an organisation affiliated with owning org" do - let(:managing_agent) { create(:organisation) } - let(:user) { create(:user, organisation: managing_agent) } - let(:attributes) { setup_section_params } + context "when blank" do + let(:attributes) { { bulk_upload:, field_2: "" } } - before do - create(:organisation_relationship, child_organisation: managing_agent, parent_organisation: owning_org) + it "is not permitted as setup error" do + parser.valid? + setup_errors = parser.errors.select { |e| e.options[:category] == :setup } + + expect(setup_errors.find { |e| e.attribute == :field_2 }.message).to eql("You must answer reported by") end + it "blocks log creation" do + parser.valid? + expect(parser).to be_block_log_creation + end + end + + context "when cannot find managing org" do + let(:attributes) { { bulk_upload:, field_2: "donotexist" } } + it "is not permitted as setup error" do parser.valid? - expect(parser.log.owning_organisation_id).to be(owning_org.id) - expect(parser.log.managing_organisation_id).to be(managing_agent.id) + setup_errors = parser.errors.select { |e| e.options[:category] == :setup } + + expect(setup_errors.find { |e| e.attribute == :field_2 }.message).to eql("You must answer reported by") + end + + it "blocks log creation" do + parser.valid? + expect(parser).to be_block_log_creation end end - context "when user is part of an organisation not affiliated with owning org" do - let(:unaffiliated_org) { create(:organisation) } - let(:user) { create(:user, organisation: unaffiliated_org) } - let(:attributes) { setup_section_params } + context "when not affiliated with managing org" do + let(:unaffiliated_org) { create(:organisation, :with_old_visible_id) } + + let(:attributes) { { bulk_upload:, field_1: owning_org.old_visible_id, field_2: unaffiliated_org.old_visible_id } } it "is not permitted as setup error" do parser.valid? setup_errors = parser.errors.select { |e| e.options[:category] == :setup } - expect(setup_errors.find { |e| e.attribute == :field_3 }.message).to eql("This user belongs to an organisation that does not have a relationship with the owning organisation") + expect(setup_errors.find { |e| e.attribute == :field_2 }.message).to eql("This organisation does not have a relationship with the owning organisation") end it "blocks log creation" do diff --git a/yarn.lock b/yarn.lock index d6e84caac..1286245d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3245,10 +3245,10 @@ govuk-frontend@4.7.0: resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-4.7.0.tgz#69950b6c2e69f435ffe9aa60d8dee232dac977de" integrity sha512-0OsdCusF5qvLWwKziU8zqxiC0nq6WP0ZQuw51ymZ/1V0tO71oIKMlSLN2S9bm8RcEGSoidPt2A34gKxePrLjvg== -govuk-frontend@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-5.0.0.tgz#c08a4d1115fb31eb39b6d19979c627f816185dd7" - integrity sha512-3WSfvQ+3kw/q/m8jrq/t8XnMUA8D2r0uhGyZaDbIh1gWTJBQzJBHbHiKYI9nc9ixIXdCFsc9RozkgEm57a795g== +govuk-frontend@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-5.1.0.tgz#55e520940b587ddd023e96251efaa076acc9bd5f" + integrity sha512-Dc3J+uOI4i2VR3BVyfxbf6qVjTT4n4bBqbD0/Io6feP8pt/4IfKdP1vWimZf+BwMKKMXacw10hmdy5UcD6Cr8w== govuk-prototype-kit@^13.14.1: version "13.16.0"