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..67da27c9b 100644 --- a/app/controllers/organisations_controller.rb +++ b/app/controllers/organisations_controller.rb @@ -94,10 +94,40 @@ 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") + if org_params[:active] == "false" + @organisation.users.filter_by_active + .update_all( + active: false, + confirmed_at: nil, + sign_in_count: 0, + initial_confirmation_sent: false, + reactivate_with_organisation: true) + flash[:notice] = I18n.t("organisation.deactivated", organisation: @organisation.name) + elsif org_params[:active] == "true" + users_to_reactivate = @organisation.users.where(reactivate_with_organisation: true) + users_to_reactivate.each do |user| + user.update(active: true, reactivate_with_organisation: false) + 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 +269,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/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..04dd969fa 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? 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..250529492 100644 --- a/app/models/location.rb +++ b/app/models/location.rb @@ -142,7 +142,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..dcb9a29ea 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -37,6 +37,7 @@ 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 :merged_during_open_collection_period, -> { where("merge_date >= ?", FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period) } has_paper_trail @@ -138,6 +139,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..a912250a9 100644 --- a/app/models/scheme.rb +++ b/app/models/scheme.rb @@ -268,7 +268,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/policies/organisation_policy.rb b/app/policies/organisation_policy.rb new file mode 100644 index 000000000..4e0e2c1b0 --- /dev/null +++ b/app/policies/organisation_policy.rb @@ -0,0 +1,17 @@ +class OrganisationPolicy + attr_reader :user, :organisation + + def initialize(user, organisation) + @user = user + @organisation = organisation + end + + %w[ + deactivate? + reactivate? + ].each do |method_name| + define_method method_name do + user.support? + end + 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/organisations/show.html.erb b/app/views/organisations/show.html.erb index e2e07e28c..824922639 100644 --- a/app/views/organisations/show.html.erb +++ b/app/views/organisations/show.html.erb @@ -40,3 +40,15 @@ <%= render partial: "organisations/merged_organisation_details" %> + +<% if @organisation.active? %> + <% if OrganisationPolicy.new(current_user, @organisation).deactivate? %> + <%= govuk_button_link_to "Deactivate this organisation", deactivate_organisation_path(@organisation), warning: true %> + <% end %> +<% else %> + <% if OrganisationPolicy.new(current_user, @organisation).reactivate? %> + + <%= govuk_button_link_to "Reactivate this organisation", reactivate_organisation_path(@organisation) %> + + <% end %> +<% end %> diff --git a/app/views/organisations/toggle_active.html.erb b/app/views/organisations/toggle_active.html.erb new file mode 100644 index 000000000..075da6029 --- /dev/null +++ b/app/views/organisations/toggle_active.html.erb @@ -0,0 +1,25 @@ +<% title = "#{action.humanize} #{@organisation.name}" %> +<% content_for :title, title %> + +<% content_for :before_content do %> + <%= govuk_back_link( + href: organisation_path(@organisation), + ) %> +<% end %> + +<%= form_for(@organisation, as: :organisation, html: { method: :patch }) do |f| %> +
+
+

+ <%= @organisation.name %> + Are you sure you want to <%= action %> this organisation? +

+ <%= govuk_warning_text text: I18n.t("warnings.organisation.#{action}") %> + + <% active_value = action != "deactivate" %> + <%= f.hidden_field :active, value: active_value %> + + <%= f.govuk_submit "#{action.capitalize} this organisation" %> +
+
+<% end %> diff --git a/app/views/schemes/show.html.erb b/app/views/schemes/show.html.erb index 31ca1cba9..1aefadef5 100644 --- a/app/views/schemes/show.html.erb +++ b/app/views/schemes/show.html.erb @@ -49,7 +49,7 @@ -<% if SchemePolicy.new(current_user, @scheme).deactivate? %> +<% if @scheme.owning_organisation.active? && SchemePolicy.new(current_user, @scheme).deactivate? %> <%= toggle_scheme_link(@scheme) %> <% end %> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 0465f67bb..925f1ada7 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -31,7 +31,7 @@ <% if current_user.support? %> <% null_option = [OpenStruct.new(id: "", name: "Select an option")] %> - <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> + <% organisations = Organisation.filter_by_active.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> <% answer_options = null_option + organisations %> <% if @organisation_id %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index a93532e7b..c62fccf2c 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -127,8 +127,8 @@ end %> <% end %> -
- <% 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..1ec17cb48 --- /dev/null +++ b/db/migrate/20240305112507_add_default_value_to_organisation_active_field.rb @@ -0,0 +1,8 @@ +class AddDefaultValueToOrganisationActiveField < ActiveRecord::Migration[7.0] + def change + change_column :organisations, :active, :boolean, :default => true + + execute "UPDATE organisations + SET active = true;" + 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