diff --git a/app/controllers/locations_controller.rb b/app/controllers/locations_controller.rb
index b84185b51..2b75da1a0 100644
--- a/app/controllers/locations_controller.rb
+++ b/app/controllers/locations_controller.rb
@@ -14,8 +14,8 @@ class LocationsController < ApplicationController
def index
authorize @scheme
- @pagy, @locations = pagy(filter_manager.filtered_locations(@scheme.locations, search_term, session_filters))
- @total_count = @scheme.locations.size
+ @pagy, @locations = pagy(filter_manager.filtered_locations(@scheme.locations.visible, search_term, session_filters))
+ @total_count = @scheme.locations.visible.size
@searched = search_term.presence
@filter_type = "scheme_locations"
end
@@ -230,6 +230,11 @@ class LocationsController < ApplicationController
end
end
+ def delete
+ @location.discard!
+ redirect_to scheme_locations_path(@scheme), notice: I18n.t("notification.location_deleted", postcode: @location.postcode)
+ end
+
private
def authorize_user
diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb
index 4612e6bc9..dc5a36c9b 100644
--- a/app/controllers/organisations_controller.rb
+++ b/app/controllers/organisations_controller.rb
@@ -21,7 +21,7 @@ class OrganisationsController < ApplicationController
end
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))
@searched = search_term.presence
diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb
index 5eec2a294..cfc6fe8a0 100644
--- a/app/controllers/schemes_controller.rb
+++ b/app/controllers/schemes_controller.rb
@@ -13,11 +13,11 @@ class SchemesController < ApplicationController
def index
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
- @total_count = all_schemes.size
+ @total_count = all_visible_schemes.size
@filter_type = "schemes"
end
@@ -223,6 +223,11 @@ class SchemesController < ApplicationController
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
def authorize_user
diff --git a/app/helpers/locations_helper.rb b/app/helpers/locations_helper.rb
index f718e9576..f963c7040 100644
--- a/app/helpers/locations_helper.rb
+++ b/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?
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)
if location.confirmed
"#{location.postcode} #{location.startdate.blank? || location.startdate.before?(Time.zone.now) ? 'has been' : 'will be'} added to this scheme"
diff --git a/app/helpers/schemes_helper.rb b/app/helpers/schemes_helper.rb
index 078419619..1cc89d3d5 100644
--- a/app/helpers/schemes_helper.rb
+++ b/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?
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)
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)]
diff --git a/app/models/form/lettings/questions/location_id.rb b/app/models/form/lettings/questions/location_id.rb
index cbc9b840a..d79bcab76 100644
--- a/app/models/form/lettings/questions/location_id.rb
+++ b/app/models/form/lettings/questions/location_id.rb
@@ -20,7 +20,7 @@ class Form::Lettings::Questions::LocationId < ::Form::Question
answer_opts = {}
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
end
@@ -29,7 +29,7 @@ class Form::Lettings::Questions::LocationId < ::Form::Question
def displayed_answer_options(lettings_log, _user = nil)
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) }
end
diff --git a/app/models/form/lettings/questions/scheme_id.rb b/app/models/form/lettings/questions/scheme_id.rb
index 4c533f43a..ef7904cc8 100644
--- a/app/models/form/lettings/questions/scheme_id.rb
+++ b/app/models/form/lettings/questions/scheme_id.rb
@@ -19,8 +19,8 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question
answer_opts = { "" => "Select an option" }
return answer_opts unless ActiveRecord::Base.connected?
- Scheme.select(:id, :service_name, :primary_client_group,
- :secondary_client_group).each_with_object(answer_opts) do |scheme, hsh|
+ Scheme.visible.select(:id, :service_name, :primary_client_group,
+ :secondary_client_group).each_with_object(answer_opts) do |scheme, hsh|
hsh[scheme.id.to_s] = scheme
hsh
end
@@ -29,10 +29,10 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question
def displayed_answer_options(lettings_log, _user = nil)
organisation = lettings_log.owning_organisation || lettings_log.created_by&.organisation
schemes = if organisation
- Scheme.includes(:locations).select(:id).where(owning_organisation_id: organisation.id,
- confirmed: true)
+ Scheme.visible.includes(:locations).select(:id).where(owning_organisation_id: organisation.id,
+ confirmed: true)
else
- Scheme.includes(:locations).select(:id).where(confirmed: true)
+ Scheme.visible.includes(:locations).select(:id).where(confirmed: true)
end
filtered_scheme_ids = schemes.joins(:locations).merge(Location.started_in_2_weeks).map(&:id)
answer_options.select do |k, _v|
diff --git a/app/models/location.rb b/app/models/location.rb
index bfe9f77a4..43285bfbb 100644
--- a/app/models/location.rb
+++ b/app/models/location.rb
@@ -79,6 +79,8 @@ class Location < ApplicationRecord
.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
enum local_authorities: LOCAL_AUTHORITIES
@@ -138,6 +140,7 @@ class Location < ApplicationRecord
end
def status_at(date)
+ return :deleted if discarded_at.present?
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
@@ -190,6 +193,10 @@ class Location < ApplicationRecord
LocalAuthority.where(id: [la.id] + la.linked_local_authority_ids)
end
+ def discard!
+ update!(discarded_at: Time.zone.now)
+ end
+
private
PIO = PostcodeService.new
diff --git a/app/models/scheme.rb b/app/models/scheme.rb
index 0bfd56373..2518293a0 100644
--- a/app/models/scheme.rb
+++ b/app/models/scheme.rb
@@ -77,6 +77,8 @@ class Scheme < ApplicationRecord
.where.not(id: activating_soon.pluck(:id))
}
+ scope :visible, -> { where(discarded_at: nil) }
+
validate :validate_confirmed
validate :validate_owning_organisation
@@ -229,7 +231,7 @@ class Scheme < ApplicationRecord
end
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
required_attributes.any? do |attribute|
@@ -264,6 +266,7 @@ class Scheme < ApplicationRecord
end
def status_at(date)
+ return :deleted if discarded_at.present?
return :incomplete unless confirmed && locations.confirmed.any?
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
@@ -288,4 +291,9 @@ class Scheme < ApplicationRecord
def deactivates_in_a_long_time?
status_at(6.months.from_now) == :deactivating_soon
end
+
+ def discard!
+ update!(discarded_at: Time.zone.now)
+ locations.each(&:discard!)
+ end
end
diff --git a/app/policies/location_policy.rb b/app/policies/location_policy.rb
index 5d6d6d467..436b961c6 100644
--- a/app/policies/location_policy.rb
+++ b/app/policies/location_policy.rb
@@ -26,6 +26,17 @@ class LocationPolicy
user.data_coordinator? && scheme_owned_by_user_org_or_stock_owner
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[
update_postcode?
update_local_authority?
@@ -75,4 +86,10 @@ private
def scheme_owned_by_user_org_or_stock_owner
scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id)
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
diff --git a/app/policies/scheme_policy.rb b/app/policies/scheme_policy.rb
index f2710eb06..6b97a46de 100644
--- a/app/policies/scheme_policy.rb
+++ b/app/policies/scheme_policy.rb
@@ -65,9 +65,26 @@ class SchemePolicy
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
def scheme_owned_by_user_org_or_stock_owner
scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id)
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
diff --git a/app/services/feature_toggle.rb b/app/services/feature_toggle.rb
index 22d43f513..f145b7132 100644
--- a/app/services/feature_toggle.rb
+++ b/app/services/feature_toggle.rb
@@ -26,4 +26,12 @@ class FeatureToggle
def self.service_moved?
false
end
+
+ def self.delete_scheme_enabled?
+ !Rails.env.production?
+ end
+
+ def self.delete_location_enabled?
+ !Rails.env.production?
+ end
end
diff --git a/app/views/locations/check_answers.html.erb b/app/views/locations/check_answers.html.erb
index 63a48d4d5..8cd8bde2a 100644
--- a/app/views/locations/check_answers.html.erb
+++ b/app/views/locations/check_answers.html.erb
@@ -42,6 +42,9 @@
<% if LocationPolicy.new(current_user, @location).create? %>
<%= 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 %>
<% end %>
diff --git a/app/views/locations/delete_confirmation.html.erb b/app/views/locations/delete_confirmation.html.erb
new file mode 100644
index 000000000..0eea3adc8
--- /dev/null
+++ b/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 %>
+
+
+
+
Delete <%= @location.postcode %>
+
+ <%= content_for(:title) %>
+
+
+ <%= govuk_warning_text(text: "You will not be able to undo this action.") %>
+
+
+ <%= 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 %>
+
+
+
diff --git a/app/views/locations/show.html.erb b/app/views/locations/show.html.erb
index 9b11e4052..86de3a362 100644
--- a/app/views/locations/show.html.erb
+++ b/app/views/locations/show.html.erb
@@ -19,7 +19,12 @@
<%= summary_list.with_row do |row| %>
<% row.with_key { attr[:name] } %>
<% 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? %>
+ This location was active in an open or editable collection year, and cannot be deleted.
+ <% end %>
+ <% end %>
<% elsif attr[:attribute].eql?("postcode") && @location.is_la_inferred %>
<% row.with_value do %>
<%= details_html(attr) %>
@@ -45,3 +50,7 @@
<% if LocationPolicy.new(current_user, @location).deactivate? %>
<%= toggle_location_link(@location) %>
<% end %>
+
+<% if LocationPolicy.new(current_user, @location).delete? && FeatureToggle.delete_location_enabled? %>
+ <%= delete_location_link(@location) %>
+<% end %>
diff --git a/app/views/schemes/check_answers.html.erb b/app/views/schemes/check_answers.html.erb
index 71e23b25c..3f8365f6e 100644
--- a/app/views/schemes/check_answers.html.erb
+++ b/app/views/schemes/check_answers.html.erb
@@ -23,4 +23,8 @@
<% if SchemePolicy.new(current_user, @scheme).create? %>
<%= f.govuk_submit button_label %>
<% end %>
+
+ <% if SchemePolicy.new(current_user, @scheme).delete? && FeatureToggle.delete_scheme_enabled? %>
+ <%= delete_scheme_link(@scheme) %>
+ <% end %>
<% end %>
diff --git a/app/views/schemes/delete_confirmation.html.erb b/app/views/schemes/delete_confirmation.html.erb
new file mode 100644
index 000000000..d4b0dd5ea
--- /dev/null
+++ b/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 %>
+
+
+
+
Delete <%= @scheme.service_name %>
+
+ <%= content_for(:title) %>
+
+
+ <%= govuk_warning_text(text: "You will not be able to undo this action.") %>
+
+
+ <%= 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 %>
+
+
+
diff --git a/app/views/schemes/show.html.erb b/app/views/schemes/show.html.erb
index c45cefb14..31ca1cba9 100644
--- a/app/views/schemes/show.html.erb
+++ b/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? %>
Complete this scheme by adding a location using the <%= govuk_link_to("‘locations’ tab", scheme_locations_path(@scheme)) %>.
<% end %>
+ <% if @scheme.deactivated? && current_user.support? && !SchemePolicy.new(current_user, @scheme).delete? %>
+ This scheme was active in an open or editable collection year, and cannot be deleted.
+ <% end %>
<% elsif attr[:id] != "secondary_client_group" || @scheme.has_other_client_group == "Yes" %>
@@ -49,3 +52,7 @@
<% if SchemePolicy.new(current_user, @scheme).deactivate? %>
<%= toggle_scheme_link(@scheme) %>
<% end %>
+
+<% if SchemePolicy.new(current_user, @scheme).delete? && FeatureToggle.delete_scheme_enabled? %>
+ <%= delete_scheme_link(@scheme) %>
+<% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index e2934273f..6a105b213 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -196,6 +196,8 @@ en:
duplicate_sets:
one: "There is %{count} set 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:
organisation:
diff --git a/config/routes.rb b/config/routes.rb
index 99ac0cc31..f0f497291 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -79,6 +79,8 @@ Rails.application.routes.draw do
patch "new-deactivation", to: "schemes#new_deactivation"
patch "deactivate", to: "schemes#deactivate"
patch "reactivate", to: "schemes#reactivate"
+ get "delete-confirmation", to: "schemes#delete_confirmation"
+ delete "delete", to: "schemes#delete"
collection do
get "csv-download", to: "schemes#download_csv"
@@ -111,6 +113,8 @@ Rails.application.routes.draw do
patch "new-deactivation", to: "locations#new_deactivation"
patch "deactivate", to: "locations#deactivate"
patch "reactivate", to: "locations#reactivate"
+ get "delete-confirmation", to: "locations#delete_confirmation"
+ delete "delete", to: "locations#delete"
end
end
get "scheme-changes", to: "schemes#changes"
diff --git a/db/migrate/20240301125651_add_discarded_at_column.rb b/db/migrate/20240301125651_add_discarded_at_column.rb
new file mode 100644
index 000000000..ed752d650
--- /dev/null
+++ b/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
diff --git a/db/migrate/20240304100017_add_discarded_at_column_to_schemes.rb b/db/migrate/20240304100017_add_discarded_at_column_to_schemes.rb
new file mode 100644
index 000000000..57ced4dee
--- /dev/null
+++ b/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
diff --git a/db/schema.rb b/db/schema.rb
index 5c754b39c..da9c4b0aa 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -374,6 +374,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do
t.string "location_admin_district"
t.boolean "confirmed"
t.boolean "is_la_inferred"
+ t.datetime "discarded_at"
t.index ["old_id"], name: "index_locations_on_old_id", unique: true
t.index ["scheme_id"], name: "index_locations_on_scheme_id"
end
@@ -722,6 +723,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do
t.integer "total_units"
t.boolean "confirmed"
t.datetime "startdate"
+ t.datetime "discarded_at"
t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id"
end
diff --git a/spec/models/form/lettings/questions/location_id_spec.rb b/spec/models/form/lettings/questions/location_id_spec.rb
index a2c41af80..8406b8119 100644
--- a/spec/models/form/lettings/questions/location_id_spec.rb
+++ b/spec/models/form/lettings/questions/location_id_spec.rb
@@ -80,6 +80,18 @@ RSpec.describe Form::Lettings::Questions::LocationId, type: :model do
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
before do
FactoryBot.create(:location, scheme:, startdate: Time.utc(2022, 5, 13))
diff --git a/spec/models/form/lettings/questions/scheme_id_spec.rb b/spec/models/form/lettings/questions/scheme_id_spec.rb
index c0cf6fa3b..ec9283113 100644
--- a/spec/models/form/lettings/questions/scheme_id_spec.rb
+++ b/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)
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
context "when there are no schemes with locations" do
diff --git a/spec/models/scheme_spec.rb b/spec/models/scheme_spec.rb
index 2f1036c1a..9b663595c 100644
--- a/spec/models/scheme_spec.rb
+++ b/spec/models/scheme_spec.rb
@@ -304,6 +304,14 @@ RSpec.describe Scheme, type: :model do
expect(scheme.status).to eq(:activating_soon)
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
describe "status_at" do
diff --git a/spec/policies/location_policy_spec.rb b/spec/policies/location_policy_spec.rb
new file mode 100644
index 000000000..efc56978b
--- /dev/null
+++ b/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
diff --git a/spec/policies/scheme_policy_spec.rb b/spec/policies/scheme_policy_spec.rb
new file mode 100644
index 000000000..c22be81bb
--- /dev/null
+++ b/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
diff --git a/spec/requests/locations_controller_spec.rb b/spec/requests/locations_controller_spec.rb
index 996dd3de0..751953b6f 100644
--- a/spec/requests/locations_controller_spec.rb
+++ b/spec/requests/locations_controller_spec.rb
@@ -1405,6 +1405,23 @@ RSpec.describe LocationsController, type: :request do
expect(page).to have_content("Check your answers")
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
let(:params) { { location: { confirmed: true } } }
@@ -1825,6 +1842,11 @@ RSpec.describe LocationsController, type: :request do
expect(response).to have_http_status(:ok)
expect(page).to have_link("Reactivate this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/new-reactivation")
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
context "with location that's deactivating soon" do
@@ -1883,6 +1905,108 @@ RSpec.describe LocationsController, type: :request do
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
describe "#reactivate" do
@@ -2040,4 +2164,150 @@ RSpec.describe LocationsController, type: :request do
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
diff --git a/spec/requests/organisations_controller_spec.rb b/spec/requests/organisations_controller_spec.rb
index 68de93c51..22d74470c 100644
--- a/spec/requests/organisations_controller_spec.rb
+++ b/spec/requests/organisations_controller_spec.rb
@@ -44,6 +44,7 @@ RSpec.describe OrganisationsController, type: :request do
let(:user) { create(:user, :support) }
let!(:schemes) { create_list(:scheme, 5) }
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
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
@@ -131,6 +132,10 @@ RSpec.describe OrganisationsController, type: :request do
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
let!(:searched_scheme) { create(:scheme, owning_organisation: user.organisation) }
let(:search_param) { searched_scheme.id }
diff --git a/spec/requests/schemes_controller_spec.rb b/spec/requests/schemes_controller_spec.rb
index 6e00eb733..c33397983 100644
--- a/spec/requests/schemes_controller_spec.rb
+++ b/spec/requests/schemes_controller_spec.rb
@@ -56,6 +56,19 @@ RSpec.describe SchemesController, type: :request do
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
let(:parent_organisation) { create(: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")
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
let!(:same_org_scheme) { create(:scheme, owning_organisation: user.organisation) }
let!(:specific_organisation) { create(:organisation) }
@@ -577,6 +602,11 @@ RSpec.describe SchemesController, type: :request do
expect(response).to have_http_status(:ok)
expect(page).to have_link("Reactivate this scheme", href: "/schemes/#{scheme.id}/new-reactivation")
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
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.intended_stay)
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
@@ -2132,6 +2248,7 @@ RSpec.describe SchemesController, type: :request do
let!(:scheme) { create(:scheme) }
before do
+ create(:location, scheme:)
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
get "/schemes/#{scheme.id}/check-answers"
@@ -2141,6 +2258,22 @@ RSpec.describe SchemesController, type: :request do
expect(response).to have_http_status(:ok)
expect(page).to have_content("Check your changes before creating this scheme")
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
@@ -2641,4 +2774,157 @@ RSpec.describe SchemesController, type: :request do
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
diff --git a/spec/views/locations/show.html.erb_spec.rb b/spec/views/locations/show.html.erb_spec.rb
index 0b6dee65e..c2510c79b 100644
--- a/spec/views/locations/show.html.erb_spec.rb
+++ b/spec/views/locations/show.html.erb_spec.rb
@@ -51,6 +51,7 @@ RSpec.describe "locations/show.html.erb" do
assign(:location, location)
allow(view).to receive(:current_user).and_return(user)
+ allow(location).to receive(:deactivated?).and_return(false)
render
@@ -62,6 +63,7 @@ RSpec.describe "locations/show.html.erb" do
assign(:location, location)
allow(view).to receive(:current_user).and_return(user)
+ allow(location).to receive(:deactivated?).and_return(false)
render