diff --git a/app/frontend/controllers/accessible_autocomplete_controller.js b/app/frontend/controllers/accessible_autocomplete_controller.js
index b510a6b02..f3a6ca1d8 100644
--- a/app/frontend/controllers/accessible_autocomplete_controller.js
+++ b/app/frontend/controllers/accessible_autocomplete_controller.js
@@ -22,6 +22,7 @@ export default class extends Controller {
}
},
autoselect: true,
+ placeholder: 'Start typing to search',
templates: { suggestion: (value) => suggestion(value, options) },
name: rawFieldName,
onConfirm: (val) => {
diff --git a/app/helpers/form_page_helper.rb b/app/helpers/form_page_helper.rb
index 99c5276bc..aefbed1c1 100644
--- a/app/helpers/form_page_helper.rb
+++ b/app/helpers/form_page_helper.rb
@@ -10,4 +10,12 @@ module FormPageHelper
def accessed_from_duplicate_logs?(referrer)
%w[duplicate_logs duplicate_logs_banner].include?(referrer)
end
+
+ def duplicate_log_set_path(log, original_log_id)
+ send("#{log.class.name.underscore}_duplicate_logs_path", log, original_log_id:)
+ end
+
+ def relevant_check_answers_path(log, subsection)
+ send("#{log.class.name.underscore}_#{subsection.id}_check_answers_path", log)
+ end
end
diff --git a/app/helpers/review_helper.rb b/app/helpers/review_helper.rb
index e76602a28..87fb691eb 100644
--- a/app/helpers/review_helper.rb
+++ b/app/helpers/review_helper.rb
@@ -11,17 +11,16 @@ module ReviewHelper
end
def review_breadcrumbs(log)
- class_name = log.class.model_name.human.downcase
if log.collection_closed_for_editing?
content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
breadcrumb_logs_title(log, current_user) => breadcrumb_logs_link(log, current_user),
- "Log #{log.id}" => "",
})
else
content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
breadcrumb_logs_title(log, current_user) => breadcrumb_logs_link(log, current_user),
"Log #{log.id}" => url_for(log),
- "Review #{class_name}" => "",
})
end
end
diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb
index 91a56c981..c8ab06b3d 100644
--- a/app/models/lettings_log.rb
+++ b/app/models/lettings_log.rb
@@ -63,7 +63,7 @@ class LettingsLog < Log
.or(filter_by_tenant_code(param))
.or(filter_by_propcode(param))
.or(filter_by_postcode(param))
- .or(filter_by_id(param))
+ .or(filter_by_id(param.gsub(/log/i, "")))
}
scope :after_date, ->(date) { where("lettings_logs.startdate >= ?", date) }
scope :before_date, ->(date) { where("lettings_logs.startdate < ?", date) }
diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb
index c59462cae..e75e4bb55 100644
--- a/app/models/sales_log.rb
+++ b/app/models/sales_log.rb
@@ -48,7 +48,7 @@ class SalesLog < Log
scope :search_by, lambda { |param|
filter_by_purchaser_code(param)
.or(filter_by_postcode(param))
- .or(filter_by_id(param))
+ .or(filter_by_id(param.gsub(/log/i, "")))
}
scope :age1_answered, -> { where.not(age1: nil).or(where(age1_known: [1, 2])) }
scope :duplicate_logs, lambda { |log|
diff --git a/app/models/validations/tenancy_validations.rb b/app/models/validations/tenancy_validations.rb
index 26cccdd81..bd55203fb 100644
--- a/app/models/validations/tenancy_validations.rb
+++ b/app/models/validations/tenancy_validations.rb
@@ -3,48 +3,65 @@ module Validations::TenancyValidations
# or 'validate_' to run on submit as well
include Validations::SharedValidations
- def validate_fixed_term_tenancy(record)
- is_present = record.tenancylength.present?
- is_in_range = record.tenancylength.to_i.between?(min_tenancy_length(record), 99)
- rent_type_dependent_conditions = [
- {
- condition: (record.is_assured_shorthold_tenancy? && !is_in_range) && is_present,
- error: I18n.t(
- "validations.tenancy.length.shorthold",
- min_tenancy_length: min_tenancy_length(record),
- ),
- },
- {
- condition: (record.is_secure_tenancy? && !is_in_range) && is_present,
- error: I18n.t(
- "validations.tenancy.length.secure",
- min_tenancy_length: min_tenancy_length(record),
- ),
- },
- {
- condition: (record.is_periodic_tenancy? && !is_in_range) && is_present,
- error: I18n.t(
- "validations.tenancy.length.secure",
- min_tenancy_length: min_tenancy_length(record),
- ),
- },
- ]
- rent_type_independent_conditions = [
- {
- condition: !(record.is_secure_tenancy? || record.is_assured_shorthold_tenancy? || record.is_periodic_tenancy?) && is_present,
- error: I18n.t("validations.tenancy.length.fixed_term_not_required"),
- },
- ]
- conditions = rent_type_dependent_conditions + rent_type_independent_conditions
-
- conditions.each do |condition|
- next unless condition[:condition]
-
- record.errors.add :needstype, condition[:error]
- record.errors.add :rent_type, condition[:error] if rent_type_dependent_conditions.include?(condition)
- record.errors.add :tenancylength, :tenancylength_invalid, message: condition[:error]
- record.errors.add :tenancy, condition[:error]
- end
+ def validate_supported_housing_fixed_tenancy_length(record)
+ return unless record.tenancy_type_fixed_term? && record.is_supported_housing?
+ return if record.tenancylength.blank?
+
+ min_tenancy_length = 1
+ return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
+
+ message = I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:)
+ record.errors.add :needstype, message
+ record.errors.add :tenancylength, :tenancylength_invalid, message: message
+ record.errors.add :tenancy, message
+ end
+
+ def validate_general_needs_fixed_tenancy_length_affordable_social_rent(record)
+ return unless record.tenancy_type_fixed_term? && record.affordable_or_social_rent? && record.is_general_needs?
+ return if record.tenancylength.blank?
+
+ min_tenancy_length = 2
+ return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
+
+ message = I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:)
+ record.errors.add :needstype, message
+ record.errors.add :rent_type, message
+ record.errors.add :tenancylength, :tenancylength_invalid, message: message
+ record.errors.add :tenancy, message
+ end
+
+ def validate_general_needs_fixed_tenancy_length_intermediate_rent(record)
+ return unless record.tenancy_type_fixed_term? && !record.affordable_or_social_rent? && record.is_general_needs?
+ return if record.tenancylength.blank?
+
+ min_tenancy_length = 1
+ return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
+
+ message = I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:)
+ record.errors.add :needstype, message
+ record.errors.add :rent_type, message
+ record.errors.add :tenancylength, :tenancylength_invalid, message: message
+ record.errors.add :tenancy, message
+ end
+
+ def validate_periodic_tenancy_length(record)
+ return unless record.is_periodic_tenancy? && record.tenancylength.present?
+
+ min_tenancy_length = 1
+ return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
+
+ message = I18n.t("validations.tenancy.length.invalid_periodic", min_tenancy_length:)
+ record.errors.add :tenancylength, :tenancylength_invalid, message: message
+ record.errors.add :tenancy, message
+ end
+
+ def validate_tenancy_length_blank_when_not_required(record)
+ return if record.tenancylength.blank?
+ return if record.tenancy_type_fixed_term? || record.is_periodic_tenancy?
+
+ message = I18n.t("validations.tenancy.length.fixed_term_not_required")
+ record.errors.add :tenancylength, :tenancylength_invalid, message: message
+ record.errors.add :tenancy, message
end
def validate_other_tenancy_type(record)
@@ -59,8 +76,4 @@ module Validations::TenancyValidations
record.errors.add :hhmemb, I18n.t("validations.tenancy.joint_more_than_one_member")
end
end
-
- def min_tenancy_length(record)
- record.is_supported_housing? || record.renttype == 3 || record.is_periodic_tenancy? ? 1 : 2
- end
end
diff --git a/app/services/bulk_upload/lettings/year2023/row_parser.rb b/app/services/bulk_upload/lettings/year2023/row_parser.rb
index 9fda600b5..3c48bc141 100644
--- a/app/services/bulk_upload/lettings/year2023/row_parser.rb
+++ b/app/services/bulk_upload/lettings/year2023/row_parser.rb
@@ -337,6 +337,30 @@ class BulkUpload::Lettings::Year2023::RowParser
},
on: :after_log
+ validates :field_116,
+ inclusion: {
+ in: [1, 2],
+ message: I18n.t("validations.invalid_option", question: "was the letting made under the Choice-Based Lettings (CBL)"),
+ if: -> { field_116.present? },
+ },
+ on: :after_log
+
+ validates :field_117,
+ inclusion: {
+ in: [1, 2],
+ message: I18n.t("validations.invalid_option", question: "was the letting made under the Common Allocation Policy (CAP)"),
+ if: -> { field_117.present? },
+ },
+ on: :after_log
+
+ validates :field_118,
+ inclusion: {
+ in: [1, 2],
+ message: I18n.t("validations.invalid_option", question: "was the letting made under the Common Housing Register (CHR)"),
+ if: -> { field_118.present? },
+ },
+ on: :after_log
+
validates :field_46, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 1 must be a number or the letter R" }, on: :after_log
validates :field_52, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 2 must be a number or the letter R" }, on: :after_log, if: proc { details_known?(2).zero? }
validates :field_56, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 3 must be a number or the letter R" }, on: :after_log, if: proc { details_known?(3).zero? }
diff --git a/app/services/bulk_upload/lettings/year2024/row_parser.rb b/app/services/bulk_upload/lettings/year2024/row_parser.rb
index 3496e0db0..e03fd4817 100644
--- a/app/services/bulk_upload/lettings/year2024/row_parser.rb
+++ b/app/services/bulk_upload/lettings/year2024/row_parser.rb
@@ -337,6 +337,38 @@ class BulkUpload::Lettings::Year2024::RowParser
},
on: :after_log
+ validates :field_112,
+ inclusion: {
+ in: [1, 2],
+ message: I18n.t("validations.invalid_option", question: "was the letting made under the Choice-Based Lettings (CBL)"),
+ if: -> { field_112.present? },
+ },
+ on: :after_log
+
+ validates :field_113,
+ inclusion: {
+ in: [1, 2],
+ message: I18n.t("validations.invalid_option", question: "was the letting made under the Common Allocation Policy (CAP)"),
+ if: -> { field_113.present? },
+ },
+ on: :after_log
+
+ validates :field_114,
+ inclusion: {
+ in: [1, 2],
+ message: I18n.t("validations.invalid_option", question: "was the letting made under the Common Housing Register (CHR)"),
+ if: -> { field_114.present? },
+ },
+ on: :after_log
+
+ validates :field_115,
+ inclusion: {
+ in: [1, 2],
+ message: I18n.t("validations.invalid_option", question: "was the letting made under the Accessible Register"),
+ if: -> { field_115.present? },
+ },
+ on: :after_log
+
validates :field_42, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 1 must be a number or the letter R" }, on: :after_log
validates :field_48, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 2 must be a number or the letter R" }, on: :after_log, if: proc { details_known?(2).zero? }
validates :field_52, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 3 must be a number or the letter R" }, on: :after_log, if: proc { details_known?(3).zero? }
@@ -376,6 +408,7 @@ class BulkUpload::Lettings::Year2024::RowParser
validate :validate_created_by_exists, on: :after_log
validate :validate_created_by_related, on: :after_log
+ validate :validate_all_charges_given, on: :after_log, if: proc { is_carehome.zero? }
validate :validate_address_option_found, on: :after_log
validate :validate_nulls, on: :after_log
@@ -383,7 +416,6 @@ class BulkUpload::Lettings::Year2024::RowParser
validate :validate_uprn_exists_if_any_key_address_fields_are_blank, on: :after_log, unless: -> { supported_housing? }
validate :validate_incomplete_soft_validations, on: :after_log
- validate :validate_all_charges_given, on: :after_log, if: proc { is_carehome.zero? }
validate :validate_nationality, on: :after_log
def self.question_for_field(field)
@@ -681,8 +713,8 @@ private
end
def validate_leaving_reason_for_renewal
- if field_7 == 1 && ![40, 42].include?(field_98)
- errors.add(:field_98, I18n.t("validations.household.reason.renewal_reason_needed"))
+ if field_7 == 1 && ![50, 51, 52, 53].include?(field_98)
+ errors.add(:field_98, I18n.t("validations.household.reason.renewal_reason_needed_2024"))
end
end
@@ -830,16 +862,28 @@ private
def validate_all_charges_given
return if supported_housing? && field_125 == 1
- { field_125: "basic rent",
+ blank_charge_fields, other_charge_fields = {
+ field_125: "basic rent",
field_126: "service charge",
field_127: "personal service charge",
- field_128: "support charge" }.each do |field, charge|
- if public_send(field.to_sym).blank?
- errors.add(field, I18n.t("validations.financial.charges.missing_charges", question: charge))
+ field_128: "support charge",
+ }.partition { |field, _| public_send(field).blank? }.map(&:to_h)
+
+ blank_charge_fields.each do |field, charge|
+ errors.add(field, I18n.t("validations.financial.charges.missing_charges", question: charge))
+ end
+
+ other_charge_fields.each do |field, _charge|
+ blank_charge_fields.each do |_blank_field, blank_charge|
+ errors.add(field, I18n.t("validations.financial.charges.missing_charges", question: blank_charge))
end
end
end
+ def all_charges_given?
+ field_125.present? && field_126.present? && field_127.present? && field_128.present?
+ end
+
def setup_question?(question)
log.form.setup_sections[0].subsections[0].questions.include?(question)
end
@@ -1179,10 +1223,10 @@ private
attributes["benefits"] = field_121
attributes["period"] = field_123
- attributes["brent"] = field_125
- attributes["scharge"] = field_126
- attributes["pscharge"] = field_127
- attributes["supcharg"] = field_128
+ attributes["brent"] = field_125 if all_charges_given?
+ attributes["scharge"] = field_126 if all_charges_given?
+ attributes["pscharge"] = field_127 if all_charges_given?
+ attributes["supcharg"] = field_128 if all_charges_given?
attributes["chcharge"] = field_124
attributes["is_carehome"] = is_carehome
attributes["household_charge"] = supported_housing? ? field_122 : nil
diff --git a/app/services/bulk_upload/sales/year2024/row_parser.rb b/app/services/bulk_upload/sales/year2024/row_parser.rb
index 2132c5e59..7a1481300 100644
--- a/app/services/bulk_upload/sales/year2024/row_parser.rb
+++ b/app/services/bulk_upload/sales/year2024/row_parser.rb
@@ -344,7 +344,7 @@ class BulkUpload::Sales::Year2024::RowParser
validates :field_103,
inclusion: {
in: [1, 2],
- if: proc { field_88 != 100 },
+ if: proc { field_88.present? && field_88 != 100 && shared_ownership? },
question: QUESTIONS[:field_103],
},
on: :before_log
diff --git a/app/services/filter_manager.rb b/app/services/filter_manager.rb
index 28962f0b6..ef74a5575 100644
--- a/app/services/filter_manager.rb
+++ b/app/services/filter_manager.rb
@@ -27,7 +27,7 @@ class FilterManager
logs = logs.public_send("filter_by_#{category}", values, user)
end
- logs = logs.order(created_at: :desc)
+ logs = logs.order(id: :desc)
if user.support?
if logs.first&.lettings?
logs.all.includes(:owning_organisation, :managing_organisation)
diff --git a/app/views/form/check_answers.html.erb b/app/views/form/check_answers.html.erb
index 9247f1aab..7c26dd123 100644
--- a/app/views/form/check_answers.html.erb
+++ b/app/views/form/check_answers.html.erb
@@ -1,8 +1,8 @@
<% content_for :title, "#{subsection.id.humanize} - Check your answers" %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
breadcrumb_logs_title(@log, current_user) => breadcrumb_logs_link(@log, current_user),
"Log #{@log.id}" => url_for(@log),
- subsection.label => "",
}) %>
diff --git a/app/views/form/page.html.erb b/app/views/form/page.html.erb
index a16c01c89..32ccdaed5 100644
--- a/app/views/form/page.html.erb
+++ b/app/views/form/page.html.erb
@@ -1,7 +1,15 @@
<% content_for :title, @page.header.presence || @page.questions.first.header.html_safe %>
-
-<% content_for :before_content do %>
- <%= govuk_back_link(href: send(@log.form.previous_page_redirect_path(@page, @log, current_user, params[:referrer]), @log)) %>
+<% if accessed_from_duplicate_logs?(request.query_parameters["referrer"]) %>
+ <% content_for :before_content do %>
+ <%= govuk_back_link(href: duplicate_log_set_path(@log, request.query_parameters["original_log_id"])) %>
+ <% end %>
+<% else %>
+ <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
+ breadcrumb_logs_title(@log, current_user) => breadcrumb_logs_link(@log, current_user),
+ "Log #{@log.id}" => url_for(@log),
+ @subsection.label => relevant_check_answers_path(@log, @subsection),
+ }) %>
<% end %>
@@ -66,7 +74,7 @@
<% if !@page.interruption_screen? %>
<% if accessed_from_duplicate_logs?(request.query_parameters["referrer"]) %>
<%= f.govuk_submit "Save changes" %>
- <%= govuk_link_to "Cancel", send("#{@log.class.name.underscore}_duplicate_logs_path", @log, original_log_id: request.query_parameters["original_log_id"]) %>
+ <%= govuk_link_to "Cancel", duplicate_log_set_path(@log, request.query_parameters["original_log_id"]) %>
<% elsif returning_to_question_page?(@page, request.query_parameters["referrer"]) %>
<%= f.govuk_submit "Save changes" %>
<%= govuk_link_to "Cancel", send(@log.form.cancel_path(@page, @log), @log) %>
diff --git a/app/views/locations/index.html.erb b/app/views/locations/index.html.erb
index 1705724bb..88b17321e 100644
--- a/app/views/locations/index.html.erb
+++ b/app/views/locations/index.html.erb
@@ -4,9 +4,9 @@
<% if current_user.support? %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
"Schemes (#{@scheme.owning_organisation.name})" => schemes_organisation_path(@scheme.owning_organisation),
content_for(:title) => scheme_path(@scheme),
- "Locations" => "",
}) %>
<% else %>
<% content_for :before_content do %>
diff --git a/app/views/logs/edit.html.erb b/app/views/logs/edit.html.erb
index b4769698b..68bf78e87 100644
--- a/app/views/logs/edit.html.erb
+++ b/app/views/logs/edit.html.erb
@@ -1,7 +1,7 @@
<% content_for :title, "Log #{@log.id}" %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
breadcrumb_logs_title(@log, current_user) => breadcrumb_logs_link(@log, current_user),
- content_for(:title) => "",
}) %>
diff --git a/app/views/schemes/show.html.erb b/app/views/schemes/show.html.erb
index fee4b8a83..c45cefb14 100644
--- a/app/views/schemes/show.html.erb
+++ b/app/views/schemes/show.html.erb
@@ -3,8 +3,8 @@
<% if current_user.support? %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
"Schemes (#{@scheme.owning_organisation.name})" => schemes_organisation_path(@scheme.owning_organisation),
- content_for(:title) => "",
}) %>
<% else %>
<% content_for :before_content do %>
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
index 895a2fe79..a8f12cd36 100644
--- a/app/views/users/show.html.erb
+++ b/app/views/users/show.html.erb
@@ -2,8 +2,8 @@
<% if current_user.support? %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
+ "Home" => root_path,
"Users (#{@user.organisation.name})" => users_organisation_path(@user.organisation),
- content_for(:title) => "",
}) %>
<% else %>
<% content_for :before_content do %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 8f542c8e0..8612e0367 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -545,6 +545,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'
+ renewal_reason_needed_2024: 'The reason for leaving must be "End of social housing tenancy - no fault", "End of social housing tenancy - evicted due to anti-social behaviour (ASB)", "End of social housing tenancy - evicted due to rent arrears" or "End of social housing tenancy - evicted for any other reason"'
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"
@@ -558,8 +559,8 @@ en:
tenancy:
length:
fixed_term_not_required: "You must only answer the length of the tenancy if it's fixed-term"
- shorthold: "Enter a tenancy length between %{min_tenancy_length} and 99 years for a tenancy of this type"
- secure: "Enter a tenancy length between %{min_tenancy_length} and 99 years (or don't specify the length) for a tenancy of this type"
+ invalid_fixed: "Enter a tenancy length between %{min_tenancy_length} and 99 years for a tenancy of this type"
+ invalid_periodic: "Enter a tenancy length between %{min_tenancy_length} and 99 years (or don't specify the length) for a tenancy of this type"
internal_transfer: "Answer must be secure tenancy as this tenancy is an internal transfer"
cannot_be_internal_transfer: "Answer cannot be internal transfer as this is not a secure tenancy"
not_joint: "This cannot be a joint tenancy as you've told us there's only one person in the household"
diff --git a/public/files/2024_25_lettings_paper_form.pdf b/public/files/2024_25_lettings_paper_form.pdf
index 16eb2277f..e65e6b528 100644
Binary files a/public/files/2024_25_lettings_paper_form.pdf and b/public/files/2024_25_lettings_paper_form.pdf differ
diff --git a/public/files/bulk-upload-lettings-specification-2024-25.xlsx b/public/files/bulk-upload-lettings-specification-2024-25.xlsx
index e8f7602bd..700f72603 100644
Binary files a/public/files/bulk-upload-lettings-specification-2024-25.xlsx and b/public/files/bulk-upload-lettings-specification-2024-25.xlsx differ
diff --git a/public/files/bulk-upload-lettings-template-2024-25.xlsx b/public/files/bulk-upload-lettings-template-2024-25.xlsx
index d5930e885..5074d32b2 100644
Binary files a/public/files/bulk-upload-lettings-template-2024-25.xlsx and b/public/files/bulk-upload-lettings-template-2024-25.xlsx differ
diff --git a/spec/features/form/accessible_autocomplete_spec.rb b/spec/features/form/accessible_autocomplete_spec.rb
index 255f95f83..e525da46f 100644
--- a/spec/features/form/accessible_autocomplete_spec.rb
+++ b/spec/features/form/accessible_autocomplete_spec.rb
@@ -60,9 +60,13 @@ RSpec.describe "Accessible Autocomplete" do
it "maintains enhancement state across back navigation", js: true do
find("#lettings-log-prevloc-field").click.native.send_keys("T", "h", "a", "n", :down, :enter)
click_button("Save and continue")
- click_link(text: "Back")
+ page.go_back
expect(page).to have_selector("input", class: "autocomplete__input", count: 1)
end
+
+ it "displays the placeholder text", js: true do
+ expect(find("#lettings-log-prevloc-field")["placeholder"]).to eq("Start typing to search")
+ end
end
context "when searching schemes" do
diff --git a/spec/features/form/form_navigation_spec.rb b/spec/features/form/form_navigation_spec.rb
index 256b16d74..bb326c76c 100644
--- a/spec/features/form/form_navigation_spec.rb
+++ b/spec/features/form/form_navigation_spec.rb
@@ -86,41 +86,18 @@ RSpec.describe "Form Navigation" do
expect(page).to have_current_path("/lettings-logs/#{empty_lettings_log.id}/household-characteristics/check-answers")
end
- describe "Back link directs correctly", js: true do
- it "go back to tasklist page from tenant code" do
- visit("/lettings-logs/#{id}")
- visit("/lettings-logs/#{id}/tenant-code-test")
- click_link(text: "Back")
- expect(page).to have_content("Log #{id}")
- end
-
- it "go back to tenant code page from tenant age page", js: true do
- visit("/lettings-logs/#{id}/tenant-code-test")
- click_button("Save and continue")
- visit("/lettings-logs/#{id}/person-1-age")
- click_link(text: "Back")
- expect(page).to have_field("lettings-log-tenancycode-field")
- end
-
- it "doesn't get stuck in infinite loops", js: true do
- visit("/lettings-logs")
- visit("/lettings-logs/#{id}/net-income")
- fill_in("lettings-log-earnings-field", with: 740)
- choose("lettings-log-incfreq-1-field", allow_label_click: true)
- click_button("Save and continue")
- click_link(text: "Back")
- click_link(text: "Back")
- expect(page).to have_current_path("/lettings-logs/#{id}")
- end
-
- context "when changing an answer from the check answers page", js: true do
- it "the back button routes correctly" do
- visit("/lettings-logs/#{id}/household-characteristics/check-answers")
- first("a", text: /Answer/).click
- click_link("Back")
- expect(page).to have_current_path("/lettings-logs/#{id}/household-characteristics/check-answers")
- end
- end
+ it "has correct breadcrumbs" do
+ visit("/lettings-logs/#{id}/armed-forces")
+ breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
+ expect(breadcrumbs.length).to eq 4
+ expect(breadcrumbs[0].text).to eq "Home"
+ expect(breadcrumbs[0][:href]).to eq root_path
+ expect(breadcrumbs[1].text).to eq "Lettings logs"
+ expect(breadcrumbs[1][:href]).to eq lettings_logs_path
+ expect(breadcrumbs[2].text).to eq "Log #{lettings_log.id}"
+ expect(breadcrumbs[2][:href]).to eq lettings_log_path(lettings_log)
+ expect(breadcrumbs[3].text).to eq "Household needs"
+ expect(breadcrumbs[3][:href]).to eq lettings_log_household_needs_check_answers_path(lettings_log)
end
end
@@ -198,5 +175,14 @@ RSpec.describe "Form Navigation" do
lettings_log.reload
expect(lettings_log.duplicates.count).to eq(1)
end
+
+ it "shows back link to duplicate logs page instead of log breadcrumbs" do
+ expect(lettings_log.duplicates.count).to eq(1)
+ visit("lettings-logs/#{id}/tenant-code-test?first_remaining_duplicate_id=#{id}&original_log_id=#{id}&referrer=duplicate_logs")
+ breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
+ expect(breadcrumbs.length).to eq 0
+ click_link(text: "Back")
+ expect(page).to have_current_path("/lettings-logs/#{id}/duplicate-logs?original_log_id=#{id}")
+ end
end
end
diff --git a/spec/features/form/page_routing_spec.rb b/spec/features/form/page_routing_spec.rb
index e6c821221..0ecb8f5f1 100644
--- a/spec/features/form/page_routing_spec.rb
+++ b/spec/features/form/page_routing_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe "Form Page Routing" do
choose("lettings-log-preg-occ-1-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-yes-page")
- click_link(text: "Back")
+ page.go_back
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question")
choose("lettings-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue")
@@ -155,4 +155,111 @@ RSpec.describe "Form Page Routing" do
end
end
end
+
+ describe "#depends_on_met" do
+ it "returns true if there is no depends_on" do
+ depends_on = nil
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
+ end
+
+ it "returns true if the depends_on is met" do
+ depends_on = [{ "armedforces" => 1 }]
+ lettings_log.armedforces = 1
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
+ end
+
+ it "returns false if the depends_on is not met" do
+ depends_on = [{ "armedforces" => 1 }]
+ lettings_log.armedforces = 0
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(false)
+ end
+
+ it "returns true if a complex depends_on is met" do
+ depends_on = [{ "is_la_inferred" => false, "is_general_needs?" => true }]
+ lettings_log.is_la_inferred = false
+ lettings_log.needstype = 1
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
+ end
+
+ it "returns false if any part of a complex depends_on is not met" do
+ depends_on = [{ "is_la_inferred" => false, "is_general_needs?" => true }]
+ lettings_log.is_la_inferred = false
+ lettings_log.needstype = 2
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(false)
+ end
+
+ it "returns true if the first of multiple depends_ons are met" do
+ depends_on = [{ "is_la_inferred" => false }, { "is_general_needs?" => true }]
+ lettings_log.is_la_inferred = false
+ lettings_log.needstype = 2
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
+ end
+
+ it "returns true if the last of multiple depends_ons are met" do
+ depends_on = [{ "is_la_inferred" => false }, { "is_general_needs?" => true }]
+ lettings_log.is_la_inferred = true
+ lettings_log.needstype = 1
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
+ end
+
+ context "with operator-based depends_ons" do
+ it "returns true if an operator-based depends_on is met" do
+ depends_on = [
+ {
+ "details_known_2" => 0,
+ "age2" => {
+ "operator" => ">",
+ "operand" => 15,
+ },
+ },
+ { "details_known_2" => 0, "age2" => nil },
+ ]
+ lettings_log.details_known_2 = 0
+ lettings_log.age2 = 16
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
+ end
+
+ it "returns false if an operator-based depends_on is not met" do
+ depends_on = [
+ {
+ "details_known_2" => 0,
+ "age2" => {
+ "operator" => ">",
+ "operand" => 15,
+ },
+ },
+ { "details_known_2" => 0, "age2" => nil },
+ ]
+ lettings_log.details_known_2 = 0
+ lettings_log.age2 = 15
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(false)
+ end
+
+ it "returns true if an operator-based depends_on is met on an inequality threshold" do
+ depends_on = [
+ {
+ "details_known_2" => 0,
+ "age2" => {
+ "operator" => ">=",
+ "operand" => 15,
+ },
+ },
+ { "details_known_2" => 0, "age2" => nil },
+ ]
+ lettings_log.details_known_2 = 0
+ lettings_log.age2 = 15
+
+ expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
+ end
+ end
+ end
end
diff --git a/spec/features/lettings_log_spec.rb b/spec/features/lettings_log_spec.rb
index f5aefb6e4..f8740e6f8 100644
--- a/spec/features/lettings_log_spec.rb
+++ b/spec/features/lettings_log_spec.rb
@@ -157,10 +157,13 @@ RSpec.describe "Lettings Log Features" do
it "has the correct breadcrumbs with the correct links" do
visit lettings_log_setup_check_answers_path(lettings_log)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
- expect(breadcrumbs.first.text).to eq "Lettings logs (DLUHC)"
- expect(breadcrumbs.first[:href]).to eq lettings_logs_organisation_path(lettings_log.owning_organisation)
- expect(breadcrumbs[1].text).to eq "Log #{lettings_log.id}"
- expect(breadcrumbs[1][:href]).to eq lettings_log_path(lettings_log)
+ expect(breadcrumbs.length).to eq 3
+ expect(breadcrumbs[0].text).to eq "Home"
+ expect(breadcrumbs[0][:href]).to eq root_path
+ expect(breadcrumbs[1].text).to eq "Lettings logs (DLUHC)"
+ expect(breadcrumbs[1][:href]).to eq lettings_logs_organisation_path(lettings_log.owning_organisation)
+ expect(breadcrumbs[2].text).to eq "Log #{lettings_log.id}"
+ expect(breadcrumbs[2][:href]).to eq lettings_log_path(lettings_log)
end
end
@@ -170,10 +173,13 @@ RSpec.describe "Lettings Log Features" do
it "has the correct breadcrumbs with the correct links" do
visit review_lettings_log_path(lettings_log)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
- expect(breadcrumbs.first.text).to eq "Lettings logs (DLUHC)"
- expect(breadcrumbs.first[:href]).to eq lettings_logs_organisation_path(lettings_log.owning_organisation)
- expect(breadcrumbs[1].text).to eq "Log #{lettings_log.id}"
- expect(breadcrumbs[1][:href]).to eq lettings_log_path(lettings_log)
+ expect(breadcrumbs.length).to eq 3
+ expect(breadcrumbs[0].text).to eq "Home"
+ expect(breadcrumbs[0][:href]).to eq root_path
+ expect(breadcrumbs[1].text).to eq "Lettings logs (DLUHC)"
+ expect(breadcrumbs[1][:href]).to eq lettings_logs_organisation_path(lettings_log.owning_organisation)
+ expect(breadcrumbs[2].text).to eq "Log #{lettings_log.id}"
+ expect(breadcrumbs[2][:href]).to eq lettings_log_path(lettings_log)
end
end
diff --git a/spec/features/sales_log_spec.rb b/spec/features/sales_log_spec.rb
index 83fd2f458..2fa221156 100644
--- a/spec/features/sales_log_spec.rb
+++ b/spec/features/sales_log_spec.rb
@@ -164,10 +164,13 @@ RSpec.describe "Sales Log Features" do
it "has the correct breadcrumbs with the correct links" do
visit sales_log_setup_check_answers_path(sales_log.id)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
- expect(breadcrumbs.first.text).to eq "Sales logs (DLUHC)"
- expect(breadcrumbs.first[:href]).to eq sales_logs_organisation_path(sales_log.owning_organisation)
- expect(breadcrumbs[1].text).to eq "Log #{sales_log.id}"
- expect(breadcrumbs[1][:href]).to eq sales_log_path(sales_log.id)
+ expect(breadcrumbs.length).to eq 3
+ expect(breadcrumbs[0].text).to eq "Home"
+ expect(breadcrumbs[0][:href]).to eq root_path
+ expect(breadcrumbs[1].text).to eq "Sales logs (DLUHC)"
+ expect(breadcrumbs[1][:href]).to eq sales_logs_organisation_path(sales_log.owning_organisation)
+ expect(breadcrumbs[2].text).to eq "Log #{sales_log.id}"
+ expect(breadcrumbs[2][:href]).to eq sales_log_path(sales_log.id)
end
end
@@ -175,10 +178,13 @@ RSpec.describe "Sales Log Features" do
it "has the correct breadcrumbs with the correct links" do
visit review_sales_log_path(sales_log.id, sales_log: true)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
- expect(breadcrumbs.first.text).to eq "Sales logs (DLUHC)"
- expect(breadcrumbs.first[:href]).to eq sales_logs_organisation_path(sales_log.owning_organisation)
- expect(breadcrumbs[1].text).to eq "Log #{sales_log.id}"
- expect(breadcrumbs[1][:href]).to eq sales_log_path(sales_log.id)
+ expect(breadcrumbs.length).to eq 3
+ expect(breadcrumbs[0].text).to eq "Home"
+ expect(breadcrumbs[0][:href]).to eq root_path
+ expect(breadcrumbs[1].text).to eq "Sales logs (DLUHC)"
+ expect(breadcrumbs[1][:href]).to eq sales_logs_organisation_path(sales_log.owning_organisation)
+ expect(breadcrumbs[2].text).to eq "Log #{sales_log.id}"
+ expect(breadcrumbs[2][:href]).to eq sales_log_path(sales_log.id)
end
end
end
diff --git a/spec/models/lettings_log_spec.rb b/spec/models/lettings_log_spec.rb
index f27a7f7e5..d702a3805 100644
--- a/spec/models/lettings_log_spec.rb
+++ b/spec/models/lettings_log_spec.rb
@@ -112,10 +112,17 @@ RSpec.describe LettingsLog do
end
it "validates tenancy type" do
- expect(validator).to receive(:validate_fixed_term_tenancy)
expect(validator).to receive(:validate_other_tenancy_type)
end
+ it "validates tenancy length" do
+ expect(validator).to receive(:validate_supported_housing_fixed_tenancy_length)
+ expect(validator).to receive(:validate_general_needs_fixed_tenancy_length_affordable_social_rent)
+ expect(validator).to receive(:validate_general_needs_fixed_tenancy_length_intermediate_rent)
+ expect(validator).to receive(:validate_periodic_tenancy_length)
+ expect(validator).to receive(:validate_tenancy_length_blank_when_not_required)
+ end
+
it "validates the previous postcode" do
expect(validator).to receive(:validate_previous_accommodation_postcode)
end
@@ -2828,6 +2835,18 @@ RSpec.describe LettingsLog do
expect(result.first.id).to eq lettings_log_to_search.id
end
+ it "allows searching by id including the word log" do
+ result = described_class.search_by("log#{lettings_log_to_search.id}")
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq lettings_log_to_search.id
+ end
+
+ it "allows searching by id including the capitalised word Log" do
+ result = described_class.search_by("Log#{lettings_log_to_search.id}")
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq lettings_log_to_search.id
+ end
+
context "when lettings log is supported housing" do
let(:location) { create(:location, postcode: "W6 0ST") }
diff --git a/spec/models/sales_log_spec.rb b/spec/models/sales_log_spec.rb
index 1ad889e84..18b5dc5e8 100644
--- a/spec/models/sales_log_spec.rb
+++ b/spec/models/sales_log_spec.rb
@@ -162,6 +162,50 @@ RSpec.describe SalesLog, type: :model do
end
end
+ describe "#search_by" do
+ let!(:sales_log_to_search) { create(:sales_log, :completed) }
+
+ it "allows searching using ID" do
+ result = described_class.search_by(sales_log_to_search.id.to_s)
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq sales_log_to_search.id
+ end
+
+ it "allows searching using purchaser code" do
+ result = described_class.search_by(sales_log_to_search.purchaser_code)
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq sales_log_to_search.id
+ end
+
+ it "allows searching by a Property Postcode" do
+ result = described_class.search_by(sales_log_to_search.postcode_full)
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq sales_log_to_search.id
+ end
+
+ it "allows searching by id including the word log" do
+ result = described_class.search_by("log#{sales_log_to_search.id}")
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq sales_log_to_search.id
+ end
+
+ it "allows searching by id including the capitalised word Log" do
+ result = described_class.search_by("Log#{sales_log_to_search.id}")
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq sales_log_to_search.id
+ end
+
+ context "when postcode has spaces and lower case letters" do
+ let(:matching_postcode_lower_case_with_spaces) { sales_log_to_search.postcode_full.downcase.chars.insert(3, " ").join }
+
+ it "allows searching by a Property Postcode" do
+ result = described_class.search_by(matching_postcode_lower_case_with_spaces)
+ expect(result.count).to eq(1)
+ expect(result.first.id).to eq sales_log_to_search.id
+ end
+ end
+ end
+
context "when filtering by year or nil" do
before do
Timecop.freeze(Time.utc(2021, 5, 3))
diff --git a/spec/models/validations/tenancy_validations_spec.rb b/spec/models/validations/tenancy_validations_spec.rb
index 3d39e1e39..f5ffc05b0 100644
--- a/spec/models/validations/tenancy_validations_spec.rb
+++ b/spec/models/validations/tenancy_validations_spec.rb
@@ -3,280 +3,272 @@ require "rails_helper"
RSpec.describe Validations::TenancyValidations do
subject(:tenancy_validator) { validator_class.new }
- before do
- Timecop.freeze(Time.zone.local(2021, 5, 1))
- end
+ let(:validator_class) { Class.new { include Validations::TenancyValidations } }
- after do
- Timecop.unfreeze
- end
+ describe "tenancy length validations" do
+ let(:record) { FactoryBot.create(:lettings_log, :setup_completed) }
- let(:validator_class) { Class.new { include Validations::TenancyValidations } }
- let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2021, 5, 1), needstype: 1, rent_type: 1) }
-
- describe "fixed term tenancy validations" do
- context "when fixed term tenancy" do
- context "when type of tenancy is not assured or assured shorthold" do
- let(:expected_error) { I18n.t("validations.tenancy.length.fixed_term_not_required") }
-
- it "tenancy length should not be present" do
- record.tenancy = 3
- record.tenancylength = 10
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["rent_type"]).not_to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
- end
- end
+ shared_examples "adds expected errors based on the tenancy length" do |tenancy_type_case, error_fields, min_tenancy_length|
+ context "and tenancy type is #{tenancy_type_case[:name]}" do
+ let(:expected_error) { tenancy_type_case[:expected_error].call(min_tenancy_length) }
- context "when type of tenancy is assured shorthold" do
- let(:expected_error) do
- I18n.t(
- "validations.tenancy.length.shorthold",
- min_tenancy_length: 2,
- )
- end
+ before { record.tenancy = tenancy_type_case[:code] }
- before { record.tenancy = 4 }
+ context "and tenancy length is less than #{min_tenancy_length}" do
+ before { record.tenancylength = min_tenancy_length - 1 }
- context "when tenancy length is less than 2" do
- it "adds an error" do
- record.tenancylength = 1
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["rent_type"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
+ it "adds errors to #{error_fields.join(', ')}" do
+ validation.call(record)
+ error_fields.each do |field|
+ expect(record.errors[field]).to include(match(expected_error))
+ end
+ expect(record.errors.size).to be(error_fields.length)
end
end
- context "when tenancy length is greater than 99" do
- it "adds an error" do
- record.tenancylength = 100
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["rent_type"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
+ context "and tenancy length is more than 99" do
+ before { record.tenancylength = 100 }
+
+ it "adds errors to #{error_fields.join(', ')}" do
+ validation.call(record)
+ error_fields.each do |field|
+ expect(record.errors[field]).to include(match(expected_error))
+ end
+ expect(record.errors.size).to be(error_fields.length)
end
end
- context "when tenancy length is between 2-99" do
- it "does not add an error" do
- record.tenancylength = 3
- tenancy_validator.validate_fixed_term_tenancy(record)
+ context "and tenancy length is between #{min_tenancy_length} and 99" do
+ before { record.tenancylength = min_tenancy_length }
+
+ it "does not add errors" do
+ validation.call(record)
expect(record.errors).to be_empty
end
end
- context "when tenancy length has not been answered" do
- it "does not add an error" do
- record.tenancylength = nil
- tenancy_validator.validate_fixed_term_tenancy(record)
+ context "and tenancy length is not set" do
+ before { record.tenancylength = nil }
+
+ it "does not add errors" do
+ validation.call(record)
expect(record.errors).to be_empty
end
end
end
+ end
- context "when the collection start year is before 2022" do
- context "when type of tenancy is secure" do
- let(:expected_error) do
- I18n.t(
- "validations.tenancy.length.secure",
- min_tenancy_length: 2,
- )
- end
+ shared_examples "does not add errors when tenancy type is not fixed term" do
+ context "and tenancy type is not fixed term" do
+ before do
+ record.tenancy = 8
+ record.tenancylength = 0
+ end
+
+ it "does not add errors" do
+ validation.call(record)
+ expect(record.errors).to be_empty
+ end
+ end
+ end
- before { record.tenancy = 1 }
+ fixed_term_tenancy_type_cases = [
+ {
+ name: "assured shorthold",
+ code: 4,
+ expected_error: ->(min_tenancy_length) { I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:) },
+ },
+ {
+ name: "secure fixed term",
+ code: 6,
+ expected_error: ->(min_tenancy_length) { I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:) },
+ },
+ ]
+
+ describe "#validate_supported_housing_fixed_tenancy_length" do
+ subject(:validation) { ->(record) { tenancy_validator.validate_supported_housing_fixed_tenancy_length(record) } }
+
+ context "when needs type is supported housing" do
+ before { record.needstype = 2 }
+
+ error_fields = %w[needstype tenancylength tenancy]
+ fixed_term_tenancy_type_cases.each do |tenancy_type_case|
+ include_examples "adds expected errors based on the tenancy length", tenancy_type_case, error_fields, 1
+ end
- context "when tenancy length is less than 2" do
- it "adds an error" do
- record.tenancylength = 1
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
- end
- end
+ include_examples "does not add errors when tenancy type is not fixed term"
+ end
- context "when tenancy length is greater than 99" do
- it "adds an error" do
- record.tenancylength = 100
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
- end
+ context "when needs type is general needs" do
+ before do
+ record.needstype = 1
+ record.tenancy = 4
+ record.tenancylength = 0
+ end
+
+ it "does not add errors" do
+ validation.call(record)
+ expect(record.errors).to be_empty
+ end
+ end
+ end
+
+ describe "#validate_general_needs_fixed_tenancy_length_affordable_social_rent" do
+ subject(:validation) { ->(record) { tenancy_validator.validate_general_needs_fixed_tenancy_length_affordable_social_rent(record) } }
+
+ context "when needs type is general needs" do
+ before { record.needstype = 1 }
+
+ context "and rent type is affordable or social rent" do
+ before { record.renttype = 1 }
+
+ error_fields = %w[needstype rent_type tenancylength tenancy]
+ fixed_term_tenancy_type_cases.each do |tenancy_type_case|
+ include_examples "adds expected errors based on the tenancy length", tenancy_type_case, error_fields, 2
end
- context "when tenancy length is between 2-99" do
- it "does not add an error" do
- record.tenancylength = 3
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
+ include_examples "does not add errors when tenancy type is not fixed term"
+ end
+
+ context "and rent type is intermediate rent" do
+ before do
+ record.renttype = 3
+ record.tenancy = 4
+ record.tenancylength = 0
end
- context "when tenancy length has not been answered" do
- it "does not add an error" do
- record.tenancylength = nil
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
+ it "does not add errors" do
+ validation.call(record)
+ expect(record.errors).to be_empty
end
end
end
- context "when the collection start year is 2022 or later" do
+ context "when needs type is supported housing" do
before do
- Timecop.freeze(2022, 5, 1)
+ record.needstype = 2
+ record.renttype = 1
+ record.tenancy = 4
+ record.tenancylength = 0
end
- after do
- Timecop.unfreeze
+ it "does not add errors" do
+ validation.call(record)
+ expect(record.errors).to be_empty
end
+ end
+ end
- let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2022, 5, 1), needstype: 1, rent_type: 1) }
+ describe "#validate_general_needs_fixed_tenancy_length_intermediate_rent" do
+ subject(:validation) { ->(record) { tenancy_validator.validate_general_needs_fixed_tenancy_length_intermediate_rent(record) } }
- context "when type of tenancy is Secure - fixed term" do
- let(:expected_error) do
- I18n.t(
- "validations.tenancy.length.secure",
- min_tenancy_length: 2,
- )
- end
+ context "when needs type is general needs" do
+ before { record.needstype = 1 }
- before { record.tenancy = 6 }
+ context "and rent type is intermediate rent" do
+ before { record.renttype = 3 }
- context "when tenancy length is less than 2" do
- it "adds an error" do
- record.tenancylength = 1
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
- end
+ error_fields = %w[needstype rent_type tenancylength tenancy]
+ fixed_term_tenancy_type_cases.each do |tenancy_type_case|
+ include_examples "adds expected errors based on the tenancy length", tenancy_type_case, error_fields, 1
end
- context "when tenancy length is greater than 99" do
- it "adds an error" do
- record.tenancylength = 100
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
- end
- end
+ include_examples "does not add errors when tenancy type is not fixed term"
+ end
- context "when tenancy length is between 2-99" do
- it "does not add an error" do
- record.tenancylength = 3
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
+ context "and rent type is not intermediate rent" do
+ before do
+ record.renttype = 2
+ record.tenancy = 4
+ record.tenancylength = 0
end
- context "when tenancy length has not been answered" do
- it "does not add an error" do
- record.tenancylength = nil
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
+ it "does not add errors" do
+ validation.call(record)
+ expect(record.errors).to be_empty
end
end
+ end
- context "when type of tenancy is Secure - lifetime" do
- let(:expected_error) do
- I18n.t(
- "validations.tenancy.length.secure",
- min_tenancy_length: 2,
- )
- end
+ context "when needs type is supported housing" do
+ before do
+ record.needstype = 2
+ record.renttype = 3
+ record.tenancy = 4
+ record.tenancylength = 0
+ end
- before { record.tenancy = 7 }
+ it "does not add errors" do
+ validation.call(record)
+ expect(record.errors).to be_empty
+ end
+ end
+ end
- context "when tenancy length is less than 2" do
- it "adds an error" do
- record.tenancylength = 1
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
- end
- end
+ describe "#validate_periodic_tenancy_length" do
+ subject(:validation) { ->(record) { tenancy_validator.validate_periodic_tenancy_length(record) } }
- context "when tenancy length is greater than 99" do
- it "adds an error" do
- record.tenancylength = 100
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
- end
- end
+ periodic_tenancy_case = {
+ name: "periodic",
+ code: 8,
+ expected_error: ->(min_tenancy_length) { I18n.t("validations.tenancy.length.invalid_periodic", min_tenancy_length:) },
+ }
+ error_fields = %w[tenancylength tenancy]
+ include_examples "adds expected errors based on the tenancy length", periodic_tenancy_case, error_fields, 1
- context "when tenancy length is between 2-99" do
- it "does not add an error" do
- record.tenancylength = 3
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
- end
+ context "when tenancy type is not periodic" do
+ before do
+ record.tenancy = 6
+ record.tenancylength = 0
+ end
- context "when tenancy length has not been answered" do
- it "does not add an error" do
- record.tenancylength = nil
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
- end
+ it "does not add errors" do
+ validation.call(record)
+ expect(record.errors).to be_empty
end
+ end
- context "when type of tenancy is periodic" do
- let(:expected_error) do
- I18n.t(
- "validations.tenancy.length.secure",
- min_tenancy_length: 1,
- )
- end
+ describe "#validate_tenancy_length_blank_when_not_required" do
+ context "when a tenancy length is provided" do
+ before { record.tenancylength = 10 }
- before { record.tenancy = 8 }
+ context "and tenancy type is not fixed term or periodic" do
+ before { record.tenancy = 5 }
- context "when tenancy length is less than 1" do
- it "adds an error" do
- record.tenancylength = 0
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
+ it "adds errors to tenancylength and tenancy" do
+ tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
+ expected_error = I18n.t("validations.tenancy.length.fixed_term_not_required")
+ expect(record.errors["tenancylength"]).to include(expected_error)
+ expect(record.errors["tenancy"]).to include(expected_error)
end
end
- context "when tenancy length is greater than 99" do
- it "adds an error" do
- record.tenancylength = 100
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors["needstype"]).to include(match(expected_error))
- expect(record.errors["tenancylength"]).to include(match(expected_error))
- expect(record.errors["tenancy"]).to include(match(expected_error))
+ tenancy_types_with_length = [
+ { name: "assured shorthold", code: 4 },
+ { name: "secure fixed term", code: 6 },
+ { name: "periodic", code: 8 },
+ ]
+ tenancy_types_with_length.each do |type|
+ context "and tenancy type is #{type[:name]}" do
+ before { record.tenancy = type[:code] }
+
+ it "does not add errors" do
+ tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
+ expect(record.errors).to be_empty
+ end
end
end
+ end
- context "when tenancy length is between 2-99" do
- it "does not add an error" do
- record.tenancylength = 3
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
+ context "when tenancy length is not provided" do
+ before do
+ record.tenancylength = nil
+ record.tenancy = 5
end
- context "when tenancy length has not been answered" do
- it "does not add an error" do
- record.tenancylength = nil
- tenancy_validator.validate_fixed_term_tenancy(record)
- expect(record.errors).to be_empty
- end
+ it "does not add errors" do
+ tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
+ expect(record.errors).to be_empty
end
end
end
@@ -284,6 +276,7 @@ RSpec.describe Validations::TenancyValidations do
end
describe "tenancy type validations" do
+ let(:record) { FactoryBot.create(:lettings_log, :setup_completed) }
let(:field) { "validations.other_field_missing" }
let(:main_field_label) { "tenancy type" }
let(:other_field) { "tenancyother" }
@@ -327,20 +320,11 @@ RSpec.describe Validations::TenancyValidations do
describe "joint tenancy validation" do
context "when the data inputter has said that there is only one member in the household" do
- before do
- Timecop.freeze(2022, 5, 1)
- end
-
- after do
- Timecop.unfreeze
- end
-
- let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2022, 5, 1)) }
+ let(:record) { FactoryBot.create(:lettings_log, :setup_completed, hhmemb: 1) }
let(:expected_error) { I18n.t("validations.tenancy.not_joint") }
let(:hhmemb_expected_error) { I18n.t("validations.tenancy.joint_more_than_one_member") }
it "displays an error if the data inputter says the letting is a joint tenancy" do
- record.hhmemb = 1
record.joint = 1
tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to include(match(expected_error))
@@ -348,7 +332,6 @@ RSpec.describe Validations::TenancyValidations do
end
it "does not display an error if the data inputter says the letting is not a joint tenancy" do
- record.hhmemb = 1
record.joint = 2
tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to be_empty
@@ -356,7 +339,6 @@ RSpec.describe Validations::TenancyValidations do
end
it "does not display an error if the data inputter has given the household members but not input if it is a joint tenancy" do
- record.hhmemb = 1
record.joint = nil
tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to be_empty
@@ -364,7 +346,6 @@ RSpec.describe Validations::TenancyValidations do
end
it "does not error when don't know answer to joint" do
- record.hhmemb = 1
record.joint = 3
tenancy_validator.validate_joint_tenancy(record)
diff --git a/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
index 7435a3d74..a5dd076aa 100644
--- a/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
+++ b/spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
@@ -1997,6 +1997,15 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
expect(parser.log.cbl).to be(0)
end
end
+
+ context "when field_116 is not a permitted value" do
+ let(:attributes) { { bulk_upload:, field_116: 3 } }
+
+ it "adds an error" do
+ parser.valid?
+ expect(parser.errors[:field_116]).to include("Enter a valid value for was the letting made under the Choice-Based Lettings (CBL)")
+ end
+ end
end
describe "#chr" do
@@ -2015,6 +2024,15 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
expect(parser.log.chr).to be(0)
end
end
+
+ context "when field_118 is not a permitted value" do
+ let(:attributes) { { bulk_upload:, field_118: 3 } }
+
+ it "adds an error" do
+ parser.valid?
+ expect(parser.errors[:field_118]).to include("Enter a valid value for was the letting made under the Common Housing Register (CHR)")
+ end
+ end
end
describe "#cap" do
@@ -2033,6 +2051,15 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
expect(parser.log.cap).to be(0)
end
end
+
+ context "when field_117 is not a permitted value" do
+ let(:attributes) { { bulk_upload:, field_117: 3 } }
+
+ it "adds an error" do
+ parser.valid?
+ expect(parser.errors[:field_117]).to include("Enter a valid value for was the letting made under the Common Allocation Policy (CAP)")
+ end
+ end
end
describe "#letting_allocation_unknown" do
diff --git a/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb b/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
index b6ccdf7ab..cd398dabd 100644
--- a/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
+++ b/spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
@@ -993,27 +993,43 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
describe "#field_98" do # leaving reason
context "when field_7 is 1 meaning it is a renewal" do
- context "when field_98 is 40" do
- let(:attributes) { { bulk_upload:, field_98: "40", field_7: "1" } }
+ context "when field_98 is 50" do
+ let(:attributes) { { bulk_upload:, field_98: "50", field_7: "1" } }
it "is permitted" do
expect(parser.errors[:field_98]).to be_blank
end
end
- context "when field_98 is 42" do
- let(:attributes) { { bulk_upload:, field_98: "42", field_7: "1" } }
+ context "when field_98 is 51" do
+ let(:attributes) { { bulk_upload:, field_98: "51", field_7: "1" } }
it "is permitted" do
expect(parser.errors[:field_98]).to be_blank
end
end
- context "when field_98 is not 40 or 42" do
+ context "when field_98 is 52" do
+ let(:attributes) { { bulk_upload:, field_98: "52", field_7: "1" } }
+
+ it "is permitted" do
+ expect(parser.errors[:field_98]).to be_blank
+ end
+ end
+
+ context "when field_98 is 53" do
+ let(:attributes) { { bulk_upload:, field_98: "53", field_7: "1" } }
+
+ it "is permitted" do
+ expect(parser.errors[:field_98]).to be_blank
+ end
+ end
+
+ context "when field_98 is not 50, 51, 52 or 53" do
let(:attributes) { { bulk_upload:, field_98: "1", field_7: "1" } }
it "is not permitted" do
- expect(parser.errors[:field_98]).to be_present
+ expect(parser.errors[:field_98]).to include('The reason for leaving must be "End of social housing tenancy - no fault", "End of social housing tenancy - evicted due to anti-social behaviour (ASB)", "End of social housing tenancy - evicted due to rent arrears" or "End of social housing tenancy - evicted for any other reason"')
end
end
end
@@ -1654,7 +1670,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
context "when soft validation is triggered and not required" do
- let(:attributes) { setup_section_params.merge({ field_125: 120, field_123: 1, field_29: 1, field_4: 1, field_11: "1", field_23: "E09000008" }) }
+ let(:attributes) { setup_section_params.merge({ field_125: 120, field_126: 120, field_127: 120, field_128: 120, field_123: 1, field_29: 1, field_4: 1, field_11: "1", field_23: "E09000008" }) }
it "adds an error to the relevant fields" do
expect(parser.errors.where(:field_125, category: :soft_validation)).to be_present
@@ -1890,6 +1906,15 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
expect(parser.log.cbl).to be(0)
end
end
+
+ context "when field_112 is not a permitted value" do
+ let(:attributes) { { bulk_upload:, field_112: 3 } }
+
+ it "adds an error" do
+ parser.valid?
+ expect(parser.errors[:field_112]).to include("Enter a valid value for was the letting made under the Choice-Based Lettings (CBL)")
+ end
+ end
end
describe "#chr" do
@@ -1908,6 +1933,15 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
expect(parser.log.chr).to be(0)
end
end
+
+ context "when field_114 is not a permitted value" do
+ let(:attributes) { { bulk_upload:, field_114: 3 } }
+
+ it "adds an error" do
+ parser.valid?
+ expect(parser.errors[:field_114]).to include("Enter a valid value for was the letting made under the Common Housing Register (CHR)")
+ end
+ end
end
describe "#cap" do
@@ -1926,6 +1960,42 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
expect(parser.log.cap).to be(0)
end
end
+
+ context "when field_113 is not a permitted value" do
+ let(:attributes) { { bulk_upload:, field_113: 3 } }
+
+ it "adds an error" do
+ parser.valid?
+ expect(parser.errors[:field_113]).to include("Enter a valid value for was the letting made under the Common Allocation Policy (CAP)")
+ end
+ end
+ end
+
+ describe "#accessible_register" do
+ context "when field_115 is yes ie 1" do
+ let(:attributes) { { bulk_upload:, field_115: 1 } }
+
+ it "sets value to 1" do
+ expect(parser.log.accessible_register).to be(1)
+ end
+ end
+
+ context "when field_115 is no ie 2" do
+ let(:attributes) { { bulk_upload:, field_115: 2 } }
+
+ it "sets value to 0" do
+ expect(parser.log.accessible_register).to be(0)
+ end
+ end
+
+ context "when field_115 is not a permitted value" do
+ let(:attributes) { { bulk_upload:, field_115: 3 } }
+
+ it "adds an error" do
+ parser.valid?
+ expect(parser.errors[:field_115]).to include("Enter a valid value for was the letting made under the Accessible Register")
+ end
+ end
end
describe "#letting_allocation_unknown" do
@@ -2187,7 +2257,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
describe "#chcharge" do
- let(:attributes) { { bulk_upload:, field_124: "123.45", field_125: "123.45", field_126: "123.45", field_127: "123.45", field_128: "123.45" } }
+ let(:attributes) { setup_section_params.merge({ field_124: "123.45", field_125: "123.45", field_126: "123.45", field_127: "123.45", field_128: "123.45" }) }
it "sets value given" do
expect(parser.log.chcharge).to eq(123.45)
@@ -2208,7 +2278,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
describe "#supcharg" do
- let(:attributes) { { bulk_upload:, field_128: "123.45" } }
+ let(:attributes) { setup_section_params.merge({ field_125: "330", field_126: "0", field_127: "0", field_128: "123.45" }) }
it "sets value given" do
expect(parser.log.supcharg).to eq(123.45)
@@ -2216,7 +2286,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
context "when other charges are not given" do
context "and it is carehome" do
- let(:attributes) { { bulk_upload:, field_128: "123.45", field_124: "123.45", field_125: nil, field_126: nil, field_127: nil } }
+ let(:attributes) { setup_section_params.merge({ field_128: "123.45", field_124: "123.45", field_125: nil, field_126: nil, field_127: nil }) }
it "does not set charges values" do
parser.log.save!
@@ -2237,7 +2307,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
context "and it is not carehome" do
- let(:attributes) { { bulk_upload:, field_128: "123.45", field_124: nil, field_125: nil, field_126: nil, field_127: nil } }
+ let(:attributes) { setup_section_params.merge({ field_128: "123.45", field_124: nil, field_125: nil, field_126: nil, field_127: nil }) }
it "does not set charges values" do
parser.log.save!
@@ -2253,14 +2323,38 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
expect(parser.errors[:field_125]).to eql(["Please enter the basic rent. If there is no basic rent, please enter '0'."])
expect(parser.errors[:field_126]).to eql(["Please enter the service charge. If there is no service charge, please enter '0'."])
expect(parser.errors[:field_127]).to eql(["Please enter the personal service charge. If there is no personal service charge, please enter '0'."])
- expect(parser.errors[:field_128]).to be_empty
+ expect(parser.errors[:field_128]).to eql(["Please enter the basic rent. If there is no basic rent, please enter '0'.", "Please enter the service charge. If there is no service charge, please enter '0'.", "Please enter the personal service charge. If there is no personal service charge, please enter '0'."])
+ end
+ end
+ end
+
+ context "when supscharg is not given" do
+ context "and it is not carehome" do
+ let(:attributes) { setup_section_params.merge({ field_123: 1, field_124: nil, field_125: "350.45", field_126: "0", field_127: "0", field_128: nil }) }
+
+ it "does not set charges values" do
+ parser.log.save!
+ expect(parser.log.period).not_to be_nil
+ expect(parser.log.tcharge).to be_nil
+ expect(parser.log.brent).to be_nil
+ expect(parser.log.supcharg).to be_nil
+ expect(parser.log.pscharge).to be_nil
+ expect(parser.log.scharge).to be_nil
+ end
+
+ it "adds an error to all charges" do
+ parser.valid?
+ expect(parser.errors[:field_125]).to eql(["Please enter the support charge. If there is no support charge, please enter '0'."])
+ expect(parser.errors[:field_126]).to eql(["Please enter the support charge. If there is no support charge, please enter '0'."])
+ expect(parser.errors[:field_127]).to eql(["Please enter the support charge. If there is no support charge, please enter '0'."])
+ expect(parser.errors[:field_128]).to eql(["Please enter the support charge. If there is no support charge, please enter '0'."])
end
end
end
end
describe "#pscharge" do
- let(:attributes) { { bulk_upload:, field_127: "123.45" } }
+ let(:attributes) { { bulk_upload:, field_125: "111.45", field_126: "0", field_127: "123.45", field_128: "0" } }
it "sets value given" do
expect(parser.log.pscharge).to eq(123.45)
@@ -2268,7 +2362,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
describe "#scharge" do
- let(:attributes) { { bulk_upload:, field_126: "123.45" } }
+ let(:attributes) { { bulk_upload:, field_125: "111.45", field_126: "123.45", field_127: "0", field_128: "0" } }
it "sets value given" do
expect(parser.log.scharge).to eq(123.45)
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 ba2edf33a..ce81300b5 100644
--- a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
+++ b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
@@ -1009,6 +1009,22 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
end
end
+ context "when value is 3 and stairowned is not answered" do
+ let(:attributes) { setup_section_params.merge(field_103: "3", field_86: "1", field_87: "50", field_88: nil, field_109: nil) }
+
+ it "does not add errors" do
+ expect(parser.errors[:field_103]).not_to include("Enter a valid value for Was a mortgage used for the purchase of this property? - Shared ownership")
+ end
+ end
+
+ context "when it's not shared ownership" do
+ let(:attributes) { setup_section_params.merge(field_8: "2", field_103: "3", field_86: "1", field_87: "50", field_88: "99", field_109: nil) }
+
+ it "does not add errors" do
+ expect(parser.errors[:field_103]).not_to include("Enter a valid value for Was a mortgage used for the purchase of this property? - Shared ownership")
+ end
+ end
+
context "when value is 3 and stairowned is 100" do
let(:attributes) { setup_section_params.merge(field_103: "3", field_86: "1", field_87: "50", field_88: "100", field_109: nil) }
diff --git a/spec/views/form/page_view_spec.rb b/spec/views/form/page_view_spec.rb
index 614f56562..6664981f9 100644
--- a/spec/views/form/page_view_spec.rb
+++ b/spec/views/form/page_view_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe "form/page" do
end
before do
+ sign_in create(:user)
assign(:log, lettings_log)
assign(:page, page)
assign(:subsection, subsection)