Compare commits

..

No commits in common. '9c22fd469c7219393ad6acbb472544ac10167133' and 'a2ee52a8f73e2db618bc776cbcc7b32110d90d64' have entirely different histories.

  1. 36
      app/components/create_log_actions_component.html.erb
  2. 20
      app/frontend/styles/_testing-tools.scss
  3. 1
      app/frontend/styles/application.scss
  4. 2
      app/helpers/filters_helper.rb
  5. 4
      app/models/lettings_log.rb
  6. 15
      app/models/validations/household_validations.rb
  7. 8
      app/services/bulk_upload/lettings/year2024/row_parser.rb
  8. 8
      app/services/bulk_upload/lettings/year2025/row_parser.rb
  9. 2
      app/views/bulk_upload_lettings_logs/forms/prepare_your_file.html.erb
  10. 2
      app/views/bulk_upload_sales_logs/forms/prepare_your_file.html.erb
  11. 2
      app/views/bulk_upload_shared/guidance.html.erb
  12. 7
      app/views/home/_data_box.html.erb
  13. 2
      app/views/merge_requests/_merge_request_list.html.erb
  14. 2
      app/views/organisation_relationships/_related_org_list.erb
  15. 2
      app/views/organisations/_organisation_list.html.erb
  16. 2
      app/views/schemes/_scheme_list.html.erb
  17. 2
      app/views/users/_user_list.html.erb
  18. 2
      config/locales/validations/lettings/2024/bulk_upload.en.yml
  19. 2
      config/locales/validations/lettings/2025/bulk_upload.en.yml
  20. 3
      config/locales/validations/lettings/household.en.yml
  21. 8
      spec/models/validations/household_validations_spec.rb
  22. 21
      spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
  23. 21
      spec/services/bulk_upload/lettings/year2025/row_parser_spec.rb

36
app/components/create_log_actions_component.html.erb

@ -9,38 +9,10 @@
<% end %>
<% if FeatureToggle.create_test_logs_enabled? %>
<div class="govuk-inset-text app-testing-tools__inset">
<span class="govuk-tag app-testing-tools__tag">Testing tools</span>
<span class="govuk-body govuk-body-s">These tools can only be seen and used in testing environments.</span>
<div>
<%= govuk_button_link_to create_test_log_href, class: "govuk-button" do %>
New test log
<svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" aria-hidden="true" focusable="false">
<path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path>
</svg>
<% end %>
<%= govuk_button_link_to create_setup_test_log_href, class: "govuk-button" do %>
New test log (setup only)
<svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" aria-hidden="true" focusable="false">
<path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path>
</svg>
<% end %>
<%= govuk_button_link_to create_test_bulk_upload_href(2024), class: "govuk-button govuk-button--secondary" do %>
24/25 BU test file
<svg class="govuk-button__start-icon bi bi-download" xmlns="http://www.w3.org/2000/svg" width="18" height="19" fill="currentColor" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.4">
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5" />
<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z" />
</svg>
<% end %>
<%= govuk_button_link_to create_test_bulk_upload_href(2025), class: "govuk-button govuk-button--secondary" do %>
25/26 BU test file
<svg class="govuk-button__start-icon bi bi-download" xmlns="http://www.w3.org/2000/svg" width="18" height="19" fill="currentColor" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.4">
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5" />
<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z" />
</svg>
<% end %>
</div>
</div>
<%= govuk_link_to "New test log", create_test_log_href %>
<%= govuk_link_to "New test log (setup only)", create_setup_test_log_href %>
<%= govuk_link_to "24 BU test file", create_test_bulk_upload_href(2024) %>
<%= govuk_link_to "25 BU test file", create_test_bulk_upload_href(2025) %>
<% end %>
<% end %>
</div>

20
app/frontend/styles/_testing-tools.scss

@ -1,20 +0,0 @@
.app-testing-tools__inset {
border-left-color: #f47738;
margin-bottom: 0;
margin-top: 0;
padding-top: 5px;
padding-bottom: 5px;
}
.app-testing-tools__link {
@include govuk-link-common;
@include govuk-link-style-no-visited-state;
}
.app-testing-tools__tag {
@include govuk-font(14);
background-color: #fcd6c3;
margin-top: 0;
margin-bottom: 10px;
margin-right: 15px;
}

1
app/frontend/styles/application.scss

@ -49,7 +49,6 @@ $govuk-breakpoints: (
@import "sub-navigation";
@import "unread-notification";
@import "red-link";
@import "testing-tools";
@import "custom-rails-admin";
@import "node_modules/@ministryofjustice/frontend/moj/components/date-picker/date-picker";

2
app/helpers/filters_helper.rb

@ -167,7 +167,7 @@ module FiltersHelper
def reset_filters_link(filter_type, filter_path_params = {})
if applied_filters_count(filter_type).positive?
govuk_link_to "Clear", clear_filters_path(filter_type:, filter_path_params:), aria: { label: "Clear filters" }
govuk_link_to "Clear", clear_filters_path(filter_type:, filter_path_params:)
end
end

4
app/models/lettings_log.rb

@ -381,10 +381,6 @@ class LettingsLog < Log
referral == 1
end
def is_from_prp_only_housing_register_or_waiting_list?
referral_type == 3
end
def is_relet_to_temp_tenant?
# 9: Re-let to tenant who occupied same property as temporary accommodation
rsnvac == 9

15
app/models/validations/household_validations.rb

@ -30,15 +30,10 @@ module Validations::HouseholdValidations
end
validate_other_field(record, 20, :reason, :reasonother)
if record.is_reason_permanently_decanted?
if record.referral_type.present? && !record.is_from_prp_only_housing_register_or_waiting_list?
record.errors.add :referral_type, I18n.t("validations.lettings.household.referral_type.leaving_last_settled_home.reason_permanently_decanted")
end
if record.referral.present? && !record.is_internal_transfer?
record.errors.add :referral, I18n.t("validations.lettings.household.referral.leaving_last_settled_home.reason_permanently_decanted")
record.errors.add :reason, I18n.t("validations.lettings.household.reason.leaving_last_settled_home.not_internal_transfer")
end
if record.is_reason_permanently_decanted? && record.referral.present? && !record.is_internal_transfer?
record.errors.add :referral, I18n.t("validations.lettings.household.referral.leaving_last_settled_home.reason_permanently_decanted")
record.errors.add :referral_type, I18n.t("validations.lettings.household.referral.leaving_last_settled_home.reason_permanently_decanted")
record.errors.add :reason, I18n.t("validations.lettings.household.reason.leaving_last_settled_home.not_internal_transfer")
end
return unless record.form.start_year_2024_or_later?
@ -177,6 +172,7 @@ module Validations::HouseholdValidations
label = record.form.get_question("prevten", record).present? ? record.form.get_question("prevten", record).label_from_value(record.prevten) : ""
record.errors.add :prevten, :internal_transfer_non_social_housing, message: I18n.t("validations.lettings.household.prevten.internal_transfer", prevten: label)
record.errors.add :referral, :internal_transfer_non_social_housing, message: I18n.t("validations.lettings.household.referral.prevten_invalid", prevten: label)
record.errors.add :referral_type, :internal_transfer_non_social_housing, message: I18n.t("validations.lettings.household.referral.prevten_invalid", prevten: label)
end
end
@ -186,6 +182,7 @@ module Validations::HouseholdValidations
if record.is_internal_transfer? && record.owning_organisation.provider_type == "PRP" && record.is_prevten_la_general_needs?
record.errors.add :prevten, :internal_transfer_fixed_or_lifetime, message: I18n.t("validations.lettings.household.prevten.la_general_needs.internal_transfer")
record.errors.add :referral, :internal_transfer_fixed_or_lifetime, message: I18n.t("validations.lettings.household.referral.la_general_needs.internal_transfer")
record.errors.add :referral_type, :internal_transfer_fixed_or_lifetime, message: I18n.t("validations.lettings.household.referral.la_general_needs.internal_transfer")
end
end

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

@ -445,7 +445,6 @@ class BulkUpload::Lettings::Year2024::RowParser
validate :validate_incomplete_soft_validations, on: :after_log
validate :validate_nationality, on: :after_log
validate :validate_reasonpref_reason_values, on: :after_log
validate :validate_prevten_value_when_renewal, on: :after_log
validate :validate_nulls, on: :after_log
@ -675,13 +674,6 @@ private
end
end
def validate_prevten_value_when_renewal
return unless field_7 == 1
return if field_100.blank? || [6, 30, 31, 32, 33, 34, 35, 36].include?(field_100)
errors.add(:field_100, I18n.t("#{ERROR_BASE_KEY}.prevten.invalid"))
end
def duplicate_check_fields
[
"startdate",

8
app/services/bulk_upload/lettings/year2025/row_parser.rb

@ -444,7 +444,6 @@ class BulkUpload::Lettings::Year2025::RowParser
validate :validate_incomplete_soft_validations, on: :after_log
validate :validate_nationality, on: :after_log
validate :validate_reasonpref_reason_values, on: :after_log
validate :validate_prevten_value_when_renewal, on: :after_log
validate :validate_nulls, on: :after_log
@ -674,13 +673,6 @@ private
end
end
def validate_prevten_value_when_renewal
return unless field_7 == 1
return if field_100.blank? || [6, 30, 31, 32, 33, 34, 35, 38].include?(field_100)
errors.add(:field_100, I18n.t("#{ERROR_BASE_KEY}.prevten.invalid"))
end
def duplicate_check_fields
[
"startdate",

2
app/views/bulk_upload_lettings_logs/forms/prepare_your_file.html.erb

@ -20,7 +20,7 @@
<h2 class="govuk-heading-s">Create your file</h2>
<%= govuk_list [
"Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log - your data should start in column B.",
"Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. Leave column A blank - the bulk upload fields start in column B.",
"Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.",
"Use the #{govuk_link_to "Lettings bulk upload Specification (#{@form.year_combo})", @form.specification_path} to check your data is in the correct format.".html_safe,
"<strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.".html_safe,

2
app/views/bulk_upload_sales_logs/forms/prepare_your_file.html.erb

@ -20,7 +20,7 @@
<h2 class="govuk-heading-s">Create your file</h2>
<%= govuk_list [
"Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log - your data should start in column B.",
"Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. The bulk upload fields start at column B. Leave column A blank.",
"Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.",
"Use the #{govuk_link_to "Sales bulk upload Specification (#{@form.year_combo})", @form.specification_path} to check your data is in the correct format.".html_safe,
"<strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.".html_safe,

2
app/views/bulk_upload_shared/guidance.html.erb

@ -32,7 +32,7 @@
<%= govuk_list ["the CORE form questions and their field numbers", "each field’s valid responses", "if/when certain fields can be left blank", "which fields are used to check for duplicate logs"], type: :bullet %>
<p class="govuk-body">You can paste your data below the headers or copy the headers and insert them above the data in your file - your data should start in column B.</p>
<p class="govuk-body">You can paste your data below the headers or copy the headers and insert them above the data in your file. The bulk upload fields start at column B. Leave column A blank.</p>
<p class="govuk-body">Make sure that each column of data aligns with the corresponding question in the headers. We recommend ordering your data to match the headers, but you can also reorder the headers to match your data. When processing the file, we check what each column of data represents based on the headers above.</p>
<p class="govuk-body"><%= govuk_link_to "Download the lettings bulk upload template (#{@form.year} to #{@form.year + 1})", @form.lettings_template_path %></p>
<p class="govuk-body"><%= govuk_link_to "Download the sales bulk upload template (#{@form.year} to #{@form.year + 1})", @form.sales_template_path %></p>

7
app/views/home/_data_box.html.erb

@ -1,5 +1,6 @@
<div class="app-data-box__upper">
<%= govuk_link_to data_box[:path], class: "govuk-link--no-visited-state govuk-link--no-underline" do %>
<span class="app-data-box__count"><%= data_box[:count] %></span><br><%= data_box[:text] %>
<% end %>
<div class="app-data-box__count">
<%= govuk_link_to data_box[:count], data_box[:path], class: "govuk-link--no-visited-state govuk-link--no-underline" %>
</div>
<%= govuk_link_to data_box[:text], data_box[:path], class: "govuk-link--no-visited-state" %>
</div>

2
app/views/merge_requests/_merge_request_list.html.erb

@ -1,4 +1,4 @@
<section class="app-table-group" aria-labelledby="<%= title.dasherize %>">
<section class="app-table-group" tabindex="0" aria-labelledby="<%= title.dasherize %>">
<% if @merge_requests.empty? %>
<p>No merge requests</p>
<% else %>

2
app/views/organisation_relationships/_related_org_list.erb

@ -1,4 +1,4 @@
<section class="app-table-group" aria-labelledby="<%= title.dasherize %>">
<section class="app-table-group" tabindex="0" aria-labelledby="<%= title.dasherize %>">
<%= govuk_table do |table| %>
<%= table.with_caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<%= render(SearchResultCaptionComponent.new(searched:, count: pagy.count, item_label:, total_count:, item: search_item, filters_count: 0)) %>

2
app/views/organisations/_organisation_list.html.erb

@ -1,4 +1,4 @@
<section class="app-table-group" aria-labelledby="<%= title.dasherize %>">
<section class="app-table-group" tabindex="0" aria-labelledby="<%= title.dasherize %>">
<%= govuk_table do |table| %>
<%= table.with_caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<%= render(SearchResultCaptionComponent.new(searched:, count: pagy.count, item_label:, total_count:, item: "organisation", filters_count: applied_filters_count(@filter_type))) %>

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

@ -1,4 +1,4 @@
<section class="app-table-group" aria-labelledby="<%= title.dasherize %>">
<section class="app-table-group" tabindex="0" aria-labelledby="<%= title.dasherize %>">
<%= govuk_table do |table| %>
<%= table.with_caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<span class="app-search__caption">

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

@ -1,4 +1,4 @@
<section class="app-table-group" aria-labelledby="<%= title.dasherize %>">
<section class="app-table-group" tabindex="0" aria-labelledby="<%= title.dasherize %>">
<%= govuk_table do |table| %>
<%= table.with_caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<%= render(SearchResultCaptionComponent.new(searched:, count: pagy.count, item_label:, total_count:, item: "user", filters_count: applied_filters_count(@filter_type))) %>

2
config/locales/validations/lettings/2024/bulk_upload.en.yml

@ -62,5 +62,3 @@ en:
conflict:
dont_know: "You cannot select 'Don't know' if any of the other reasonable preference reasons are also selected."
other: "You cannot select this reasonable preference reason as you've also selected 'Don't know' as a reason."
prevten:
invalid: "You said this letting is a renewal to the same tenant in the same property in the set up section. This means where the household was immediately before this letting must be \"Fixed-term local authority general needs tenancy\", \"Fixed-term private registered provider (PRP) general needs tenancy\", \"Lifetime local authority general needs tenancy\", \"Lifetime private registered provider (PRP) general needs tenancy\", \"Extra care housing\", \"Specialist retirement housing\", \"Sheltered housing for adults under 55 years\" or \"Other supported housing.\""

2
config/locales/validations/lettings/2025/bulk_upload.en.yml

@ -62,5 +62,3 @@ en:
conflict:
dont_know: "You cannot select 'Don't know' if any of the other reasonable preference reasons are also selected."
other: "You cannot select this reasonable preference reason as you've also selected 'Don't know' as a reason."
prevten:
invalid: "You said this letting is a renewal to the same tenant in the same property in the set up section. This means where the household was immediately before this letting must be \"Fixed-term local authority general needs tenancy\", \"Fixed-term private registered provider (PRP) general needs tenancy\", \"Lifetime local authority general needs tenancy\", \"Lifetime private registered provider (PRP) general needs tenancy\", \"Extra care housing\", \"Older people's housing for tenants with low support needs\" or \"Other supported housing.\""

3
config/locales/validations/lettings/household.en.yml

@ -107,6 +107,3 @@ en:
la_general_needs:
internal_transfer: "Answer cannot be internal transfer as it’s the same landlord on the tenancy agreement and the household had either a fixed-term or lifetime local authority general needs tenancy immediately before this letting."
referral_type:
leaving_last_settled_home:
reason_permanently_decanted: "Answer must be from a PRP-only housing register or waiting list (no local authority involvement) as the tenant was permanently decanted from another property owned by this landlord."

8
spec/models/validations/household_validations_spec.rb

@ -137,7 +137,7 @@ RSpec.describe Validations::HouseholdValidations do
expect(record.errors["referral"])
.to include(match(I18n.t("validations.lettings.household.referral.leaving_last_settled_home.reason_permanently_decanted")))
expect(record.errors["referral_type"])
.to include(match(I18n.t("validations.lettings.household.referral_type.leaving_last_settled_home.reason_permanently_decanted")))
.to include(match(I18n.t("validations.lettings.household.referral.leaving_last_settled_home.reason_permanently_decanted")))
end
end
@ -163,6 +163,8 @@ RSpec.describe Validations::HouseholdValidations do
household_validator.validate_referral(record)
expect(record.errors["referral"])
.to include(match(I18n.t("validations.lettings.household.referral.la_general_needs.internal_transfer")))
expect(record.errors["referral_type"])
.to include(match(I18n.t("validations.lettings.household.referral.la_general_needs.internal_transfer")))
expect(record.errors["prevten"])
.to include(match(I18n.t("validations.lettings.household.prevten.la_general_needs.internal_transfer")))
@ -170,6 +172,8 @@ RSpec.describe Validations::HouseholdValidations do
household_validator.validate_referral(record)
expect(record.errors["referral"])
.to include(match(I18n.t("validations.lettings.household.referral.la_general_needs.internal_transfer")))
expect(record.errors["referral_type"])
.to include(match(I18n.t("validations.lettings.household.referral.la_general_needs.internal_transfer")))
expect(record.errors["prevten"])
.to include(match(I18n.t("validations.lettings.household.prevten.la_general_needs.internal_transfer")))
end
@ -767,6 +771,8 @@ RSpec.describe Validations::HouseholdValidations do
.to include(match I18n.t("validations.lettings.household.prevten.internal_transfer", prevten: label))
expect(record.errors["referral"])
.to include(match I18n.t("validations.lettings.household.referral.prevten_invalid", prevten: ""))
expect(record.errors["referral_type"])
.to include(match I18n.t("validations.lettings.household.referral.prevten_invalid", prevten: ""))
end
end
end

21
spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb

@ -1216,27 +1216,6 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
end
describe "#field_100" do
context "when log is a renewal and field 100 is an invalid value" do
let(:attributes) { { bulk_upload:, field_7: 1, field_100: 5 } }
it "adds an error to field 100" do
parser.valid?
expect(parser.errors[:field_100]).to be_present
expect(parser.errors[:field_100]).to include(I18n.t("validations.lettings.2024.bulk_upload.prevten.invalid"))
end
end
context "when log is a renewal and field 100 is a valid value" do
let(:attributes) { { bulk_upload:, field_7: 1, field_100: 32 } }
it "does not add an error" do
parser.valid?
expect(parser.errors[:field_100]).to be_blank
end
end
end
describe "#field_112 - 115 (lettings allocation methods)" do
%i[field_112 field_113 field_114 field_115].each do |field|
context "when only #{field} is not given" do

21
spec/services/bulk_upload/lettings/year2025/row_parser_spec.rb

@ -1053,27 +1053,6 @@ RSpec.describe BulkUpload::Lettings::Year2025::RowParser do
end
end
describe "#field_100" do
context "when log is a renewal and field 100 is an invalid value" do
let(:attributes) { { bulk_upload:, field_7: 1, field_100: 4 } }
it "adds an error to field 100" do
parser.valid?
expect(parser.errors[:field_100]).to be_present
expect(parser.errors[:field_100]).to include(I18n.t("validations.lettings.2025.bulk_upload.prevten.invalid"))
end
end
context "when log is a renewal and field 100 is a valid value" do
let(:attributes) { { bulk_upload:, field_7: 1, field_100: 38 } }
it "does not add an error" do
parser.valid?
expect(parser.errors[:field_100]).to be_blank
end
end
end
describe "#field_112 - 115 (lettings allocation methods)" do
%i[field_112 field_113 field_114 field_115].each do |field|
context "when only #{field} is not given" do

Loading…
Cancel
Save