Browse Source

Merge branch 'main' into CLDC-1669-add-location-redesign

# Conflicts:
#	app/helpers/locations_helper.rb
#	app/views/locations/index.html.erb
#	spec/helpers/locations_helper_spec.rb
#	spec/models/location_spec.rb
pull/1034/head
natdeanlewissoftwire 4 years ago
parent
commit
a09abb29f0
  1. 50
      app/controllers/bulk_upload_lettings_logs_controller.rb
  2. 50
      app/controllers/bulk_upload_sales_logs_controller.rb
  3. 21
      app/helpers/logs_helper.rb
  4. 4
      app/helpers/navigation_items_helper.rb
  5. 10
      app/helpers/schemes_helper.rb
  6. 8
      app/models/form.rb
  7. 5
      app/models/form_handler.rb
  8. 41
      app/models/forms/bulk_upload_lettings/prepare_your_file.rb
  9. 19
      app/models/forms/bulk_upload_lettings/upload_your_file.rb
  10. 37
      app/models/forms/bulk_upload_lettings/year.rb
  11. 41
      app/models/forms/bulk_upload_sales/prepare_your_file.rb
  12. 19
      app/models/forms/bulk_upload_sales/upload_your_file.rb
  13. 37
      app/models/forms/bulk_upload_sales/year.rb
  14. 25
      app/models/location.rb
  15. 21
      app/models/scheme.rb
  16. 5
      app/models/validations/date_validations.rb
  17. 11
      app/models/validations/setup_validations.rb
  18. 35
      app/models/validations/shared_validations.rb
  19. 33
      app/views/bulk_upload_lettings_logs/forms/prepare_your_file.html.erb
  20. 17
      app/views/bulk_upload_lettings_logs/forms/upload_your_file.html.erb
  21. 16
      app/views/bulk_upload_lettings_logs/forms/year.html.erb
  22. 33
      app/views/bulk_upload_sales_logs/forms/prepare_your_file.html.erb
  23. 17
      app/views/bulk_upload_sales_logs/forms/upload_your_file.html.erb
  24. 16
      app/views/bulk_upload_sales_logs/forms/year.html.erb
  25. 135
      app/views/locations/index.html.erb
  26. 12
      app/views/logs/index.html.erb
  27. 30
      app/views/schemes/show.html.erb
  28. 6
      config/forms/2022_2023.json
  29. 4
      config/initializers/feature_toggle.rb
  30. 20
      config/locales/en.yml
  31. 14
      config/routes.rb
  32. 51
      docs/infrastructure.md
  33. BIN
      public/files/bulk-upload-lettings-template-v1.xlsx
  34. BIN
      public/files/bulk-upload-sales-template-v1.xlsx
  35. 2
      spec/components/check_answers_summary_list_card_component_spec.rb
  36. 4
      spec/factories/lettings_log.rb
  37. 2
      spec/factories/location.rb
  38. 2
      spec/factories/scheme.rb
  39. 51
      spec/features/bulk_upload_lettings_logs_spec.rb
  40. 51
      spec/features/bulk_upload_sales_logs_spec.rb
  41. 3
      spec/features/form/check_answers_page_spec.rb
  42. 1
      spec/features/form/validations_spec.rb
  43. 18
      spec/features/schemes_spec.rb
  44. 2
      spec/fixtures/files/lettings_logs_download.csv
  45. 2
      spec/fixtures/files/lettings_logs_download_non_support.csv
  46. 4
      spec/helpers/locations_helper_spec.rb
  47. 107
      spec/helpers/schemes_helper_spec.rb
  48. 9
      spec/helpers/tag_helper_spec.rb
  49. 3
      spec/jobs/email_csv_job_spec.rb
  50. 34
      spec/models/form_spec.rb
  51. 12
      spec/models/forms/bulk_upload_lettings/year_spec.rb
  52. 12
      spec/models/forms/bulk_upload_sales/year_spec.rb
  53. 4
      spec/models/lettings_log_spec.rb
  54. 71
      spec/models/location_spec.rb
  55. 34
      spec/models/scheme_spec.rb
  56. 147
      spec/models/validations/date_validations_spec.rb
  57. 194
      spec/models/validations/setup_validations_spec.rb
  58. 1
      spec/rails_helper.rb
  59. 34
      spec/requests/bulk_upload_lettings_logs_controller_spec.rb
  60. 34
      spec/requests/bulk_upload_sales_logs_controller_spec.rb
  61. 1
      spec/requests/form_controller_spec.rb
  62. 34
      spec/requests/locations_controller_spec.rb
  63. 2
      spec/requests/schemes_controller_spec.rb
  64. 8
      spec/services/exports/lettings_log_export_service_spec.rb
  65. 6
      spec/services/imports/lettings_logs_import_service_spec.rb

50
app/controllers/bulk_upload_lettings_logs_controller.rb

@ -0,0 +1,50 @@
class BulkUploadLettingsLogsController < ApplicationController
before_action :authenticate_user!
def start
if in_crossover_period?
redirect_to bulk_upload_lettings_log_path(id: "year")
else
redirect_to bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year: current_year })
end
end
def show
render form.view_path
end
def update
if form.valid?
redirect_to form.next_path
else
render form.view_path
end
end
private
def current_year
FormHandler.instance.forms["current_lettings"].start_date.year
end
def in_crossover_period?
FormHandler.instance.forms.values.any?(&:in_crossover_period?)
end
def form
@form ||= case params[:id]
when "year"
Forms::BulkUploadLettings::Year.new(form_params)
when "prepare-your-file"
Forms::BulkUploadLettings::PrepareYourFile.new(form_params)
when "upload-your-file"
Forms::BulkUploadLettings::UploadYourFile.new(form_params)
else
raise "Page not found for path #{params[:id]}"
end
end
def form_params
params.fetch(:form, {}).permit(:year)
end
end

50
app/controllers/bulk_upload_sales_logs_controller.rb

@ -0,0 +1,50 @@
class BulkUploadSalesLogsController < ApplicationController
before_action :authenticate_user!
def start
if in_crossover_period?
redirect_to bulk_upload_sales_log_path(id: "year")
else
redirect_to bulk_upload_sales_log_path(id: "prepare-your-file", form: { year: current_year })
end
end
def show
render form.view_path
end
def update
if form.valid?
redirect_to form.next_path
else
render form.view_path
end
end
private
def current_year
FormHandler.instance.forms["current_sales"].start_date.year
end
def in_crossover_period?
FormHandler.instance.forms.values.any?(&:in_crossover_period?)
end
def form
@form ||= case params[:id]
when "year"
Forms::BulkUploadSales::Year.new(form_params)
when "prepare-your-file"
Forms::BulkUploadSales::PrepareYourFile.new(form_params)
when "upload-your-file"
Forms::BulkUploadSales::UploadYourFile.new(form_params)
else
raise "Page not found for path #{params[:id]}"
end
end
def form_params
params.fetch(:form, {}).permit(:year)
end
end

21
app/helpers/logs_helper.rb

@ -0,0 +1,21 @@
module LogsHelper
def log_type_for_controller(controller)
case controller.class.to_s
when "LettingsLogsController"
"lettings"
when "SalesLogsController"
"sales"
else
raise "Log type not found for #{controller.class}"
end
end
def bulk_upload_path_for_controller(controller, id:)
case log_type_for_controller(controller)
when "lettings"
bulk_upload_lettings_log_path(id:)
when "sales"
bulk_upload_sales_log_path(id:)
end
end
end

4
app/helpers/navigation_items_helper.rb

@ -65,11 +65,11 @@ module NavigationItemsHelper
private
def lettings_logs_current?(path)
path == "/lettings-logs"
path.starts_with?("/lettings-logs")
end
def sales_logs_current?(path)
path == "/sales-logs"
path.starts_with?("/sales-logs")
end
def users_current?(path)

10
app/helpers/schemes_helper.rb

@ -1,5 +1,5 @@
module SchemesHelper
def display_scheme_attributes(scheme)
def display_scheme_attributes(scheme, user)
base_attributes = [
{ name: "Scheme code", value: scheme.id_to_display },
{ name: "Name", value: scheme.service_name, edit: true },
@ -18,11 +18,15 @@ module SchemesHelper
]
if FeatureToggle.scheme_toggle_enabled?
base_attributes.append({ name: "Status", value: scheme.status })
base_attributes.append({ name: "Status", value: status_tag(scheme.status) })
end
if user.data_coordinator?
base_attributes.delete_if { |item| item[:name] == "Housing stock owned by" }
end
if scheme.arrangement_type_same?
base_attributes.delete({ name: "Organisation providing support", value: scheme.managing_organisation&.name })
base_attributes.delete_if { |item| item[:name] == "Organisation providing support" }
end
base_attributes
end

8
app/models/form.rb

@ -223,4 +223,12 @@ class Form
end
end
end
def in_crossover_period?(now: Time.zone.now)
((end_date - 3.months) < now) && (now < end_date)
end
def inspect
"#<#{self.class} @type=#{type} @name=#{name}>"
end
end

5
app/models/form_handler.rb

@ -49,6 +49,11 @@ class FormHandler
today < window_end_date ? today.year - 1 : today.year
end
def collection_start_date(date)
window_end_date = Time.zone.local(date.year, 4, 1)
date < window_end_date ? Time.zone.local(date.year - 1, 4, 1) : Time.zone.local(date.year, 4, 1)
end
def current_collection_start_date
Time.zone.local(current_collection_start_year, 4, 1)
end

41
app/models/forms/bulk_upload_lettings/prepare_your_file.rb

@ -0,0 +1,41 @@
module Forms
module BulkUploadLettings
class PrepareYourFile
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
def view_path
"bulk_upload_lettings_logs/forms/prepare_your_file"
end
def back_path
if in_crossover_period?
Rails.application.routes.url_helpers.bulk_upload_lettings_log_path(id: "year", form: { year: })
else
Rails.application.routes.url_helpers.lettings_logs_path
end
end
def next_path
bulk_upload_lettings_log_path(id: "upload-your-file", form: { year: })
end
def template_path
"/files/bulk-upload-lettings-template-v1.xlsx"
end
def year_combo
"#{year}/#{year + 1 - 2000}"
end
private
def in_crossover_period?
FormHandler.instance.forms.values.any?(&:in_crossover_period?)
end
end
end
end

19
app/models/forms/bulk_upload_lettings/upload_your_file.rb

@ -0,0 +1,19 @@
module Forms
module BulkUploadLettings
class UploadYourFile
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
def view_path
"bulk_upload_lettings_logs/forms/upload_your_file"
end
def back_path
bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year: })
end
end
end
end

37
app/models/forms/bulk_upload_lettings/year.rb

@ -0,0 +1,37 @@
module Forms
module BulkUploadLettings
class Year
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
validates :year, presence: true
def view_path
"bulk_upload_lettings_logs/forms/year"
end
def options
possible_years.map do |year|
OpenStruct.new(id: year, name: "#{year}/#{year + 1}")
end
end
def back_path
lettings_logs_path
end
def next_path
bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year: })
end
private
def possible_years
FormHandler.instance.lettings_forms.values.map { |form| form.start_date.year }.sort.reverse
end
end
end
end

41
app/models/forms/bulk_upload_sales/prepare_your_file.rb

@ -0,0 +1,41 @@
module Forms
module BulkUploadSales
class PrepareYourFile
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
def view_path
"bulk_upload_sales_logs/forms/prepare_your_file"
end
def back_path
if in_crossover_period?
Rails.application.routes.url_helpers.bulk_upload_sales_log_path(id: "year", form: { year: })
else
Rails.application.routes.url_helpers.sales_logs_path
end
end
def next_path
bulk_upload_sales_log_path(id: "upload-your-file", form: { year: })
end
def template_path
"/files/bulk-upload-sales-template-v1.xlsx"
end
def year_combo
"#{year}/#{year + 1 - 2000}"
end
private
def in_crossover_period?
FormHandler.instance.forms.values.any?(&:in_crossover_period?)
end
end
end
end

19
app/models/forms/bulk_upload_sales/upload_your_file.rb

@ -0,0 +1,19 @@
module Forms
module BulkUploadSales
class UploadYourFile
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
def view_path
"bulk_upload_sales_logs/forms/upload_your_file"
end
def back_path
bulk_upload_sales_log_path(id: "prepare-your-file", form: { year: })
end
end
end
end

37
app/models/forms/bulk_upload_sales/year.rb

@ -0,0 +1,37 @@
module Forms
module BulkUploadSales
class Year
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
validates :year, presence: true
def view_path
"bulk_upload_sales_logs/forms/year"
end
def options
possible_years.map do |year|
OpenStruct.new(id: year, name: "#{year}/#{year + 1}")
end
end
def back_path
sales_logs_path
end
def next_path
bulk_upload_sales_log_path(id: "prepare-your-file", form: { year: })
end
private
def possible_years
FormHandler.instance.sales_forms.values.map { |form| form.start_date.year }.sort.reverse
end
end
end
end

25
app/models/location.rb

@ -375,20 +375,29 @@ class Location < ApplicationRecord
end
def available_from
startdate || [created_at, FormHandler.instance.current_collection_start_date].min
return startdate if startdate.present?
FormHandler.instance.collection_start_date(created_at)
end
def open_deactivation
location_deactivation_periods.deactivations_without_reactivation.first
end
def status
open_deactivation = location_deactivation_periods.deactivations_without_reactivation.first
recent_deactivation = location_deactivation_periods.order("created_at").last
def recent_deactivation
location_deactivation_periods.order("created_at").last
end
return :deactivated if open_deactivation&.deactivation_date.present? && Time.zone.now >= open_deactivation.deactivation_date
return :deactivating_soon if open_deactivation&.deactivation_date.present? && Time.zone.now < open_deactivation.deactivation_date
return :reactivating_soon if recent_deactivation&.reactivation_date.present? && Time.zone.now < recent_deactivation.reactivation_date
return :activating_soon if startdate.present? && Time.zone.now < startdate
def status(date = Time.zone.now)
return :incomplete unless confirmed
return :deactivated if open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date
return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
return :reactivating_soon if recent_deactivation&.reactivation_date.present? && date < recent_deactivation.reactivation_date
return :activating_soon if startdate.present? && date < startdate
:active
end
alias_method :status_at, :status
def active?
status == :active

21
app/models/scheme.rb

@ -210,21 +210,26 @@ class Scheme < ApplicationRecord
end
def available_from
[created_at, FormHandler.instance.current_collection_start_date].min
FormHandler.instance.collection_start_date(created_at)
end
def status
return :incomplete unless confirmed
def open_deactivation
scheme_deactivation_periods.deactivations_without_reactivation.first
end
open_deactivation = scheme_deactivation_periods.deactivations_without_reactivation.first
recent_deactivation = scheme_deactivation_periods.order("created_at").last
def recent_deactivation
scheme_deactivation_periods.order("created_at").last
end
return :deactivated if open_deactivation&.deactivation_date.present? && Time.zone.now >= open_deactivation.deactivation_date
return :deactivating_soon if open_deactivation&.deactivation_date.present? && Time.zone.now < open_deactivation.deactivation_date
return :reactivating_soon if recent_deactivation&.reactivation_date.present? && Time.zone.now < recent_deactivation.reactivation_date
def status(date = Time.zone.now)
return :incomplete unless confirmed
return :deactivated if open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date
return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
return :reactivating_soon if recent_deactivation&.reactivation_date.present? && date < recent_deactivation.reactivation_date
:active
end
alias_method :status_at, :status
def active?
status == :active

5
app/models/validations/date_validations.rb

@ -1,4 +1,6 @@
module Validations::DateValidations
include Validations::SharedValidations
def validate_property_major_repairs(record)
date_valid?("mrcdate", record)
if record["startdate"].present? && record["mrcdate"].present? && record["startdate"] < record["mrcdate"]
@ -59,6 +61,9 @@ module Validations::DateValidations
if record["mrcdate"].present? && record.startdate < record["mrcdate"]
record.errors.add :startdate, I18n.t("validations.setup.startdate.after_major_repair_date")
end
location_during_startdate_validation(record, :startdate)
scheme_during_startdate_validation(record, :startdate)
end
private

11
app/models/validations/setup_validations.rb

@ -1,10 +1,21 @@
module Validations::SetupValidations
include Validations::SharedValidations
def validate_irproduct_other(record)
if intermediate_product_rent_type?(record) && record.irproduct_other.blank?
record.errors.add :irproduct_other, I18n.t("validations.setup.intermediate_rent_product_name.blank")
end
end
def validate_location(record)
location_during_startdate_validation(record, :location_id)
end
def validate_scheme(record)
location_during_startdate_validation(record, :scheme_id)
scheme_during_startdate_validation(record, :scheme_id)
end
private
def intermediate_product_rent_type?(record)

35
app/models/validations/shared_validations.rb

@ -33,4 +33,39 @@ module Validations::SharedValidations
end
end
end
def location_during_startdate_validation(record, field)
location_inactive_status = inactive_status(record.startdate, record.location)
if location_inactive_status.present?
date, scope, deactivation_date = location_inactive_status.values_at(:date, :scope, :deactivation_date)
record.errors.add field, I18n.t("validations.setup.startdate.location.#{scope}", postcode: record.location.postcode, date:, deactivation_date:)
end
end
def scheme_during_startdate_validation(record, field)
scheme_inactive_status = inactive_status(record.startdate, record.scheme)
if scheme_inactive_status.present?
date, scope, deactivation_date = scheme_inactive_status.values_at(:date, :scope, :deactivation_date)
record.errors.add field, I18n.t("validations.setup.startdate.scheme.#{scope}", name: record.scheme.service_name, date:, deactivation_date:)
end
end
def inactive_status(date, resource)
return if date.blank? || resource.blank?
status = resource.status_at(date)
return unless %i[reactivating_soon activating_soon deactivated].include?(status)
closest_reactivation = resource.recent_deactivation
open_deactivation = resource.open_deactivation
date = case status
when :reactivating_soon then closest_reactivation.reactivation_date
when :activating_soon then resource&.available_from
when :deactivated then open_deactivation.deactivation_date
end
{ scope: status, date: date&.to_formatted_s(:govuk_date), deactivation_date: closest_reactivation&.deactivation_date&.to_formatted_s(:govuk_date) }
end
end

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

@ -0,0 +1,33 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<%= form_with model: @form, scope: :form, url: bulk_upload_lettings_log_path(id: "prepare-your-file"), method: :patch do |f| %>
<%= f.hidden_field :year %>
<span class="govuk-caption-l">Upload lettings logs in bulk (<%= @form.year_combo %>)</span>
<h1 class="govuk-heading-l">Prepare your file</h1>
<h2 class="govuk-heading-m">Create your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Download the <%= govuk_link_to "bulk lettings template", @form.template_path %></li>
<li>Export the data from your housing management system, matching the template</li>
<li>If you cannot export it in this format, you may have to input it manually</li>
</ul>
<h2 class="govuk-heading-m">Check your data</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Check data is complete and formatted correctly, using data specifications (opens in a new tab)</li>
</ul>
<h2 class="govuk-heading-m">Save your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Save the file (CSV format <strong>only</strong>)</li>
</ul>
<%= f.govuk_submit %>
<% end %>
</div>
</div>

17
app/views/bulk_upload_lettings_logs/forms/upload_your_file.html.erb

@ -0,0 +1,17 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<%= form_with model: @form, scope: :form, url: bulk_upload_lettings_log_path(id: "upload-your-file"), method: :patch do |f| %>
<%= f.govuk_error_summary %>
<div>
Upload your file goes here
</div>
<div>
year selected <%= @form.year %>
</div>
<%= f.govuk_submit %>
<% end %>

16
app/views/bulk_upload_lettings_logs/forms/year.html.erb

@ -0,0 +1,16 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<%= form_with model: @form, scope: :form, url: bulk_upload_lettings_log_path(id: "year"), method: :patch do |f| %>
<%= f.govuk_error_summary %>
<%= f.govuk_collection_radio_buttons :year,
@form.options,
:id,
:name,
legend: { text: "Which year are you uploading data for?", size: "l" },
caption: { text: "Upload lettings logs in bulk", size: "l" } %>
<%= f.govuk_submit %>
<% end %>

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

@ -0,0 +1,33 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<%= form_with model: @form, scope: :form, url: bulk_upload_sales_log_path(id: "prepare-your-file"), method: :patch do |f| %>
<%= f.hidden_field :year %>
<span class="govuk-caption-l">Upload sales logs in bulk (<%= @form.year_combo %>)</span>
<h1 class="govuk-heading-l">Prepare your file</h1>
<h2 class="govuk-heading-m">Create your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Download the <%= govuk_link_to "bulk sales template", @form.template_path %></li>
<li>Export the data from your housing management system, matching the template</li>
<li>If you cannot export it in this format, you may have to input it manually</li>
</ul>
<h2 class="govuk-heading-m">Check your data</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Check data is complete and formatted correctly, using data specifications (opens in a new tab)</li>
</ul>
<h2 class="govuk-heading-m">Save your file</h2>
<ul class="govuk-list govuk-list--bullet">
<li>Save the file (CSV format <strong>only</strong>)</li>
</ul>
<%= f.govuk_submit %>
<% end %>
</div>
</div>

17
app/views/bulk_upload_sales_logs/forms/upload_your_file.html.erb

@ -0,0 +1,17 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<%= form_with model: @form, scope: :form, url: bulk_upload_sales_log_path(id: "upload-your-file"), method: :patch do |f| %>
<%= f.govuk_error_summary %>
<div>
Upload your file goes here
</div>
<div>
year selected <%= @form.year %>
</div>
<%= f.govuk_submit %>
<% end %>

16
app/views/bulk_upload_sales_logs/forms/year.html.erb

@ -0,0 +1,16 @@
<% content_for :before_content do %>
<%= govuk_back_link href: @form.back_path %>
<% end %>
<%= form_with model: @form, scope: :form, url: bulk_upload_sales_log_path(id: "year"), method: :patch do |f| %>
<%= f.govuk_error_summary %>
<%= f.govuk_collection_radio_buttons :year,
@form.options,
:id,
:name,
legend: { text: "Which year are you uploading data for?", size: "l" },
caption: { text: "Upload sales logs in bulk", size: "l" } %>
<%= f.govuk_submit %>
<% end %>

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

@ -11,57 +11,104 @@
<%= render partial: "organisations/headings", locals: { main: @scheme.service_name, sub: nil } %>
<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, "Locations")) %>
<% if FeatureToggle.location_toggle_enabled? %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<% end %>
<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, "Locations")) %>
<h2 class="govuk-visually-hidden">Locations</h2>
<h2 class="govuk-visually-hidden">Locations</h2>
<%= render SearchComponent.new(current_user:, search_label: "Search by location name or postcode", value: @searched) %>
<%= render SearchComponent.new(current_user:, search_label: "Search by location name or postcode", value: @searched) %>
<%= govuk_section_break(visible: true, size: "m") %>
<%= govuk_section_break(visible: true, size: "m") %>
<% if FeatureToggle.location_toggle_enabled? %>
</div>
</div>
<% end %>
<%= govuk_table do |table| %>
<%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<%= render(SearchResultCaptionComponent.new(searched: @searched, count: @pagy.count, item_label:, total_count: @total_count, item: "locations", path: request.path)) %>
<% end %>
<%= table.head do |head| %>
<%= head.row do |row| %>
<% row.cell(header: true, text: "Code", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Postcode", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Units", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Common unit type", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Mobility type", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Local authority", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Available from", html_attributes: {
scope: "col",
}) %>
<% end %>
<% end %>
<% @locations.each do |location| %>
<%= table.body do |body| %>
<%= body.row do |row| %>
<% row.cell(text: location.id) %>
<% row.cell(text: simple_format(location_cell_postcode(location, location.confirmed ? scheme_location_path(@scheme, location) : location.postcode.present? ? scheme_location_check_answers_path(@scheme, location, route: "locations") : scheme_location_postcode_path(@scheme, location)), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %>
<% row.cell(text: location.units) %>
<% row.cell(text: simple_format("<span>#{location.type_of_unit}</span>")) %>
<% row.cell(text: location.mobility_type) %>
<% row.cell(text: location.location_admin_district) %>
<% row.cell(text: location.startdate&.to_formatted_s(:govuk_date)) %>
<% if FeatureToggle.location_toggle_enabled? %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<%= govuk_table do |table| %>
<%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<%= render(SearchResultCaptionComponent.new(searched: @searched, count: @pagy.count, item_label:, total_count: @total_count, item: "locations", path: request.path)) %>
<% end %>
<%= table.head do |head| %>
<%= head.row do |row| %>
<% row.cell(header: true, text: "Postcode", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Location code", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Status", html_attributes: {
scope: "col",
}) %>
<% end %>
<% end %>
<% @locations.each do |location| %>
<%= table.body do |body| %>
<%= body.row do |row| %>
<% row.cell(text: simple_format(location_cell_postcode(location, location.confirmed ? scheme_location_path(@scheme, location) : location.postcode.present? ? scheme_location_check_answers_path(@scheme, location, route: "locations") : scheme_location_postcode_path(@scheme, location)), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %>
<% row.cell(text: location.id) %>
<% row.cell(text: status_tag(location.status)) %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= govuk_button_link_to "Add a location", new_scheme_location_path(@scheme), secondary: true %>
</div>
</div>
<% else %>
<%= govuk_table do |table| %>
<%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %>
<%= render(SearchResultCaptionComponent.new(searched: @searched, count: @pagy.count, item_label:, total_count: @total_count, item: "locations", path: request.path)) %>
<% end %>
<%= table.head do |head| %>
<%= head.row do |row| %>
<% row.cell(header: true, text: "Code", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Postcode", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Units", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Common unit type", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Mobility type", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Local authority", html_attributes: {
scope: "col",
}) %>
<% row.cell(header: true, text: "Available from", html_attributes: {
scope: "col",
}) %>
<% end %>
<% end %>
<% @locations.each do |location| %>
<%= table.body do |body| %>
<%= body.row do |row| %>
<% row.cell(text: location.id) %>
<% row.cell(text: simple_format(location_cell_postcode(location, location.confirmed ? scheme_location_path(@scheme, location) : location.postcode.present? ? scheme_location_check_answers_path(@scheme, location, route: "locations") : scheme_location_postcode_path(@scheme, location)), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %>
<% row.cell(text: location.units) %>
<% row.cell do %>
<span><%= simple_format(location.type_of_unit) %></span>
<% end %>
<% row.cell(text: location.mobility_type) %>
<% row.cell(text: location.location_admin_district) %>
<% row.cell(text: location.startdate&.to_formatted_s(:govuk_date)) %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= govuk_button_link_to "Add a location", new_scheme_location_path(@scheme), secondary: true %>
<% end %>
<%= govuk_button_link_to "Add a location", new_scheme_location_path(@scheme), secondary: true %>
<%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "locations" } %>

12
app/views/logs/index.html.erb

@ -10,14 +10,18 @@
<% end %>
<div class="app-filter-layout" data-controller="filter-layout">
<div class="govuk-button-group app-filter-toggle">
<div class="govuk-button-group app-filter-toggle govuk-!-margin-bottom-6">
<% if current_page?(controller: 'lettings_logs', action: 'index') %>
<%= govuk_button_to "Create a new lettings log", lettings_logs_path %>
<%= govuk_button_to "Create a new lettings log", lettings_logs_path, class: "govuk-!-margin-right-6" %>
<% end %>
<% if FeatureToggle.sales_log_enabled? && current_page?(controller: 'sales_logs', action: 'index') %>
<%= govuk_button_to "Create a new sales log", sales_logs_path %>
<%= govuk_button_to "Create a new sales log", sales_logs_path, class: "govuk-!-margin-right-6" %>
<% end %>
<% if FeatureToggle.bulk_upload_logs? %>
<%= govuk_button_link_to "Upload #{log_type_for_controller(controller)} logs in bulk", bulk_upload_path_for_controller(controller, id: "start"), secondary: true %>
<% end %>
<%#= govuk_link_to "Upload logs", bulk_upload_lettings_logs_path %>
</div>
<%= render partial: "log_filters" %>

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

@ -10,19 +10,27 @@
<%= render partial: "organisations/headings", locals: { main: @scheme.service_name, sub: nil } %>
<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, "Locations")) %>
<% if FeatureToggle.location_toggle_enabled? %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<% end %>
<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, "Locations")) %>
<h2 class="govuk-visually-hidden">Scheme</h2>
<h2 class="govuk-visually-hidden">Scheme</h2>
<%= govuk_summary_list do |summary_list| %>
<% display_scheme_attributes(@scheme).each do |attr| %>
<% next if current_user.data_coordinator? && attr[:name] == ("Housing stock owned by") %>
<%= summary_list.row do |row| %>
<% row.key { attr[:name].eql?("Registered under Care Standards Act 2000") ? "Registered under Care Standards Act 2000" : attr[:name].to_s.humanize } %>
<% row.value { attr[:name].eql?("Status") ? status_tag(attr[:value]) : details_html(attr) } %>
<% row.action(text: "Change", href: scheme_edit_name_path(scheme_id: @scheme.id)) if attr[:edit] %>
<% end %>
<% end %>
<%= govuk_summary_list do |summary_list| %>
<% display_scheme_attributes(@scheme, current_user).each do |attr| %>
<%= summary_list.row do |row| %>
<% row.key { attr[:name] } %>
<% row.value { details_html(attr) } %>
<% row.action(text: "Change", href: scheme_edit_name_path(scheme_id: @scheme.id)) if attr[:edit] %>
<% end %>
<% end %>
<% end %>
<% if FeatureToggle.location_toggle_enabled? %>
</div>
</div>
<% end %>
<% if FeatureToggle.scheme_toggle_enabled? %>

6
config/forms/2022_2023.json

@ -5929,7 +5929,7 @@
"description": "",
"questions": {
"housingneeds_type": {
"header": "What type of access need do they have?",
"header": "What type of access needs do they have?",
"hint_text": "",
"type": "radio",
"check_answer_label": "Disabled access needs",
@ -5947,7 +5947,7 @@
"value": true
},
"3": {
"value": "None of the above"
"value": "None of the listed options"
}
}
},
@ -7470,7 +7470,7 @@
"household_charge": {
"check_answer_label": "Does the household pay rent or charges?",
"header": "Does the household pay rent or other charges for the accommodation?",
"hint_text": "",
"hint_text": "If rent is charged on the property then answer Yes to this question, even if the tenants do not pay it themselves.",
"type": "radio",
"answer_options": {
"0": {

4
config/initializers/feature_toggle.rb

@ -22,4 +22,8 @@ class FeatureToggle
def self.managing_for_other_user_enabled?
!Rails.env.production?
end
def self.bulk_upload_logs?
!Rails.env.production?
end
end

20
config/locales/en.yml

@ -38,6 +38,18 @@ en:
create_password: "Create a password to finish setting up your account"
reset_password: "Reset your password"
activemodel:
errors:
models:
forms/bulk_upload_lettings/year:
attributes:
year:
blank: You must select a collection period to upload for
forms/bulk_upload_sales/year:
attributes:
year:
blank: You must select a collection period to upload for
activerecord:
errors:
models:
@ -120,6 +132,14 @@ en:
before_scheme_end_date: "The tenancy start date must be before the end date for this supported housing scheme"
after_void_date: "Enter a tenancy start date that is after the void date"
after_major_repair_date: "Enter a tenancy start date that is after the major repair date"
location:
deactivated: "The location %{postcode} was deactivated on %{date} and was not available on the day you entered."
reactivating_soon: "The location %{postcode} was deactivated on %{deactivation_date} and is not available on the date you entered. It reactivates on %{date}"
activating_soon: "The location %{postcode} is not available until %{date}. Enter a tenancy start date after %{date}"
scheme:
deactivated: "%{name} was deactivated on %{date} and was not available on the day you entered"
reactivating_soon: "%{name} was deactivated on %{deactivation_date} and is not available on the date you entered. It reactivates on %{date}"
activating_soon: "%{name} is not available until %{date}. Enter a tenancy start date after %{date}"
property:
mrcdate:

14
config/routes.rb

@ -125,6 +125,12 @@ Rails.application.routes.draw do
get "csv-download", to: "lettings_logs#download_csv"
post "email-csv", to: "lettings_logs#email_csv"
get "csv-confirmation", to: "lettings_logs#csv_confirmation"
resources :bulk_upload_lettings_logs, path: "bulk-upload-logs" do
collection do
get :start
end
end
end
member do
@ -144,6 +150,14 @@ Rails.application.routes.draw do
end
resources :sales_logs, path: "/sales-logs" do
collection do
resources :bulk_upload_sales_logs, path: "bulk-upload-logs" do
collection do
get :start
end
end
end
FormHandler.instance.sales_forms.each do |_key, form|
form.pages.map do |page|
get page.id.to_s.dasherize, to: "form#show_page"

51
docs/infrastructure.md

@ -122,6 +122,57 @@ After a sucessful deployment a comment will be added to the pull request with th
Once a pull request has been closed the review app infrastructure will be tore down to save on any costs. Should you wish to re-open a closed pull request the review app will be spun up again.
### How to fix review app deployment failures
One reason a review app deployment might fail is that it is attempting to run migrations which conflict with data in the database. For example you might have introduced a unique constraint, but the database associated with the review app has duplicate data in it that would violate this constraint, and so the migration cannot be run. There are two main ways to remedy this:
**Method 1 - Edit database via console**
1. Log in to Cloud Foundry
```bash
cf login -a api.london.cloud.service.gov.uk -u <your_username>
```
* Your username should be the email address you signed up to GOVUK PaaS with.
* Choose the dev environment whilst logging in.
2. If you were already logged in then Cloud Foundry, then instead just target the dev environment
```bash
cf target -o dluhc-core -s dev
```
3. Find the name of your app
```bash
cf apps
```
* The app name will be in this format: `dluhc-core-review-<pull-request-number>`.
4. Open a console for your app
```bash
cf ssh <app-name-here> -t -c "/tmp/lifecycle/launcher /home/vcap/app 'rails console' ''"
```
5. Edit the database as appropriate, e.g. delete dodgy data and recreate correctly
**Method 2 - Nuke and restart**
1. Find the name of your app
```bash
cf apps
```
* The app name will be in this format: `dluhc-core-review-<pull-request-number>`.
2. Delete the app
```bash
cf delete <app-name-here>
```
3. Find the name of the matching Postgres service
```bash
cf services
```
* The service name will be in this format: `dluhc-core-review-<pull-request-number>-postgres`.
4. Delete the service
```bash
cf delete-service <service-name-here>
```
* Use `cf services` or `cf service <service-name-here>` to check the operation status.
* There's no need to delete the Redis service.
5. Re-run the whole review app pipeline in GitHub
* If it fails it's likely that the deletion from the previous step hadn't completed yet. So just wait a few minutes and re-run the pipeline again.
## Setting up Infrastructure for a new environment
### Staging

BIN
public/files/bulk-upload-lettings-template-v1.xlsx

Binary file not shown.

BIN
public/files/bulk-upload-sales-template-v1.xlsx

Binary file not shown.

2
spec/components/check_answers_summary_list_card_component_spec.rb

@ -3,7 +3,7 @@ require "rails_helper"
RSpec.describe CheckAnswersSummaryListCardComponent, type: :component do
context "when given a set of questions" do
let(:user) { FactoryBot.build(:user) }
let(:log) { FactoryBot.build(:lettings_log, :completed, age2: 99) }
let(:log) { FactoryBot.build(:lettings_log, :completed, age2: 99, startdate: Time.zone.local(2021, 5, 1)) }
let(:subsection_id) { "household_characteristics" }
let(:subsection) { log.form.get_subsection(subsection_id) }
let(:questions) { subsection.applicable_questions(log) }

4
spec/factories/lettings_log.rb

@ -60,7 +60,7 @@ FactoryBot.define do
illness { 1 }
preg_occ { 2 }
startertenancy { 1 }
tenancylength { 5 }
tenancylength { nil }
tenancy { 1 }
ppostcode_full { Faker::Address.postcode }
rsnvac { 6 }
@ -134,7 +134,7 @@ FactoryBot.define do
property_relet { 0 }
mrcdate { Time.zone.local(2020, 5, 5, 10, 36, 49) }
incref { 0 }
startdate { Time.utc(2022, 2, 2, 10, 36, 49) }
startdate { Time.zone.today }
armedforces { 1 }
builtype { 1 }
unitletas { 2 }

2
spec/factories/location.rb

@ -7,7 +7,7 @@ FactoryBot.define do
mobility_type { %w[A M N W X].sample }
location_code { "E09000033" }
location_admin_district { "Westminster" }
startdate { Faker::Date.between(from: 6.months.ago, to: Time.zone.today) }
startdate { nil }
confirmed { true }
scheme
trait :export do

2
spec/factories/scheme.rb

@ -12,7 +12,7 @@ FactoryBot.define do
owning_organisation { FactoryBot.create(:organisation) }
managing_organisation { FactoryBot.create(:organisation) }
confirmed { true }
created_at { Time.zone.now }
created_at { Time.zone.local(2021, 4, 1) }
trait :export do
sensitive { 1 }
registered_under_care_act { 1 }

51
spec/features/bulk_upload_lettings_logs_spec.rb

@ -0,0 +1,51 @@
require "rails_helper"
RSpec.describe "Bulk upload lettings log" do
let(:user) { create(:user) }
before do
sign_in user
end
context "when during crossover period" do
it "shows journey with year option" do
Timecop.freeze(2023, 6, 1) do
visit("/lettings-logs")
expect(page).to have_link("Upload lettings logs in bulk")
click_link("Upload lettings logs in bulk")
expect(page).to have_content("Which year")
click_button("Continue")
expect(page).to have_content("You must select a collection period to upload for")
choose("2022/2023")
click_button("Continue")
click_link("Back")
expect(page.find_field("form-year-2022-field")).to be_checked
click_button("Continue")
expect(page).to have_content("Upload lettings logs in bulk (2022/23)")
click_button("Continue")
expect(page).to have_content("Upload your file")
end
end
end
context "when not it crossover period" do
it "shows journey with year option" do
Timecop.freeze(2023, 10, 1) do
visit("/lettings-logs")
expect(page).to have_link("Upload lettings logs in bulk")
click_link("Upload lettings logs in bulk")
expect(page).to have_content("Upload lettings logs in bulk (2022/23)")
click_button("Continue")
expect(page).to have_content("Upload your file")
end
end
end
end

51
spec/features/bulk_upload_sales_logs_spec.rb

@ -0,0 +1,51 @@
require "rails_helper"
RSpec.describe "Bulk upload sales log" do
let(:user) { create(:user) }
before do
sign_in user
end
context "when during crossover period" do
it "shows journey with year option" do
Timecop.freeze(2023, 6, 1) do
visit("/sales-logs")
expect(page).to have_link("Upload sales logs in bulk")
click_link("Upload sales logs in bulk")
expect(page).to have_content("Which year")
click_button("Continue")
expect(page).to have_content("You must select a collection period to upload for")
choose("2022/2023")
click_button("Continue")
click_link("Back")
expect(page.find_field("form-year-2022-field")).to be_checked
click_button("Continue")
expect(page).to have_content("Upload sales logs in bulk (2022/23)")
click_button("Continue")
expect(page).to have_content("Upload your file")
end
end
end
context "when not it crossover period" do
it "shows journey with year option" do
Timecop.freeze(2023, 10, 1) do
visit("/sales-logs")
expect(page).to have_link("Upload sales logs in bulk")
click_link("Upload sales logs in bulk")
expect(page).to have_content("Upload sales logs in bulk (2022/23)")
click_button("Continue")
expect(page).to have_content("Upload your file")
end
end
end
end

3
spec/features/form/check_answers_page_spec.rb

@ -7,7 +7,7 @@ RSpec.describe "Form Check Answers Page" do
let(:subsection) { "household-characteristics" }
let(:conditional_subsection) { "conditional-question" }
let(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) }
let(:location) { FactoryBot.create(:location, scheme:, mobility_type: "N") }
let(:location) { FactoryBot.create(:location, scheme:, mobility_type: "N", startdate: Time.zone.local(2021, 4, 1)) }
let(:lettings_log) do
FactoryBot.create(
@ -36,6 +36,7 @@ RSpec.describe "Form Check Answers Page" do
:completed,
owning_organisation: user.organisation,
managing_organisation: user.organisation,
startdate: Time.zone.local(2021, 5, 1),
)
end
let(:id) { lettings_log.id }

1
spec/features/form/validations_spec.rb

@ -28,6 +28,7 @@ RSpec.describe "validations" do
managing_organisation: user.organisation,
status: 1,
declaration: nil,
startdate: Time.zone.local(2021, 5, 1),
)
end
let(:id) { lettings_log.id }

18
spec/features/schemes_spec.rb

@ -195,11 +195,27 @@ RSpec.describe "Schemes scheme Features" do
expect(page).to have_link("Locations")
end
context "when I click locations link" do
context "when I click locations link and the new locations layout feature toggle is enabled" do
before do
click_link("Locations")
end
it "shows details of those locations" do
locations.each do |location|
expect(page).to have_content(location.id)
expect(page).to have_content(location.postcode)
expect(page).to have_content(location.name)
expect(page).to have_content("Active")
end
end
end
context "when I click locations link and the new locations layout feature toggle is disabled" do
before do
allow(FeatureToggle).to receive(:location_toggle_enabled?).and_return(false)
click_link("Locations")
end
it "shows details of those locations" do
locations.each do |location|
expect(page).to have_content(location.id)

2
spec/fixtures/files/lettings_logs_download.csv vendored

@ -1,2 +1,2 @@
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,needstype,renewal,startdate,rent_type_detail,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,hhmemb,relat2,age2,sex2,retirement_value_check,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,is_previous_la_inferred,prevloc_label,prevloc,illness_type_1,illness_type_2,is_la_inferred,la_label,la,postcode_known,postcode_full,previous_la_known,wchair,preg_occ,cbl,earnings,incfreq,net_income_value_check,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,first_time_property_let_as_social_housing,unitletas,builtype,voiddate,renttype,lettype,totchild,totelder,totadult,net_income_known,nocharge,is_carehome,household_charge,referral,tshortfall,chcharge,ppcodenk,age1_known,age2_known,age3_known,age4_known,age5_known,age6_known,age7_known,age8_known,ethnic_group,letting_allocation_unknown,details_known_2,details_known_3,details_known_4,details_known_5,details_known_6,details_known_7,details_known_8,has_benefits,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,rent_value_check,old_form_id,lar,irproduct,old_id,joint,illness_type_0,tshortfall_known,sheltered,pregnancy_value_check,hhtype,new_old,vacdays,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_managing_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,Supported housing,,2 October 2021,London Affordable Rent,,,,,,,,,,,,,,,,,,,,No,,,,,No,Westminster,E09000033,,SE1 1TE,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,,9,1,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2022-06-05 01:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,Supported housing,,2 October 2021,London Affordable Rent,,,,,,,,,,,,,,,,,,,,No,,,,,No,Westminster,E09000033,,SE1 1TE,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,,9,1,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}

1 id status created_at updated_at created_by_name is_dpo owning_organisation_name managing_organisation_name collection_start_year needstype renewal startdate rent_type_detail irproduct_other tenancycode propcode age1 sex1 ecstat1 hhmemb relat2 age2 sex2 retirement_value_check ecstat2 armedforces leftreg illness housingneeds_a housingneeds_b housingneeds_c housingneeds_h is_previous_la_inferred prevloc_label prevloc illness_type_1 illness_type_2 is_la_inferred la_label la postcode_known postcode_full previous_la_known wchair preg_occ cbl earnings incfreq net_income_value_check benefits hb period brent scharge pscharge supcharg tcharge offered layear ppostcode_full mrcdate declaration ethnic national prevten age3 sex3 ecstat3 age4 sex4 ecstat4 age5 sex5 ecstat5 age6 sex6 ecstat6 age7 sex7 ecstat7 age8 sex8 ecstat8 homeless underoccupation_benefitcap reservist startertenancy tenancylength tenancy rsnvac unittype_gn beds waityear reasonpref chr cap reasonother housingneeds_f housingneeds_g illness_type_3 illness_type_4 illness_type_8 illness_type_5 illness_type_6 illness_type_7 illness_type_9 illness_type_10 rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow tenancyother property_owner_organisation property_manager_organisation purchaser_code reason majorrepairs hbrentshortfall property_relet incref first_time_property_let_as_social_housing unitletas builtype voiddate renttype lettype totchild totelder totadult net_income_known nocharge is_carehome household_charge referral tshortfall chcharge ppcodenk age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known ethnic_group letting_allocation_unknown details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 has_benefits wrent wscharge wpschrge wsupchrg wtcharge wtshortfall refused housingneeds wchchrg newprop relat3 relat4 relat5 relat6 relat7 relat8 rent_value_check old_form_id lar irproduct old_id joint illness_type_0 tshortfall_known sheltered pregnancy_value_check hhtype new_old vacdays major_repairs_date_value_check void_date_value_check housingneeds_type housingneeds_other unittype_sh scheme_code scheme_service_name scheme_sensitive scheme_type scheme_registered_under_care_act scheme_owning_organisation_name scheme_managing_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_admin_district location_startdate
2 {id} in_progress 2022-02-08 16:52:15 +0000 2022-02-08 16:52:15 +0000 Danny Rojas No DLUHC DLUHC 2021 Supported housing 2 October 2021 London Affordable Rent No No Westminster E09000033 SE1 1TE 2 2 8 0 0 0 0 0 0 9 1 6 {scheme_code} {scheme_service_name} {scheme_sensitive} Missing No DLUHC DLUHC {scheme_primary_client_group} {scheme_secondary_client_group} {scheme_support_type} {scheme_intended_stay} 2022-06-05 01:00:00 +0100 2021-04-01 00:00:00 +0100 {location_code} SE1 1TE Downing Street 20 Bungalow Fitted with equipment and adaptations Westminster {location_startdate}

2
spec/fixtures/files/lettings_logs_download_non_support.csv vendored

@ -1,2 +1,2 @@
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,renewal,startdate,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,relat2,age2,sex2,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,prevloc_label,illness_type_1,illness_type_2,la_label,postcode_full,wchair,preg_occ,cbl,earnings,incfreq,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,unitletas,builtype,voiddate,lettype,nocharge,household_charge,referral,tshortfall,chcharge,ppcodenk,ethnic_group,has_benefits,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,illness_type_0,sheltered,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_managing_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,,2 October 2021,,,,,,,,,,,,,,,,,,,,,Westminster,SE1 1TE,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,0,,,,,,,0,0,,,,,,,,,,,,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2022-06-05 01:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,,2 October 2021,,,,,,,,,,,,,,,,,,,,,Westminster,SE1 1TE,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,0,,,,,,,0,0,,,,,,,,,,,,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}

1 id status created_at updated_at created_by_name is_dpo owning_organisation_name managing_organisation_name collection_start_year renewal startdate irproduct_other tenancycode propcode age1 sex1 ecstat1 relat2 age2 sex2 ecstat2 armedforces leftreg illness housingneeds_a housingneeds_b housingneeds_c housingneeds_h prevloc_label illness_type_1 illness_type_2 la_label postcode_full wchair preg_occ cbl earnings incfreq benefits hb period brent scharge pscharge supcharg tcharge offered layear ppostcode_full mrcdate declaration ethnic national prevten age3 sex3 ecstat3 age4 sex4 ecstat4 age5 sex5 ecstat5 age6 sex6 ecstat6 age7 sex7 ecstat7 age8 sex8 ecstat8 homeless underoccupation_benefitcap reservist startertenancy tenancylength tenancy rsnvac unittype_gn beds waityear reasonpref chr cap reasonother housingneeds_f housingneeds_g illness_type_3 illness_type_4 illness_type_8 illness_type_5 illness_type_6 illness_type_7 illness_type_9 illness_type_10 rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow tenancyother property_owner_organisation property_manager_organisation purchaser_code reason majorrepairs hbrentshortfall property_relet incref unitletas builtype voiddate lettype nocharge household_charge referral tshortfall chcharge ppcodenk ethnic_group has_benefits refused housingneeds wchchrg newprop relat3 relat4 relat5 relat6 relat7 relat8 lar irproduct joint illness_type_0 sheltered major_repairs_date_value_check void_date_value_check housingneeds_type housingneeds_other unittype_sh scheme_code scheme_service_name scheme_sensitive scheme_type scheme_registered_under_care_act scheme_owning_organisation_name scheme_managing_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_admin_district location_startdate
2 {id} in_progress 2022-02-08 16:52:15 +0000 2022-02-08 16:52:15 +0000 Danny Rojas No DLUHC DLUHC 2021 2 October 2021 Westminster SE1 1TE 2 8 0 0 0 6 {scheme_code} {scheme_service_name} {scheme_sensitive} Missing No DLUHC DLUHC {scheme_primary_client_group} {scheme_secondary_client_group} {scheme_support_type} {scheme_intended_stay} 2022-06-05 01:00:00 +0100 2021-04-01 00:00:00 +0100 {location_code} SE1 1TE Downing Street 20 Bungalow Fitted with equipment and adaptations Westminster {location_startdate}

4
spec/helpers/locations_helper_spec.rb

@ -154,11 +154,11 @@ RSpec.describe LocationsHelper do
context "when viewing availability" do
context "with no deactivations" do
it "displays created_at as availability date if startdate is not present" do
it "displays previous collection start date as availability date if created_at is earlier than collection start date" do
location.update!(startdate: nil)
availability_attribute = display_location_attributes(location).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from #{location.created_at.to_formatted_s(:govuk_date)}")
expect(availability_attribute).to eq("Active from 1 April 2021")
end
it "displays current collection start date as availability date if created_at is later than collection start date" do

107
spec/helpers/schemes_helper_spec.rb

@ -2,7 +2,7 @@ require "rails_helper"
RSpec.describe SchemesHelper do
describe "Active periods" do
let(:scheme) { FactoryBot.create(:scheme) }
let(:scheme) { FactoryBot.create(:scheme, created_at: Time.zone.today) }
before do
Timecop.freeze(2022, 10, 10)
@ -87,40 +87,97 @@ RSpec.describe SchemesHelper do
end
end
include TagHelper
describe "display_scheme_attributes" do
let!(:scheme) { FactoryBot.create(:scheme, created_at: Time.zone.local(2022, 4, 1)) }
let(:owning_organisation) { FactoryBot.create(:organisation, name: "Acme LTD Owning") }
let(:managing_organisation) { FactoryBot.create(:organisation, name: "Acme LTD Managing") }
let!(:scheme) do
FactoryBot.create(:scheme,
service_name: "Test service_name",
sensitive: 0,
scheme_type: 7,
registered_under_care_act: 3,
owning_organisation:,
managing_organisation:,
arrangement_type: "V",
primary_client_group: "S",
has_other_client_group: 1,
secondary_client_group: "I",
support_type: 4,
intended_stay: "P",
created_at: Time.zone.local(2022, 4, 1))
end
let!(:scheme_where_managing_organisation_is_owning_organisation) { FactoryBot.create(:scheme, arrangement_type: "D") }
let(:support_user) { FactoryBot.create(:user, :support) }
let(:coordinator_user) { FactoryBot.create(:user, :data_coordinator) }
it "returns correct display attributes for a support user" do
attributes = [
{ name: "Scheme code", value: "S#{scheme.id}" },
{ name: "Name", value: "Test service_name", edit: true },
{ name: "Confidential information", value: "No", edit: true },
{ name: "Type of scheme", value: "Housing for older people" },
{ name: "Registered under Care Standards Act 2000", value: "Yes – registered care home providing personal care" },
{ name: "Housing stock owned by", value: "Acme LTD Owning", edit: true },
{ name: "Support services provided by", value: "A registered charity or voluntary organisation" },
{ name: "Organisation providing support", value: "Acme LTD Managing" },
{ name: "Primary client group", value: "Rough sleepers" },
{ name: "Has another client group", value: "Yes" },
{ name: "Secondary client group", value: "Refugees (permanent)" },
{ name: "Level of support given", value: "High level" },
{ name: "Intended length of stay", value: "Permanent" },
{ name: "Availability", value: "Active from 1 April 2022" },
{ name: "Status", value: status_tag(:active) },
]
expect(display_scheme_attributes(scheme, support_user)).to eq(attributes)
end
it "returns correct display attributes" do
it "returns correct display attributes for a coordinator user" do
attributes = [
{ name: "Scheme code", value: scheme.id_to_display },
{ name: "Name", value: scheme.service_name, edit: true },
{ name: "Confidential information", value: scheme.sensitive, edit: true },
{ name: "Type of scheme", value: scheme.scheme_type },
{ name: "Registered under Care Standards Act 2000", value: scheme.registered_under_care_act },
{ name: "Housing stock owned by", value: scheme.owning_organisation.name, edit: true },
{ name: "Support services provided by", value: scheme.arrangement_type },
{ name: "Primary client group", value: scheme.primary_client_group },
{ name: "Has another client group", value: scheme.has_other_client_group },
{ name: "Secondary client group", value: scheme.secondary_client_group },
{ name: "Level of support given", value: scheme.support_type },
{ name: "Intended length of stay", value: scheme.intended_stay },
{ name: "Scheme code", value: "S#{scheme.id}" },
{ name: "Name", value: "Test service_name", edit: true },
{ name: "Confidential information", value: "No", edit: true },
{ name: "Type of scheme", value: "Housing for older people" },
{ name: "Registered under Care Standards Act 2000", value: "Yes – registered care home providing personal care" },
{ name: "Support services provided by", value: "A registered charity or voluntary organisation" },
{ name: "Organisation providing support", value: "Acme LTD Managing" },
{ name: "Primary client group", value: "Rough sleepers" },
{ name: "Has another client group", value: "Yes" },
{ name: "Secondary client group", value: "Refugees (permanent)" },
{ name: "Level of support given", value: "High level" },
{ name: "Intended length of stay", value: "Permanent" },
{ name: "Availability", value: "Active from 1 April 2022" },
{ name: "Status", value: :active },
{ name: "Status", value: status_tag(:active) },
]
expect(display_scheme_attributes(scheme)).to eq(attributes)
expect(display_scheme_attributes(scheme, coordinator_user)).to eq(attributes)
end
context "when the scheme toggle is disabled" do
it "doesn't show the scheme status" do
allow(FeatureToggle).to receive(:scheme_toggle_enabled?).and_return(false)
attributes = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Status" }
expect(attributes).to be_nil
end
end
context "when the managing organisation is the owning organisation" do
it "doesn't show the organisation providing support" do
attributes = display_scheme_attributes(scheme_where_managing_organisation_is_owning_organisation, support_user).find { |x| x[:name] == "Organisation providing support" }
expect(attributes).to be_nil
end
end
context "when viewing availability" do
context "with no deactivations" do
it "displays created_at as availability date" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from #{scheme.created_at.to_formatted_s(:govuk_date)}")
end
it "displays current collection start date as availability date if created_at is later than collection start date" do
scheme.update!(created_at: Time.zone.local(2022, 4, 16))
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 1 April 2022")
end
@ -135,7 +192,7 @@ RSpec.describe SchemesHelper do
end
it "displays the timeline of availability" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 1 April 2022 to 9 August 2022\nDeactivated on 10 August 2022\nActive from 1 September 2022 to 14 September 2022\nDeactivated on 15 September 2022\nActive from 28 September 2022")
end
@ -149,7 +206,7 @@ RSpec.describe SchemesHelper do
end
it "displays the timeline of availability" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 1 April 2022 to 9 August 2022\nDeactivated on 10 August 2022\nActive from 1 September 2022 to 14 September 2022\nDeactivated on 15 September 2022")
end
@ -165,7 +222,7 @@ RSpec.describe SchemesHelper do
end
it "displays the timeline of availability" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 1 April 2022 to 14 June 2022\nDeactivated on 15 June 2022\nActive from 18 June 2022 to 23 September 2022\nDeactivated on 24 September 2022\nActive from 28 September 2022")
end
@ -179,7 +236,7 @@ RSpec.describe SchemesHelper do
end
it "displays the timeline of availability" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 1 April 2022 to 14 June 2022\nDeactivated on 15 June 2022\nActive from 28 September 2022")
end
@ -196,7 +253,7 @@ RSpec.describe SchemesHelper do
end
it "displays the timeline of availability" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 1 April 2022 to 14 June 2022\nDeactivated on 15 June 2022\nActive from 28 September 2022 to 23 October 2022\nDeactivated on 24 October 2022\nActive from 28 October 2022")
end
@ -211,7 +268,7 @@ RSpec.describe SchemesHelper do
end
it "displays the timeline of availability" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
availability_attribute = display_scheme_attributes(scheme, support_user).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 1 April 2022 to 9 October 2022\nDeactivated on 10 October 2022\nActive from 11 December 2022")
end

9
spec/helpers/tag_helper_spec.rb

@ -11,6 +11,15 @@ RSpec.describe TagHelper do
it "returns tag with correct status text and colour and custom class" do
expect(status_tag("not_started", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--grey app-tag--small\">Not started</strong>")
expect(status_tag("cannot_start_yet", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--grey app-tag--small\">Cannot start yet</strong>")
expect(status_tag("in_progress", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--blue app-tag--small\">In progress</strong>")
expect(status_tag("completed", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--green app-tag--small\">Completed</strong>")
expect(status_tag("active", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--green app-tag--small\">Active</strong>")
expect(status_tag("incomplete", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--red app-tag--small\">Incomplete</strong>")
expect(status_tag("deactivating_soon", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--yellow app-tag--small\">Deactivating soon</strong>")
expect(status_tag("activating_soon", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--blue app-tag--small\">Activating soon</strong>")
expect(status_tag("reactivating_soon", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--blue app-tag--small\">Reactivating soon</strong>")
expect(status_tag("deactivated", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--grey app-tag--small\">Deactivated</strong>")
end
end
end

3
spec/jobs/email_csv_job_spec.rb

@ -33,7 +33,8 @@ describe EmailCsvJob do
:completed,
owning_organisation: organisation,
managing_organisation: organisation,
created_by: user)
created_by: user,
startdate: Time.zone.local(2021, 5, 1))
allow(Storage::S3Service).to receive(:new).and_return(storage_service)
allow(storage_service).to receive(:write_file)

34
spec/models/form_spec.rb

@ -235,4 +235,38 @@ RSpec.describe Form, type: :model do
expect(form.sections[1].class).to eq(Form::Sales::Sections::PropertyInformation)
end
end
describe "#in_crossover_period?" do
context "when now not specified" do
context "when after end period" do
subject(:form) { described_class.new(nil, 2022, [], "sales") }
it "returns false" do
Timecop.freeze(2023, 8, 1) do
expect(form).not_to be_in_crossover_period
end
end
end
context "when during crossover" do
subject(:form) { described_class.new(nil, 2022, [], "sales") }
it "returns true" do
Timecop.freeze(2023, 6, 1) do
expect(form).to be_in_crossover_period
end
end
end
context "when before crossover" do
subject(:form) { described_class.new(nil, 2022, [], "sales") }
it "returns false" do
Timecop.freeze(2023, 1, 1) do
expect(form).not_to be_in_crossover_period
end
end
end
end
end
end

12
spec/models/forms/bulk_upload_lettings/year_spec.rb

@ -0,0 +1,12 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadLettings::Year do
subject(:form) { described_class.new }
describe "#options" do
it "returns correct years" do
expect(form.options.map(&:id)).to eql([2022, 2021])
expect(form.options.map(&:name)).to eql(%w[2022/2023 2021/2022])
end
end
end

12
spec/models/forms/bulk_upload_sales/year_spec.rb

@ -0,0 +1,12 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadSales::Year do
subject(:form) { described_class.new }
describe "#options" do
it "returns correct years" do
expect(form.options.map(&:id)).to eql([2022, 2021])
expect(form.options.map(&:name)).to eql(%w[2022/2023 2021/2022])
end
end
end

4
spec/models/lettings_log_spec.rb

@ -1672,7 +1672,7 @@ RSpec.describe LettingsLog do
let(:scheme) { FactoryBot.create(:scheme) }
let!(:location) { FactoryBot.create(:location, scheme:) }
before { lettings_log.update!(scheme:) }
before { lettings_log.update!(startdate: Time.zone.local(2022, 4, 2), scheme:) }
it "derives the scheme location" do
record_from_db = ActiveRecord::Base.connection.execute("select location_id from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -2375,7 +2375,7 @@ RSpec.describe LettingsLog do
describe "csv download" do
let(:scheme) { FactoryBot.create(:scheme) }
let(:location) { FactoryBot.create(:location, :export, scheme:, type_of_unit: 6, postcode: "SE11TE") }
let(:location) { FactoryBot.create(:location, :export, scheme:, type_of_unit: 6, postcode: "SE11TE", startdate: Time.zone.local(2021, 10, 1)) }
let(:user) { FactoryBot.create(:user, organisation: location.scheme.owning_organisation) }
let(:expected_content) { csv_export_file.read }

71
spec/models/location_spec.rb

@ -34,12 +34,18 @@ RSpec.describe Location, type: :model do
location.valid?(:postcode)
expect(location.errors.count).to eq(1)
end
it "does add an error when the postcode is missing" do
location.postcode = nil
expect { location.save! }
.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Postcode #{I18n.t('validations.postcode')}")
end
end
describe "#units" do
let(:location) { FactoryBot.build(:location) }
it "does add an error when units is nil" do
it "does add an error when the number of units is invalid" do
location.units = nil
location.valid?(:units)
expect(location.errors.count).to eq(1)
@ -49,13 +55,23 @@ RSpec.describe Location, type: :model do
describe "#type_of_unit" do
let(:location) { FactoryBot.build(:location) }
it "does add an error when the type_of_unit is nil" do
it "does add an error when the type of unit is invalid" do
location.type_of_unit = nil
location.valid?(:type_of_unit)
expect(location.errors.count).to eq(1)
end
end
describe "#mobility_type" do
let(:location) { FactoryBot.build(:location) }
it "does add an error when the mobility type is invalid" do
location.mobility_type = nil
expect { location.save! }
.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Mobility type #{I18n.t('activerecord.errors.models.location.attributes.mobility_type.blank')}")
end
end
describe "paper trail" do
let(:location) { FactoryBot.create(:location) }
let!(:name) { location.name }
@ -123,6 +139,13 @@ RSpec.describe Location, type: :model do
Timecop.unfreeze
end
context "when location is not confirmed" do
it "returns incomplete " do
location.confirmed = false
expect(location.status).to eq(:incomplete)
end
end
context "when there have not been any previous deactivations" do
it "returns active if the location has no deactivation records" do
expect(location.status).to eq(:active)
@ -208,4 +231,48 @@ RSpec.describe Location, type: :model do
end
end
end
describe "available_from" do
context "when there is a startdate" do
let(:location) { FactoryBot.build(:location, startdate: Time.zone.local(2022, 4, 6)) }
it "returns the startdate" do
expect(location.available_from).to eq(Time.zone.local(2022, 4, 6))
end
end
context "when there is no start date" do
context "and the location was created at the start of the 2022/23 collection window" do
let(:location) { FactoryBot.build(:location, created_at: Time.zone.local(2022, 4, 6), startdate: nil) }
it "returns the beginning of 22/23 collection window" do
expect(location.available_from).to eq(Time.zone.local(2022, 4, 1))
end
end
context "and the location was created at the end of the 2022/23 collection window" do
let(:location) { FactoryBot.build(:location, created_at: Time.zone.local(2023, 2, 6), startdate: nil) }
it "returns the beginning of 22/23 collection window" do
expect(location.available_from).to eq(Time.zone.local(2022, 4, 1))
end
end
context "and the location was created at the start of the 2021/22 collection window" do
let(:location) { FactoryBot.build(:location, created_at: Time.zone.local(2021, 4, 6), startdate: nil) }
it "returns the beginning of 21/22 collection window" do
expect(location.available_from).to eq(Time.zone.local(2021, 4, 1))
end
end
context "and the location was created at the end of the 2021/22 collection window" do
let(:location) { FactoryBot.build(:location, created_at: Time.zone.local(2022, 2, 6), startdate: nil) }
it "returns the beginning of 21/22 collection window" do
expect(location.available_from).to eq(Time.zone.local(2021, 4, 1))
end
end
end
end
end

34
spec/models/scheme_spec.rb

@ -190,4 +190,38 @@ RSpec.describe Scheme, type: :model do
expect(all_schemes[2].status).to eq(:incomplete)
end
end
describe "available_from" do
context "when the scheme was created at the start of the 2022/23 collection window" do
let(:scheme) { FactoryBot.build(:scheme, created_at: Time.zone.local(2022, 4, 6)) }
it "returns the beginning of 22/23 collection window" do
expect(scheme.available_from).to eq(Time.zone.local(2022, 4, 1))
end
end
context "when the scheme was created at the end of the 2022/23 collection window" do
let(:scheme) { FactoryBot.build(:scheme, created_at: Time.zone.local(2023, 2, 6)) }
it "returns the beginning of 22/23 collection window" do
expect(scheme.available_from).to eq(Time.zone.local(2022, 4, 1))
end
end
context "when the scheme was created at the start of the 2021/22 collection window" do
let(:scheme) { FactoryBot.build(:scheme, created_at: Time.zone.local(2021, 4, 6)) }
it "returns the beginning of 21/22 collection window" do
expect(scheme.available_from).to eq(Time.zone.local(2021, 4, 1))
end
end
context "when the scheme was created at the end of the 2021/22 collection window" do
let(:scheme) { FactoryBot.build(:scheme, created_at: Time.zone.local(2022, 2, 6)) }
it "returns the beginning of 21/22 collection window" do
expect(scheme.available_from).to eq(Time.zone.local(2021, 4, 1))
end
end
end
end

147
spec/models/validations/date_validations_spec.rb

@ -83,6 +83,153 @@ RSpec.describe Validations::DateValidations do
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to be_empty
end
context "with a deactivated location" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: nil) }
before do
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), location:)
location.reload
end
it "produces error when tenancy start date is during deactivated location period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
record.startdate = Time.zone.local(2022, 6, 1)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "with a location that is reactivating soon" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: nil) }
before do
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), location:)
location.reload
end
it "produces error when tenancy start date is during deactivated location period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022", deactivation_date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
record.startdate = Time.zone.local(2022, 9, 1)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "with a location that has many reactivations soon" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: nil) }
before do
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), location:)
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 2), reactivation_date: Time.zone.local(2022, 8, 3), location:)
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 1), reactivation_date: Time.zone.local(2022, 9, 4), location:)
location.reload
end
it "produces error when tenancy start date is during deactivated location period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 September 2022", deactivation_date: "1 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
record.startdate = Time.zone.local(2022, 10, 1)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "with a location with no deactivation periods" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: Time.zone.local(2022, 9, 15)) }
it "produces no error" do
record.startdate = Time.zone.local(2022, 10, 15)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to be_empty
end
it "produces an error when the date is before available_from date" do
record.startdate = Time.zone.local(2022, 8, 15)
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
end
end
context "with a scheme that is reactivating soon" do
let(:scheme) { create(:scheme) }
before do
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), scheme:)
scheme.reload
end
it "produces error when tenancy start date is during deactivated scheme period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.scheme = scheme
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 August 2022", deactivation_date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do
record.startdate = Time.zone.local(2022, 9, 1)
record.scheme = scheme
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "with a scheme that has many reactivations soon" do
let(:scheme) { create(:scheme) }
before do
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), scheme:)
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 2), reactivation_date: Time.zone.local(2022, 8, 3), scheme:)
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 1), reactivation_date: Time.zone.local(2022, 9, 4), scheme:)
scheme.reload
end
it "produces error when tenancy start date is during deactivated scheme period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.scheme = scheme
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 September 2022", deactivation_date: "1 June 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do
record.startdate = Time.zone.local(2022, 10, 1)
record.scheme = scheme
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to be_empty
end
end
end
describe "major repairs date" do

194
spec/models/validations/setup_validations_spec.rb

@ -30,4 +30,198 @@ RSpec.describe Validations::SetupValidations do
expect(record.errors["irproduct_other"]).to be_empty
end
end
describe "#validate_scheme" do
context "with a deactivated location" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: nil) }
before do
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), location:)
location.reload
end
it "produces error when tenancy start date is during deactivated location period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
record.startdate = Time.zone.local(2022, 6, 1)
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"]).to be_empty
end
end
context "with a location that is reactivating soon" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: nil) }
before do
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), location:)
location.reload
end
it "produces error when tenancy start date is during deactivated location period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022", deactivation_date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
record.startdate = Time.zone.local(2022, 9, 1)
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"]).to be_empty
end
end
context "with a location with no deactivation periods" do
let(:scheme) { create(:scheme, created_at: Time.zone.local(2022, 10, 3)) }
let(:location) { create(:location, scheme:, startdate: Time.zone.local(2022, 9, 15)) }
it "produces no error" do
record.startdate = Time.zone.local(2022, 10, 15)
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"]).to be_empty
end
it "produces an error when the date is before available_from date" do
record.startdate = Time.zone.local(2022, 8, 15)
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
end
end
context "with a scheme that is reactivating soon" do
let(:scheme) { create(:scheme, created_at: Time.zone.local(2022, 4, 1)) }
before do
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), scheme:)
scheme.reload
end
it "produces error when tenancy start date is during deactivated scheme period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.scheme = scheme
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 August 2022", deactivation_date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do
record.startdate = Time.zone.local(2022, 9, 1)
record.scheme = scheme
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"]).to be_empty
end
end
context "with a scheme that has many reactivations soon" do
let(:scheme) { create(:scheme, created_at: Time.zone.local(2022, 4, 1)) }
before do
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), scheme:)
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 2), reactivation_date: Time.zone.local(2022, 8, 3), scheme:)
create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 1), reactivation_date: Time.zone.local(2022, 9, 4), scheme:)
scheme.reload
end
it "produces error when tenancy start date is during deactivated scheme period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.scheme = scheme
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 September 2022", deactivation_date: "1 June 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do
record.startdate = Time.zone.local(2022, 10, 1)
record.scheme = scheme
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"]).to be_empty
end
end
end
describe "#validate_location" do
context "with a deactivated location" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: nil) }
before do
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), location:)
location.reload
end
it "produces error when tenancy start date is during deactivated location period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"])
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
record.startdate = Time.zone.local(2022, 6, 1)
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"]).to be_empty
end
end
context "with a location that is reactivating soon" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: nil) }
before do
create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 8, 4), location:)
location.reload
end
it "produces error when tenancy start date is during deactivated location period" do
record.startdate = Time.zone.local(2022, 7, 5)
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022", deactivation_date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
record.startdate = Time.zone.local(2022, 9, 1)
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"]).to be_empty
end
end
context "with a location with no deactivation periods" do
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, startdate: Time.zone.local(2022, 9, 15)) }
it "produces no error" do
record.startdate = Time.zone.local(2022, 10, 15)
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"]).to be_empty
end
it "produces an error when the date is before available_from date" do
record.startdate = Time.zone.local(2022, 8, 15)
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"])
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
end
end
end
end

1
spec/rails_helper.rb

@ -82,6 +82,7 @@ RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
config.include Devise::Test::IntegrationHelpers, type: :request
config.include Devise::Test::IntegrationHelpers, type: :feature
config.include ViewComponent::TestHelpers, type: :component
config.include Capybara::RSpecMatchers, type: :component
config.include ActiveJob::TestHelper

34
spec/requests/bulk_upload_lettings_logs_controller_spec.rb

@ -0,0 +1,34 @@
require "rails_helper"
RSpec.describe BulkUploadLettingsLogsController, type: :request do
let(:user) { FactoryBot.create(:user) }
let(:organisation) { user.organisation }
before do
sign_in user
end
describe "GET /lettings-logs/bulk-upload-logs/start" do
context "when not in crossover period" do
let(:expected_year) { FormHandler.instance.forms["current_lettings"].start_date.year }
it "redirects to /prepare-your-file" do
Timecop.freeze(2022, 1, 1) do
get "/lettings-logs/bulk-upload-logs/start", params: {}
expect(response).to redirect_to("/lettings-logs/bulk-upload-logs/prepare-your-file?form%5Byear%5D=#{expected_year}")
end
end
end
context "when in crossover period" do
it "redirects to /year" do
Timecop.freeze(2023, 6, 1) do
get "/lettings-logs/bulk-upload-logs/start", params: {}
expect(response).to redirect_to("/lettings-logs/bulk-upload-logs/year")
end
end
end
end
end

34
spec/requests/bulk_upload_sales_logs_controller_spec.rb

@ -0,0 +1,34 @@
require "rails_helper"
RSpec.describe BulkUploadSalesLogsController, type: :request do
let(:user) { FactoryBot.create(:user) }
let(:organisation) { user.organisation }
before do
sign_in user
end
describe "GET /sales-logs/bulk-upload-logs/start" do
context "when not in crossover period" do
let(:expected_year) { FormHandler.instance.forms["current_sales"].start_date.year }
it "redirects to /prepare-your-file" do
Timecop.freeze(2022, 1, 1) do
get "/sales-logs/bulk-upload-logs/start", params: {}
expect(response).to redirect_to("/sales-logs/bulk-upload-logs/prepare-your-file?form%5Byear%5D=#{expected_year}")
end
end
end
context "when in crossover period" do
it "redirects to /year" do
Timecop.freeze(2023, 6, 1) do
get "/sales-logs/bulk-upload-logs/start", params: {}
expect(response).to redirect_to("/sales-logs/bulk-upload-logs/year")
end
end
end
end
end

1
spec/requests/form_controller_spec.rb

@ -28,6 +28,7 @@ RSpec.describe FormController, type: :request do
:completed,
owning_organisation: organisation,
managing_organisation: organisation,
startdate: Time.zone.local(2021, 5, 1),
)
end
let(:headers) { { "Accept" => "text/html" } }

34
spec/requests/locations_controller_spec.rb

@ -125,7 +125,7 @@ RSpec.describe LocationsController, type: :request do
context "when signed in as a data coordinator user" do
let(:user) { FactoryBot.create(:user, :data_coordinator) }
let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) }
let!(:locations) { FactoryBot.create_list(:location, 3, scheme:) }
let!(:locations) { FactoryBot.create_list(:location, 3, scheme:, startdate: Time.zone.local(2022, 4, 1)) }
before do
sign_in user
@ -136,7 +136,7 @@ RSpec.describe LocationsController, type: :request do
let!(:another_scheme) { FactoryBot.create(:scheme) }
before do
FactoryBot.create(:location, scheme:)
FactoryBot.create(:location, scheme:, startdate: Time.zone.local(2022, 4, 1))
end
it "returns 404 not found" do
@ -145,7 +145,18 @@ RSpec.describe LocationsController, type: :request do
end
end
it "shows scheme" do
it "shows locations with correct data wben the new locations layout feature toggle is enabled" do
locations.each do |location|
expect(page).to have_content(location.id)
expect(page).to have_content(location.postcode)
expect(page).to have_content(location.name)
expect(page).to have_content(location.status)
end
end
it "shows locations with correct data wben the new locations layout feature toggle is disabled" do
allow(FeatureToggle).to receive(:location_toggle_enabled?).and_return(false)
get "/schemes/#{scheme.id}/locations"
locations.each do |location|
expect(page).to have_content(location.id)
expect(page).to have_content(location.postcode)
@ -242,7 +253,7 @@ RSpec.describe LocationsController, type: :request do
context "when signed in as a support user" do
let(:user) { FactoryBot.create(:user, :support) }
let!(:scheme) { FactoryBot.create(:scheme) }
let!(:locations) { FactoryBot.create_list(:location, 3, scheme:) }
let!(:locations) { FactoryBot.create_list(:location, 3, scheme:, startdate: Time.zone.local(2022, 4, 1)) }
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
@ -250,11 +261,24 @@ RSpec.describe LocationsController, type: :request do
get "/schemes/#{scheme.id}/locations"
end
it "shows scheme" do
it "shows locations with correct data wben the new locations layout feature toggle is enabled" do
locations.each do |location|
expect(page).to have_content(location.id)
expect(page).to have_content(location.postcode)
expect(page).to have_content(location.name)
expect(page).to have_content(location.status)
end
end
it "shows locations with correct data wben the new locations layout feature toggle is disabled" do
allow(FeatureToggle).to receive(:location_toggle_enabled?).and_return(false)
get "/schemes/#{scheme.id}/locations"
locations.each do |location|
expect(page).to have_content(location.id)
expect(page).to have_content(location.postcode)
expect(page).to have_content(location.type_of_unit)
expect(page).to have_content(location.mobility_type)
expect(page).to have_content(location.location_admin_district)
expect(page).to have_content(location.startdate&.to_formatted_s(:govuk_date))
end
end

2
spec/requests/schemes_controller_spec.rb

@ -1767,7 +1767,7 @@ RSpec.describe SchemesController, type: :request do
context "when signed in as a data coordinator" do
let(:user) { FactoryBot.create(:user, :data_coordinator) }
let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) }
let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation, created_at: Time.zone.today) }
let!(:location) { FactoryBot.create(:location, scheme:) }
let(:deactivation_date) { Time.utc(2022, 10, 10) }
let!(:lettings_log) { FactoryBot.create(:lettings_log, :sh, location:, scheme:, startdate:, owning_organisation: user.organisation) }

8
spec/services/exports/lettings_log_export_service_spec.rb

@ -59,7 +59,7 @@ RSpec.describe Exports::LettingsLogExportService do
end
context "and one lettings log is available for export" do
let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737") }
let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737", startdate: Time.utc(2022, 2, 2, 10, 36, 49), tenancylength: 5) }
it "generates a ZIP export file with the expected filename" do
expect(storage_service).to receive(:write_file).with(expected_zip_filename, any_args)
@ -237,7 +237,7 @@ RSpec.describe Exports::LettingsLogExportService do
let(:csv_export_file) { File.open("spec/fixtures/exports/general_needs_log.csv", "r:UTF-8") }
let(:expected_csv_filename) { "export_2022_05_01.csv" }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737") }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737", startdate: Time.utc(2022, 2, 2, 10, 36, 49), tenancylength: 5) }
it "generates an CSV export file with the expected content" do
expected_content = replace_entity_ids(lettings_log, csv_export_file.read)
@ -254,9 +254,9 @@ RSpec.describe Exports::LettingsLogExportService do
let(:organisation) { FactoryBot.create(:organisation, provider_type: "LA") }
let(:user) { FactoryBot.create(:user, organisation:) }
let(:scheme) { FactoryBot.create(:scheme, :export, owning_organisation: organisation) }
let(:location) { FactoryBot.create(:location, :export, scheme:) }
let(:location) { FactoryBot.create(:location, :export, scheme:, startdate: Time.zone.local(2021, 4, 1)) }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, :export, :sh, scheme:, location:, created_by: user, owning_organisation: organisation) }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, :export, :sh, scheme:, location:, created_by: user, owning_organisation: organisation, startdate: Time.utc(2022, 2, 2, 10, 36, 49)) }
it "generates an XML export file with the expected content" do
expected_content = replace_entity_ids(lettings_log, export_file.read)

6
spec/services/imports/lettings_logs_import_service_spec.rb

@ -30,9 +30,9 @@ RSpec.describe Imports::LettingsLogsImportService do
FactoryBot.create(:user, old_user_id: "e29c492473446dca4d50224f2bb7cf965a261d6f", organisation:)
# Location setup
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme1.id, mobility_type: "W")
FactoryBot.create(:location, scheme_id: scheme1.id)
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme2.id, mobility_type: "W")
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme1.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, scheme_id: scheme1.id, startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme2.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
# Stub the form handler to use the real form
allow(FormHandler.instance).to receive(:get_form).with("previous_lettings").and_return(real_2021_2022_form)

Loading…
Cancel
Save