diff --git a/app/controllers/organisation_relationships_controller.rb b/app/controllers/organisation_relationships_controller.rb
index 0ac66bd31..0e3d230ef 100644
--- a/app/controllers/organisation_relationships_controller.rb
+++ b/app/controllers/organisation_relationships_controller.rb
@@ -14,7 +14,7 @@ class OrganisationRelationshipsController < ApplicationController
]
def stock_owners
- stock_owners = organisation.stock_owners
+ stock_owners = organisation.stock_owners.filter_by_active
unpaginated_filtered_stock_owners = filtered_collection(stock_owners, search_term)
@pagy, @stock_owners = pagy(unpaginated_filtered_stock_owners)
@@ -23,7 +23,7 @@ class OrganisationRelationshipsController < ApplicationController
end
def managing_agents
- managing_agents = organisation.managing_agents
+ managing_agents = organisation.managing_agents.filter_by_active
unpaginated_filtered_managing_agents = filtered_collection(managing_agents, search_term)
@pagy, @managing_agents = pagy(unpaginated_filtered_managing_agents)
@@ -48,7 +48,7 @@ class OrganisationRelationshipsController < ApplicationController
flash[:notice] = "#{@organisation_relationship.parent_organisation.name} is now one of #{current_user.data_coordinator? ? 'your' : "this organisation's"} stock owners"
redirect_to stock_owners_organisation_path
else
- @organisations = Organisation.where.not(id: organisation.id).pluck(:id, :name)
+ @organisations = Organisation.filter_by_active.where.not(id: organisation.id).pluck(:id, :name)
render "organisation_relationships/add_stock_owner", status: :unprocessable_entity
end
end
@@ -60,7 +60,7 @@ class OrganisationRelationshipsController < ApplicationController
flash[:notice] = "#{@organisation_relationship.child_organisation.name} is now one of #{current_user.data_coordinator? ? 'your' : "this organisation's"} managing agents"
redirect_to managing_agents_organisation_path
else
- @organisations = Organisation.where.not(id: organisation.id).pluck(:id, :name)
+ @organisations = Organisation.filter_by_active.where.not(id: organisation.id).pluck(:id, :name)
render "organisation_relationships/add_managing_agent", status: :unprocessable_entity
end
end
@@ -110,7 +110,7 @@ private
end
def organisations
- @organisations ||= Organisation.where.not(id: organisation.id).pluck(:id, :name)
+ @organisations ||= Organisation.filter_by_active.where.not(id: organisation.id).pluck(:id, :name)
end
def parent_organisation
diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb
index 4982c4287..e7f5c4bef 100644
--- a/app/controllers/organisations_controller.rb
+++ b/app/controllers/organisations_controller.rb
@@ -94,10 +94,37 @@ class OrganisationsController < ApplicationController
end
end
+ def deactivate
+ authorize @organisation
+
+ render "toggle_active", locals: { action: "deactivate" }
+ end
+
+ def reactivate
+ authorize @organisation
+
+ render "toggle_active", locals: { action: "reactivate" }
+ end
+
def update
- if current_user.data_coordinator? || current_user.support?
+ if (current_user.data_coordinator? && org_params[:active].nil?) || current_user.support?
if @organisation.update(org_params)
- flash[:notice] = I18n.t("organisation.updated")
+ case org_params[:active]
+ when "false"
+ @organisation.users.filter_by_active.each do |user|
+ user.deactivate!(reactivate_with_organisation: true)
+ end
+ flash[:notice] = I18n.t("organisation.deactivated", organisation: @organisation.name)
+ when "true"
+ users_to_reactivate = @organisation.users.where(reactivate_with_organisation: true)
+ users_to_reactivate.each do |user|
+ user.reactivate!
+ user.send_confirmation_instructions
+ end
+ flash[:notice] = I18n.t("organisation.reactivated", organisation: @organisation.name)
+ else
+ flash[:notice] = I18n.t("organisation.updated")
+ end
redirect_to details_organisation_path(@organisation)
end
else
@@ -239,7 +266,7 @@ private
end
def org_params
- params.require(:organisation).permit(:name, :address_line1, :address_line2, :postcode, :phone, :holds_own_stock, :provider_type, :housing_registration_no)
+ params.require(:organisation).permit(:name, :address_line1, :address_line2, :postcode, :phone, :holds_own_stock, :provider_type, :housing_registration_no, :active)
end
def codes_only_export?
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 6a76cb047..3fe3b1813 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -62,9 +62,10 @@ class UsersController < ApplicationController
else
user_name = @user.name&.possessive || @user.email.possessive
if user_params[:active] == "false"
- @user.update!(confirmed_at: nil, sign_in_count: 0, initial_confirmation_sent: false)
+ @user.deactivate!
flash[:notice] = I18n.t("devise.activation.deactivated", user_name:)
elsif user_params[:active] == "true"
+ @user.reactivate!
@user.send_confirmation_instructions
flash[:notice] = I18n.t("devise.activation.reactivated", user_name:)
elsif user_params.key?("email")
diff --git a/app/helpers/toggle_active_organisation_helper.rb b/app/helpers/toggle_active_organisation_helper.rb
new file mode 100644
index 000000000..10b9b0983
--- /dev/null
+++ b/app/helpers/toggle_active_organisation_helper.rb
@@ -0,0 +1,13 @@
+module ToggleActiveOrganisationHelper
+ def toggle_organisation_form_path(action, organisation)
+ if action == "deactivate"
+ organisation_new_deactivation_path(organisation)
+ else
+ organisation_reactivate_path(organisation)
+ end
+ end
+
+ def date_type_question(action)
+ action == "deactivate" ? :deactivation_date_type : :reactivation_date_type
+ end
+end
diff --git a/app/models/form/lettings/questions/managing_organisation.rb b/app/models/form/lettings/questions/managing_organisation.rb
index 51eccdaac..ea85ff207 100644
--- a/app/models/form/lettings/questions/managing_organisation.rb
+++ b/app/models/form/lettings/questions/managing_organisation.rb
@@ -31,11 +31,11 @@ class Form::Lettings::Questions::ManagingOrganisation < ::Form::Question
end
orgs = if user.support?
- log.owning_organisation.managing_agents
+ log.owning_organisation.managing_agents.filter_by_active
elsif user.organisation.absorbed_organisations.include?(log.owning_organisation)
- user.organisation.managing_agents + log.owning_organisation.managing_agents
+ user.organisation.managing_agents.filter_by_active + log.owning_organisation.managing_agents.filter_by_active
else
- user.organisation.managing_agents
+ user.organisation.managing_agents.filter_by_active
end
user.organisation.absorbed_organisations.each do |absorbed_org|
diff --git a/app/models/form/lettings/questions/stock_owner.rb b/app/models/form/lettings/questions/stock_owner.rb
index 682c64247..6ce0e5496 100644
--- a/app/models/form/lettings/questions/stock_owner.rb
+++ b/app/models/form/lettings/questions/stock_owner.rb
@@ -30,7 +30,7 @@ class Form::Lettings::Questions::StockOwner < ::Form::Question
end
if user.support?
- Organisation.where(holds_own_stock: true).find_each do |org|
+ Organisation.filter_by_active.where(holds_own_stock: true).find_each do |org|
if org.merge_date.present?
answer_opts[org.id] = "#{org.name} (inactive as of #{org.merge_date.to_fs(:govuk_date)})" if org.merge_date >= FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period
elsif org.absorbed_organisations.merged_during_open_collection_period.exists? && org.available_from.present?
@@ -40,7 +40,7 @@ class Form::Lettings::Questions::StockOwner < ::Form::Question
end
end
else
- user.organisation.stock_owners.each do |stock_owner|
+ user.organisation.stock_owners.filter_by_active.each do |stock_owner|
answer_opts[stock_owner.id] = stock_owner.name
end
recently_absorbed_organisations.each do |absorbed_org|
diff --git a/app/models/form/sales/questions/managing_organisation.rb b/app/models/form/sales/questions/managing_organisation.rb
index f98dd0100..54d7ab6e0 100644
--- a/app/models/form/sales/questions/managing_organisation.rb
+++ b/app/models/form/sales/questions/managing_organisation.rb
@@ -31,11 +31,11 @@ class Form::Sales::Questions::ManagingOrganisation < ::Form::Question
end
orgs = if user.support?
- log.owning_organisation.managing_agents
+ log.owning_organisation.managing_agents.filter_by_active
elsif user.organisation.absorbed_organisations.include?(log.owning_organisation)
- user.organisation.managing_agents + log.owning_organisation.managing_agents
+ user.organisation.managing_agents.filter_by_active + log.owning_organisation.managing_agents.filter_by_active
else
- user.organisation.managing_agents
+ user.organisation.managing_agents.filter_by_active
end.pluck(:id, :name).to_h
user.organisation.absorbed_organisations.each do |absorbed_org|
diff --git a/app/models/form/sales/questions/owning_organisation_id.rb b/app/models/form/sales/questions/owning_organisation_id.rb
index 062fbcaaf..dc3913882 100644
--- a/app/models/form/sales/questions/owning_organisation_id.rb
+++ b/app/models/form/sales/questions/owning_organisation_id.rb
@@ -25,7 +25,7 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question
answer_opts[user.organisation.id] = "#{user.organisation.name} (Your organisation)"
end
- user.organisation.stock_owners.where(holds_own_stock: true).find_each do |org|
+ user.organisation.stock_owners.filter_by_active.where(holds_own_stock: true).find_each do |org|
answer_opts[org.id] = org.name
end
end
@@ -44,7 +44,7 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question
end
if user.support?
- Organisation.where(holds_own_stock: true).find_each do |org|
+ Organisation.filter_by_active.where(holds_own_stock: true).find_each do |org|
if org.merge_date.present?
answer_opts[org.id] = "#{org.name} (inactive as of #{org.merge_date.to_fs(:govuk_date)})" if org.merge_date >= FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period
elsif org.absorbed_organisations.merged_during_open_collection_period.exists? && org.available_from.present?
diff --git a/app/models/location.rb b/app/models/location.rb
index 43285bfbb..dfcbef41b 100644
--- a/app/models/location.rb
+++ b/app/models/location.rb
@@ -40,6 +40,7 @@ class Location < ApplicationRecord
if scopes.any?
filtered_records = filtered_records
.left_outer_joins(:location_deactivation_periods)
+ .joins(scheme: [:owning_organisation])
.order("location_deactivation_periods.created_at DESC")
.merge(scopes.reduce(&:or))
end
@@ -53,27 +54,39 @@ class Location < ApplicationRecord
}
scope :deactivated, lambda {
+ deactivated_by_organisation
+ .or(deactivated_directly)
+ }
+
+ scope :deactivated_by_organisation, lambda {
+ merge(Organisation.filter_by_inactive)
+ }
+
+ scope :deactivated_directly, lambda {
merge(LocationDeactivationPeriod.deactivations_without_reactivation)
- .where("location_deactivation_periods.deactivation_date <= ?", Time.zone.now)
+ .where("location_deactivation_periods.deactivation_date <= ?", Time.zone.now)
}
scope :deactivating_soon, lambda {
merge(LocationDeactivationPeriod.deactivations_without_reactivation)
.where("location_deactivation_periods.deactivation_date > ?", Time.zone.now)
+ .where.not(id: joins(scheme: [:owning_organisation]).deactivated_by_organisation.pluck(:id))
}
scope :reactivating_soon, lambda {
where.not("location_deactivation_periods.reactivation_date IS NULL")
.where("location_deactivation_periods.reactivation_date > ?", Time.zone.now)
+ .where.not(id: joins(scheme: [:owning_organisation]).deactivated_by_organisation.pluck(:id))
}
scope :activating_soon, lambda {
- where("startdate > ?", Time.zone.now)
+ where("locations.startdate > ?", Time.zone.now)
}
scope :active_status, lambda {
where.not(id: joins(:location_deactivation_periods).reactivating_soon.pluck(:id))
- .where.not(id: joins(:location_deactivation_periods).deactivated.pluck(:id))
+ .where.not(id: joins(scheme: [:owning_organisation]).deactivated_by_organisation.pluck(:id))
+ .where.not(id: joins(:location_deactivation_periods).deactivated_directly.pluck(:id))
.where.not(id: incomplete.pluck(:id))
.where.not(id: joins(:location_deactivation_periods).deactivating_soon.pluck(:id))
.where.not(id: activating_soon.pluck(:id))
@@ -142,7 +155,8 @@ class Location < ApplicationRecord
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 :deactivated if scheme.owning_organisation.status_at(date) == :deactivated ||
+ open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date
return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
return :reactivating_soon if last_deactivation_before(date)&.reactivation_date.present? && date < last_deactivation_before(date).reactivation_date
return :activating_soon if startdate.present? && date < startdate
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index 0a852d2fd..b5c6f36aa 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -37,6 +37,8 @@ class Organisation < ApplicationRecord
scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") }
scope :search_by, ->(param) { search_by_name(param) }
+ scope :filter_by_active, -> { where(active: true) }
+ scope :filter_by_inactive, -> { where(active: false) }
scope :merged_during_open_collection_period, -> { where("merge_date >= ?", FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period) }
has_paper_trail
@@ -138,6 +140,7 @@ class Organisation < ApplicationRecord
def status_at(date)
return :merged if merge_date.present? && merge_date < date
+ return :deactivated unless active
:active
end
diff --git a/app/models/scheme.rb b/app/models/scheme.rb
index 2518293a0..5b95ed98a 100644
--- a/app/models/scheme.rb
+++ b/app/models/scheme.rb
@@ -35,6 +35,7 @@ class Scheme < ApplicationRecord
if scopes.any?
filtered_records = filtered_records
.left_outer_joins(:scheme_deactivation_periods)
+ .joins(:owning_organisation)
.merge(scopes.reduce(&:or))
end
@@ -45,35 +46,48 @@ class Scheme < ApplicationRecord
where.not(confirmed: true)
.or(where(confirmed: nil))
.or(where.not(id: Location.select(:scheme_id).where(confirmed: true).distinct))
+ .where.not(id: joins(:owning_organisation).deactivated_by_organisation.pluck(:id))
+ .where.not(id: joins(:scheme_deactivation_periods).deactivated_directly.pluck(:id))
.where.not(id: joins(:scheme_deactivation_periods).reactivating_soon.pluck(:id))
- .where.not(id: joins(:scheme_deactivation_periods).deactivated.pluck(:id))
.where.not(id: joins(:scheme_deactivation_periods).deactivating_soon.pluck(:id))
}
scope :deactivated, lambda {
+ deactivated_by_organisation
+ .or(deactivated_directly)
+ }
+
+ scope :deactivated_by_organisation, lambda {
+ merge(Organisation.filter_by_inactive)
+ }
+
+ scope :deactivated_directly, lambda {
merge(SchemeDeactivationPeriod.deactivations_without_reactivation)
- .where("scheme_deactivation_periods.deactivation_date <= ?", Time.zone.now)
+ .where("scheme_deactivation_periods.deactivation_date <= ?", Time.zone.now)
}
scope :deactivating_soon, lambda {
merge(SchemeDeactivationPeriod.deactivations_without_reactivation)
.where("scheme_deactivation_periods.deactivation_date > ? AND scheme_deactivation_periods.deactivation_date < ? ", Time.zone.now, 6.months.from_now)
+ .where.not(id: joins(:owning_organisation).deactivated_by_organisation.pluck(:id))
}
scope :reactivating_soon, lambda {
where.not("scheme_deactivation_periods.reactivation_date IS NULL")
.where("scheme_deactivation_periods.reactivation_date > ?", Time.zone.now)
+ .where.not(id: joins(:owning_organisation).deactivated_by_organisation.pluck(:id))
}
scope :activating_soon, lambda {
- where("startdate > ?", Time.zone.now)
+ where("schemes.startdate > ?", Time.zone.now)
}
scope :active_status, lambda {
where.not(id: joins(:scheme_deactivation_periods).reactivating_soon.pluck(:id))
- .where.not(id: joins(:scheme_deactivation_periods).deactivated.pluck(:id))
.where.not(id: incomplete.pluck(:id))
.where.not(id: joins(:scheme_deactivation_periods).deactivating_soon.pluck(:id))
+ .where.not(id: joins(:owning_organisation).deactivated_by_organisation.pluck(:id))
+ .where.not(id: joins(:owning_organisation).joins(:scheme_deactivation_periods).deactivated_directly.pluck(:id))
.where.not(id: activating_soon.pluck(:id))
}
@@ -268,7 +282,8 @@ class Scheme < ApplicationRecord
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 :deactivated if owning_organisation.status_at(date) == :deactivated ||
+ (open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date)
return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
return :reactivating_soon if last_deactivation_before(date)&.reactivation_date.present? && date < last_deactivation_before(date).reactivation_date
return :activating_soon if startdate.present? && date < startdate
diff --git a/app/models/user.rb b/app/models/user.rb
index 6d13e8cd1..27187529a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -134,6 +134,23 @@ class User < ApplicationRecord
update!(is_dpo: true)
end
+ def deactivate!(reactivate_with_organisation: false)
+ update!(
+ active: false,
+ confirmed_at: nil,
+ sign_in_count: 0,
+ initial_confirmation_sent: false,
+ reactivate_with_organisation:,
+ )
+ end
+
+ def reactivate!
+ update!(
+ active: true,
+ reactivate_with_organisation: false,
+ )
+ end
+
MFA_TEMPLATE_ID = "6bdf5ee1-8e01-4be1-b1f9-747061d8a24c".freeze
RESET_PASSWORD_TEMPLATE_ID = "2c410c19-80a7-481c-a531-2bcb3264f8e6".freeze
CONFIRMABLE_TEMPLATE_ID = "3fc2e3a7-0835-4b84-ab7a-ce51629eb614".freeze
diff --git a/app/policies/organisation_policy.rb b/app/policies/organisation_policy.rb
new file mode 100644
index 000000000..3e0c9a946
--- /dev/null
+++ b/app/policies/organisation_policy.rb
@@ -0,0 +1,16 @@
+class OrganisationPolicy
+ attr_reader :user, :organisation
+
+ def initialize(user, organisation)
+ @user = user
+ @organisation = organisation
+ end
+
+ def deactivate?
+ user.support? && organisation.status == :active
+ end
+
+ def reactivate?
+ user.support? && organisation.status == :deactivated
+ end
+end
diff --git a/app/services/feature_toggle.rb b/app/services/feature_toggle.rb
index 987a087ac..810bfb845 100644
--- a/app/services/feature_toggle.rb
+++ b/app/services/feature_toggle.rb
@@ -28,14 +28,14 @@ class FeatureToggle
end
def self.delete_scheme_enabled?
- !Rails.env.production?
+ true
end
def self.delete_location_enabled?
- !Rails.env.production?
+ true
end
def self.delete_user_enabled?
- !Rails.env.production?
+ true
end
end
diff --git a/app/views/locations/show.html.erb b/app/views/locations/show.html.erb
index 86de3a362..8ac8f6b23 100644
--- a/app/views/locations/show.html.erb
+++ b/app/views/locations/show.html.erb
@@ -47,7 +47,7 @@
-<% if LocationPolicy.new(current_user, @location).deactivate? %>
+<% if @location.scheme.owning_organisation.active? && LocationPolicy.new(current_user, @location).deactivate? %>
<%= toggle_location_link(@location) %>
<% end %>
diff --git a/app/views/organisation_relationships/managing_agents.html.erb b/app/views/organisation_relationships/managing_agents.html.erb
index a01a354d2..726533e53 100644
--- a/app/views/organisation_relationships/managing_agents.html.erb
+++ b/app/views/organisation_relationships/managing_agents.html.erb
@@ -5,19 +5,35 @@
<%= render SubNavigationComponent.new(
items: secondary_items(request.path, @organisation.id),
) %>
+ <% if !@organisation.active? %>
+ <%= govuk_notification_banner(title_text: "Important") do %>
+
A managing agent can submit logs for this organisation.
<% if @total_count == 0 %>
This organisation does not currently have any managing agents.
<% end %>
<% else %>
+ <% if !@organisation.active? %>
+ <%= govuk_notification_banner(title_text: "Important") do %>
+
+ You cannot add any new managing agents.
+ <% end %>
+ <% end %>
<%= render partial: "organisations/headings", locals: { main: "Your managing agents", sub: current_user.organisation.name } %>
A managing agent can submit logs for this organisation.
<% if @total_count == 0 %>
This organisation does not currently have any managing agents.
<% end %>
<% end %>
-<% if current_user.support? || current_user.data_coordinator? %>
+<% if (current_user.support? || current_user.data_coordinator?) && @organisation.active? %>
<%= govuk_button_link_to "Add a managing agent", managing_agents_add_organisation_path, html: { method: :get } %>
<% end %>
<% if @total_count != 0 %>
diff --git a/app/views/organisation_relationships/stock_owners.html.erb b/app/views/organisation_relationships/stock_owners.html.erb
index 4be22f7b9..41b7af06d 100644
--- a/app/views/organisation_relationships/stock_owners.html.erb
+++ b/app/views/organisation_relationships/stock_owners.html.erb
@@ -2,19 +2,35 @@
<% if current_user.support? %>
<%= render partial: "organisations/headings", locals: { main: @organisation.name, sub: nil } %>
<%= render SubNavigationComponent.new(items: secondary_items(request.path, @organisation.id)) %>
+ <% if !@organisation.active? %>
+ <%= govuk_notification_banner(title_text: "Important") do %>
+ This organisation can submit logs for its stock owners.
<% if @total_count == 0 %>
This organisation does not currently have any stock owners.
<% end %>
<% else %>
+ <% if !@organisation.active? %>
+ <%= govuk_notification_banner(title_text: "Important") do %>
+
+ You cannot add any new stock owners.
+ <% end %>
+ <% end %>
<%= render partial: "organisations/headings", locals: { main: "Your stock owners", sub: current_user.organisation.name } %>
Your organisation can submit logs for its stock owners.
<% if @total_count == 0 %>
You do not currently have any stock owners.
<% end %>
<% end %>
-<% if current_user.support? || current_user.data_coordinator? %>
+<% if (current_user.support? || current_user.data_coordinator?) && @organisation.active? %>
<%= govuk_button_link_to "Add a stock owner", stock_owners_add_organisation_path, html: { method: :get } %>
<% end %>
<% if @total_count != 0 %>
diff --git a/app/views/organisations/show.html.erb b/app/views/organisations/show.html.erb
index e2e07e28c..2dced52bd 100644
--- a/app/views/organisations/show.html.erb
+++ b/app/views/organisations/show.html.erb
@@ -40,3 +40,12 @@
<%= render partial: "organisations/merged_organisation_details" %>
+
+<% if OrganisationPolicy.new(current_user, @organisation).deactivate? %>
+ <%= govuk_button_link_to "Deactivate this organisation", deactivate_organisation_path(@organisation), warning: true %>
+<% end %>
+<% if OrganisationPolicy.new(current_user, @organisation).reactivate? %>
+
- <% if current_user.can_toggle_active?(@user) %>
+ <% if @user.organisation.active? && current_user.can_toggle_active?(@user) %>
+
<% if @user.active? %>
<%= govuk_button_link_to "Deactivate user", deactivate_user_path(@user), warning: true %>
<% if current_user.support? && @user.last_sign_in_at.nil? %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 079967095..68bea0c8f 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -34,6 +34,8 @@ en:
feedback_form: "https://forms.office.com/Pages/ResponsePage.aspx?id=EGg0v32c3kOociSi7zmVqC4YDsCJ3llAvEZelBFBLUBURFVUTzFDTUJPQlM4M0laTE5DTlNFSjJBQi4u"
organisation:
updated: "Organisation details updated"
+ reactivated: "%{organisation} has been reactivated."
+ deactivated: "%{organisation} has been deactivated."
user:
create_password: "Create a password to finish setting up your account"
reset_password: "Reset your password"
@@ -860,6 +862,9 @@ Make sure these answers are correct."
offered: "Times previously offered since becoming available"
warnings:
+ organisation:
+ deactivate: "All schemes and users at this organisation will be deactivated. All the organisation's relationships will be removed. It will no longer be possible to create logs for this organisation."
+ reactivate: "All schemes, users, and relationships that were active when this organisation was deactivated will be reactivated."
location:
deactivate:
existing_logs: "It will not be possible to add logs with this location if their tenancy start date is on or after the date you enter. Any existing logs may be affected."
diff --git a/config/routes.rb b/config/routes.rb
index 79dcf0a04..b6b362569 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -179,6 +179,8 @@ Rails.application.routes.draw do
post "managing-agents", to: "organisation_relationships#create_managing_agent"
delete "managing-agents", to: "organisation_relationships#delete_managing_agent"
get "merge-request", to: "organisations#merge_request"
+ get "deactivate", to: "organisations#deactivate"
+ get "reactivate", to: "organisations#reactivate"
end
end
diff --git a/db/migrate/20240304112411_add_reactivate_with_organisation_to_users.rb b/db/migrate/20240304112411_add_reactivate_with_organisation_to_users.rb
new file mode 100644
index 000000000..e66b3108a
--- /dev/null
+++ b/db/migrate/20240304112411_add_reactivate_with_organisation_to_users.rb
@@ -0,0 +1,5 @@
+class AddReactivateWithOrganisationToUsers < ActiveRecord::Migration[7.0]
+ def change
+ add_column :users, :reactivate_with_organisation, :boolean
+ end
+end
diff --git a/db/migrate/20240305112507_add_default_value_to_organisation_active_field.rb b/db/migrate/20240305112507_add_default_value_to_organisation_active_field.rb
new file mode 100644
index 000000000..8984b80b5
--- /dev/null
+++ b/db/migrate/20240305112507_add_default_value_to_organisation_active_field.rb
@@ -0,0 +1,12 @@
+class AddDefaultValueToOrganisationActiveField < ActiveRecord::Migration[7.0]
+ def up
+ change_column :organisations, :active, :boolean, default: true
+
+ execute "UPDATE organisations
+ SET active = true;"
+ end
+
+ def down
+ change_column :organisations, :active, :boolean
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index cca8b7f5c..bb13372cd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -453,7 +453,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do
t.string "managing_agents_label"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.boolean "active"
+ t.boolean "active", default: true
t.integer "old_association_type"
t.string "software_supplier_id"
t.string "housing_management_system"
@@ -764,6 +764,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do
t.string "unconfirmed_email"
t.boolean "initial_confirmation_sent"
t.datetime "discarded_at"
+ t.boolean "reactivate_with_organisation"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["encrypted_otp_secret_key"], name: "index_users_on_encrypted_otp_secret_key", unique: true
diff --git a/spec/models/form/lettings/questions/managing_organisation_spec.rb b/spec/models/form/lettings/questions/managing_organisation_spec.rb
index 86d58d4d3..45c089698 100644
--- a/spec/models/form/lettings/questions/managing_organisation_spec.rb
+++ b/spec/models/form/lettings/questions/managing_organisation_spec.rb
@@ -57,6 +57,7 @@ RSpec.describe Form::Lettings::Questions::ManagingOrganisation, type: :model do
let(:managing_org1) { create(:organisation, name: "Managing org 1") }
let(:managing_org2) { create(:organisation, name: "Managing org 2") }
let(:managing_org3) { create(:organisation, name: "Managing org 3") }
+ let(:inactive_managing_org) { create(:organisation, name: "Inactive managing org", active: false) }
let(:log) { create(:lettings_log, managing_organisation: managing_org1) }
let!(:org_rel1) do
@@ -76,7 +77,9 @@ RSpec.describe Form::Lettings::Questions::ManagingOrganisation, type: :model do
}
end
- it "shows current managing agent at top, followed by user's org (with hint), followed by the managing agents of the user's org" do
+ it "shows current managing agent at top, followed by user's org (with hint), followed by the active managing agents of the user's org" do
+ create(:organisation_relationship, parent_organisation: user.organisation, child_organisation: inactive_managing_org)
+
expect(question.displayed_answer_options(log, user)).to eq(options)
end
end
@@ -100,6 +103,10 @@ RSpec.describe Form::Lettings::Questions::ManagingOrganisation, type: :model do
create(:organisation_relationship, parent_organisation: log_owning_org, child_organisation: managing_org3)
end
+ before do
+ create(:organisation, name: "Inactive managing org", active: false)
+ end
+
context "when org owns stock" do
let(:options) do
{
@@ -111,7 +118,7 @@ RSpec.describe Form::Lettings::Questions::ManagingOrganisation, type: :model do
}
end
- it "shows current managing agent at top, followed by the current owning organisation (with hint), followed by the managing agents of the current owning organisation" do
+ it "shows current managing agent at top, followed by the current owning organisation (with hint), followed by the active managing agents of the current owning organisation" do
log_owning_org.update!(holds_own_stock: true)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
@@ -133,7 +140,7 @@ RSpec.describe Form::Lettings::Questions::ManagingOrganisation, type: :model do
org_rel2.child_organisation.update!(merge_date: Time.zone.local(2023, 8, 2), absorbing_organisation_id: log_owning_org.id)
end
- it "shows current managing agent at top, followed by the current owning organisation (with hint), followed by the managing agents of the current owning organisation" do
+ it "shows current managing agent at top, followed by the current owning organisation (with hint), followed by the active managing agents of the current owning organisation" do
log_owning_org.update!(holds_own_stock: true)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
@@ -149,7 +156,7 @@ RSpec.describe Form::Lettings::Questions::ManagingOrganisation, type: :model do
}
end
- it "shows current managing agent at top, followed by the managing agents of the current owning organisation" do
+ it "shows current managing agent at top, followed by the active managing agents of the current owning organisation" do
log_owning_org.update!(holds_own_stock: false)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
diff --git a/spec/models/form/lettings/questions/stock_owner_spec.rb b/spec/models/form/lettings/questions/stock_owner_spec.rb
index af899e4ab..cb600b986 100644
--- a/spec/models/form/lettings/questions/stock_owner_spec.rb
+++ b/spec/models/form/lettings/questions/stock_owner_spec.rb
@@ -46,6 +46,7 @@ RSpec.describe Form::Lettings::Questions::StockOwner, type: :model do
let(:owning_org_1) { create(:organisation, name: "Owning org 1") }
let(:owning_org_2) { create(:organisation, name: "Owning org 2") }
+ let(:inactive_owning_org) { create(:organisation, name: "Inactive owning org", active: false) }
let!(:org_rel) do
create(:organisation_relationship, child_organisation: user.organisation, parent_organisation: owning_org_2)
end
@@ -61,7 +62,8 @@ RSpec.describe Form::Lettings::Questions::StockOwner, type: :model do
}
end
- it "shows current stock owner at top, followed by user's org (with hint), followed by the stock owners of the user's org" do
+ it "shows current stock owner at top, followed by user's org (with hint), followed by the active stock owners of the user's org" do
+ create(:organisation_relationship, child_organisation: user.organisation, parent_organisation: inactive_owning_org)
user.organisation.update!(holds_own_stock: true)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
@@ -93,7 +95,8 @@ RSpec.describe Form::Lettings::Questions::StockOwner, type: :model do
}
end
- it "shows current stock owner at top, followed by the stock owners of the user's org" do
+ it "shows current stock owner at top, followed by the active stock active owners of the user's org" do
+ create(:organisation_relationship, child_organisation: user.organisation, parent_organisation: inactive_owning_org)
user.organisation.update!(holds_own_stock: false)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
@@ -203,21 +206,21 @@ RSpec.describe Form::Lettings::Questions::StockOwner, type: :model do
end
context "when user is support" do
- let(:user) { create(:user, :support) }
+ let!(:user) { create(:user, :support) }
+ let!(:log) { create(:lettings_log) }
- let(:log) { create(:lettings_log) }
+ it "shows active orgs where organisation holds own stock" do
+ non_stock_organisation = create(:organisation, name: "Non-stockholding org", holds_own_stock: false)
+ inactive_organisation = create(:organisation, name: "Inactive org", active: false)
- let(:non_stock_organisation) { create(:organisation, holds_own_stock: false) }
- let(:expected_opts) do
- Organisation.where(holds_own_stock: true).each_with_object(options) do |organisation, hsh|
+ expected_opts = Organisation.filter_by_active.where(holds_own_stock: true).each_with_object(options) do |organisation, hsh|
hsh[organisation.id] = organisation.name
hsh
end
- end
- it "shows orgs where organisation holds own stock" do
expect(question.displayed_answer_options(log, user)).to eq(expected_opts)
expect(question.displayed_answer_options(log, user)).not_to include(non_stock_organisation.id)
+ expect(question.displayed_answer_options(log, user)).not_to include(inactive_organisation.id)
end
context "and org has recently absorbed other orgs and does not have available from date" do
diff --git a/spec/models/form/sales/questions/managing_organisation_spec.rb b/spec/models/form/sales/questions/managing_organisation_spec.rb
index 716b1b917..30574e049 100644
--- a/spec/models/form/sales/questions/managing_organisation_spec.rb
+++ b/spec/models/form/sales/questions/managing_organisation_spec.rb
@@ -57,6 +57,7 @@ RSpec.describe Form::Sales::Questions::ManagingOrganisation, type: :model do
let(:managing_org1) { create(:organisation, name: "Managing org 1") }
let(:managing_org2) { create(:organisation, name: "Managing org 2") }
let(:managing_org3) { create(:organisation, name: "Managing org 3") }
+ let(:inactive_org) { create(:organisation, name: "Inactive org", active: false) }
let(:log) do
create(:lettings_log, owning_organisation: log_owning_org, managing_organisation: managing_org1,
@@ -80,7 +81,8 @@ RSpec.describe Form::Sales::Questions::ManagingOrganisation, type: :model do
}
end
- it "shows current managing agent at top, followed by the current owning organisation (with hint), followed by the managing agents of the current owning organisation" do
+ it "shows current managing agent at top, followed by the current owning organisation (with hint), followed by the active managing agents of the current owning organisation" do
+ create(:organisation_relationship, parent_organisation: log_owning_org, child_organisation: inactive_org)
log_owning_org.update!(holds_own_stock: true)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
@@ -96,7 +98,8 @@ RSpec.describe Form::Sales::Questions::ManagingOrganisation, type: :model do
}
end
- it "shows current managing agent at top, followed by the managing agents of the current owning organisation" do
+ it "shows current managing agent at top, followed by the active managing agents of the current owning organisation" do
+ create(:organisation_relationship, parent_organisation: log_owning_org, child_organisation: inactive_org)
log_owning_org.update!(holds_own_stock: false)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
diff --git a/spec/models/form/sales/questions/owning_organisation_id_spec.rb b/spec/models/form/sales/questions/owning_organisation_id_spec.rb
index 7f14824db..54a08299b 100644
--- a/spec/models/form/sales/questions/owning_organisation_id_spec.rb
+++ b/spec/models/form/sales/questions/owning_organisation_id_spec.rb
@@ -57,6 +57,7 @@ RSpec.describe Form::Sales::Questions::OwningOrganisationId, type: :model do
let(:owning_org_1) { create(:organisation, name: "Owning org 1") }
let(:owning_org_2) { create(:organisation, name: "Owning org 2") }
+ let(:inactive_owning_org) { create(:organisation, name: "Inactive owning org", active: false) }
let(:non_stock_owner) { create(:organisation, name: "Non stock owner", holds_own_stock: false) }
let(:log) { create(:lettings_log, owning_organisation: owning_org_1) }
@@ -75,7 +76,8 @@ RSpec.describe Form::Sales::Questions::OwningOrganisationId, type: :model do
}
end
- it "shows user organisation, current owning organisation and the stock owners that hold their stock" do
+ it "shows user organisation, current owning organisation and the activestock owners that hold their stock" do
+ create(:organisation_relationship, child_organisation: user.organisation, parent_organisation: inactive_owning_org)
user.organisation.update!(holds_own_stock: true)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
@@ -95,7 +97,8 @@ RSpec.describe Form::Sales::Questions::OwningOrganisationId, type: :model do
create(:organisation_relationship, child_organisation: user.organisation, parent_organisation: non_stock_owner)
end
- it "shows current owning organisation and the stock owners that hold their stock" do
+ it "shows current owning organisation and the active stock owners that hold their stock" do
+ create(:organisation_relationship, child_organisation: user.organisation, parent_organisation: inactive_owning_org)
user.organisation.update!(holds_own_stock: false)
expect(question.displayed_answer_options(log, user)).to eq(options)
end
@@ -204,20 +207,21 @@ RSpec.describe Form::Sales::Questions::OwningOrganisationId, type: :model do
context "when user is support" do
let(:user) { create(:user, :support, organisation: organisation_1) }
-
let(:log) { create(:lettings_log, created_by: user) }
- let(:non_stock_organisation) { create(:organisation, holds_own_stock: false) }
- let(:expected_opts) do
- Organisation.where(holds_own_stock: true).each_with_object(options) do |organisation, hsh|
+ it "shows active orgs where organisation holds own stock" do
+ non_stock_organisation = create(:organisation, holds_own_stock: false)
+ inactive_org = create(:organisation, active: false)
+
+ expected_opts = Organisation.filter_by_active.where(holds_own_stock: true).each_with_object(options) do |organisation, hsh|
hsh[organisation.id] = organisation.name
hsh
end
- end
- it "shows orgs where organisation holds own stock" do
expect(question.displayed_answer_options(log, user)).to eq(expected_opts)
expect(question.displayed_answer_options(log, user)).not_to include(non_stock_organisation.id)
+ expect(question.displayed_answer_options(log, user)).not_to include(inactive_org.id)
+ expect(question.displayed_answer_options(log, user)).to include(organisation_1.id)
end
context "when an org has recently absorbed other orgs" do
diff --git a/spec/models/location_spec.rb b/spec/models/location_spec.rb
index 58a101496..3bdc55b44 100644
--- a/spec/models/location_spec.rb
+++ b/spec/models/location_spec.rb
@@ -870,6 +870,11 @@ RSpec.describe Location, type: :model do
expect(location.status).to eq(:deactivating_soon)
end
+ it "returns deactivated if the owning organisation is deactivated" do
+ location.scheme.owning_organisation.active = false
+ expect(location.status).to eq(:deactivated)
+ end
+
it "returns deactivated if deactivation_date is in the past" do
FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 6), location:)
location.save!
@@ -969,6 +974,9 @@ RSpec.describe Location, type: :model do
end
describe "filter by status" do
+ let!(:deactivated_organisation) { FactoryBot.create(:organisation, active: false) }
+ let!(:deactivated_by_organisation_scheme) { FactoryBot.create(:scheme, owning_organisation: deactivated_organisation) }
+ let!(:deactivated_by_organisation_location) { FactoryBot.create(:location, scheme: deactivated_by_organisation_scheme) }
let!(:incomplete_location) { FactoryBot.create(:location, :incomplete, startdate: Time.zone.local(2022, 4, 1)) }
let!(:incomplete_location_with_nil_confirmed) { FactoryBot.create(:location, :incomplete, startdate: Time.zone.local(2022, 4, 1), confirmed: nil) }
let!(:active_location) { FactoryBot.create(:location, startdate: Time.zone.local(2022, 4, 1)) }
@@ -1015,8 +1023,9 @@ RSpec.describe Location, type: :model do
context "when filtering by deactivated status" do
it "returns only deactivated locations" do
- expect(described_class.filter_by_status(%w[deactivated]).count).to eq(1)
- expect(described_class.filter_by_status(%w[deactivated]).first).to eq(deactivated_location)
+ expect(described_class.filter_by_status(%w[deactivated]).count).to eq(2)
+ expect(described_class.filter_by_status(%w[deactivated])).to include(deactivated_location)
+ expect(described_class.filter_by_status(%w[deactivated])).to include(deactivated_by_organisation_location)
end
end
diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb
index ad9034d35..98b082c56 100644
--- a/spec/models/organisation_spec.rb
+++ b/spec/models/organisation_spec.rb
@@ -212,8 +212,8 @@ RSpec.describe Organisation, type: :model do
describe "scopes" do
before do
- create(:organisation, name: "Joe Bloggs")
- create(:organisation, name: "Tom Smith")
+ create(:organisation, name: "Joe Bloggs", active: false)
+ create(:organisation, name: "Tom Smith", active: true)
end
context "when searching by name" do
@@ -229,5 +229,42 @@ RSpec.describe Organisation, type: :model do
expect(described_class.search_by("joe").count).to eq(1)
end
end
+
+ context "when searching by active" do
+ it "returns only active records" do
+ results = described_class.filter_by_active
+ expect(results.count).to eq(1)
+ expect(results[0].name).to eq("Tom Smith")
+ end
+ end
+ end
+
+ describe "status" do
+ let!(:organisation) { create(:organisation) }
+
+ it "returns inactive when organisation inactive" do
+ organisation.active = false
+
+ expect(organisation.status).to be(:deactivated)
+ end
+
+ it "returns active when organisation active" do
+ organisation.active = true
+
+ expect(organisation.status).to be(:active)
+ end
+
+ it "returns merged when organisation merged in the past" do
+ organisation.merge_date = 1.month.ago
+
+ expect(organisation.status).to be(:merged)
+ end
+
+ it "does not return merged when organisation merges in the future" do
+ organisation.active = true
+ organisation.merge_date = Time.zone.now + 1.month
+
+ expect(organisation.status).to be(:active)
+ end
end
end
diff --git a/spec/models/scheme_spec.rb b/spec/models/scheme_spec.rb
index 9b663595c..c84be444f 100644
--- a/spec/models/scheme_spec.rb
+++ b/spec/models/scheme_spec.rb
@@ -112,11 +112,13 @@ RSpec.describe Scheme, type: :model do
end
context "when filtering by status" do
+ let!(:deactivated_organisation) { FactoryBot.create(:organisation, active: false) }
let!(:incomplete_scheme) { FactoryBot.create(:scheme, :incomplete, service_name: "name") }
let!(:incomplete_scheme_2) { FactoryBot.create(:scheme, :incomplete, service_name: "name") }
let!(:incomplete_scheme_with_nil_confirmed) { FactoryBot.create(:scheme, :incomplete, service_name: "name", confirmed: nil) }
let(:active_scheme) { FactoryBot.create(:scheme) }
let(:active_scheme_2) { FactoryBot.create(:scheme) }
+ let!(:deactivated_by_organisation_scheme) { FactoryBot.create(:scheme, owning_organisation: deactivated_organisation) }
let(:deactivating_soon_scheme) { FactoryBot.create(:scheme) }
let(:deactivating_soon_scheme_2) { FactoryBot.create(:scheme) }
let(:deactivated_scheme) { FactoryBot.create(:scheme) }
@@ -181,9 +183,10 @@ RSpec.describe Scheme, type: :model do
context "when filtering by deactivated status" do
it "returns only deactivated schemes" do
- expect(described_class.filter_by_status(%w[deactivated]).count).to eq(2)
+ expect(described_class.filter_by_status(%w[deactivated]).count).to eq(3)
expect(described_class.filter_by_status(%w[deactivated])).to include(deactivated_scheme)
expect(described_class.filter_by_status(%w[deactivated])).to include(deactivated_scheme_2)
+ expect(described_class.filter_by_status(%w[deactivated])).to include(deactivated_by_organisation_scheme)
end
end
@@ -231,6 +234,11 @@ RSpec.describe Scheme, type: :model do
expect(scheme.status).to eq(:deactivating_soon)
end
+ it "returns deactivated if the owning organisation is deactivated" do
+ scheme.owning_organisation.active = false
+ expect(scheme.status).to eq(:deactivated)
+ end
+
it "returns deactivated if deactivation_date is in the past" do
FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 6), scheme:)
scheme.reload
diff --git a/spec/policies/organisation_policy_spec.rb b/spec/policies/organisation_policy_spec.rb
new file mode 100644
index 000000000..4fb4c6761
--- /dev/null
+++ b/spec/policies/organisation_policy_spec.rb
@@ -0,0 +1,66 @@
+require "rails_helper"
+
+RSpec.describe OrganisationPolicy do
+ subject(:policy) { described_class }
+
+ let(:organisation) { FactoryBot.create(:organisation) }
+ let(:data_provider) { FactoryBot.create(:user, :data_provider) }
+ let(:data_coordinator) { FactoryBot.create(:user, :data_coordinator) }
+ let(:support) { FactoryBot.create(:user, :support) }
+
+ permissions :deactivate? do
+ it "does not permit data providers to deactivate an organisation" do
+ organisation.active = true
+ expect(policy).not_to permit(data_provider, organisation)
+ end
+
+ it "does not permit data coordinators to deactivate an organisation" do
+ organisation.active = true
+ expect(policy).not_to permit(data_coordinator, organisation)
+ end
+
+ it "permits support users to deactivate an active organisation" do
+ organisation.active = true
+ expect(policy).to permit(support, organisation)
+ end
+
+ it "does not permit support users to deactivate an inactive organisation" do
+ organisation.active = false
+ expect(policy).not_to permit(support, organisation)
+ end
+
+ it "does not permit support users to deactivate a merged organisation" do
+ organisation.active = true
+ organisation.merge_date = Time.zone.local(2023, 8, 2)
+ expect(policy).not_to permit(support, organisation)
+ end
+ end
+
+ permissions :reactivate? do
+ it "does not permit data providers to reactivate an organisation" do
+ organisation.active = false
+ expect(policy).not_to permit(data_provider, organisation)
+ end
+
+ it "does not permit data coordinators to reactivate an organisation" do
+ organisation.active = false
+ expect(policy).not_to permit(data_coordinator, organisation)
+ end
+
+ it "permits support users to reactivate an inactive organisation" do
+ organisation.active = false
+ expect(policy).to permit(support, organisation)
+ end
+
+ it "does not permit support users to reactivate an active organisation" do
+ organisation.active = true
+ expect(policy).not_to permit(support, organisation)
+ end
+
+ it "does not permit support users to reactivate a merged organisation" do
+ organisation.active = false
+ organisation.merge_date = Time.zone.local(2023, 8, 2)
+ expect(policy).not_to permit(support, organisation)
+ end
+ end
+end
diff --git a/spec/requests/organisation_relationships_controller_spec.rb b/spec/requests/organisation_relationships_controller_spec.rb
index 4c22a2aa2..feb687e0c 100644
--- a/spec/requests/organisation_relationships_controller_spec.rb
+++ b/spec/requests/organisation_relationships_controller_spec.rb
@@ -18,11 +18,13 @@ RSpec.describe OrganisationRelationshipsController, type: :request do
context "with an organisation that the user belongs to" do
let!(:stock_owner) { FactoryBot.create(:organisation) }
let!(:other_org_stock_owner) { FactoryBot.create(:organisation, name: "Foobar LTD") }
+ let!(:inactive_stock_owner) { FactoryBot.create(:organisation, name: "Inactive LTD", active: false) }
let!(:other_organisation) { FactoryBot.create(:organisation, name: "Foobar LTD 2") }
before do
FactoryBot.create(:organisation_relationship, child_organisation: organisation, parent_organisation: stock_owner)
FactoryBot.create(:organisation_relationship, child_organisation: other_organisation, parent_organisation: other_org_stock_owner)
+ FactoryBot.create(:organisation_relationship, child_organisation: organisation, parent_organisation: inactive_stock_owner)
get "/organisations/#{organisation.id}/stock-owners", headers:, params: {}
end
@@ -46,11 +48,18 @@ RSpec.describe OrganisationRelationshipsController, type: :request do
expect(page).not_to have_content(other_org_stock_owner.name)
end
+ it "does not show inactive stock owners" do
+ expect(page).not_to have_content(inactive_stock_owner.name)
+ end
+
it "shows the pagination count" do
expect(page).to have_content("1 total stock owners")
end
context "when adding a stock owner" do
+ let!(:active_organisation) { FactoryBot.create(:organisation, name: "Active Org", active: true) }
+ let!(:inactive_organisation) { FactoryBot.create(:organisation, name: "Inactive LTD", active: false) }
+
before do
get "/organisations/#{organisation.id}/stock-owners/add", headers:, params: {}
end
@@ -66,6 +75,27 @@ RSpec.describe OrganisationRelationshipsController, type: :request do
it "shows a cancel button" do
expect(page).to have_link("Cancel", href: "/organisations/#{organisation.id}/stock-owners")
end
+
+ it "includes only active organisations as options" do
+ expect(response.body).to include(active_organisation.name)
+ expect(response.body).not_to include(inactive_organisation.name)
+ end
+ end
+
+ context "and current organisation is deactivated" do
+ before do
+ organisation.update!(active: false)
+ get "/organisations/#{organisation.id}/stock-owners", headers:, params: {}
+ end
+
+ it "does not show the add stock owner button" do
+ expect(page).not_to have_link("Add a stock owner")
+ end
+
+ it "shows a banner" do
+ expect(page).to have_content("This organisation is deactivated.")
+ expect(page).to have_content("You cannot add any new stock owners.")
+ end
end
end
@@ -84,11 +114,13 @@ RSpec.describe OrganisationRelationshipsController, type: :request do
context "with an organisation that the user belongs to" do
let!(:managing_agent) { FactoryBot.create(:organisation) }
let!(:other_org_managing_agent) { FactoryBot.create(:organisation, name: "Foobar LTD") }
+ let!(:inactive_managing_agent) { FactoryBot.create(:organisation, name: "Inactive LTD", active: false) }
let!(:other_organisation) { FactoryBot.create(:organisation, name: "Foobar LTD") }
before do
FactoryBot.create(:organisation_relationship, parent_organisation: organisation, child_organisation: managing_agent)
FactoryBot.create(:organisation_relationship, parent_organisation: other_organisation, child_organisation: other_org_managing_agent)
+ FactoryBot.create(:organisation_relationship, parent_organisation: organisation, child_organisation: inactive_managing_agent)
get "/organisations/#{organisation.id}/managing-agents", headers:, params: {}
end
@@ -112,12 +144,35 @@ RSpec.describe OrganisationRelationshipsController, type: :request do
expect(page).not_to have_content(other_org_managing_agent.name)
end
+ it "does not show inactive managing-agents" do
+ expect(page).not_to have_content(inactive_managing_agent.name)
+ end
+
it "shows the pagination count" do
expect(page).to have_content("1 total managing agents")
end
+
+ context "and current organisation is deactivated" do
+ before do
+ organisation.update!(active: false)
+ get "/organisations/#{organisation.id}/managing-agents", headers:, params: {}
+ end
+
+ it "does not show the add managing agent button" do
+ expect(page).not_to have_link("Add a managing agent")
+ end
+
+ it "shows a banner" do
+ expect(page).to have_content("This organisation is deactivated.")
+ expect(page).to have_content("You cannot add any new managing agents.")
+ end
+ end
end
context "when adding a managing agent" do
+ let!(:active_organisation) { FactoryBot.create(:organisation, name: "Active Org", active: true) }
+ let!(:inactive_organisation) { FactoryBot.create(:organisation, name: "Inactive LTD", active: false) }
+
before do
get "/organisations/#{organisation.id}/managing-agents/add", headers:, params: {}
end
@@ -125,6 +180,11 @@ RSpec.describe OrganisationRelationshipsController, type: :request do
it "has the correct header" do
expect(response.body).to include("What is the name of your managing agent?")
end
+
+ it "includes only active organisations as options" do
+ expect(response.body).to include(active_organisation.name)
+ expect(response.body).not_to include(inactive_organisation.name)
+ end
end
context "with an organisation that are not in scope for the user, i.e. that they do not belong to" do
diff --git a/spec/requests/organisations_controller_spec.rb b/spec/requests/organisations_controller_spec.rb
index 53e830592..fa5163003 100644
--- a/spec/requests/organisations_controller_spec.rb
+++ b/spec/requests/organisations_controller_spec.rb
@@ -579,6 +579,32 @@ RSpec.describe OrganisationsController, type: :request do
expect(whodunnit_actor).to be_a(User)
expect(whodunnit_actor.id).to eq(user.id)
end
+
+ context "with active parameter true" do
+ let(:params) do
+ {
+ id: organisation.id,
+ organisation: { active: "true" },
+ }
+ end
+
+ it "redirects" do
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
+ context "with active parameter false" do
+ let(:params) do
+ {
+ id: organisation.id,
+ organisation: { active: "false" },
+ }
+ end
+
+ it "redirects" do
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
end
context "with an organisation that the user does not belong to" do
@@ -1407,6 +1433,100 @@ RSpec.describe OrganisationsController, type: :request do
end
end
+ describe "#update" do
+ context "with active parameter false" do
+ let(:params) { { id: organisation.id, organisation: { active: "false" } } }
+
+ user_to_update = nil
+
+ before do
+ user_to_update = create(:user, :data_coordinator, organisation:)
+ patch "/organisations/#{organisation.id}", headers:, params:
+ end
+
+ it "deactivates associated users" do
+ user_to_update.reload
+ expect(user_to_update.active).to eq(false)
+ expect(user_to_update.reactivate_with_organisation).to eq(true)
+ end
+ end
+
+ context "with active parameter true" do
+ user_to_reactivate = nil
+ user_not_to_reactivate = nil
+
+ let(:params) do
+ {
+ id: organisation.id,
+ organisation: { active: "true" },
+ }
+ end
+ let(:notify_client) { instance_double(Notifications::Client) }
+ let(:devise_notify_mailer) { DeviseNotifyMailer.new }
+
+ let(:expected_personalisation) do
+ {
+ name: user_to_reactivate.name,
+ email: user_to_reactivate.email,
+ organisation: organisation.name,
+ link: include("/account/confirmation?confirmation_token="),
+ }
+ end
+
+ before do
+ allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer)
+ allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client)
+ allow(notify_client).to receive(:send_email).and_return(true)
+
+ user_to_reactivate = create(:user, :data_coordinator, organisation:, active: false, reactivate_with_organisation: true)
+ user_not_to_reactivate = create(:user, :data_coordinator, organisation:, active: false, reactivate_with_organisation: false)
+ patch "/organisations/#{organisation.id}", headers:, params:
+ end
+
+ it "reactivates users deactivated with organisation" do
+ user_to_reactivate.reload
+ user_not_to_reactivate.reload
+ expect(user_to_reactivate.active).to eq(true)
+ expect(user_to_reactivate.reactivate_with_organisation).to eq(false)
+ expect(user_not_to_reactivate.active).to eq(false)
+ end
+
+ it "sends invitation emails" do
+ expect(notify_client).to have_received(:send_email).with(email_address: user_to_reactivate.email, template_id: User::BETA_ONBOARDING_TEMPLATE_ID, personalisation: expected_personalisation).once
+ end
+ end
+ end
+
+ describe "#deactivate" do
+ before do
+ get "/organisations/#{organisation.id}/deactivate", headers:, params: {}
+ end
+
+ it "shows deactivation page with deactivate and cancel buttons for the organisation" do
+ expect(path).to include("/organisations/#{organisation.id}/deactivate")
+ expect(page).to have_content(organisation.name)
+ expect(page).to have_content("Are you sure you want to deactivate this organisation?")
+ expect(page).to have_button("Deactivate this organisation")
+ expect(page).to have_link("Cancel", href: "/organisations/#{organisation.id}")
+ end
+ end
+
+ describe "#reactivate" do
+ let(:inactive_organisation) { create(:organisation, name: "Inactive org", active: false) }
+
+ before do
+ get "/organisations/#{inactive_organisation.id}/reactivate", headers:, params: {}
+ end
+
+ it "shows reactivation page with reactivate and cancel buttons for the organisation" do
+ expect(path).to include("/organisations/#{inactive_organisation.id}/reactivate")
+ expect(page).to have_content(inactive_organisation.name)
+ expect(page).to have_content("Are you sure you want to reactivate this organisation?")
+ expect(page).to have_button("Reactivate this organisation")
+ expect(page).to have_link("Cancel", href: "/organisations/#{inactive_organisation.id}")
+ end
+ end
+
describe "#create" do
let(:name) { " Unique new org name" }
let(:address_line1) { "12 Random Street" }
diff --git a/spec/views/locations/show.html.erb_spec.rb b/spec/views/locations/show.html.erb_spec.rb
index c2510c79b..9caa079e0 100644
--- a/spec/views/locations/show.html.erb_spec.rb
+++ b/spec/views/locations/show.html.erb_spec.rb
@@ -1,50 +1,51 @@
require "rails_helper"
RSpec.describe "locations/show.html.erb" do
- context "when a data provider" do
- let(:user) { create(:user) }
+ let(:scheme) do
+ instance_double(
+ Scheme,
+ owning_organisation: user.organisation,
+ id: 1,
+ service_name: "some name",
+ id_to_display: "S1",
+ sensitive: false,
+ scheme_type: "some type",
+ registered_under_care_act: false,
+ arrangement_type: "some other type",
+ primary_client_group: false,
+ has_other_client_group: false,
+ secondary_client_group: false,
+ support_type: "some support type",
+ intended_stay: "some intended stay",
+ available_from: 1.week.ago,
+ scheme_deactivation_periods: [],
+ status: :active,
+ )
+ end
- let(:scheme) do
- instance_double(
- Scheme,
- owning_organisation: user.organisation,
- id: 1,
- service_name: "some name",
- id_to_display: "S1",
- sensitive: false,
- scheme_type: "some type",
- registered_under_care_act: false,
- arrangement_type: "some other type",
- primary_client_group: false,
- has_other_client_group: false,
- secondary_client_group: false,
- support_type: "some support type",
- intended_stay: "some intended stay",
- available_from: 1.week.ago,
- scheme_deactivation_periods: [],
- status: :active,
- )
- end
+ let(:location) do
+ instance_double(
+ Location,
+ id: 5,
+ name: "some location",
+ postcode: "EC1N 2TD",
+ linked_local_authorities: [],
+ units: "",
+ type_of_unit: "",
+ mobility_type: "",
+ available_from: 1.week.ago,
+ location_deactivation_periods: [],
+ status: :active,
+ active?: true,
+ scheme:,
+ deactivates_in_a_long_time?: false,
+ is_la_inferred: nil,
+ deactivated?: false,
+ )
+ end
- let(:location) do
- instance_double(
- Location,
- id: 5,
- name: "some location",
- postcode: "EC1N 2TD",
- linked_local_authorities: [],
- units: "",
- type_of_unit: "",
- mobility_type: "",
- available_from: 1.week.ago,
- location_deactivation_periods: [],
- status: :active,
- active?: true,
- scheme:,
- deactivates_in_a_long_time?: false,
- is_la_inferred: nil,
- )
- end
+ context "when a data provider" do
+ let(:user) { create(:user) }
it "does not see add a location button" do
assign(:scheme, scheme)
@@ -70,4 +71,32 @@ RSpec.describe "locations/show.html.erb" do
expect(rendered).not_to have_content("Change")
end
end
+
+ context "when a support user" do
+ let(:user) { create(:user, role: "support") }
+
+ it "sees deactivate scheme location button" do
+ assign(:scheme, scheme)
+ assign(:location, location)
+
+ allow(view).to receive(:current_user).and_return(user)
+
+ render
+
+ expect(rendered).to have_content("Deactivate this location")
+ end
+
+ it "does not see deactivate scheme location button when organisation is deactivated" do
+ user.organisation.active = false
+
+ assign(:scheme, scheme)
+ assign(:location, location)
+
+ allow(view).to receive(:current_user).and_return(user)
+
+ render
+
+ expect(rendered).not_to have_content("Deactivate this location")
+ end
+ end
end
diff --git a/spec/views/organisations/show.html.erb_spec.rb b/spec/views/organisations/show.html.erb_spec.rb
index 119462349..de4996c36 100644
--- a/spec/views/organisations/show.html.erb_spec.rb
+++ b/spec/views/organisations/show.html.erb_spec.rb
@@ -113,6 +113,20 @@ RSpec.describe "organisations/show.html.erb" do
expect(fragment).to have_link(text: "View agreement", href: "/organisations/#{organisation_with_dsa.id}/data-sharing-agreement")
end
end
+
+ it "shows deactivate button when organisation is active" do
+ user.organisation.active = true
+ render
+ expect(fragment).to have_content("Deactivate this organisation")
+ expect(fragment).not_to have_content("Reactivate this organisation")
+ end
+
+ it "shows reactivate button when organisation is inactive" do
+ user.organisation.active = false
+ render
+ expect(fragment).not_to have_content("Deactivate this organisation")
+ expect(fragment).to have_content("Reactivate this organisation")
+ end
end
context "when not dpo" do
diff --git a/spec/views/schemes/show.html.erb_spec.rb b/spec/views/schemes/show.html.erb_spec.rb
index 4a0447c11..797a95d60 100644
--- a/spec/views/schemes/show.html.erb_spec.rb
+++ b/spec/views/schemes/show.html.erb_spec.rb
@@ -1,10 +1,15 @@
require "rails_helper"
RSpec.describe "schemes/show.html.erb" do
+ let(:organisation) { create(:organisation, holds_own_stock: true) }
+ let(:scheme) { create(:scheme, owning_organisation: organisation, confirmed: true) }
+
+ before do
+ create(:location, scheme:, confirmed: true)
+ end
+
context "when data provider" do
- let(:organisation) { create(:organisation, holds_own_stock: true) }
let(:user) { build(:user, organisation:) }
- let(:scheme) { create(:scheme, owning_organisation: user.organisation) }
it "does not render button to deactivate schemes" do
assign(:scheme, scheme)
@@ -26,4 +31,29 @@ RSpec.describe "schemes/show.html.erb" do
expect(rendered).not_to have_content("Change")
end
end
+
+ context "when support" do
+ let(:user) { build(:user, organisation:, role: "support") }
+
+ it "renders button to deactivate scheme" do
+ assign(:scheme, scheme)
+
+ allow(view).to receive(:current_user).and_return(user)
+
+ render
+
+ expect(rendered).to have_content("Deactivate this scheme")
+ end
+
+ it "does not render button to deactivate scheme if organisation is deactivated" do
+ organisation.active = false
+ assign(:scheme, scheme)
+
+ allow(view).to receive(:current_user).and_return(user)
+
+ render
+
+ expect(rendered).not_to have_content("Deactivate this scheme")
+ end
+ end
end