Browse Source

CLDC-2478 Allow deleting locations (#2285)

* Add delete confirmation page

* Allow deleting location

* Add delete location button and update policy

* Add delete button to CYA

* Update location policy

* Do not display deleted locationa as an option

* Move delete button into the button group

* Add informative text for locations that have logs

* Refactor query

* CLDC-2478 Allow deleting scheme (#2286)

* Add delete confirmation page

* Allow deleting scheme

* Add delete scheme button and update policy

* Add delete button to CYA

* Update scheme policy

* Do not display deleted schemes as an option

* Add informative text for schemesrbe that have logs

* Refactor query

* Update tests

* Add feature toggle
CLDC-3229-review-app-for-bu-testing
kosiakkatrina 9 months ago committed by GitHub
parent
commit
5bbf0148b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 9
      app/controllers/locations_controller.rb
  2. 2
      app/controllers/organisations_controller.rb
  3. 11
      app/controllers/schemes_controller.rb
  4. 4
      app/helpers/locations_helper.rb
  5. 4
      app/helpers/schemes_helper.rb
  6. 4
      app/models/form/lettings/questions/location_id.rb
  7. 10
      app/models/form/lettings/questions/scheme_id.rb
  8. 7
      app/models/location.rb
  9. 10
      app/models/scheme.rb
  10. 17
      app/policies/location_policy.rb
  11. 17
      app/policies/scheme_policy.rb
  12. 8
      app/services/feature_toggle.rb
  13. 3
      app/views/locations/check_answers.html.erb
  14. 24
      app/views/locations/delete_confirmation.html.erb
  15. 11
      app/views/locations/show.html.erb
  16. 4
      app/views/schemes/check_answers.html.erb
  17. 24
      app/views/schemes/delete_confirmation.html.erb
  18. 7
      app/views/schemes/show.html.erb
  19. 2
      config/locales/en.yml
  20. 4
      config/routes.rb
  21. 5
      db/migrate/20240301125651_add_discarded_at_column.rb
  22. 5
      db/migrate/20240304100017_add_discarded_at_column_to_schemes.rb
  23. 2
      db/schema.rb
  24. 12
      spec/models/form/lettings/questions/location_id_spec.rb
  25. 13
      spec/models/form/lettings/questions/scheme_id_spec.rb
  26. 8
      spec/models/scheme_spec.rb
  27. 92
      spec/policies/location_policy_spec.rb
  28. 94
      spec/policies/scheme_policy_spec.rb
  29. 270
      spec/requests/locations_controller_spec.rb
  30. 5
      spec/requests/organisations_controller_spec.rb
  31. 286
      spec/requests/schemes_controller_spec.rb
  32. 2
      spec/views/locations/show.html.erb_spec.rb

9
app/controllers/locations_controller.rb

@ -14,8 +14,8 @@ class LocationsController < ApplicationController
def index def index
authorize @scheme authorize @scheme
@pagy, @locations = pagy(filter_manager.filtered_locations(@scheme.locations, search_term, session_filters)) @pagy, @locations = pagy(filter_manager.filtered_locations(@scheme.locations.visible, search_term, session_filters))
@total_count = @scheme.locations.size @total_count = @scheme.locations.visible.size
@searched = search_term.presence @searched = search_term.presence
@filter_type = "scheme_locations" @filter_type = "scheme_locations"
end end
@ -230,6 +230,11 @@ class LocationsController < ApplicationController
end end
end end
def delete
@location.discard!
redirect_to scheme_locations_path(@scheme), notice: I18n.t("notification.location_deleted", postcode: @location.postcode)
end
private private
def authorize_user def authorize_user

2
app/controllers/organisations_controller.rb

@ -21,7 +21,7 @@ class OrganisationsController < ApplicationController
end end
def schemes def schemes
organisation_schemes = Scheme.where(owning_organisation: [@organisation] + @organisation.parent_organisations) organisation_schemes = Scheme.visible.where(owning_organisation: [@organisation] + @organisation.parent_organisations)
@pagy, @schemes = pagy(filter_manager.filtered_schemes(organisation_schemes, search_term, session_filters)) @pagy, @schemes = pagy(filter_manager.filtered_schemes(organisation_schemes, search_term, session_filters))
@searched = search_term.presence @searched = search_term.presence

11
app/controllers/schemes_controller.rb

@ -13,11 +13,11 @@ class SchemesController < ApplicationController
def index def index
redirect_to schemes_organisation_path(current_user.organisation) unless current_user.support? redirect_to schemes_organisation_path(current_user.organisation) unless current_user.support?
all_schemes = Scheme.all all_visible_schemes = Scheme.visible
@pagy, @schemes = pagy(filter_manager.filtered_schemes(all_schemes, search_term, session_filters)) @pagy, @schemes = pagy(filter_manager.filtered_schemes(all_visible_schemes, search_term, session_filters))
@searched = search_term.presence @searched = search_term.presence
@total_count = all_schemes.size @total_count = all_visible_schemes.size
@filter_type = "schemes" @filter_type = "schemes"
end end
@ -223,6 +223,11 @@ class SchemesController < ApplicationController
def csv_confirmation; end def csv_confirmation; end
def delete
@scheme.discard!
redirect_to schemes_organisation_path(@scheme.owning_organisation), notice: I18n.t("notification.scheme_deleted", service_name: @scheme.service_name)
end
private private
def authorize_user def authorize_user

4
app/helpers/locations_helper.rb

@ -73,6 +73,10 @@ module LocationsHelper
return govuk_button_link_to "Reactivate this location", scheme_location_new_reactivation_path(location.scheme, location) if location.deactivated? return govuk_button_link_to "Reactivate this location", scheme_location_new_reactivation_path(location.scheme, location) if location.deactivated?
end end
def delete_location_link(location)
govuk_button_link_to "Delete this location", scheme_location_delete_confirmation_path(location.scheme, location), warning: true
end
def location_creation_success_notice(location) def location_creation_success_notice(location)
if location.confirmed if location.confirmed
"#{location.postcode} #{location.startdate.blank? || location.startdate.before?(Time.zone.now) ? 'has been' : 'will be'} added to this scheme" "#{location.postcode} #{location.startdate.blank? || location.startdate.before?(Time.zone.now) ? 'has been' : 'will be'} added to this scheme"

4
app/helpers/schemes_helper.rb

@ -15,6 +15,10 @@ module SchemesHelper
return govuk_button_link_to "Reactivate this scheme", scheme_new_reactivation_path(scheme) if scheme.deactivated? return govuk_button_link_to "Reactivate this scheme", scheme_new_reactivation_path(scheme) if scheme.deactivated?
end end
def delete_scheme_link(scheme)
govuk_button_link_to "Delete this scheme", scheme_delete_confirmation_path(scheme), warning: true
end
def owning_organisation_options(current_user) def owning_organisation_options(current_user)
all_orgs = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } all_orgs = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) }
user_org = [OpenStruct.new(id: current_user.organisation_id, name: current_user.organisation.name)] user_org = [OpenStruct.new(id: current_user.organisation_id, name: current_user.organisation.name)]

4
app/models/form/lettings/questions/location_id.rb

@ -20,7 +20,7 @@ class Form::Lettings::Questions::LocationId < ::Form::Question
answer_opts = {} answer_opts = {}
return answer_opts unless ActiveRecord::Base.connected? return answer_opts unless ActiveRecord::Base.connected?
Location.started_in_2_weeks.select(:id, :postcode, :name).each_with_object(answer_opts) do |location, hsh| Location.visible.started_in_2_weeks.select(:id, :postcode, :name).each_with_object(answer_opts) do |location, hsh|
hsh[location.id.to_s] = { "value" => location.postcode, "hint" => location.name } hsh[location.id.to_s] = { "value" => location.postcode, "hint" => location.name }
hsh hsh
end end
@ -29,7 +29,7 @@ class Form::Lettings::Questions::LocationId < ::Form::Question
def displayed_answer_options(lettings_log, _user = nil) def displayed_answer_options(lettings_log, _user = nil)
return {} unless lettings_log.scheme return {} unless lettings_log.scheme
scheme_location_ids = lettings_log.scheme.locations.confirmed.pluck(:id) scheme_location_ids = lettings_log.scheme.locations.visible.confirmed.pluck(:id)
answer_options.select { |k, _v| scheme_location_ids.include?(k.to_i) } answer_options.select { |k, _v| scheme_location_ids.include?(k.to_i) }
end end

10
app/models/form/lettings/questions/scheme_id.rb

@ -19,8 +19,8 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question
answer_opts = { "" => "Select an option" } answer_opts = { "" => "Select an option" }
return answer_opts unless ActiveRecord::Base.connected? return answer_opts unless ActiveRecord::Base.connected?
Scheme.select(:id, :service_name, :primary_client_group, Scheme.visible.select(:id, :service_name, :primary_client_group,
:secondary_client_group).each_with_object(answer_opts) do |scheme, hsh| :secondary_client_group).each_with_object(answer_opts) do |scheme, hsh|
hsh[scheme.id.to_s] = scheme hsh[scheme.id.to_s] = scheme
hsh hsh
end end
@ -29,10 +29,10 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question
def displayed_answer_options(lettings_log, _user = nil) def displayed_answer_options(lettings_log, _user = nil)
organisation = lettings_log.owning_organisation || lettings_log.created_by&.organisation organisation = lettings_log.owning_organisation || lettings_log.created_by&.organisation
schemes = if organisation schemes = if organisation
Scheme.includes(:locations).select(:id).where(owning_organisation_id: organisation.id, Scheme.visible.includes(:locations).select(:id).where(owning_organisation_id: organisation.id,
confirmed: true) confirmed: true)
else else
Scheme.includes(:locations).select(:id).where(confirmed: true) Scheme.visible.includes(:locations).select(:id).where(confirmed: true)
end end
filtered_scheme_ids = schemes.joins(:locations).merge(Location.started_in_2_weeks).map(&:id) filtered_scheme_ids = schemes.joins(:locations).merge(Location.started_in_2_weeks).map(&:id)
answer_options.select do |k, _v| answer_options.select do |k, _v|

7
app/models/location.rb

@ -79,6 +79,8 @@ class Location < ApplicationRecord
.where.not(id: activating_soon.pluck(:id)) .where.not(id: activating_soon.pluck(:id))
} }
scope :visible, -> { where(discarded_at: nil) }
LOCAL_AUTHORITIES = LocalAuthority.all.map { |la| [la.name, la.code] }.to_h LOCAL_AUTHORITIES = LocalAuthority.all.map { |la| [la.name, la.code] }.to_h
enum local_authorities: LOCAL_AUTHORITIES enum local_authorities: LOCAL_AUTHORITIES
@ -138,6 +140,7 @@ class Location < ApplicationRecord
end end
def status_at(date) def status_at(date)
return :deleted if discarded_at.present?
return :incomplete unless confirmed return :incomplete unless confirmed
return :deactivated if open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date 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 :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
@ -190,6 +193,10 @@ class Location < ApplicationRecord
LocalAuthority.where(id: [la.id] + la.linked_local_authority_ids) LocalAuthority.where(id: [la.id] + la.linked_local_authority_ids)
end end
def discard!
update!(discarded_at: Time.zone.now)
end
private private
PIO = PostcodeService.new PIO = PostcodeService.new

10
app/models/scheme.rb

@ -77,6 +77,8 @@ class Scheme < ApplicationRecord
.where.not(id: activating_soon.pluck(:id)) .where.not(id: activating_soon.pluck(:id))
} }
scope :visible, -> { where(discarded_at: nil) }
validate :validate_confirmed validate :validate_confirmed
validate :validate_owning_organisation validate :validate_owning_organisation
@ -229,7 +231,7 @@ class Scheme < ApplicationRecord
end end
def validate_confirmed def validate_confirmed
required_attributes = attribute_names - %w[id created_at updated_at old_id old_visible_id confirmed end_date sensitive secondary_client_group total_units deactivation_date deactivation_date_type startdate] required_attributes = attribute_names - %w[id created_at updated_at old_id old_visible_id confirmed end_date sensitive secondary_client_group total_units deactivation_date deactivation_date_type startdate discarded_at]
if confirmed == true if confirmed == true
required_attributes.any? do |attribute| required_attributes.any? do |attribute|
@ -264,6 +266,7 @@ class Scheme < ApplicationRecord
end end
def status_at(date) def status_at(date)
return :deleted if discarded_at.present?
return :incomplete unless confirmed && locations.confirmed.any? return :incomplete unless confirmed && locations.confirmed.any?
return :deactivated if open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date 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 :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
@ -288,4 +291,9 @@ class Scheme < ApplicationRecord
def deactivates_in_a_long_time? def deactivates_in_a_long_time?
status_at(6.months.from_now) == :deactivating_soon status_at(6.months.from_now) == :deactivating_soon
end end
def discard!
update!(discarded_at: Time.zone.now)
locations.each(&:discard!)
end
end end

17
app/policies/location_policy.rb

@ -26,6 +26,17 @@ class LocationPolicy
user.data_coordinator? && scheme_owned_by_user_org_or_stock_owner user.data_coordinator? && scheme_owned_by_user_org_or_stock_owner
end end
def delete_confirmation?
delete?
end
def delete?
return false unless user.support?
return false unless location.status == :incomplete || location.status == :deactivated
!has_any_logs_in_editable_collection_period
end
%w[ %w[
update_postcode? update_postcode?
update_local_authority? update_local_authority?
@ -75,4 +86,10 @@ private
def scheme_owned_by_user_org_or_stock_owner def scheme_owned_by_user_org_or_stock_owner
scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id) scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id)
end end
def has_any_logs_in_editable_collection_period
editable_from_date = FormHandler.instance.earliest_open_for_editing_collection_start_date
LettingsLog.where(location_id: location.id).after_date(editable_from_date).or(LettingsLog.where(startdate: nil, location_id: location.id)).any?
end
end end

17
app/policies/scheme_policy.rb

@ -65,9 +65,26 @@ class SchemePolicy
end end
end end
def delete_confirmation?
delete?
end
def delete?
return false unless user.support?
return false unless scheme.status == :incomplete || scheme.status == :deactivated
!has_any_logs_in_editable_collection_period
end
private private
def scheme_owned_by_user_org_or_stock_owner def scheme_owned_by_user_org_or_stock_owner
scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id) scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id)
end end
def has_any_logs_in_editable_collection_period
editable_from_date = FormHandler.instance.earliest_open_for_editing_collection_start_date
LettingsLog.where(scheme_id: scheme.id).after_date(editable_from_date).or(LettingsLog.where(startdate: nil, scheme_id: scheme.id)).any?
end
end end

8
app/services/feature_toggle.rb

@ -26,4 +26,12 @@ class FeatureToggle
def self.service_moved? def self.service_moved?
false false
end end
def self.delete_scheme_enabled?
!Rails.env.production?
end
def self.delete_location_enabled?
!Rails.env.production?
end
end end

3
app/views/locations/check_answers.html.erb

@ -42,6 +42,9 @@
<% if LocationPolicy.new(current_user, @location).create? %> <% if LocationPolicy.new(current_user, @location).create? %>
<div class="govuk-button-group"> <div class="govuk-button-group">
<%= govuk_button_to "Save and return to locations", scheme_location_confirm_path(@scheme, @location, route: params[:route]), method: :patch %> <%= govuk_button_to "Save and return to locations", scheme_location_confirm_path(@scheme, @location, route: params[:route]), method: :patch %>
<% if LocationPolicy.new(current_user, @location).delete? && FeatureToggle.delete_location_enabled? %>
<%= delete_location_link(@location) %>
<% end %>
<%= govuk_button_link_to "Cancel", scheme_locations_path(@scheme), secondary: true %> <%= govuk_button_link_to "Cancel", scheme_locations_path(@scheme), secondary: true %>
</div> </div>
<% end %> <% end %>

24
app/views/locations/delete_confirmation.html.erb

@ -0,0 +1,24 @@
<% content_for :before_content do %>
<% content_for :title, "Are you sure you want to delete this location?" %>
<%= govuk_back_link(href: :back) %>
<% end %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<span class="govuk-caption-xl">Delete <%= @location.postcode %></span>
<h1 class="govuk-heading-xl">
<%= content_for(:title) %>
</h1>
<%= govuk_warning_text(text: "You will not be able to undo this action.") %>
<div class="govuk-button-group">
<%= govuk_button_to(
"Delete this location",
scheme_location_delete_path(@scheme, @location),
method: :delete,
) %>
<%= govuk_button_link_to "Cancel", scheme_location_path(@scheme, @location), html: { method: :get }, secondary: true %>
</div>
</div>
</div>

11
app/views/locations/show.html.erb

@ -19,7 +19,12 @@
<%= summary_list.with_row do |row| %> <%= summary_list.with_row do |row| %>
<% row.with_key { attr[:name] } %> <% row.with_key { attr[:name] } %>
<% if attr[:attribute].eql?("status") %> <% if attr[:attribute].eql?("status") %>
<%= row.with_value { status_tag_from_resource(@location) } %> <%= row.with_value do %>
<%= details_html({ name: "Status", value: status_tag_from_resource(@location), id: "status" }) %>
<% if @location.deactivated? && current_user.support? && !LocationPolicy.new(current_user, @location).delete? %>
<span class="app-!-colour-muted">This location was active in an open or editable collection year, and cannot be deleted.</span>
<% end %>
<% end %>
<% elsif attr[:attribute].eql?("postcode") && @location.is_la_inferred %> <% elsif attr[:attribute].eql?("postcode") && @location.is_la_inferred %>
<% row.with_value do %> <% row.with_value do %>
<%= details_html(attr) %> <%= details_html(attr) %>
@ -45,3 +50,7 @@
<% if LocationPolicy.new(current_user, @location).deactivate? %> <% if LocationPolicy.new(current_user, @location).deactivate? %>
<%= toggle_location_link(@location) %> <%= toggle_location_link(@location) %>
<% end %> <% end %>
<% if LocationPolicy.new(current_user, @location).delete? && FeatureToggle.delete_location_enabled? %>
<%= delete_location_link(@location) %>
<% end %>

4
app/views/schemes/check_answers.html.erb

@ -23,4 +23,8 @@
<% if SchemePolicy.new(current_user, @scheme).create? %> <% if SchemePolicy.new(current_user, @scheme).create? %>
<%= f.govuk_submit button_label %> <%= f.govuk_submit button_label %>
<% end %> <% end %>
<% if SchemePolicy.new(current_user, @scheme).delete? && FeatureToggle.delete_scheme_enabled? %>
<%= delete_scheme_link(@scheme) %>
<% end %>
<% end %> <% end %>

24
app/views/schemes/delete_confirmation.html.erb

@ -0,0 +1,24 @@
<% content_for :before_content do %>
<% content_for :title, "Are you sure you want to delete this scheme?" %>
<%= govuk_back_link(href: :back) %>
<% end %>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<span class="govuk-caption-xl">Delete <%= @scheme.service_name %></span>
<h1 class="govuk-heading-xl">
<%= content_for(:title) %>
</h1>
<%= govuk_warning_text(text: "You will not be able to undo this action.") %>
<div class="govuk-button-group">
<%= govuk_button_to(
"Delete this scheme",
scheme_delete_path(@scheme),
method: :delete,
) %>
<%= govuk_button_link_to "Cancel", scheme_path(@scheme), html: { method: :get }, secondary: true %>
</div>
</div>
</div>

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

@ -29,6 +29,9 @@
<% if @scheme.confirmed? && @scheme.locations.confirmed.none? && LocationPolicy.new(current_user, @scheme.locations.new).create? %> <% if @scheme.confirmed? && @scheme.locations.confirmed.none? && LocationPolicy.new(current_user, @scheme.locations.new).create? %>
<span class="app-!-colour-muted">Complete this scheme by adding a location using the <%= govuk_link_to("‘locations’ tab", scheme_locations_path(@scheme)) %>.</span> <span class="app-!-colour-muted">Complete this scheme by adding a location using the <%= govuk_link_to("‘locations’ tab", scheme_locations_path(@scheme)) %>.</span>
<% end %> <% end %>
<% if @scheme.deactivated? && current_user.support? && !SchemePolicy.new(current_user, @scheme).delete? %>
<span class="app-!-colour-muted">This scheme was active in an open or editable collection year, and cannot be deleted.</span>
<% end %>
</dd> </dd>
</div> </div>
<% elsif attr[:id] != "secondary_client_group" || @scheme.has_other_client_group == "Yes" %> <% elsif attr[:id] != "secondary_client_group" || @scheme.has_other_client_group == "Yes" %>
@ -49,3 +52,7 @@
<% if SchemePolicy.new(current_user, @scheme).deactivate? %> <% if SchemePolicy.new(current_user, @scheme).deactivate? %>
<%= toggle_scheme_link(@scheme) %> <%= toggle_scheme_link(@scheme) %>
<% end %> <% end %>
<% if SchemePolicy.new(current_user, @scheme).delete? && FeatureToggle.delete_scheme_enabled? %>
<%= delete_scheme_link(@scheme) %>
<% end %>

2
config/locales/en.yml

@ -196,6 +196,8 @@ en:
duplicate_sets: duplicate_sets:
one: "There is %{count} set of duplicate logs" one: "There is %{count} set of duplicate logs"
other: "There are %{count} sets of duplicate logs" other: "There are %{count} sets of duplicate logs"
location_deleted: "%{postcode} has been deleted."
scheme_deleted: "%{service_name} has been deleted."
validations: validations:
organisation: organisation:

4
config/routes.rb

@ -79,6 +79,8 @@ Rails.application.routes.draw do
patch "new-deactivation", to: "schemes#new_deactivation" patch "new-deactivation", to: "schemes#new_deactivation"
patch "deactivate", to: "schemes#deactivate" patch "deactivate", to: "schemes#deactivate"
patch "reactivate", to: "schemes#reactivate" patch "reactivate", to: "schemes#reactivate"
get "delete-confirmation", to: "schemes#delete_confirmation"
delete "delete", to: "schemes#delete"
collection do collection do
get "csv-download", to: "schemes#download_csv" get "csv-download", to: "schemes#download_csv"
@ -111,6 +113,8 @@ Rails.application.routes.draw do
patch "new-deactivation", to: "locations#new_deactivation" patch "new-deactivation", to: "locations#new_deactivation"
patch "deactivate", to: "locations#deactivate" patch "deactivate", to: "locations#deactivate"
patch "reactivate", to: "locations#reactivate" patch "reactivate", to: "locations#reactivate"
get "delete-confirmation", to: "locations#delete_confirmation"
delete "delete", to: "locations#delete"
end end
end end
get "scheme-changes", to: "schemes#changes" get "scheme-changes", to: "schemes#changes"

5
db/migrate/20240301125651_add_discarded_at_column.rb

@ -0,0 +1,5 @@
class AddDiscardedAtColumn < ActiveRecord::Migration[7.0]
def change
add_column :locations, :discarded_at, :datetime
end
end

5
db/migrate/20240304100017_add_discarded_at_column_to_schemes.rb

@ -0,0 +1,5 @@
class AddDiscardedAtColumnToSchemes < ActiveRecord::Migration[7.0]
def change
add_column :schemes, :discarded_at, :datetime
end
end

2
db/schema.rb

@ -374,6 +374,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do
t.string "location_admin_district" t.string "location_admin_district"
t.boolean "confirmed" t.boolean "confirmed"
t.boolean "is_la_inferred" t.boolean "is_la_inferred"
t.datetime "discarded_at"
t.index ["old_id"], name: "index_locations_on_old_id", unique: true t.index ["old_id"], name: "index_locations_on_old_id", unique: true
t.index ["scheme_id"], name: "index_locations_on_scheme_id" t.index ["scheme_id"], name: "index_locations_on_scheme_id"
end end
@ -722,6 +723,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do
t.integer "total_units" t.integer "total_units"
t.boolean "confirmed" t.boolean "confirmed"
t.datetime "startdate" t.datetime "startdate"
t.datetime "discarded_at"
t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id" t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id"
end end

12
spec/models/form/lettings/questions/location_id_spec.rb

@ -80,6 +80,18 @@ RSpec.describe Form::Lettings::Questions::LocationId, type: :model do
end end
end end
context "and all the locations are deleted" do
before do
FactoryBot.create(:location, scheme:, discarded_at: Time.utc(2022, 5, 12))
FactoryBot.create(:location, scheme:, discarded_at: Time.utc(2022, 5, 12))
lettings_log.update!(scheme:)
end
it "the displayed_answer_options is an empty hash" do
expect(question.displayed_answer_options(lettings_log)).to eq({})
end
end
context "and all but one of the locations have a startdate more than 2 weeks in the future" do context "and all but one of the locations have a startdate more than 2 weeks in the future" do
before do before do
FactoryBot.create(:location, scheme:, startdate: Time.utc(2022, 5, 13)) FactoryBot.create(:location, scheme:, startdate: Time.utc(2022, 5, 13))

13
spec/models/form/lettings/questions/scheme_id_spec.rb

@ -147,6 +147,19 @@ RSpec.describe Form::Lettings::Questions::SchemeId, type: :model do
expect(question.displayed_answer_options(lettings_log)).to eq(expected_answer) expect(question.displayed_answer_options(lettings_log)).to eq(expected_answer)
end end
end end
context "when the scheme is deleted" do
let(:scheme) { FactoryBot.create(:scheme, owning_organisation: organisation, discarded_at: Time.zone.yesterday) }
before do
FactoryBot.create(:location, startdate: Time.zone.tomorrow, scheme:)
end
it "has the correct answer_options based on the schemes the user's organisation owns or manages" do
expected_answer = { "" => "Select an option" }
expect(question.displayed_answer_options(lettings_log)).to eq(expected_answer)
end
end
end end
context "when there are no schemes with locations" do context "when there are no schemes with locations" do

8
spec/models/scheme_spec.rb

@ -304,6 +304,14 @@ RSpec.describe Scheme, type: :model do
expect(scheme.status).to eq(:activating_soon) expect(scheme.status).to eq(:activating_soon)
end end
end end
context "when scheme has discarded_at value" do
let(:scheme) { FactoryBot.create(:scheme, discarded_at: Time.zone.now) }
it "returns deleted" do
expect(scheme.status).to eq(:deleted)
end
end
end end
describe "status_at" do describe "status_at" do

92
spec/policies/location_policy_spec.rb

@ -0,0 +1,92 @@
require "rails_helper"
RSpec.describe LocationPolicy do
subject(:policy) { described_class }
let(:data_provider) { FactoryBot.create(:user, :data_provider) }
let(:data_coordinator) { FactoryBot.create(:user, :data_coordinator) }
let(:support) { FactoryBot.create(:user, :support) }
permissions :delete? do
let(:location) { FactoryBot.create(:location) }
context "with active location" do
it "does not allow deleting a location as a provider" do
expect(policy).not_to permit(data_provider, location)
end
it "does not allow allows deleting a location as a coordinator" do
expect(policy).not_to permit(data_coordinator, location)
end
it "does not allow deleting a location as a support user" do
expect(policy).not_to permit(support, location)
end
end
context "with incomplete location" do
before do
location.update!(units: nil)
end
it "does not allow deleting a location as a provider" do
expect(policy).not_to permit(data_provider, location)
end
it "does not allow allows deleting a location as a coordinator" do
expect(policy).not_to permit(data_coordinator, location)
end
it "allows deleting a location as a support user" do
expect(policy).to permit(support, location)
end
end
context "with deactivated location" do
before do
location.location_deactivation_periods << create(:location_deactivation_period, deactivation_date: Time.zone.local(2024, 4, 10), location:)
location.save!
Timecop.freeze(Time.utc(2024, 4, 10))
log = create(:lettings_log, scheme: location.scheme, location:)
log.startdate = Time.zone.local(2022, 10, 10)
log.save!(validate: false)
end
after do
Timecop.unfreeze
end
context "and associated logs in editable collection period" do
before do
create(:lettings_log, scheme: location.scheme, location:)
end
it "does not allow deleting a location as a provider" do
expect(policy).not_to permit(data_provider, location)
end
it "does not allow allows deleting a location as a coordinator" do
expect(policy).not_to permit(data_coordinator, location)
end
it "does not allow deleting a location as a support user" do
expect(policy).not_to permit(support, location)
end
end
context "and no associated logs in editable collection period" do
it "does not allow deleting a location as a provider" do
expect(policy).not_to permit(data_provider, location)
end
it "does not allow allows deleting a location as a coordinator" do
expect(policy).not_to permit(data_coordinator, location)
end
it "allows deleting a location as a support user" do
expect(policy).to permit(support, location)
end
end
end
end
end

94
spec/policies/scheme_policy_spec.rb

@ -0,0 +1,94 @@
require "rails_helper"
RSpec.describe SchemePolicy do
subject(:policy) { described_class }
let(:data_provider) { create(:user, :data_provider) }
let(:data_coordinator) { create(:user, :data_coordinator) }
let(:support) { create(:user, :support) }
permissions :delete? do
let(:scheme) { create(:scheme) }
before do
create(:location, scheme:)
end
context "with active scheme" do
it "does not allow deleting a scheme as a provider" do
expect(policy).not_to permit(data_provider, scheme)
end
it "does not allow allows deleting a scheme as a coordinator" do
expect(policy).not_to permit(data_coordinator, scheme)
end
it "does not allow deleting a scheme as a support user" do
expect(policy).not_to permit(support, scheme)
end
end
context "with incomplete scheme" do
let(:scheme) { create(:scheme, :incomplete) }
it "does not allow deleting a scheme as a provider" do
expect(policy).not_to permit(data_provider, scheme)
end
it "does not allow allows deleting a scheme as a coordinator" do
expect(policy).not_to permit(data_coordinator, scheme)
end
it "allows deleting a scheme as a support user" do
expect(policy).to permit(support, scheme)
end
end
context "with deactivated scheme" do
before do
scheme.scheme_deactivation_periods << create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2024, 4, 10), scheme:)
scheme.save!
Timecop.freeze(Time.utc(2024, 4, 10))
log = create(:lettings_log, :sh, owning_organisation: scheme.owning_organisation, scheme:)
log.startdate = Time.zone.local(2022, 10, 10)
log.save!(validate: false)
end
after do
Timecop.unfreeze
end
context "and associated logs in editable collection period" do
before do
create(:lettings_log, :sh, owning_organisation: scheme.owning_organisation, scheme:, startdate: Time.zone.local(2024, 4, 9))
end
it "does not allow deleting a scheme as a provider" do
expect(policy).not_to permit(data_provider, scheme)
end
it "does not allow allows deleting a scheme as a coordinator" do
expect(policy).not_to permit(data_coordinator, scheme)
end
it "does not allow deleting a scheme as a support user" do
expect(policy).not_to permit(support, scheme)
end
end
context "and no associated logs in editable collection period" do
it "does not allow deleting a scheme as a provider" do
expect(policy).not_to permit(data_provider, scheme)
end
it "does not allow allows deleting a scheme as a coordinator" do
expect(policy).not_to permit(data_coordinator, scheme)
end
it "allows deleting a scheme as a support user" do
expect(policy).to permit(support, scheme)
end
end
end
end
end

270
spec/requests/locations_controller_spec.rb

@ -1405,6 +1405,23 @@ RSpec.describe LocationsController, type: :request do
expect(page).to have_content("Check your answers") expect(page).to have_content("Check your answers")
end end
context "with an active location" do
it "does not render delete this location" do
expect(location.status).to eq(:active)
expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
end
context "with an incomplete location" do
it "renders delete this location" do
location.update!(units: nil)
get "/schemes/#{scheme.id}/locations/#{location.id}/check-answers"
expect(location.reload.status).to eq(:incomplete)
expect(page).to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
end
context "when location is confirmed" do context "when location is confirmed" do
let(:params) { { location: { confirmed: true } } } let(:params) { { location: { confirmed: true } } }
@ -1825,6 +1842,11 @@ RSpec.describe LocationsController, type: :request do
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(page).to have_link("Reactivate this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/new-reactivation") expect(page).to have_link("Reactivate this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/new-reactivation")
end end
it "does not render delete this location" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
end end
context "with location that's deactivating soon" do context "with location that's deactivating soon" do
@ -1883,6 +1905,108 @@ RSpec.describe LocationsController, type: :request do
end end
end end
end end
context "when signed in as a support user" do
let(:user) { create(:user, :support) }
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:) }
let(:add_deactivations) { location.location_deactivation_periods << location_deactivation_period }
before do
Timecop.freeze(Time.utc(2022, 10, 10))
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
add_deactivations
location.save!
get "/schemes/#{scheme.id}/locations/#{location.id}"
end
after do
Timecop.unfreeze
end
context "with active location" do
let(:add_deactivations) {}
it "does not render delete this location" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
it "does not render informative text about deleting the location" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_content("This location was active in an open or editable collection year, and cannot be deleted.")
end
end
context "with deactivated location" do
let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), location:) }
it "renders delete this location" do
expect(response).to have_http_status(:ok)
expect(page).to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
context "and associated logs in editable collection period" do
before do
create(:lettings_log, :sh, location:, scheme:, startdate: Time.zone.local(2022, 9, 9), owning_organisation: user.organisation)
get "/schemes/#{scheme.id}/locations/#{location.id}"
end
it "does not render delete this location" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
it "adds informative text about deleting the location" do
expect(response).to have_http_status(:ok)
expect(page).to have_content("This location was active in an open or editable collection year, and cannot be deleted.")
end
end
end
context "with incomplete location" do
let(:add_deactivations) {}
before do
location.update!(units: nil)
get "/schemes/#{scheme.id}/locations/#{location.id}"
end
it "renders delete this location" do
expect(location.reload.status).to eq(:incomplete)
expect(response).to have_http_status(:ok)
expect(page).to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
end
context "with location that's deactivating soon" do
let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 12), location:) }
it "does not render delete this location" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
end
context "with location that's deactivating in more than 6 months" do
let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2023, 6, 12), location:) }
it "does not render delete this location" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
end
context "with location that's reactivating soon" do
let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 4, 12), reactivation_date: Time.zone.local(2022, 10, 12), location:) }
it "does not render delete this location" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation")
end
end
end
end end
describe "#reactivate" do describe "#reactivate" do
@ -2040,4 +2164,150 @@ RSpec.describe LocationsController, type: :request do
end end
end end
end end
describe "#delete-confirmation" do
let(:scheme) { create(:scheme, owning_organisation: user.organisation) }
let(:location) { create(:location, scheme:, created_at: Time.zone.local(2022, 4, 1)) }
before do
get "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation"
end
context "when not signed in" do
it "redirects to the sign in page" do
expect(response).to redirect_to("/account/sign-in")
end
end
context "when signed in" do
before do
Timecop.freeze(Time.utc(2022, 10, 10))
location.location_deactivation_periods << create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), location:)
location.save!
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
get "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation"
end
after do
Timecop.unfreeze
end
context "with a data provider user" do
let(:user) { create(:user) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a data coordinator user" do
let(:user) { create(:user, :data_coordinator) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a support user user" do
let(:user) { create(:user, :support) }
it "shows the correct title" do
expect(page.find("h1").text).to include "Are you sure you want to delete this location?"
end
it "shows a warning to the user" do
expect(page).to have_selector(".govuk-warning-text", text: "You will not be able to undo this action")
end
it "shows a button to delete the selected location" do
expect(page).to have_selector("form.button_to button", text: "Delete this location")
end
it "the delete location button submits the correct data to the correct path" do
form_containing_button = page.find("form.button_to")
expect(form_containing_button[:action]).to eq scheme_location_delete_path(scheme, location)
expect(form_containing_button).to have_field "_method", type: :hidden, with: "delete"
end
it "shows a cancel link with the correct style" do
expect(page).to have_selector("a.govuk-button--secondary", text: "Cancel")
end
it "shows cancel link that links back to the location page" do
expect(page).to have_link(text: "Cancel", href: scheme_location_path(scheme, location))
end
end
end
end
describe "#delete" do
let(:scheme) { create(:scheme, owning_organisation: user.organisation) }
let(:location) { create(:location, scheme:, name: "Location to delete", created_at: Time.zone.local(2022, 4, 1)) }
before do
Timecop.freeze(Time.utc(2022, 10, 10))
location.location_deactivation_periods << create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), location:)
location.save!
delete "/schemes/#{scheme.id}/locations/#{location.id}/delete"
end
after do
Timecop.unfreeze
end
context "when not signed in" do
it "redirects to the sign in page" do
expect(response).to redirect_to("/account/sign-in")
end
end
context "when signed in" do
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
delete "/schemes/#{scheme.id}/locations/#{location.id}/delete"
end
context "with a data provider user" do
let(:user) { create(:user) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a data coordinator user" do
let(:user) { create(:user, :data_coordinator) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a support user user" do
let(:user) { create(:user, :support) }
it "deletes the location" do
location.reload
expect(location.status).to eq(:deleted)
expect(location.discarded_at).not_to be nil
end
it "redirects to the scheme locations list and displays a notice that the location has been deleted" do
expect(response).to redirect_to scheme_locations_path(scheme)
follow_redirect!
expect(page).to have_selector(".govuk-notification-banner--success")
expect(page).to have_selector(".govuk-notification-banner--success", text: "has been deleted.")
end
it "does not display the deleted location" do
expect(response).to redirect_to scheme_locations_path(scheme)
follow_redirect!
expect(page).not_to have_content("Location to delete")
end
end
end
end
end end

5
spec/requests/organisations_controller_spec.rb

@ -44,6 +44,7 @@ RSpec.describe OrganisationsController, type: :request do
let(:user) { create(:user, :support) } let(:user) { create(:user, :support) }
let!(:schemes) { create_list(:scheme, 5) } let!(:schemes) { create_list(:scheme, 5) }
let!(:same_org_scheme) { create(:scheme, owning_organisation: user.organisation) } let!(:same_org_scheme) { create(:scheme, owning_organisation: user.organisation) }
let!(:deleted_scheme) { create(:scheme, owning_organisation: user.organisation, discarded_at: Time.zone.yesterday) }
before do before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false) allow(user).to receive(:need_two_factor_authentication?).and_return(false)
@ -131,6 +132,10 @@ RSpec.describe OrganisationsController, type: :request do
end end
end end
it "does not show deleted schemes" do
expect(page).not_to have_content(deleted_scheme.id_to_display)
end
context "when searching" do context "when searching" do
let!(:searched_scheme) { create(:scheme, owning_organisation: user.organisation) } let!(:searched_scheme) { create(:scheme, owning_organisation: user.organisation) }
let(:search_param) { searched_scheme.id } let(:search_param) { searched_scheme.id }

286
spec/requests/schemes_controller_spec.rb

@ -56,6 +56,19 @@ RSpec.describe SchemesController, type: :request do
end end
end end
context "when there are deleted schemes" do
let!(:deleted_scheme) { create(:scheme, service_name: "deleted", discarded_at: Time.zone.yesterday, owning_organisation: user.organisation) }
before do
get "/schemes"
end
it "does not show deleted schemes" do
follow_redirect!
expect(page).not_to have_content(deleted_scheme.id_to_display)
end
end
context "when parent organisation has schemes" do context "when parent organisation has schemes" do
let(:parent_organisation) { create(:organisation) } let(:parent_organisation) { create(:organisation) }
let!(:parent_schemes) { create_list(:scheme, 5, owning_organisation: parent_organisation) } let!(:parent_schemes) { create_list(:scheme, 5, owning_organisation: parent_organisation) }
@ -191,6 +204,18 @@ RSpec.describe SchemesController, type: :request do
expect(page).to have_content("Schemes") expect(page).to have_content("Schemes")
end end
context "when there are deleted schemes" do
let!(:deleted_scheme) { create(:scheme, service_name: "deleted", discarded_at: Time.zone.yesterday, owning_organisation: user.organisation) }
before do
get "/schemes"
end
it "does not show deleted schemes" do
expect(page).not_to have_content(deleted_scheme.id_to_display)
end
end
describe "scheme and location csv downloads" do describe "scheme and location csv downloads" do
let!(:same_org_scheme) { create(:scheme, owning_organisation: user.organisation) } let!(:same_org_scheme) { create(:scheme, owning_organisation: user.organisation) }
let!(:specific_organisation) { create(:organisation) } let!(:specific_organisation) { create(:organisation) }
@ -577,6 +602,11 @@ RSpec.describe SchemesController, type: :request do
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(page).to have_link("Reactivate this scheme", href: "/schemes/#{scheme.id}/new-reactivation") expect(page).to have_link("Reactivate this scheme", href: "/schemes/#{scheme.id}/new-reactivation")
end end
it "does not render delete this scheme" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
end end
context "with scheme that's deactivating soon" do context "with scheme that's deactivating soon" do
@ -712,6 +742,92 @@ RSpec.describe SchemesController, type: :request do
expect(page).to have_content(specific_scheme.support_type) expect(page).to have_content(specific_scheme.support_type)
expect(page).to have_content(specific_scheme.intended_stay) expect(page).to have_content(specific_scheme.intended_stay)
end end
context "when looking at scheme details" do
let!(:scheme) { create(:scheme, owning_organisation: user.organisation) }
let(:add_deactivations) { scheme.scheme_deactivation_periods << scheme_deactivation_period }
before do
create(:location, scheme:)
Timecop.freeze(Time.utc(2022, 10, 10))
sign_in user
add_deactivations
scheme.save!
get "/schemes/#{scheme.id}"
end
after do
Timecop.unfreeze
end
context "with active scheme" do
let(:add_deactivations) {}
it "does not render delete this scheme" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
it "does not render informative text about deleting the scheme" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_content("This scheme was active in an open or editable collection year, and cannot be deleted.")
end
end
context "with deactivated scheme" do
let(:scheme_deactivation_period) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), scheme:) }
it "renders delete this scheme" do
expect(response).to have_http_status(:ok)
expect(page).to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
context "and associated logs in editable collection period" do
before do
create(:lettings_log, :sh, scheme:, startdate: Time.zone.local(2022, 9, 9), owning_organisation: user.organisation)
get "/schemes/#{scheme.id}"
end
it "does not render delete this scheme" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
it "adds informative text about deleting the scheme" do
expect(response).to have_http_status(:ok)
expect(page).to have_content("This scheme was active in an open or editable collection year, and cannot be deleted.")
end
end
end
context "with scheme that's deactivating soon" do
let(:scheme_deactivation_period) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 12), scheme:) }
it "does not render delete this scheme" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
end
context "with scheme that's deactivating in more than 6 months" do
let(:scheme_deactivation_period) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2023, 5, 12), scheme:) }
it "does not render delete this scheme" do
expect(response).to have_http_status(:ok)
expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
end
context "with incomplete scheme" do
let(:add_deactivations) {}
let!(:scheme) { create(:scheme, :incomplete, owning_organisation: user.organisation) }
it "renders delete this scheme" do
expect(response).to have_http_status(:ok)
expect(page).to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
end
end
end end
end end
@ -2132,6 +2248,7 @@ RSpec.describe SchemesController, type: :request do
let!(:scheme) { create(:scheme) } let!(:scheme) { create(:scheme) }
before do before do
create(:location, scheme:)
allow(user).to receive(:need_two_factor_authentication?).and_return(false) allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user sign_in user
get "/schemes/#{scheme.id}/check-answers" get "/schemes/#{scheme.id}/check-answers"
@ -2141,6 +2258,22 @@ RSpec.describe SchemesController, type: :request do
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(page).to have_content("Check your changes before creating this scheme") expect(page).to have_content("Check your changes before creating this scheme")
end end
context "with an active scheme" do
it "does not render delete this scheme" do
expect(scheme.status).to eq(:active)
expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
end
context "with an incomplete scheme" do
let(:scheme) { create(:scheme, :incomplete) }
it "renders delete this scheme" do
expect(scheme.reload.status).to eq(:incomplete)
expect(page).to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation")
end
end
end end
end end
@ -2641,4 +2774,157 @@ RSpec.describe SchemesController, type: :request do
end end
end end
end end
describe "#delete-confirmation" do
let(:scheme) { create(:scheme, owning_organisation: user.organisation) }
before do
Timecop.freeze(Time.utc(2022, 10, 10))
scheme.scheme_deactivation_periods << create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), scheme:)
scheme.save!
get "/schemes/#{scheme.id}/delete-confirmation"
end
after do
Timecop.unfreeze
end
context "when not signed in" do
it "redirects to the sign in page" do
expect(response).to redirect_to("/account/sign-in")
end
end
context "when signed in" do
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
get "/schemes/#{scheme.id}/delete-confirmation"
end
context "with a data provider user" do
let(:user) { create(:user) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a data coordinator user" do
let(:user) { create(:user, :data_coordinator) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a support user user" do
let(:user) { create(:user, :support) }
it "shows the correct title" do
expect(page.find("h1").text).to include "Are you sure you want to delete this scheme?"
end
it "shows a warning to the user" do
expect(page).to have_selector(".govuk-warning-text", text: "You will not be able to undo this action")
end
it "shows a button to delete the selected scheme" do
expect(page).to have_selector("form.button_to button", text: "Delete this scheme")
end
it "the delete scheme button submits the correct data to the correct path" do
form_containing_button = page.find("form.button_to")
expect(form_containing_button[:action]).to eq scheme_delete_path(scheme)
expect(form_containing_button).to have_field "_method", type: :hidden, with: "delete"
end
it "shows a cancel link with the correct style" do
expect(page).to have_selector("a.govuk-button--secondary", text: "Cancel")
end
it "shows cancel link that links back to the scheme page" do
expect(page).to have_link(text: "Cancel", href: scheme_path(scheme))
end
end
end
end
describe "#delete" do
let(:scheme) { create(:scheme, service_name: "Scheme to delete", owning_organisation: user.organisation) }
let!(:locations) { create_list(:location, 2, scheme:, created_at: Time.zone.local(2022, 4, 1)) }
before do
delete "/schemes/#{scheme.id}/delete"
end
context "when not signed in" do
it "redirects to the sign in page" do
expect(response).to redirect_to("/account/sign-in")
end
end
context "when signed in" do
before do
Timecop.freeze(Time.utc(2022, 10, 10))
scheme.scheme_deactivation_periods << create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), scheme:)
scheme.save!
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
delete "/schemes/#{scheme.id}/delete"
end
after do
Timecop.unfreeze
end
context "with a data provider user" do
let(:user) { create(:user) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a data coordinator user" do
let(:user) { create(:user, :data_coordinator) }
it "returns 401 unauthorized" do
expect(response).to have_http_status(:unauthorized)
end
end
context "with a support user user" do
let(:user) { create(:user, :support) }
it "deletes the scheme" do
scheme.reload
expect(scheme.status).to eq(:deleted)
expect(scheme.discarded_at).not_to be nil
end
it "deletes associated locations" do
locations.each do |location|
location.reload
expect(location.status).to eq(:deleted)
expect(location.discarded_at).not_to be nil
end
end
it "redirects to the schemes list and displays a notice that the scheme has been deleted" do
expect(response).to redirect_to schemes_organisation_path(scheme.owning_organisation)
follow_redirect!
expect(page).to have_selector(".govuk-notification-banner--success")
expect(page).to have_selector(".govuk-notification-banner--success", text: "Scheme to delete has been deleted.")
end
it "does not display the deleted scheme" do
expect(response).to redirect_to schemes_organisation_path(scheme.owning_organisation)
follow_redirect!
expect(page).not_to have_link("Scheme to delete")
end
end
end
end
end end

2
spec/views/locations/show.html.erb_spec.rb

@ -51,6 +51,7 @@ RSpec.describe "locations/show.html.erb" do
assign(:location, location) assign(:location, location)
allow(view).to receive(:current_user).and_return(user) allow(view).to receive(:current_user).and_return(user)
allow(location).to receive(:deactivated?).and_return(false)
render render
@ -62,6 +63,7 @@ RSpec.describe "locations/show.html.erb" do
assign(:location, location) assign(:location, location)
allow(view).to receive(:current_user).and_return(user) allow(view).to receive(:current_user).and_return(user)
allow(location).to receive(:deactivated?).and_return(false)
render render

Loading…
Cancel
Save