diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e5952a80f..d1d131e2b 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -186,6 +186,18 @@ class UsersController < ApplicationController @log_reassignment = params[:log_reassignment] end + def confirm_organisation_change + if log_reassignment_params[:organisation_id].blank? || log_reassignment_params[:log_reassignment].blank? || !Organisation.where(id: log_reassignment_params[:organisation_id]).exists? + return redirect_to user_path(@user) + end + + @new_organisation = Organisation.find(log_reassignment_params[:organisation_id]) + @log_reassignment = log_reassignment_params[:log_reassignment] + @user.reassign_logs_and_update_organisation(@new_organisation, @log_reassignment) + + redirect_to user_path(@user) + end + private def validate_attributes @@ -201,7 +213,7 @@ private end if user_params.key?(:organisation_id) && user_params[:organisation_id].blank? - @user.errors.add :organisation, :blank + @user.errors.add :organisation_id, :blank end end diff --git a/app/models/user.rb b/app/models/user.rb index 200faea94..fac343879 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -287,6 +287,35 @@ class User < ApplicationRecord sales_logs.where(assigned_to: self) end + def reassign_logs_and_update_organisation(new_organisation, log_reassignment) + return unless new_organisation + + ActiveRecord::Base.transaction do + lettings_logs_to_reassign = assigned_to_lettings_logs + sales_logs_to_reassign = assigned_to_sales_logs + current_organisation = organisation + + update!(organisation: new_organisation) + + case log_reassignment + when "reassign_all" + reassign_all_orgs(new_organisation, lettings_logs_to_reassign, sales_logs_to_reassign) + when "reassign_stock_owner" + reassign_stock_owners(new_organisation, lettings_logs_to_reassign, sales_logs_to_reassign) + when "reassign_managing_agent" + reassign_managing_agents(new_organisation, lettings_logs_to_reassign, sales_logs_to_reassign) + when "unassign" + unassign_organisations(lettings_logs_to_reassign, sales_logs_to_reassign, current_organisation) + end + + rescue ActiveRecord::RecordInvalid => e + Rails.logger.error("User update failed with: #{e.message}") + Sentry.capture_exception(e) + + raise ActiveRecord::Rollback + end + end + protected # Checks whether a password is needed or not. For validations only. @@ -311,4 +340,38 @@ private DataProtectionConfirmationMailer.send_confirmation_email(self).deliver_later end + + def reassign_all_orgs(new_organisation, lettings_logs_to_reassign, sales_logs_to_reassign) + lettings_logs_to_reassign.update_all(owning_organisation_id: new_organisation.id, managing_organisation_id: new_organisation.id, values_updated_at: Time.zone.now) + sales_logs_to_reassign.update_all(owning_organisation_id: new_organisation.id, managing_organisation_id: new_organisation.id, values_updated_at: Time.zone.now) + end + + def reassign_stock_owners(new_organisation, lettings_logs_to_reassign, sales_logs_to_reassign) + lettings_logs_to_reassign.update_all(owning_organisation_id: new_organisation.id, values_updated_at: Time.zone.now) + sales_logs_to_reassign.update_all(owning_organisation_id: new_organisation.id, values_updated_at: Time.zone.now) + end + + def reassign_managing_agents(new_organisation, lettings_logs_to_reassign, sales_logs_to_reassign) + lettings_logs_to_reassign.update_all(managing_organisation_id: new_organisation.id, values_updated_at: Time.zone.now) + sales_logs_to_reassign.update_all(managing_organisation_id: new_organisation.id, values_updated_at: Time.zone.now) + end + + def unassign_organisations(lettings_logs_to_reassign, sales_logs_to_reassign, current_organisation) + if User.find_by(name: "Unassigned", organisation: current_organisation) + unassigned_user = User.find_by(name: "Unassigned", organisation: current_organisation) + else + unassigned_user = User.new( + name: "Unassigned", + organisation_id:, + is_dpo: false, + encrypted_password: SecureRandom.hex(10), + email: SecureRandom.uuid, + confirmed_at: Time.zone.now, + active: false, + ) + unassigned_user.save!(validate: false) + end + lettings_logs_to_reassign.update_all(assigned_to_id: unassigned_user.id, values_updated_at: Time.zone.now) + sales_logs_to_reassign.update_all(assigned_to_id: unassigned_user.id, values_updated_at: Time.zone.now) + end end diff --git a/config/routes.rb b/config/routes.rb index e99c3b9bb..f2c86e37c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -127,6 +127,7 @@ Rails.application.routes.draw do get "log-reassignment", to: "users#log_reassignment" patch "log-reassignment", to: "users#update_log_reassignment" get "organisation-change-confirmation", to: "users#organisation_change_confirmation" + patch "organisation-change-confirmation", to: "users#confirm_organisation_change" collection do get :search diff --git a/spec/helpers/user_helper_spec.rb b/spec/helpers/user_helper_spec.rb index 91a02f2f6..c88790aa0 100644 --- a/spec/helpers/user_helper_spec.rb +++ b/spec/helpers/user_helper_spec.rb @@ -125,14 +125,14 @@ RSpec.describe UserHelper do end end - context "with reassign all choice" do + context "with reassign managing agent choice" do it "returns the correct message" do expected_text = "You’re moving #{user.name} from #{user.organisation.name} to #{current_user.organisation.name}. The managing agent on their logs will change to #{current_user.organisation.name}." expect(organisation_change_confirmation_warning(user, current_user.organisation, "reassign_managing_agent")).to eq(expected_text) end end - context "with reassign all choice" do + context "with unassign choice" do it "returns the correct message" do expected_text = "You’re moving #{user.name} from #{user.organisation.name} to #{current_user.organisation.name}. Their logs will be unassigned." expect(organisation_change_confirmation_warning(user, current_user.organisation, "unassign")).to eq(expected_text) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6a04e9a0b..3bf618e56 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -528,4 +528,184 @@ RSpec.describe User, type: :model do end end end + + describe "#reassign_logs_and_update_organisation" do + let(:user) { create(:user) } + let(:new_organisation) { create(:organisation) } + let!(:lettings_log) { create(:lettings_log, assigned_to: user) } + let!(:sales_log) { create(:sales_log, assigned_to: user) } + + context "when reassigning all orgs for logs" do + it "reassigns all logs to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_all") + expect(lettings_log.reload.owning_organisation).to eq(new_organisation) + expect(lettings_log.managing_organisation).to eq(new_organisation) + expect(lettings_log.values_updated_at).not_to be_nil + expect(sales_log.reload.owning_organisation).to eq(new_organisation) + expect(sales_log.managing_organisation).to eq(new_organisation) + expect(sales_log.values_updated_at).not_to be_nil + end + + it "moves the user to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_all") + + expect(user.organisation).to eq(new_organisation) + end + + context "and there is an error" do + before do + allow(user).to receive(:update!).and_raise(ActiveRecord::RecordInvalid) + end + + it "rolls back the changes" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_all") + expect(lettings_log.reload.owning_organisation).not_to eq(new_organisation) + expect(lettings_log.managing_organisation).not_to eq(new_organisation) + expect(lettings_log.values_updated_at).to be_nil + expect(sales_log.reload.owning_organisation).not_to eq(new_organisation) + expect(sales_log.managing_organisation).not_to eq(new_organisation) + expect(sales_log.values_updated_at).to be_nil + expect(user.organisation).not_to eq(new_organisation) + end + end + end + + context "when reassigning stock owners for logs" do + it "reassigns stock owners for logs to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_stock_owner") + expect(lettings_log.reload.owning_organisation).to eq(new_organisation) + expect(lettings_log.managing_organisation).not_to eq(new_organisation) + expect(lettings_log.values_updated_at).not_to be_nil + expect(sales_log.reload.owning_organisation).to eq(new_organisation) + expect(sales_log.managing_organisation).not_to eq(new_organisation) + expect(sales_log.values_updated_at).not_to be_nil + end + + it "moves the user to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_stock_owner") + + expect(user.organisation).to eq(new_organisation) + end + + context "and there is an error" do + before do + allow(user).to receive(:update!).and_raise(ActiveRecord::RecordInvalid) + end + + it "rolls back the changes" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_all") + expect(lettings_log.reload.owning_organisation).not_to eq(new_organisation) + expect(lettings_log.managing_organisation).not_to eq(new_organisation) + expect(lettings_log.values_updated_at).to be_nil + expect(sales_log.reload.owning_organisation).not_to eq(new_organisation) + expect(sales_log.managing_organisation).not_to eq(new_organisation) + expect(sales_log.values_updated_at).to be_nil + expect(user.organisation).not_to eq(new_organisation) + end + end + end + + context "when reassigning managing agents for logs" do + it "reassigns managing agents for logs to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_managing_agent") + expect(lettings_log.reload.owning_organisation).not_to eq(new_organisation) + expect(lettings_log.managing_organisation).to eq(new_organisation) + expect(lettings_log.values_updated_at).not_to be_nil + expect(sales_log.reload.owning_organisation).not_to eq(new_organisation) + expect(sales_log.managing_organisation).to eq(new_organisation) + expect(sales_log.values_updated_at).not_to be_nil + end + + it "moves the user to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_managing_agent") + + expect(user.organisation).to eq(new_organisation) + end + + context "and there is an error" do + before do + allow(user).to receive(:update!).and_raise(ActiveRecord::RecordInvalid) + end + + it "rolls back the changes" do + user.reassign_logs_and_update_organisation(new_organisation, "reassign_all") + expect(lettings_log.reload.owning_organisation).not_to eq(new_organisation) + expect(lettings_log.managing_organisation).not_to eq(new_organisation) + expect(lettings_log.values_updated_at).to be_nil + expect(sales_log.reload.owning_organisation).not_to eq(new_organisation) + expect(sales_log.managing_organisation).not_to eq(new_organisation) + expect(sales_log.values_updated_at).to be_nil + expect(user.organisation).not_to eq(new_organisation) + end + end + end + + context "when unassigning the logs" do + context "and unassigned user exists" do + let!(:unassigned_user) { create(:user, name: "Unassigned", organisation: user.organisation) } + + it "reassigns all the logs to the unassigned user" do + user.reassign_logs_and_update_organisation(new_organisation, "unassign") + + expect(lettings_log.reload.assigned_to).to eq(unassigned_user) + expect(lettings_log.values_updated_at).not_to be_nil + expect(sales_log.reload.assigned_to).to eq(unassigned_user) + expect(sales_log.values_updated_at).not_to be_nil + end + + it "moves the user to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "unassign") + + expect(user.organisation).to eq(new_organisation) + end + + context "and there is an error" do + before do + allow(user).to receive(:update!).and_raise(ActiveRecord::RecordInvalid) + end + + it "rolls back the changes" do + user.reassign_logs_and_update_organisation(new_organisation, "unassign") + expect(lettings_log.reload.assigned_to).to eq(user) + expect(lettings_log.values_updated_at).to be_nil + expect(sales_log.reload.assigned_to).to eq(user) + expect(sales_log.values_updated_at).to be_nil + expect(user.organisation).not_to eq(new_organisation) + end + end + end + + context "and unassigned user doesn't exist" do + it "reassigns all the logs to the unassigned user" do + user.reassign_logs_and_update_organisation(new_organisation, "unassign") + + expect(lettings_log.reload.assigned_to.name).to eq("Unassigned") + expect(lettings_log.values_updated_at).not_to be_nil + expect(sales_log.reload.assigned_to.name).to eq("Unassigned") + expect(sales_log.values_updated_at).not_to be_nil + end + + it "moves the user to the new organisation" do + user.reassign_logs_and_update_organisation(new_organisation, "unassign") + + expect(user.organisation).to eq(new_organisation) + end + + context "and there is an error" do + before do + allow(user).to receive(:update!).and_raise(ActiveRecord::RecordInvalid) + end + + it "rolls back the changes" do + user.reassign_logs_and_update_organisation(new_organisation, "unassign") + expect(lettings_log.reload.assigned_to).to eq(user) + expect(lettings_log.values_updated_at).to be_nil + expect(sales_log.reload.assigned_to).to eq(user) + expect(sales_log.values_updated_at).to be_nil + expect(user.organisation).not_to eq(new_organisation) + end + end + end + end + end end diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 1d5b68387..46003aa06 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -2480,6 +2480,58 @@ RSpec.describe UsersController, type: :request do end end end + + describe "#confirm_organisation_change patch" do + context "when organisation id is not given" do + let(:params) { { user: { organisation_id: nil, log_reassignment: "reassign_all" } } } + + it "redirects to the user page" do + patch "/users/#{other_user.id}/organisation-change-confirmation", headers:, params: params + expect(response).to redirect_to("/users/#{other_user.id}") + end + end + + context "when reassignment option is not given" do + let(:new_organisation) { create(:organisation, name: "new org") } + let(:params) { { user: { organisation_id: new_organisation.id, log_reassignment: "reassign_all" } } } + + it "redirects to the user page" do + patch "/users/#{other_user.id}/organisation-change-confirmation", headers:, params: params + expect(response).to redirect_to("/users/#{other_user.id}") + end + end + + context "when organisation id does not exist" do + let(:params) { { user: { organisation_id: 123_123, log_reassignment: "reassign_all" } } } + + it "redirects to the user page" do + patch "/users/#{other_user.id}/organisation-change-confirmation", headers:, params: params + expect(response).to redirect_to("/users/#{other_user.id}") + end + end + + context "with valid organisation id" do + let(:new_organisation) { create(:organisation, name: "new org") } + let(:params) { { user: { organisation_id: new_organisation.id, log_reassignment: "reassign_all" } } } + let!(:lettings_log) { create(:lettings_log, assigned_to: other_user) } + let!(:sales_log) { create(:sales_log, assigned_to: other_user) } + + context "and reassign all option" do + it "updates logs and moves the user" do + patch "/users/#{other_user.id}/organisation-change-confirmation", headers:, params: params + expect(response).to redirect_to("/users/#{other_user.id}") + + expect(other_user.reload.organisation).to eq(new_organisation) + expect(other_user.lettings_logs.count).to eq(1) + expect(other_user.sales_logs.count).to eq(1) + expect(lettings_log.reload.managing_organisation).to eq(new_organisation) + expect(lettings_log.owning_organisation).to eq(new_organisation) + expect(sales_log.reload.managing_organisation).to eq(new_organisation) + expect(sales_log.owning_organisation).to eq(new_organisation) + end + end + end + end end describe "title link" do