Browse Source

Merge branch 'main' into CLDC-2069-find-UPRN-by-address

# Conflicts:
#	app/services/bulk_upload/lettings/year2024/row_parser.rb
pull/2278/head
natdeanlewissoftwire 2 years ago
parent
commit
1d17df453e
  1. 1
      app/frontend/controllers/accessible_autocomplete_controller.js
  2. 8
      app/helpers/form_page_helper.rb
  3. 5
      app/helpers/review_helper.rb
  4. 2
      app/models/lettings_log.rb
  5. 2
      app/models/sales_log.rb
  6. 105
      app/models/validations/tenancy_validations.rb
  7. 24
      app/services/bulk_upload/lettings/year2023/row_parser.rb
  8. 66
      app/services/bulk_upload/lettings/year2024/row_parser.rb
  9. 2
      app/services/bulk_upload/sales/year2024/row_parser.rb
  10. 2
      app/services/filter_manager.rb
  11. 2
      app/views/form/check_answers.html.erb
  12. 16
      app/views/form/page.html.erb
  13. 2
      app/views/locations/index.html.erb
  14. 2
      app/views/logs/edit.html.erb
  15. 2
      app/views/schemes/show.html.erb
  16. 2
      app/views/users/show.html.erb
  17. 5
      config/locales/en.yml
  18. BIN
      public/files/2024_25_lettings_paper_form.pdf
  19. BIN
      public/files/bulk-upload-lettings-specification-2024-25.xlsx
  20. BIN
      public/files/bulk-upload-lettings-template-2024-25.xlsx
  21. 6
      spec/features/form/accessible_autocomplete_spec.rb
  22. 56
      spec/features/form/form_navigation_spec.rb
  23. 109
      spec/features/form/page_routing_spec.rb
  24. 22
      spec/features/lettings_log_spec.rb
  25. 22
      spec/features/sales_log_spec.rb
  26. 21
      spec/models/lettings_log_spec.rb
  27. 44
      spec/models/sales_log_spec.rb
  28. 427
      spec/models/validations/tenancy_validations_spec.rb
  29. 27
      spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
  30. 122
      spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
  31. 16
      spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
  32. 1
      spec/views/form/page_view_spec.rb

1
app/frontend/controllers/accessible_autocomplete_controller.js

@ -22,6 +22,7 @@ export default class extends Controller {
} }
}, },
autoselect: true, autoselect: true,
placeholder: 'Start typing to search',
templates: { suggestion: (value) => suggestion(value, options) }, templates: { suggestion: (value) => suggestion(value, options) },
name: rawFieldName, name: rawFieldName,
onConfirm: (val) => { onConfirm: (val) => {

8
app/helpers/form_page_helper.rb

@ -10,4 +10,12 @@ module FormPageHelper
def accessed_from_duplicate_logs?(referrer) def accessed_from_duplicate_logs?(referrer)
%w[duplicate_logs duplicate_logs_banner].include?(referrer) %w[duplicate_logs duplicate_logs_banner].include?(referrer)
end 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 end

5
app/helpers/review_helper.rb

@ -11,17 +11,16 @@ module ReviewHelper
end end
def review_breadcrumbs(log) def review_breadcrumbs(log)
class_name = log.class.model_name.human.downcase
if log.collection_closed_for_editing? if log.collection_closed_for_editing?
content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Home" => root_path,
breadcrumb_logs_title(log, current_user) => breadcrumb_logs_link(log, current_user), breadcrumb_logs_title(log, current_user) => breadcrumb_logs_link(log, current_user),
"Log #{log.id}" => "",
}) })
else else
content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Home" => root_path,
breadcrumb_logs_title(log, current_user) => breadcrumb_logs_link(log, current_user), breadcrumb_logs_title(log, current_user) => breadcrumb_logs_link(log, current_user),
"Log #{log.id}" => url_for(log), "Log #{log.id}" => url_for(log),
"Review #{class_name}" => "",
}) })
end end
end end

2
app/models/lettings_log.rb

@ -63,7 +63,7 @@ class LettingsLog < Log
.or(filter_by_tenant_code(param)) .or(filter_by_tenant_code(param))
.or(filter_by_propcode(param)) .or(filter_by_propcode(param))
.or(filter_by_postcode(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 :after_date, ->(date) { where("lettings_logs.startdate >= ?", date) }
scope :before_date, ->(date) { where("lettings_logs.startdate < ?", date) } scope :before_date, ->(date) { where("lettings_logs.startdate < ?", date) }

2
app/models/sales_log.rb

@ -48,7 +48,7 @@ class SalesLog < Log
scope :search_by, lambda { |param| scope :search_by, lambda { |param|
filter_by_purchaser_code(param) filter_by_purchaser_code(param)
.or(filter_by_postcode(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 :age1_answered, -> { where.not(age1: nil).or(where(age1_known: [1, 2])) }
scope :duplicate_logs, lambda { |log| scope :duplicate_logs, lambda { |log|

105
app/models/validations/tenancy_validations.rb

@ -3,48 +3,65 @@ module Validations::TenancyValidations
# or 'validate_' to run on submit as well # or 'validate_' to run on submit as well
include Validations::SharedValidations include Validations::SharedValidations
def validate_fixed_term_tenancy(record) def validate_supported_housing_fixed_tenancy_length(record)
is_present = record.tenancylength.present? return unless record.tenancy_type_fixed_term? && record.is_supported_housing?
is_in_range = record.tenancylength.to_i.between?(min_tenancy_length(record), 99) return if record.tenancylength.blank?
rent_type_dependent_conditions = [
{ min_tenancy_length = 1
condition: (record.is_assured_shorthold_tenancy? && !is_in_range) && is_present, return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
error: I18n.t(
"validations.tenancy.length.shorthold", message = I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:)
min_tenancy_length: min_tenancy_length(record), record.errors.add :needstype, message
), record.errors.add :tenancylength, :tenancylength_invalid, message: message
}, record.errors.add :tenancy, message
{ end
condition: (record.is_secure_tenancy? && !is_in_range) && is_present,
error: I18n.t( def validate_general_needs_fixed_tenancy_length_affordable_social_rent(record)
"validations.tenancy.length.secure", return unless record.tenancy_type_fixed_term? && record.affordable_or_social_rent? && record.is_general_needs?
min_tenancy_length: min_tenancy_length(record), return if record.tenancylength.blank?
),
}, min_tenancy_length = 2
{ return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
condition: (record.is_periodic_tenancy? && !is_in_range) && is_present,
error: I18n.t( message = I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:)
"validations.tenancy.length.secure", record.errors.add :needstype, message
min_tenancy_length: min_tenancy_length(record), record.errors.add :rent_type, message
), record.errors.add :tenancylength, :tenancylength_invalid, message: message
}, record.errors.add :tenancy, message
] end
rent_type_independent_conditions = [
{ def validate_general_needs_fixed_tenancy_length_intermediate_rent(record)
condition: !(record.is_secure_tenancy? || record.is_assured_shorthold_tenancy? || record.is_periodic_tenancy?) && is_present, return unless record.tenancy_type_fixed_term? && !record.affordable_or_social_rent? && record.is_general_needs?
error: I18n.t("validations.tenancy.length.fixed_term_not_required"), return if record.tenancylength.blank?
},
] min_tenancy_length = 1
conditions = rent_type_dependent_conditions + rent_type_independent_conditions return if record.tenancylength.to_i.between?(min_tenancy_length, 99)
conditions.each do |condition| message = I18n.t("validations.tenancy.length.invalid_fixed", min_tenancy_length:)
next unless condition[:condition] record.errors.add :needstype, message
record.errors.add :rent_type, message
record.errors.add :needstype, condition[:error] record.errors.add :tenancylength, :tenancylength_invalid, message: message
record.errors.add :rent_type, condition[:error] if rent_type_dependent_conditions.include?(condition) record.errors.add :tenancy, message
record.errors.add :tenancylength, :tenancylength_invalid, message: condition[:error] end
record.errors.add :tenancy, condition[:error]
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 end
def validate_other_tenancy_type(record) 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") record.errors.add :hhmemb, I18n.t("validations.tenancy.joint_more_than_one_member")
end end
end end
def min_tenancy_length(record)
record.is_supported_housing? || record.renttype == 3 || record.is_periodic_tenancy? ? 1 : 2
end
end end

24
app/services/bulk_upload/lettings/year2023/row_parser.rb

@ -337,6 +337,30 @@ class BulkUpload::Lettings::Year2023::RowParser
}, },
on: :after_log 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_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_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? } 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? }

66
app/services/bulk_upload/lettings/year2024/row_parser.rb

@ -337,6 +337,38 @@ class BulkUpload::Lettings::Year2024::RowParser
}, },
on: :after_log 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_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_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? } 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_exists, on: :after_log
validate :validate_created_by_related, 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_address_option_found, on: :after_log
validate :validate_nulls, 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_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_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 validate :validate_nationality, on: :after_log
def self.question_for_field(field) def self.question_for_field(field)
@ -681,8 +713,8 @@ private
end end
def validate_leaving_reason_for_renewal def validate_leaving_reason_for_renewal
if field_7 == 1 && ![40, 42].include?(field_98) if field_7 == 1 && ![50, 51, 52, 53].include?(field_98)
errors.add(:field_98, I18n.t("validations.household.reason.renewal_reason_needed")) errors.add(:field_98, I18n.t("validations.household.reason.renewal_reason_needed_2024"))
end end
end end
@ -830,16 +862,28 @@ private
def validate_all_charges_given def validate_all_charges_given
return if supported_housing? && field_125 == 1 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_126: "service charge",
field_127: "personal service charge", field_127: "personal service charge",
field_128: "support charge" }.each do |field, charge| field_128: "support charge",
if public_send(field.to_sym).blank? }.partition { |field, _| public_send(field).blank? }.map(&:to_h)
errors.add(field, I18n.t("validations.financial.charges.missing_charges", question: charge))
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 end
end end
def all_charges_given?
field_125.present? && field_126.present? && field_127.present? && field_128.present?
end
def setup_question?(question) def setup_question?(question)
log.form.setup_sections[0].subsections[0].questions.include?(question) log.form.setup_sections[0].subsections[0].questions.include?(question)
end end
@ -1179,10 +1223,10 @@ private
attributes["benefits"] = field_121 attributes["benefits"] = field_121
attributes["period"] = field_123 attributes["period"] = field_123
attributes["brent"] = field_125 attributes["brent"] = field_125 if all_charges_given?
attributes["scharge"] = field_126 attributes["scharge"] = field_126 if all_charges_given?
attributes["pscharge"] = field_127 attributes["pscharge"] = field_127 if all_charges_given?
attributes["supcharg"] = field_128 attributes["supcharg"] = field_128 if all_charges_given?
attributes["chcharge"] = field_124 attributes["chcharge"] = field_124
attributes["is_carehome"] = is_carehome attributes["is_carehome"] = is_carehome
attributes["household_charge"] = supported_housing? ? field_122 : nil attributes["household_charge"] = supported_housing? ? field_122 : nil

2
app/services/bulk_upload/sales/year2024/row_parser.rb

@ -344,7 +344,7 @@ class BulkUpload::Sales::Year2024::RowParser
validates :field_103, validates :field_103,
inclusion: { inclusion: {
in: [1, 2], in: [1, 2],
if: proc { field_88 != 100 }, if: proc { field_88.present? && field_88 != 100 && shared_ownership? },
question: QUESTIONS[:field_103], question: QUESTIONS[:field_103],
}, },
on: :before_log on: :before_log

2
app/services/filter_manager.rb

@ -27,7 +27,7 @@ class FilterManager
logs = logs.public_send("filter_by_#{category}", values, user) logs = logs.public_send("filter_by_#{category}", values, user)
end end
logs = logs.order(created_at: :desc) logs = logs.order(id: :desc)
if user.support? if user.support?
if logs.first&.lettings? if logs.first&.lettings?
logs.all.includes(:owning_organisation, :managing_organisation) logs.all.includes(:owning_organisation, :managing_organisation)

2
app/views/form/check_answers.html.erb

@ -1,8 +1,8 @@
<% content_for :title, "#{subsection.id.humanize} - Check your answers" %> <% content_for :title, "#{subsection.id.humanize} - Check your answers" %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Home" => root_path,
breadcrumb_logs_title(@log, current_user) => breadcrumb_logs_link(@log, current_user), breadcrumb_logs_title(@log, current_user) => breadcrumb_logs_link(@log, current_user),
"Log #{@log.id}" => url_for(@log), "Log #{@log.id}" => url_for(@log),
subsection.label => "",
}) %> }) %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">

16
app/views/form/page.html.erb

@ -1,7 +1,15 @@
<% content_for :title, @page.header.presence || @page.questions.first.header.html_safe %> <% content_for :title, @page.header.presence || @page.questions.first.header.html_safe %>
<% if accessed_from_duplicate_logs?(request.query_parameters["referrer"]) %>
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link(href: send(@log.form.previous_page_redirect_path(@page, @log, current_user, params[:referrer]), @log)) %> <%= 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 %> <% end %>
<div data-controller="govukfrontend"></div> <div data-controller="govukfrontend"></div>
@ -66,7 +74,7 @@
<% if !@page.interruption_screen? %> <% if !@page.interruption_screen? %>
<% if accessed_from_duplicate_logs?(request.query_parameters["referrer"]) %> <% if accessed_from_duplicate_logs?(request.query_parameters["referrer"]) %>
<%= f.govuk_submit "Save changes" %> <%= 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"]) %> <% elsif returning_to_question_page?(@page, request.query_parameters["referrer"]) %>
<%= f.govuk_submit "Save changes" %> <%= f.govuk_submit "Save changes" %>
<%= govuk_link_to "Cancel", send(@log.form.cancel_path(@page, @log), @log) %> <%= govuk_link_to "Cancel", send(@log.form.cancel_path(@page, @log), @log) %>

2
app/views/locations/index.html.erb

@ -4,9 +4,9 @@
<% if current_user.support? %> <% if current_user.support? %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Home" => root_path,
"Schemes (#{@scheme.owning_organisation.name})" => schemes_organisation_path(@scheme.owning_organisation), "Schemes (#{@scheme.owning_organisation.name})" => schemes_organisation_path(@scheme.owning_organisation),
content_for(:title) => scheme_path(@scheme), content_for(:title) => scheme_path(@scheme),
"Locations" => "",
}) %> }) %>
<% else %> <% else %>
<% content_for :before_content do %> <% content_for :before_content do %>

2
app/views/logs/edit.html.erb

@ -1,7 +1,7 @@
<% content_for :title, "Log #{@log.id}" %> <% content_for :title, "Log #{@log.id}" %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Home" => root_path,
breadcrumb_logs_title(@log, current_user) => breadcrumb_logs_link(@log, current_user), breadcrumb_logs_title(@log, current_user) => breadcrumb_logs_link(@log, current_user),
content_for(:title) => "",
}) %> }) %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">

2
app/views/schemes/show.html.erb

@ -3,8 +3,8 @@
<% if current_user.support? %> <% if current_user.support? %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Home" => root_path,
"Schemes (#{@scheme.owning_organisation.name})" => schemes_organisation_path(@scheme.owning_organisation), "Schemes (#{@scheme.owning_organisation.name})" => schemes_organisation_path(@scheme.owning_organisation),
content_for(:title) => "",
}) %> }) %>
<% else %> <% else %>
<% content_for :before_content do %> <% content_for :before_content do %>

2
app/views/users/show.html.erb

@ -2,8 +2,8 @@
<% if current_user.support? %> <% if current_user.support? %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Home" => root_path,
"Users (#{@user.organisation.name})" => users_organisation_path(@user.organisation), "Users (#{@user.organisation.name})" => users_organisation_path(@user.organisation),
content_for(:title) => "",
}) %> }) %>
<% else %> <% else %>
<% content_for :before_content do %> <% content_for :before_content do %>

5
config/locales/en.yml

@ -545,6 +545,7 @@ en:
reason: 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" 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: '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" 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: 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" 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: tenancy:
length: length:
fixed_term_not_required: "You must only answer the length of the tenancy if it's fixed-term" 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" invalid_fixed: "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_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" 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" 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" not_joint: "This cannot be a joint tenancy as you've told us there's only one person in the household"

BIN
public/files/2024_25_lettings_paper_form.pdf

Binary file not shown.

BIN
public/files/bulk-upload-lettings-specification-2024-25.xlsx

Binary file not shown.

BIN
public/files/bulk-upload-lettings-template-2024-25.xlsx

Binary file not shown.

6
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 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) find("#lettings-log-prevloc-field").click.native.send_keys("T", "h", "a", "n", :down, :enter)
click_button("Save and continue") click_button("Save and continue")
click_link(text: "Back") page.go_back
expect(page).to have_selector("input", class: "autocomplete__input", count: 1) expect(page).to have_selector("input", class: "autocomplete__input", count: 1)
end end
it "displays the placeholder text", js: true do
expect(find("#lettings-log-prevloc-field")["placeholder"]).to eq("Start typing to search")
end
end end
context "when searching schemes" do context "when searching schemes" do

56
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") expect(page).to have_current_path("/lettings-logs/#{empty_lettings_log.id}/household-characteristics/check-answers")
end end
describe "Back link directs correctly", js: true do it "has correct breadcrumbs" do
it "go back to tasklist page from tenant code" do visit("/lettings-logs/#{id}/armed-forces")
visit("/lettings-logs/#{id}") breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
visit("/lettings-logs/#{id}/tenant-code-test") expect(breadcrumbs.length).to eq 4
click_link(text: "Back") expect(breadcrumbs[0].text).to eq "Home"
expect(page).to have_content("Log #{id}") expect(breadcrumbs[0][:href]).to eq root_path
end expect(breadcrumbs[1].text).to eq "Lettings logs"
expect(breadcrumbs[1][:href]).to eq lettings_logs_path
it "go back to tenant code page from tenant age page", js: true do expect(breadcrumbs[2].text).to eq "Log #{lettings_log.id}"
visit("/lettings-logs/#{id}/tenant-code-test") expect(breadcrumbs[2][:href]).to eq lettings_log_path(lettings_log)
click_button("Save and continue") expect(breadcrumbs[3].text).to eq "Household needs"
visit("/lettings-logs/#{id}/person-1-age") expect(breadcrumbs[3][:href]).to eq lettings_log_household_needs_check_answers_path(lettings_log)
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
end end
end end
@ -198,5 +175,14 @@ RSpec.describe "Form Navigation" do
lettings_log.reload lettings_log.reload
expect(lettings_log.duplicates.count).to eq(1) expect(lettings_log.duplicates.count).to eq(1)
end 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
end end

109
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) choose("lettings-log-preg-occ-1-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-yes-page") 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") expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question")
choose("lettings-log-preg-occ-2-field", allow_label_click: true) choose("lettings-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
@ -155,4 +155,111 @@ RSpec.describe "Form Page Routing" do
end end
end 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 end

22
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 it "has the correct breadcrumbs with the correct links" do
visit lettings_log_setup_check_answers_path(lettings_log) visit lettings_log_setup_check_answers_path(lettings_log)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link") breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
expect(breadcrumbs.first.text).to eq "Lettings logs (DLUHC)" expect(breadcrumbs.length).to eq 3
expect(breadcrumbs.first[:href]).to eq lettings_logs_organisation_path(lettings_log.owning_organisation) expect(breadcrumbs[0].text).to eq "Home"
expect(breadcrumbs[1].text).to eq "Log #{lettings_log.id}" expect(breadcrumbs[0][:href]).to eq root_path
expect(breadcrumbs[1][:href]).to eq lettings_log_path(lettings_log) 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
end end
@ -170,10 +173,13 @@ RSpec.describe "Lettings Log Features" do
it "has the correct breadcrumbs with the correct links" do it "has the correct breadcrumbs with the correct links" do
visit review_lettings_log_path(lettings_log) visit review_lettings_log_path(lettings_log)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link") breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
expect(breadcrumbs.first.text).to eq "Lettings logs (DLUHC)" expect(breadcrumbs.length).to eq 3
expect(breadcrumbs.first[:href]).to eq lettings_logs_organisation_path(lettings_log.owning_organisation) expect(breadcrumbs[0].text).to eq "Home"
expect(breadcrumbs[1].text).to eq "Log #{lettings_log.id}" expect(breadcrumbs[0][:href]).to eq root_path
expect(breadcrumbs[1][:href]).to eq lettings_log_path(lettings_log) 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
end end

22
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 it "has the correct breadcrumbs with the correct links" do
visit sales_log_setup_check_answers_path(sales_log.id) visit sales_log_setup_check_answers_path(sales_log.id)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link") breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
expect(breadcrumbs.first.text).to eq "Sales logs (DLUHC)" expect(breadcrumbs.length).to eq 3
expect(breadcrumbs.first[:href]).to eq sales_logs_organisation_path(sales_log.owning_organisation) expect(breadcrumbs[0].text).to eq "Home"
expect(breadcrumbs[1].text).to eq "Log #{sales_log.id}" expect(breadcrumbs[0][:href]).to eq root_path
expect(breadcrumbs[1][:href]).to eq sales_log_path(sales_log.id) 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 end
@ -175,10 +178,13 @@ RSpec.describe "Sales Log Features" do
it "has the correct breadcrumbs with the correct links" do it "has the correct breadcrumbs with the correct links" do
visit review_sales_log_path(sales_log.id, sales_log: true) visit review_sales_log_path(sales_log.id, sales_log: true)
breadcrumbs = page.find_all(".govuk-breadcrumbs__link") breadcrumbs = page.find_all(".govuk-breadcrumbs__link")
expect(breadcrumbs.first.text).to eq "Sales logs (DLUHC)" expect(breadcrumbs.length).to eq 3
expect(breadcrumbs.first[:href]).to eq sales_logs_organisation_path(sales_log.owning_organisation) expect(breadcrumbs[0].text).to eq "Home"
expect(breadcrumbs[1].text).to eq "Log #{sales_log.id}" expect(breadcrumbs[0][:href]).to eq root_path
expect(breadcrumbs[1][:href]).to eq sales_log_path(sales_log.id) 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 end
end end

21
spec/models/lettings_log_spec.rb

@ -112,10 +112,17 @@ RSpec.describe LettingsLog do
end end
it "validates tenancy type" do it "validates tenancy type" do
expect(validator).to receive(:validate_fixed_term_tenancy)
expect(validator).to receive(:validate_other_tenancy_type) expect(validator).to receive(:validate_other_tenancy_type)
end 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 it "validates the previous postcode" do
expect(validator).to receive(:validate_previous_accommodation_postcode) expect(validator).to receive(:validate_previous_accommodation_postcode)
end end
@ -2828,6 +2835,18 @@ RSpec.describe LettingsLog do
expect(result.first.id).to eq lettings_log_to_search.id expect(result.first.id).to eq lettings_log_to_search.id
end 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 context "when lettings log is supported housing" do
let(:location) { create(:location, postcode: "W6 0ST") } let(:location) { create(:location, postcode: "W6 0ST") }

44
spec/models/sales_log_spec.rb

@ -162,6 +162,50 @@ RSpec.describe SalesLog, type: :model do
end end
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 context "when filtering by year or nil" do
before do before do
Timecop.freeze(Time.utc(2021, 5, 3)) Timecop.freeze(Time.utc(2021, 5, 3))

427
spec/models/validations/tenancy_validations_spec.rb

@ -3,280 +3,272 @@ require "rails_helper"
RSpec.describe Validations::TenancyValidations do RSpec.describe Validations::TenancyValidations do
subject(:tenancy_validator) { validator_class.new } subject(:tenancy_validator) { validator_class.new }
before do let(:validator_class) { Class.new { include Validations::TenancyValidations } }
Timecop.freeze(Time.zone.local(2021, 5, 1))
end
after do describe "tenancy length validations" do
Timecop.unfreeze let(:record) { FactoryBot.create(:lettings_log, :setup_completed) }
end
let(:validator_class) { Class.new { include Validations::TenancyValidations } } shared_examples "adds expected errors based on the tenancy length" do |tenancy_type_case, error_fields, min_tenancy_length|
let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2021, 5, 1), needstype: 1, rent_type: 1) } context "and tenancy type is #{tenancy_type_case[:name]}" do
let(:expected_error) { tenancy_type_case[:expected_error].call(min_tenancy_length) }
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
context "when type of tenancy is assured shorthold" do before { record.tenancy = tenancy_type_case[:code] }
let(:expected_error) do
I18n.t(
"validations.tenancy.length.shorthold",
min_tenancy_length: 2,
)
end
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 errors to #{error_fields.join(', ')}" do
it "adds an error" do validation.call(record)
record.tenancylength = 1 error_fields.each do |field|
tenancy_validator.validate_fixed_term_tenancy(record) expect(record.errors[field]).to include(match(expected_error))
expect(record.errors["needstype"]).to include(match(expected_error)) end
expect(record.errors["rent_type"]).to include(match(expected_error)) expect(record.errors.size).to be(error_fields.length)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end end
end end
context "when tenancy length is greater than 99" do context "and tenancy length is more than 99" do
it "adds an error" do before { record.tenancylength = 100 }
record.tenancylength = 100
tenancy_validator.validate_fixed_term_tenancy(record) it "adds errors to #{error_fields.join(', ')}" do
expect(record.errors["needstype"]).to include(match(expected_error)) validation.call(record)
expect(record.errors["rent_type"]).to include(match(expected_error)) error_fields.each do |field|
expect(record.errors["tenancylength"]).to include(match(expected_error)) expect(record.errors[field]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error)) end
expect(record.errors.size).to be(error_fields.length)
end end
end end
context "when tenancy length is between 2-99" do context "and tenancy length is between #{min_tenancy_length} and 99" do
it "does not add an error" do before { record.tenancylength = min_tenancy_length }
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record) it "does not add errors" do
validation.call(record)
expect(record.errors).to be_empty expect(record.errors).to be_empty
end end
end end
context "when tenancy length has not been answered" do context "and tenancy length is not set" do
it "does not add an error" do before { record.tenancylength = nil }
record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record) it "does not add errors" do
validation.call(record)
expect(record.errors).to be_empty expect(record.errors).to be_empty
end end
end end
end end
end
context "when the collection start year is before 2022" do shared_examples "does not add errors when tenancy type is not fixed term" do
context "when type of tenancy is secure" do context "and tenancy type is not fixed term" do
let(:expected_error) do before do
I18n.t( record.tenancy = 8
"validations.tenancy.length.secure", record.tenancylength = 0
min_tenancy_length: 2, end
)
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 include_examples "does not add errors when tenancy type is not fixed term"
it "adds an error" do end
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
context "when tenancy length is greater than 99" do context "when needs type is general needs" do
it "adds an error" do before do
record.tenancylength = 100 record.needstype = 1
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancy = 4
expect(record.errors["needstype"]).to include(match(expected_error)) record.tenancylength = 0
expect(record.errors["tenancylength"]).to include(match(expected_error)) end
expect(record.errors["tenancy"]).to include(match(expected_error))
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 end
context "when tenancy length is between 2-99" do include_examples "does not add errors when tenancy type is not fixed term"
it "does not add an error" do end
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record) context "and rent type is intermediate rent" do
expect(record.errors).to be_empty before do
end record.renttype = 3
record.tenancy = 4
record.tenancylength = 0
end end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do validation.call(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end end
end end
end end
context "when the collection start year is 2022 or later" do context "when needs type is supported housing" do
before do before do
Timecop.freeze(2022, 5, 1) record.needstype = 2
record.renttype = 1
record.tenancy = 4
record.tenancylength = 0
end end
after do it "does not add errors" do
Timecop.unfreeze validation.call(record)
expect(record.errors).to be_empty
end 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 context "when needs type is general needs" do
let(:expected_error) do before { record.needstype = 1 }
I18n.t(
"validations.tenancy.length.secure",
min_tenancy_length: 2,
)
end
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 error_fields = %w[needstype rent_type tenancylength tenancy]
it "adds an error" do fixed_term_tenancy_type_cases.each do |tenancy_type_case|
record.tenancylength = 1 include_examples "adds expected errors based on the tenancy length", tenancy_type_case, error_fields, 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 end
context "when tenancy length is greater than 99" do include_examples "does not add errors when tenancy type is not fixed term"
it "adds an error" do end
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
context "when tenancy length is between 2-99" do context "and rent type is not intermediate rent" do
it "does not add an error" do before do
record.tenancylength = 3 record.renttype = 2
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancy = 4
expect(record.errors).to be_empty record.tenancylength = 0
end
end end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do validation.call(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end end
end end
end
context "when type of tenancy is Secure - lifetime" do context "when needs type is supported housing" do
let(:expected_error) do before do
I18n.t( record.needstype = 2
"validations.tenancy.length.secure", record.renttype = 3
min_tenancy_length: 2, record.tenancy = 4
) record.tenancylength = 0
end 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 describe "#validate_periodic_tenancy_length" do
it "adds an error" do subject(:validation) { ->(record) { tenancy_validator.validate_periodic_tenancy_length(record) } }
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
context "when tenancy length is greater than 99" do periodic_tenancy_case = {
it "adds an error" do name: "periodic",
record.tenancylength = 100 code: 8,
tenancy_validator.validate_fixed_term_tenancy(record) expected_error: ->(min_tenancy_length) { I18n.t("validations.tenancy.length.invalid_periodic", min_tenancy_length:) },
expect(record.errors["needstype"]).to include(match(expected_error)) }
expect(record.errors["tenancylength"]).to include(match(expected_error)) error_fields = %w[tenancylength tenancy]
expect(record.errors["tenancy"]).to include(match(expected_error)) include_examples "adds expected errors based on the tenancy length", periodic_tenancy_case, error_fields, 1
end
end
context "when tenancy length is between 2-99" do context "when tenancy type is not periodic" do
it "does not add an error" do before do
record.tenancylength = 3 record.tenancy = 6
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancylength = 0
expect(record.errors).to be_empty end
end
end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do validation.call(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end
end end
end
context "when type of tenancy is periodic" do describe "#validate_tenancy_length_blank_when_not_required" do
let(:expected_error) do context "when a tenancy length is provided" do
I18n.t( before { record.tenancylength = 10 }
"validations.tenancy.length.secure",
min_tenancy_length: 1,
)
end
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 errors to tenancylength and tenancy" do
it "adds an error" do tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
record.tenancylength = 0 expected_error = I18n.t("validations.tenancy.length.fixed_term_not_required")
tenancy_validator.validate_fixed_term_tenancy(record) expect(record.errors["tenancylength"]).to include(expected_error)
expect(record.errors["needstype"]).to include(match(expected_error)) expect(record.errors["tenancy"]).to include(expected_error)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end end
end end
context "when tenancy length is greater than 99" do tenancy_types_with_length = [
it "adds an error" do { name: "assured shorthold", code: 4 },
record.tenancylength = 100 { name: "secure fixed term", code: 6 },
tenancy_validator.validate_fixed_term_tenancy(record) { name: "periodic", code: 8 },
expect(record.errors["needstype"]).to include(match(expected_error)) ]
expect(record.errors["tenancylength"]).to include(match(expected_error)) tenancy_types_with_length.each do |type|
expect(record.errors["tenancy"]).to include(match(expected_error)) 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 end
end
context "when tenancy length is between 2-99" do context "when tenancy length is not provided" do
it "does not add an error" do before do
record.tenancylength = 3 record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record) record.tenancy = 5
expect(record.errors).to be_empty
end
end end
context "when tenancy length has not been answered" do it "does not add errors" do
it "does not add an error" do tenancy_validator.validate_tenancy_length_blank_when_not_required(record)
record.tenancylength = nil expect(record.errors).to be_empty
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors).to be_empty
end
end end
end end
end end
@ -284,6 +276,7 @@ RSpec.describe Validations::TenancyValidations do
end end
describe "tenancy type validations" do describe "tenancy type validations" do
let(:record) { FactoryBot.create(:lettings_log, :setup_completed) }
let(:field) { "validations.other_field_missing" } let(:field) { "validations.other_field_missing" }
let(:main_field_label) { "tenancy type" } let(:main_field_label) { "tenancy type" }
let(:other_field) { "tenancyother" } let(:other_field) { "tenancyother" }
@ -327,20 +320,11 @@ RSpec.describe Validations::TenancyValidations do
describe "joint tenancy validation" do describe "joint tenancy validation" do
context "when the data inputter has said that there is only one member in the household" do context "when the data inputter has said that there is only one member in the household" do
before do let(:record) { FactoryBot.create(:lettings_log, :setup_completed, hhmemb: 1) }
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(:expected_error) { I18n.t("validations.tenancy.not_joint") } let(:expected_error) { I18n.t("validations.tenancy.not_joint") }
let(:hhmemb_expected_error) { I18n.t("validations.tenancy.joint_more_than_one_member") } 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 it "displays an error if the data inputter says the letting is a joint tenancy" do
record.hhmemb = 1
record.joint = 1 record.joint = 1
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to include(match(expected_error)) expect(record.errors["joint"]).to include(match(expected_error))
@ -348,7 +332,6 @@ RSpec.describe Validations::TenancyValidations do
end end
it "does not display an error if the data inputter says the letting is not a joint tenancy" do 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 record.joint = 2
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to be_empty expect(record.errors["joint"]).to be_empty
@ -356,7 +339,6 @@ RSpec.describe Validations::TenancyValidations do
end 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 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 record.joint = nil
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)
expect(record.errors["joint"]).to be_empty expect(record.errors["joint"]).to be_empty
@ -364,7 +346,6 @@ RSpec.describe Validations::TenancyValidations do
end end
it "does not error when don't know answer to joint" do it "does not error when don't know answer to joint" do
record.hhmemb = 1
record.joint = 3 record.joint = 3
tenancy_validator.validate_joint_tenancy(record) tenancy_validator.validate_joint_tenancy(record)

27
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) expect(parser.log.cbl).to be(0)
end end
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 end
describe "#chr" do describe "#chr" do
@ -2015,6 +2024,15 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
expect(parser.log.chr).to be(0) expect(parser.log.chr).to be(0)
end end
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 end
describe "#cap" do describe "#cap" do
@ -2033,6 +2051,15 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
expect(parser.log.cap).to be(0) expect(parser.log.cap).to be(0)
end end
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 end
describe "#letting_allocation_unknown" do describe "#letting_allocation_unknown" do

122
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 describe "#field_98" do # leaving reason
context "when field_7 is 1 meaning it is a renewal" do context "when field_7 is 1 meaning it is a renewal" do
context "when field_98 is 40" do context "when field_98 is 50" do
let(:attributes) { { bulk_upload:, field_98: "40", field_7: "1" } } let(:attributes) { { bulk_upload:, field_98: "50", field_7: "1" } }
it "is permitted" do it "is permitted" do
expect(parser.errors[:field_98]).to be_blank expect(parser.errors[:field_98]).to be_blank
end end
end end
context "when field_98 is 42" do context "when field_98 is 51" do
let(:attributes) { { bulk_upload:, field_98: "42", field_7: "1" } } let(:attributes) { { bulk_upload:, field_98: "51", field_7: "1" } }
it "is permitted" do it "is permitted" do
expect(parser.errors[:field_98]).to be_blank expect(parser.errors[:field_98]).to be_blank
end end
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" } } let(:attributes) { { bulk_upload:, field_98: "1", field_7: "1" } }
it "is not permitted" do 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 end
end end
@ -1654,7 +1670,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end end
context "when soft validation is triggered and not required" do 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 it "adds an error to the relevant fields" do
expect(parser.errors.where(:field_125, category: :soft_validation)).to be_present 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) expect(parser.log.cbl).to be(0)
end end
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 end
describe "#chr" do describe "#chr" do
@ -1908,6 +1933,15 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
expect(parser.log.chr).to be(0) expect(parser.log.chr).to be(0)
end end
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 end
describe "#cap" do describe "#cap" do
@ -1926,6 +1960,42 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
expect(parser.log.cap).to be(0) expect(parser.log.cap).to be(0)
end end
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 end
describe "#letting_allocation_unknown" do describe "#letting_allocation_unknown" do
@ -2187,7 +2257,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end end
describe "#chcharge" do 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 it "sets value given" do
expect(parser.log.chcharge).to eq(123.45) expect(parser.log.chcharge).to eq(123.45)
@ -2208,7 +2278,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end end
describe "#supcharg" do 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 it "sets value given" do
expect(parser.log.supcharg).to eq(123.45) 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 "when other charges are not given" do
context "and it is carehome" 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 it "does not set charges values" do
parser.log.save! parser.log.save!
@ -2237,7 +2307,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end end
context "and it is not carehome" do 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 it "does not set charges values" do
parser.log.save! 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_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_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_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
end end
end end
describe "#pscharge" do 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 it "sets value given" do
expect(parser.log.pscharge).to eq(123.45) expect(parser.log.pscharge).to eq(123.45)
@ -2268,7 +2362,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end end
describe "#scharge" do 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 it "sets value given" do
expect(parser.log.scharge).to eq(123.45) expect(parser.log.scharge).to eq(123.45)

16
spec/services/bulk_upload/sales/year2024/row_parser_spec.rb

@ -1009,6 +1009,22 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
end end
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 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) } let(:attributes) { setup_section_params.merge(field_103: "3", field_86: "1", field_87: "50", field_88: "100", field_109: nil) }

1
spec/views/form/page_view_spec.rb

@ -25,6 +25,7 @@ RSpec.describe "form/page" do
end end
before do before do
sign_in create(:user)
assign(:log, lettings_log) assign(:log, lettings_log)
assign(:page, page) assign(:page, page)
assign(:subsection, subsection) assign(:subsection, subsection)

Loading…
Cancel
Save