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,
placeholder: 'Start typing to search',
templates: { suggestion: (value) => suggestion(value, options) },
name: rawFieldName,
onConfirm: (val) => {

8
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

5
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

2
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) }

2
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|

105
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

24
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? }

66
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

2
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

2
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)

2
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 => "",
}) %>
<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 :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 %>
<div data-controller="govukfrontend"></div>
@ -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) %>

2
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 %>

2
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) => "",
}) %>
<div class="govuk-grid-row">

2
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 %>

2
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 %>

5
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"

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
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

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")
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

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)
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

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
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

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
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

21
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") }

44
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))

427
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)

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)
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

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
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)

16
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) }

1
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)

Loading…
Cancel
Save