diff --git a/app/mailers/merge_completion_mailer.rb b/app/mailers/merge_completion_mailer.rb new file mode 100644 index 000000000..261866b85 --- /dev/null +++ b/app/mailers/merge_completion_mailer.rb @@ -0,0 +1,46 @@ +class MergeCompletionMailer < NotifyMailer + MERGE_COMPLETION_MERGING_ORGANISATION_TEMPLATE_ID = "b3b62e72-5ced-4515-8720-08bdc7bac792".freeze + MERGE_COMPLETION_ABSORBING_ORGANISATION_TEMPLATE_ID = "7cdfefac-84c3-4054-8bd9-63103b3847b6".freeze + ONE_ORG_MERGE_COMPLETION_ABSORBING_ORGANISATION_TEMPLATE_ID = "35456951-2046-468e-9f41-a620e94db203".freeze + + def send_merged_organisation_success_mail(email, merged_organisation_name, absorbing_organisation_name, merge_date) + send_email( + email, + MERGE_COMPLETION_MERGING_ORGANISATION_TEMPLATE_ID, + { + merged_organisation_name:, + absorbing_organisation_name:, + merge_date: merge_date.to_formatted_s(:govuk_date), + email:, + }, + ) + end + + def send_absorbing_organisation_success_mail(email, merged_organisations, absorbing_organisation_name, merge_date) + if merged_organisations.count > 1 + organisation_count = merged_organisations.count.to_s + " organisation".pluralize(merged_organisations.count) + merged_organisation_list = "The organisations are #{merged_organisations.to_sentence(last_word_connector: ' and ')}" + + send_email( + email, + MERGE_COMPLETION_ABSORBING_ORGANISATION_TEMPLATE_ID, + { + organisation_count:, + merged_organisations: merged_organisation_list, + absorbing_organisation_name:, + merge_date: merge_date.to_formatted_s(:govuk_date), + }, + ) + else + send_email( + email, + ONE_ORG_MERGE_COMPLETION_ABSORBING_ORGANISATION_TEMPLATE_ID, + { + merged_organisation: merged_organisations.first, + absorbing_organisation_name:, + merge_date: merge_date.to_formatted_s(:govuk_date), + }, + ) + end + end +end diff --git a/app/services/merge/merge_organisations_service.rb b/app/services/merge/merge_organisations_service.rb index a710c20a5..bcaad85a6 100644 --- a/app/services/merge/merge_organisations_service.rb +++ b/app/services/merge/merge_organisations_service.rb @@ -22,6 +22,7 @@ class Merge::MergeOrganisationsService end @absorbing_organisation.available_from = @merge_date if @absorbing_organisation_active_from_merge_date @absorbing_organisation.save! + send_success_emails log_success_message rescue ActiveRecord::RecordInvalid => e Rails.logger.error("Organisation merge failed with: #{e.message}") @@ -166,6 +167,19 @@ private end end + def send_success_emails + @absorbing_organisation.users.each do |user| + next unless user.active? + + merged_organisation, merged_user = find_merged_user_and_organisation_by_email(user.email) + if merged_user.present? + MergeCompletionMailer.send_merged_organisation_success_mail(merged_user[:email], merged_organisation, @absorbing_organisation.name, @merge_date).deliver_later + else + MergeCompletionMailer.send_absorbing_organisation_success_mail(user.email, @merging_organisations.map(&:name), @absorbing_organisation.name, @merge_date).deliver_later + end + end + end + def merge_boolean_organisation_attribute(attribute) @absorbing_organisation[attribute] ||= @merging_organisations.any? { |merging_organisation| merging_organisation[attribute] } end @@ -240,4 +254,12 @@ private deactivation_period.destroy! end end + + def find_merged_user_and_organisation_by_email(provided_email) + @merged_users.each do |org, users| + user = users.find { |u| u[:email] == provided_email } + return org, user if user + end + nil + end end diff --git a/spec/mailers/merge_completion_mailer_spec.rb b/spec/mailers/merge_completion_mailer_spec.rb new file mode 100644 index 000000000..2804c8977 --- /dev/null +++ b/spec/mailers/merge_completion_mailer_spec.rb @@ -0,0 +1,59 @@ +require "rails_helper" + +RSpec.describe MergeCompletionMailer do + let(:notify_client) { instance_double(Notifications::Client) } + + before do + allow(Notifications::Client).to receive(:new).and_return(notify_client) + allow(notify_client).to receive(:send_email).and_return(true) + end + + describe "#send_merged_organisation_success_mail" do + let(:merge_date) { Time.zone.local(2023, 1, 1) } + + it "sends a merge completion E-mail via notify" do + expect(notify_client).to receive(:send_email).with(hash_including({ + template_id: MergeCompletionMailer::MERGE_COMPLETION_MERGING_ORGANISATION_TEMPLATE_ID, + personalisation: hash_including({ + merged_organisation_name: "merged organisation", + absorbing_organisation_name: "absorbing organisation", + merge_date: "1 January 2023", + email: "user@example.com", + }), + })) + + described_class.new.send_merged_organisation_success_mail("user@example.com", "merged organisation", "absorbing organisation", merge_date) + end + end + + describe "#send_absorbing_organisation_success_mail" do + let(:merge_date) { Time.zone.local(2023, 1, 1) } + + it "sends a merge completion E-mail via notify for a single merge" do + expect(notify_client).to receive(:send_email).with(hash_including({ + template_id: MergeCompletionMailer::ONE_ORG_MERGE_COMPLETION_ABSORBING_ORGANISATION_TEMPLATE_ID, + personalisation: hash_including({ + merged_organisation: "merged organisation", + absorbing_organisation_name: "absorbing organisation", + merge_date: "1 January 2023", + }), + })) + + described_class.new.send_absorbing_organisation_success_mail("user@example.com", ["merged organisation"], "absorbing organisation", merge_date) + end + + it "sends a merge completion E-mail via notify for a multiple org merge" do + expect(notify_client).to receive(:send_email).with(hash_including({ + template_id: MergeCompletionMailer::MERGE_COMPLETION_ABSORBING_ORGANISATION_TEMPLATE_ID, + personalisation: hash_including({ + organisation_count: "2 organisations", + merged_organisations: "The organisations are merged organisation and other organisation", + absorbing_organisation_name: "absorbing organisation", + merge_date: "1 January 2023", + }), + })) + + described_class.new.send_absorbing_organisation_success_mail("user@example.com", ["merged organisation", "other organisation"], "absorbing organisation", merge_date) + end + end +end diff --git a/spec/services/merge/merge_organisations_service_spec.rb b/spec/services/merge/merge_organisations_service_spec.rb index cb3ec389c..e3c161a3f 100644 --- a/spec/services/merge/merge_organisations_service_spec.rb +++ b/spec/services/merge/merge_organisations_service_spec.rb @@ -2,10 +2,16 @@ require "rails_helper" RSpec.describe Merge::MergeOrganisationsService do describe "#call" do + before do + mail_double = instance_double("ActionMailer::MessageDelivery", deliver_later: nil) + allow(MergeCompletionMailer).to receive(:send_merged_organisation_success_mail).and_return(mail_double) + allow(MergeCompletionMailer).to receive(:send_absorbing_organisation_success_mail).and_return(mail_double) + end + context "when merging a single organisation into an existing organisation" do subject(:merge_organisations_service) { described_class.new(absorbing_organisation_id: absorbing_organisation.id, merging_organisation_ids: [merging_organisation_ids], merge_date: nil) } - let(:absorbing_organisation) { create(:organisation, holds_own_stock: false) } + let(:absorbing_organisation) { create(:organisation, holds_own_stock: false, name: "absorbing org") } let(:absorbing_organisation_user) { create(:user, organisation: absorbing_organisation) } let(:merging_organisation) { create(:organisation, holds_own_stock: true, name: "fake org") } @@ -840,12 +846,56 @@ RSpec.describe Merge::MergeOrganisationsService do expect(absorbing_organisation.available_from.to_date).to eq(Time.zone.today) end end + + it "sends a merge completion E-mail to the merged organisation users" do + expect(MergeCompletionMailer).to receive(:send_merged_organisation_success_mail).with(merging_organisation_user.email, "fake org", "absorbing org", Time.zone.today).once + expect(MergeCompletionMailer).to receive(:send_merged_organisation_success_mail).with(merging_organisation.data_protection_officers.first.email, "fake org", "absorbing org", Time.zone.today).once + + expect(MergeCompletionMailer).not_to receive(:send_merged_organisation_success_mail).with(absorbing_organisation.data_protection_officers.first.email, "fake org", "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_merged_organisation_success_mail).with(absorbing_organisation_user.email, "fake org", "absorbing org", Time.zone.today) + + merge_organisations_service.call + end + + it "does not send a merge completion E-mail to deactivated merged organisation users" do + merging_organisation_user.update!(active: false) + + expect(MergeCompletionMailer).to receive(:send_merged_organisation_success_mail).with(merging_organisation.data_protection_officers.first.email, "fake org", "absorbing org", Time.zone.today).once + + expect(MergeCompletionMailer).not_to receive(:send_merged_organisation_success_mail).with(merging_organisation_user.email, "fake org", "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_merged_organisation_success_mail).with(absorbing_organisation.data_protection_officers.first.email, "fake org", "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_merged_organisation_success_mail).with(absorbing_organisation_user.email, "fake org", "absorbing org", Time.zone.today) + + merge_organisations_service.call + end + + it "sends a merge completion E-mail to the original absorbing organisation users" do + expect(MergeCompletionMailer).to receive(:send_absorbing_organisation_success_mail).with(absorbing_organisation.data_protection_officers.first.email, ["fake org"], "absorbing org", Time.zone.today).once + expect(MergeCompletionMailer).to receive(:send_absorbing_organisation_success_mail).with(absorbing_organisation_user.email, ["fake org"], "absorbing org", Time.zone.today).once + + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(merging_organisation_user.email, ["fake org"], "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(merging_organisation.data_protection_officers.first.email, ["fake org"], "absorbing org", Time.zone.today) + + merge_organisations_service.call + end + + it "does not send a merge completion E-mail to deactivated original absorbing organisation users" do + absorbing_organisation_user.update!(active: false) + + expect(MergeCompletionMailer).to receive(:send_absorbing_organisation_success_mail).with(absorbing_organisation.data_protection_officers.first.email, ["fake org"], "absorbing org", Time.zone.today).once + + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(absorbing_organisation_user.email, ["fake org"], "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(merging_organisation_user.email, ["fake org"], "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(merging_organisation.data_protection_officers.first.email, ["fake org"], "absorbing org", Time.zone.today) + + merge_organisations_service.call + end end context "when merging a multiple organisations into an existing organisation" do subject(:merge_organisations_service) { described_class.new(absorbing_organisation_id: absorbing_organisation.id, merging_organisation_ids: [merging_organisation_ids], merge_date: nil) } - let(:absorbing_organisation) { create(:organisation, holds_own_stock: false) } + let(:absorbing_organisation) { create(:organisation, holds_own_stock: false, name: "absorbing org") } let(:absorbing_organisation_user) { create(:user, organisation: absorbing_organisation) } let(:merging_organisation) { create(:organisation, holds_own_stock: true, name: "fake org") } @@ -943,6 +993,34 @@ RSpec.describe Merge::MergeOrganisationsService do expect(merging_organisation.users.first).to eq(dpo) expect(merging_organisation.data_protection_confirmation.data_protection_officer).to eq(dpo) end + + it "sends a merge completion E-mail to the merged organisation users" do + expect(MergeCompletionMailer).to receive(:send_merged_organisation_success_mail).with(merging_organisation_user.email, "fake org", "absorbing org", Time.zone.today).once + expect(MergeCompletionMailer).to receive(:send_merged_organisation_success_mail).with(merging_organisation.data_protection_officers.first.email, "fake org", "absorbing org", Time.zone.today).once + + expect(MergeCompletionMailer).not_to receive(:send_merged_organisation_success_mail).with(absorbing_organisation.data_protection_officers.first.email, "fake org", "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_merged_organisation_success_mail).with(absorbing_organisation_user.email, "fake org", "absorbing org", Time.zone.today) + + merging_organisation_too.users.each do |user| + expect(MergeCompletionMailer).to receive(:send_merged_organisation_success_mail).with(user.email, "second org", "absorbing org", Time.zone.today).once + end + + merge_organisations_service.call + end + + it "sends a merge completion E-mail to the original absorbing organisation users" do + expect(MergeCompletionMailer).to receive(:send_absorbing_organisation_success_mail).with(absorbing_organisation.data_protection_officers.first.email, ["fake org", "second org"], "absorbing org", Time.zone.today).once + expect(MergeCompletionMailer).to receive(:send_absorbing_organisation_success_mail).with(absorbing_organisation_user.email, ["fake org", "second org"], "absorbing org", Time.zone.today).once + + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(merging_organisation_user.email, ["fake org", "second org"], "absorbing org", Time.zone.today) + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(merging_organisation.data_protection_officers.first.email, ["fake org", "second org"], "absorbing org", Time.zone.today) + + merging_organisation_too.users.each do |user| + expect(MergeCompletionMailer).not_to receive(:send_absorbing_organisation_success_mail).with(user.email, ["fake org", "second org"], "absorbing org", Time.zone.today) + end + + merge_organisations_service.call + end end context "and merging organisation relationships" do