diff --git a/app/controllers/locations_controller.rb b/app/controllers/locations_controller.rb index 7955ec944..b25f951ea 100644 --- a/app/controllers/locations_controller.rb +++ b/app/controllers/locations_controller.rb @@ -20,22 +20,35 @@ class LocationsController < ApplicationController def show; end - def deactivate + def new_deactivation if params[:location].blank? render "toggle_active", locals: { action: "deactivate" } - elsif params[:location][:confirm].present? && params[:location][:deactivation_date].present? - confirm_deactivation else - deactivation_date_errors - if @location.errors.present? - @location.deactivation_date_type = params[:location][:deactivation_date_type] - render "toggle_active", locals: { action: "deactivate" }, status: :unprocessable_entity + @location.run_deactivation_validations! + @location.deactivation_date = deactivation_date + @location.deactivation_date_type = params[:location][:deactivation_date_type] + if @location.valid? + redirect_to scheme_location_deactivate_confirm_path(@location, deactivation_date: @location.deactivation_date, deactivation_date_type: @location.deactivation_date_type) else - render "toggle_active_confirm", locals: { action: "deactivate", deactivation_date: } + render "toggle_active", locals: { action: "deactivate" }, status: :unprocessable_entity end end end + def deactivate_confirm + @deactivation_date = params[:deactivation_date] + @deactivation_date_type = params[:deactivation_date_type] + end + + def deactivate + @location.run_deactivation_validations! + + if @location.update!(deactivation_date:) + flash[:notice] = deactivate_success_notice + end + redirect_to scheme_location_path(@scheme, @location) + end + def reactivate render "toggle_active", locals: { action: "reactivate" } end @@ -148,13 +161,13 @@ private end def authenticate_action! - if %w[new edit update create index edit_name edit_local_authority deactivate].include?(action_name) && !((current_user.organisation == @scheme&.owning_organisation) || current_user.support?) + if %w[new edit update create index edit_name edit_local_authority new_deactivation deactivate_confirm deactivate].include?(action_name) && !((current_user.organisation == @scheme&.owning_organisation) || current_user.support?) render_not_found and return end end def location_params - required_params = params.require(:location).permit(:postcode, :name, :units, :type_of_unit, :add_another_location, :startdate, :mobility_type, :location_admin_district, :location_code).merge(scheme_id: @scheme.id) + required_params = params.require(:location).permit(:postcode, :name, :units, :type_of_unit, :add_another_location, :startdate, :mobility_type, :location_admin_district, :location_code, :deactivation_date).merge(scheme_id: @scheme.id) required_params[:postcode] = PostcodeService.clean(required_params[:postcode]) if required_params[:postcode] required_params end @@ -167,48 +180,29 @@ private location_params["location_admin_district"] != "Select an option" end - def confirm_deactivation - if @location.update(deactivation_date: params[:location][:deactivation_date]) - flash[:notice] = "#{@location.name || @location.postcode} has been deactivated" - end - redirect_to scheme_location_path(@scheme, @location) - end - - def deactivation_date_errors - if params[:location][:deactivation_date].blank? && params[:location][:deactivation_date_type].blank? - @location.errors.add(:deactivation_date_type, message: I18n.t("validations.location.deactivation_date.not_selected")) - end - - if params[:location][:deactivation_date_type] == "other" - day = params[:location]["deactivation_date(3i)"] - month = params[:location]["deactivation_date(2i)"] - year = params[:location]["deactivation_date(1i)"] - - collection_start_date = FormHandler.instance.current_collection_start_date - - if [day, month, year].any?(&:blank?) - { day:, month:, year: }.each do |period, value| - @location.errors.add(:deactivation_date, message: I18n.t("validations.location.deactivation_date.not_entered", period: period.to_s)) if value.blank? - end - elsif !Date.valid_date?(year.to_i, month.to_i, day.to_i) - @location.errors.add(:deactivation_date, message: I18n.t("validations.location.deactivation_date.invalid")) - elsif !Date.new(year.to_i, month.to_i, day.to_i).between?(collection_start_date, Date.new(2200, 1, 1)) - @location.errors.add(:deactivation_date, message: I18n.t("validations.location.deactivation_date.out_of_range", date: collection_start_date.to_formatted_s(:govuk_date))) - end + def deactivate_success_notice + case @location.status + when :deactivated + "#{@location.name} has been deactivated" + when :deactivating_soon + "#{@location.name} will deactivate on #{@location.deactivation_date.to_formatted_s(:govuk_date)}" end end def deactivation_date - return if params[:location].blank? - - collection_start_date = FormHandler.instance.current_collection_start_date - return collection_start_date if params[:location][:deactivation_date_type] == "default" - return params[:location][:deactivation_date] if params[:location][:deactivation_date_type].blank? + if params[:location].blank? + return + elsif params[:location][:deactivation_date_type] == "default" + return FormHandler.instance.current_collection_start_date + elsif params[:location][:deactivation_date].present? + return params[:location][:deactivation_date] + end day = params[:location]["deactivation_date(3i)"] month = params[:location]["deactivation_date(2i)"] year = params[:location]["deactivation_date(1i)"] + return nil if [day, month, year].any?(&:blank?) - Date.new(year.to_i, month.to_i, day.to_i) + Time.zone.local(year.to_i, month.to_i, day.to_i) if Date.valid_date?(year.to_i, month.to_i, day.to_i) end end diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb index 9a259e3a1..6766ffe85 100644 --- a/app/controllers/schemes_controller.rb +++ b/app/controllers/schemes_controller.rb @@ -21,6 +21,39 @@ class SchemesController < ApplicationController render_not_found and return unless @scheme end + def new_deactivation + if params[:scheme].blank? + render "toggle_active", locals: { action: "deactivate" } + else + @scheme.run_deactivation_validations = true + @scheme.deactivation_date = deactivation_date + @scheme.deactivation_date_type = params[:scheme][:deactivation_date_type] + if @scheme.valid? + redirect_to scheme_deactivate_confirm_path(@scheme, deactivation_date: @scheme.deactivation_date, deactivation_date_type: @scheme.deactivation_date_type) + else + render "toggle_active", locals: { action: "deactivate" }, status: :unprocessable_entity + end + end + end + + def deactivate_confirm + @deactivation_date = params[:deactivation_date] + @deactivation_date_type = params[:deactivation_date_type] + end + + def deactivate + @scheme.run_deactivation_validations! + + if @scheme.update!(deactivation_date:) + flash[:notice] = deactivate_success_notice + end + redirect_to scheme_details_path(@scheme) + end + + def reactivate + render "toggle_active", locals: { action: "reactivate" } + end + def new @scheme = Scheme.new end @@ -206,7 +239,8 @@ private :support_type, :arrangement_type, :intended_stay, - :confirmed) + :confirmed, + :deactivation_date) if arrangement_type_changed_to_different_org?(required_params) required_params[:managing_organisation_id] = nil @@ -251,7 +285,7 @@ private def authenticate_scope! head :unauthorized and return unless current_user.data_coordinator? || current_user.support? - if %w[show locations primary_client_group confirm_secondary_client_group secondary_client_group support details check_answers edit_name].include?(action_name) && !((current_user.organisation == @scheme&.owning_organisation) || current_user.support?) + if %w[show locations primary_client_group confirm_secondary_client_group secondary_client_group support details check_answers edit_name deactivate].include?(action_name) && !((current_user.organisation == @scheme&.owning_organisation) || current_user.support?) render_not_found and return end end @@ -259,4 +293,30 @@ private def redirect_if_scheme_confirmed redirect_to @scheme if @scheme.confirmed? end + + def deactivate_success_notice + case @scheme.status + when :deactivated + "#{@scheme.service_name} has been deactivated" + when :deactivating_soon + "#{@scheme.service_name} will deactivate on #{@scheme.deactivation_date.to_formatted_s(:govuk_date)}" + end + end + + def deactivation_date + if params[:scheme].blank? + return + elsif params[:scheme][:deactivation_date_type] == "default" + return FormHandler.instance.current_collection_start_date + elsif params[:scheme][:deactivation_date].present? + return params[:scheme][:deactivation_date] + end + + day = params[:scheme]["deactivation_date(3i)"] + month = params[:scheme]["deactivation_date(2i)"] + year = params[:scheme]["deactivation_date(1i)"] + return nil if [day, month, year].any?(&:blank?) + + Time.zone.local(year.to_i, month.to_i, day.to_i) if Date.valid_date?(year.to_i, month.to_i, day.to_i) + end end diff --git a/app/helpers/locations_helper.rb b/app/helpers/locations_helper.rb index e21a4724e..2a02ebc94 100644 --- a/app/helpers/locations_helper.rb +++ b/app/helpers/locations_helper.rb @@ -23,7 +23,7 @@ module LocationsHelper resource.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } end - def display_attributes(location) + def display_location_attributes(location) [ { name: "Postcode", value: location.postcode }, { name: "Local authority", value: location.location_admin_district }, diff --git a/app/helpers/schemes_helper.rb b/app/helpers/schemes_helper.rb new file mode 100644 index 000000000..0a042528b --- /dev/null +++ b/app/helpers/schemes_helper.rb @@ -0,0 +1,26 @@ +module SchemesHelper + def display_scheme_attributes(scheme) + base_attributes = [ + { name: "Scheme code", value: scheme.id_to_display }, + { name: "Name", value: scheme.service_name, edit: true }, + { name: "Confidential information", value: scheme.sensitive, edit: true }, + { name: "Type of scheme", value: scheme.scheme_type }, + { name: "Registered under Care Standards Act 2000", value: scheme.registered_under_care_act }, + { name: "Housing stock owned by", value: scheme.owning_organisation.name, edit: true }, + { name: "Support services provided by", value: scheme.arrangement_type }, + { name: "Organisation providing support", value: scheme.managing_organisation&.name }, + { name: "Primary client group", value: scheme.primary_client_group }, + { name: "Has another client group", value: scheme.has_other_client_group }, + { name: "Secondary client group", value: scheme.secondary_client_group }, + { name: "Level of support given", value: scheme.support_type }, + { name: "Intended length of stay", value: scheme.intended_stay }, + { name: "Availability", value: "Available from #{scheme.available_from.to_formatted_s(:govuk_date)}" }, + { name: "Status", value: scheme.status }, + ] + + if scheme.arrangement_type_same? + base_attributes.delete({ name: "Organisation providing support", value: scheme.managing_organisation&.name }) + end + base_attributes + end +end diff --git a/app/helpers/tag_helper.rb b/app/helpers/tag_helper.rb index 2ea23a86a..6682f97fd 100644 --- a/app/helpers/tag_helper.rb +++ b/app/helpers/tag_helper.rb @@ -7,7 +7,9 @@ module TagHelper in_progress: "In progress", completed: "Completed", active: "Active", + incomplete: "Incomplete", deactivating_soon: "Deactivating soon", + reactivating_soon: "Reactivating soon", deactivated: "Deactivated", }.freeze @@ -17,7 +19,9 @@ module TagHelper in_progress: "blue", completed: "green", active: "green", + incomplete: "red", deactivating_soon: "yellow", + reactivating_soon: "blue", deactivated: "grey", }.freeze diff --git a/app/models/form_handler.rb b/app/models/form_handler.rb index c080e6e9b..61b981436 100644 --- a/app/models/form_handler.rb +++ b/app/models/form_handler.rb @@ -50,7 +50,7 @@ class FormHandler end def current_collection_start_date - Time.utc(current_collection_start_year, 4, 1) + Time.zone.local(current_collection_start_year, 4, 1) end def form_name_from_start_year(year, type) diff --git a/app/models/location.rb b/app/models/location.rb index ab1c3620a..2df620292 100644 --- a/app/models/location.rb +++ b/app/models/location.rb @@ -1,5 +1,6 @@ class Location < ApplicationRecord validate :validate_postcode + validate :deactivation_date_errors validates :units, :type_of_unit, :mobility_type, presence: true belongs_to :scheme has_many :lettings_logs, class_name: "LettingsLog" @@ -10,7 +11,7 @@ class Location < ApplicationRecord auto_strip_attributes :name - attr_accessor :add_another_location, :deactivation_date_type + attr_accessor :add_another_location, :deactivation_date_type, :run_deactivation_validations scope :search_by_postcode, ->(postcode) { where("REPLACE(postcode, ' ', '') ILIKE ?", "%#{postcode.delete(' ')}%") } scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") } @@ -375,7 +376,37 @@ class Location < ApplicationRecord def status return :active if deactivation_date.blank? return :deactivating_soon if Time.zone.now < deactivation_date - return :deactivated if Time.zone.now >= deactivation_date + + :deactivated + end + + def active? + status == :active + end + + def run_deactivation_validations! + @run_deactivation_validations = true + end + + def implicit_run_deactivation_validations + deactivation_date.present? || @run_deactivation_validations + end + + def deactivation_date_errors + return unless implicit_run_deactivation_validations + + if deactivation_date.blank? + if deactivation_date_type.blank? + errors.add(:deactivation_date_type, message: I18n.t("validations.location.deactivation_date.not_selected")) + elsif deactivation_date_type == "other" + errors.add(:deactivation_date, message: I18n.t("validations.location.deactivation_date.invalid")) + end + else + collection_start_date = FormHandler.instance.current_collection_start_date + unless deactivation_date.between?(collection_start_date, Date.new(2200, 1, 1)) + errors.add(:deactivation_date, message: I18n.t("validations.location.deactivation_date.out_of_range", date: collection_start_date.to_formatted_s(:govuk_date))) + end + end end private diff --git a/app/models/organisation.rb b/app/models/organisation.rb index e420ca9d8..cc0df4ef6 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -77,7 +77,7 @@ class Organisation < ApplicationRecord DISPLAY_PROVIDER_TYPE[provider_type.to_sym] end - def display_attributes + def display_organisation_attributes [ { name: "Name", value: name, editable: true }, { name: "Address", value: address_string, editable: true }, diff --git a/app/models/scheme.rb b/app/models/scheme.rb index 83899f494..5de804c58 100644 --- a/app/models/scheme.rb +++ b/app/models/scheme.rb @@ -18,9 +18,12 @@ class Scheme < ApplicationRecord } validate :validate_confirmed + validate :deactivation_date_errors auto_strip_attributes :service_name + attr_accessor :deactivation_date_type, :run_deactivation_validations + SENSITIVE = { No: 0, Yes: 1, @@ -153,29 +156,6 @@ class Scheme < ApplicationRecord ] end - def display_attributes - base_attributes = [ - { name: "Scheme code", value: id_to_display }, - { name: "Name", value: service_name, edit: true }, - { name: "Confidential information", value: sensitive, edit: true }, - { name: "Type of scheme", value: scheme_type }, - { name: "Registered under Care Standards Act 2000", value: registered_under_care_act }, - { name: "Housing stock owned by", value: owning_organisation.name, edit: true }, - { name: "Support services provided by", value: arrangement_type }, - { name: "Organisation providing support", value: managing_organisation&.name }, - { name: "Primary client group", value: primary_client_group }, - { name: "Has another client group", value: has_other_client_group }, - { name: "Secondary client group", value: secondary_client_group }, - { name: "Level of support given", value: support_type }, - { name: "Intended length of stay", value: intended_stay }, - ] - - if arrangement_type_same? - base_attributes.delete({ name: "Organisation providing support", value: managing_organisation&.name }) - end - base_attributes - end - def synonyms locations.map(&:postcode).join(",") end @@ -219,7 +199,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 has_other_client_group] + required_attributes = attribute_names - %w[id created_at updated_at old_id old_visible_id confirmed end_date sensitive secondary_client_group total_units has_other_client_group deactivation_date deactivation_date_type] if confirmed == true required_attributes.any? do |attribute| @@ -230,4 +210,44 @@ class Scheme < ApplicationRecord end end end + + def available_from + created_at + end + + def status + return :active if deactivation_date.blank? + return :deactivating_soon if Time.zone.now < deactivation_date + + :deactivated + end + + def active? + status == :active + end + + def run_deactivation_validations! + @run_deactivation_validations = true + end + + def implicit_run_deactivation_validations + deactivation_date.present? || @run_deactivation_validations + end + + def deactivation_date_errors + return unless implicit_run_deactivation_validations + + if deactivation_date.blank? + if deactivation_date_type.blank? + errors.add(:deactivation_date_type, message: I18n.t("validations.scheme.deactivation_date.not_selected")) + elsif deactivation_date_type == "other" + errors.add(:deactivation_date, message: I18n.t("validations.scheme.deactivation_date.invalid")) + end + else + collection_start_date = FormHandler.instance.current_collection_start_date + unless deactivation_date.between?(collection_start_date, Date.new(2200, 1, 1)) + errors.add(:deactivation_date, message: I18n.t("validations.scheme.deactivation_date.out_of_range", date: collection_start_date.to_formatted_s(:govuk_date))) + end + end + end end diff --git a/app/views/locations/toggle_active_confirm.html.erb b/app/views/locations/deactivate_confirm.html.erb similarity index 58% rename from app/views/locations/toggle_active_confirm.html.erb rename to app/views/locations/deactivate_confirm.html.erb index 452d66e48..e3f1ae175 100644 --- a/app/views/locations/toggle_active_confirm.html.erb +++ b/app/views/locations/deactivate_confirm.html.erb @@ -4,13 +4,14 @@ <% end %>