Browse Source

Update merge orgs task (#2003)

* Allow custom merge date in merge organisations service

* Allow optional merge date in merge orgs task

* Add a rake task for merging into a new organinsation
demo-branch
kosiakkatrina 1 year ago committed by GitHub
parent
commit
a5fdf42540
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      app/services/merge/merge_organisations_service.rb
  2. 33
      lib/tasks/merge_organisations.rake
  3. 67
      spec/lib/tasks/merge_organisations_spec.rb
  4. 186
      spec/services/merge/merge_organisations_service_spec.rb

15
app/services/merge/merge_organisations_service.rb

@ -1,7 +1,9 @@
class Merge::MergeOrganisationsService class Merge::MergeOrganisationsService
def initialize(absorbing_organisation_id:, merging_organisation_ids:) def initialize(absorbing_organisation_id:, merging_organisation_ids:, merge_date: Time.zone.today, absorbing_organisation_active_from_merge_date: false)
@absorbing_organisation = Organisation.find(absorbing_organisation_id) @absorbing_organisation = Organisation.find(absorbing_organisation_id)
@merging_organisations = Organisation.find(merging_organisation_ids) @merging_organisations = Organisation.find(merging_organisation_ids)
@merge_date = merge_date || Time.zone.today
@absorbing_organisation_active_from_merge_date = absorbing_organisation_active_from_merge_date
end end
def call def call
@ -18,6 +20,7 @@ class Merge::MergeOrganisationsService
merge_sales_logs(merging_organisation) merge_sales_logs(merging_organisation)
mark_organisation_as_merged(merging_organisation) mark_organisation_as_merged(merging_organisation)
end end
@absorbing_organisation.available_from = @merge_date if @absorbing_organisation_active_from_merge_date
@absorbing_organisation.save! @absorbing_organisation.save!
log_success_message log_success_message
rescue ActiveRecord::RecordInvalid => e rescue ActiveRecord::RecordInvalid => e
@ -70,12 +73,12 @@ private
new_scheme.locations << Location.new(location.attributes.except("id", "scheme_id")) unless location.deactivated? new_scheme.locations << Location.new(location.attributes.except("id", "scheme_id")) unless location.deactivated?
end end
@merged_schemes[merging_organisation.name] << { name: new_scheme.service_name, code: new_scheme.id } @merged_schemes[merging_organisation.name] << { name: new_scheme.service_name, code: new_scheme.id }
SchemeDeactivationPeriod.create!(scheme:, deactivation_date: Time.zone.now) SchemeDeactivationPeriod.create!(scheme:, deactivation_date: @merge_date)
end end
end end
def merge_lettings_logs(merging_organisation) def merge_lettings_logs(merging_organisation)
merging_organisation.owned_lettings_logs.after_date(Time.zone.today).each do |lettings_log| merging_organisation.owned_lettings_logs.after_date(@merge_date.to_time).each do |lettings_log|
if lettings_log.scheme.present? if lettings_log.scheme.present?
scheme_to_set = @absorbing_organisation.owned_schemes.find_by(service_name: lettings_log.scheme.service_name) scheme_to_set = @absorbing_organisation.owned_schemes.find_by(service_name: lettings_log.scheme.service_name)
location_to_set = scheme_to_set.locations.find_by(name: lettings_log.location&.name, postcode: lettings_log.location&.postcode) location_to_set = scheme_to_set.locations.find_by(name: lettings_log.location&.name, postcode: lettings_log.location&.postcode)
@ -86,20 +89,20 @@ private
lettings_log.owning_organisation = @absorbing_organisation lettings_log.owning_organisation = @absorbing_organisation
lettings_log.save! lettings_log.save!
end end
merging_organisation.managed_lettings_logs.after_date(Time.zone.today).each do |lettings_log| merging_organisation.managed_lettings_logs.after_date(@merge_date.to_time).each do |lettings_log|
lettings_log.managing_organisation = @absorbing_organisation lettings_log.managing_organisation = @absorbing_organisation
lettings_log.save! lettings_log.save!
end end
end end
def merge_sales_logs(merging_organisation) def merge_sales_logs(merging_organisation)
merging_organisation.sales_logs.after_date(Time.zone.today).each do |sales_log| merging_organisation.sales_logs.after_date(@merge_date.to_time).each do |sales_log|
sales_log.update(owning_organisation: @absorbing_organisation) sales_log.update(owning_organisation: @absorbing_organisation)
end end
end end
def mark_organisation_as_merged(merging_organisation) def mark_organisation_as_merged(merging_organisation)
merging_organisation.update(merge_date: Time.zone.today, absorbing_organisation: @absorbing_organisation) merging_organisation.update(merge_date: @merge_date, absorbing_organisation: @absorbing_organisation)
end end
def log_success_message def log_success_message

33
lib/tasks/merge_organisations.rake

@ -1,12 +1,37 @@
namespace :merge do namespace :merge do
desc "Merge organisations into one" desc "Merge organisations into an existing organisation"
task :merge_organisations, %i[absorbing_organisation_id merging_organisation_ids] => :environment do |_task, args| task :merge_organisations, %i[absorbing_organisation_id merging_organisation_ids merge_date] => :environment do |_task, args|
absorbing_organisation_id = args[:absorbing_organisation_id] absorbing_organisation_id = args[:absorbing_organisation_id]
merging_organisation_ids = args[:merging_organisation_ids]&.split(" ")&.map(&:to_i) merging_organisation_ids = args[:merging_organisation_ids]&.split(" ")&.map(&:to_i)
begin
merge_date = args[:merge_date].present? ? Date.parse(args[:merge_date]) : nil
rescue StandardError
raise "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids, merge_date]. Merge date must be in format YYYY-MM-DD"
end
if merging_organisation_ids.blank? || absorbing_organisation_id.blank?
raise "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids, merge_date]"
end
service = Merge::MergeOrganisationsService.new(absorbing_organisation_id:, merging_organisation_ids:, merge_date:)
service.call
end
raise "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids]" if merging_organisation_ids.blank? || absorbing_organisation_id.blank? desc "Merge organisations into an existing organisation, make the absorbing organisation active from merge date only"
task :merge_organisations_into_new_organisation, %i[absorbing_organisation_id merging_organisation_ids merge_date] => :environment do |_task, args|
absorbing_organisation_id = args[:absorbing_organisation_id]
merging_organisation_ids = args[:merging_organisation_ids]&.split(" ")&.map(&:to_i)
begin
merge_date = args[:merge_date].present? ? Date.parse(args[:merge_date]) : nil
rescue StandardError
raise "Usage: rake merge:merge_organisations_into_new_organisation[absorbing_organisation_id, merging_organisation_ids, merge_date]. Merge date must be in format YYYY-MM-DD"
end
if merging_organisation_ids.blank? || absorbing_organisation_id.blank?
raise "Usage: rake merge:merge_organisations_into_new_organisation[absorbing_organisation_id, merging_organisation_ids, merge_date]"
end
service = Merge::MergeOrganisationsService.new(absorbing_organisation_id:, merging_organisation_ids:) service = Merge::MergeOrganisationsService.new(absorbing_organisation_id:, merging_organisation_ids:, merge_date:, absorbing_organisation_active_from_merge_date: true)
service.call service.call
end end
end end

67
spec/lib/tasks/merge_organisations_spec.rb

@ -20,22 +20,79 @@ RSpec.describe "emails" do
context "when the rake task is run" do context "when the rake task is run" do
it "raises an error when no parameters are given" do it "raises an error when no parameters are given" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids]") expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids, merge_date]")
end end
it "raises an error when only absorbing organisation is given" do it "raises an error when only absorbing organisation is given" do
expect { task.invoke(1, nil) }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids]") expect { task.invoke(1, nil) }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids, merge_date]")
end end
it "raises an error when only merging organisations are given" do it "raises an error when only merging organisations are given" do
expect { task.invoke(nil, "1 2") }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids]") expect { task.invoke(nil, "1 2") }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids, merge_date]")
end end
it "raises runs the service with correct organisation IDs" do it "raises an error when the merge date given is not valid" do
expect(Merge::MergeOrganisationsService).to receive(:new).with(absorbing_organisation_id: 1, merging_organisation_ids: [2, 3]).once expect { task.invoke("3", "1 2", "invalid_date") }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations[absorbing_organisation_id, merging_organisation_ids, merge_date]. Merge date must be in format YYYY-MM-DD")
end
it "runs the service with correct organisation IDs" do
expect(Merge::MergeOrganisationsService).to receive(:new).with(absorbing_organisation_id: 1, merging_organisation_ids: [2, 3], merge_date: nil).once
expect(merge_organisations_service).to receive(:call).once
task.invoke(1, "2 3")
end
it "runs the service with correct date when date is given" do
expect(Merge::MergeOrganisationsService).to receive(:new).with(absorbing_organisation_id: 1, merging_organisation_ids: [2, 3], merge_date: Time.zone.local(2021, 1, 13)).once
expect(merge_organisations_service).to receive(:call).once
task.invoke(1, "2 3", "2021-01-13")
end
end
end
describe ":merge_organisations_into_new_organisation", type: :task do
subject(:task) { Rake::Task["merge:merge_organisations_into_new_organisation"] }
let(:organisation) { create(:organisation) }
let(:merging_organisation) { create(:organisation) }
let(:merge_organisations_service) { Merge::MergeOrganisationsService.new(absorbing_organisation_id: organisation.id, merging_organisation_ids: [merging_organisation.id]) }
before do
allow(Merge::MergeOrganisationsService).to receive(:new).and_return(merge_organisations_service)
allow(merge_organisations_service).to receive(:call).and_return(nil)
Rake.application.rake_require("tasks/merge_organisations")
Rake::Task.define_task(:environment)
task.reenable
end
context "when the rake task is run" do
it "raises an error when no parameters are given" do
expect { task.invoke(nil) }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations_into_new_organisation[absorbing_organisation_id, merging_organisation_ids, merge_date]")
end
it "raises an error when only absorbing organisation is given" do
expect { task.invoke(1, nil) }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations_into_new_organisation[absorbing_organisation_id, merging_organisation_ids, merge_date]")
end
it "raises an error when only merging organisations are given" do
expect { task.invoke(nil, "1 2") }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations_into_new_organisation[absorbing_organisation_id, merging_organisation_ids, merge_date]")
end
it "raises an error when the merge date given is not valid" do
expect { task.invoke("3", "1 2", "invalid_date") }.to raise_error(RuntimeError, "Usage: rake merge:merge_organisations_into_new_organisation[absorbing_organisation_id, merging_organisation_ids, merge_date]. Merge date must be in format YYYY-MM-DD")
end
it "runs the service with correct organisation IDs" do
expect(Merge::MergeOrganisationsService).to receive(:new).with(absorbing_organisation_id: 1, merging_organisation_ids: [2, 3], merge_date: nil, absorbing_organisation_active_from_merge_date: true).once
expect(merge_organisations_service).to receive(:call).once expect(merge_organisations_service).to receive(:call).once
task.invoke(1, "2 3") task.invoke(1, "2 3")
end end
it "runs the service with correct date when date is given" do
expect(Merge::MergeOrganisationsService).to receive(:new).with(absorbing_organisation_id: 1, merging_organisation_ids: [2, 3], merge_date: Time.zone.local(2021, 1, 13), absorbing_organisation_active_from_merge_date: true).once
expect(merge_organisations_service).to receive(:call).once
task.invoke(1, "2 3", "2021-01-13")
end
end end
end end
end end

186
spec/services/merge/merge_organisations_service_spec.rb

@ -1,7 +1,7 @@
require "rails_helper" require "rails_helper"
RSpec.describe Merge::MergeOrganisationsService do RSpec.describe Merge::MergeOrganisationsService do
subject(:merge_organisations_service) { described_class.new(absorbing_organisation_id: absorbing_organisation.id, merging_organisation_ids: [merging_organisation_ids]) } 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) }
let(:absorbing_organisation_user) { create(:user, organisation: absorbing_organisation) } let(:absorbing_organisation_user) { create(:user, organisation: absorbing_organisation) }
@ -54,6 +54,13 @@ RSpec.describe Merge::MergeOrganisationsService do
expect(merging_organisation_user.organisation).to eq(merging_organisation) expect(merging_organisation_user.organisation).to eq(merging_organisation)
end end
it "does not set available_from for absorbing organisation" do
merge_organisations_service.call
absorbing_organisation.reload
expect(absorbing_organisation.available_from).to be_nil
end
context "and merging organisation rent periods" do context "and merging organisation rent periods" do
before do before do
OrganisationRentPeriod.create!(organisation: absorbing_organisation, rent_period: 1) OrganisationRentPeriod.create!(organisation: absorbing_organisation, rent_period: 1)
@ -215,6 +222,168 @@ RSpec.describe Merge::MergeOrganisationsService do
expect(sales_log.owning_organisation).to eq(merging_organisation) expect(sales_log.owning_organisation).to eq(merging_organisation)
end end
end end
context "and merge date is provided" do
subject(:merge_organisations_service) { described_class.new(absorbing_organisation_id: absorbing_organisation.id, merging_organisation_ids: [merging_organisation_ids], merge_date: Time.zone.yesterday) }
it "sets merge date on merged organisation" do
merge_organisations_service.call
merging_organisation.reload
expect(merging_organisation.merge_date.to_date).to eq(Time.zone.yesterday)
expect(merging_organisation.absorbing_organisation_id).to eq(absorbing_organisation.id)
end
context "and merging sales logs" do
let!(:sales_log) { create(:sales_log, saledate: Time.zone.today, owning_organisation: merging_organisation) }
before do
create(:sales_log, saledate: Time.zone.today - 2.days, owning_organisation: merging_organisation)
end
it "moves relevant logs" do
merge_organisations_service.call
absorbing_organisation.reload
expect(SalesLog.filter_by_owning_organisation(absorbing_organisation).count).to eq(1)
expect(SalesLog.filter_by_owning_organisation(absorbing_organisation).first).to eq(sales_log)
end
it "rolls back if there's an error" do
allow(Organisation).to receive(:find).with([merging_organisation_ids]).and_return(Organisation.find(merging_organisation_ids))
allow(Organisation).to receive(:find).with(absorbing_organisation.id).and_return(absorbing_organisation)
allow(absorbing_organisation).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
expect(Rails.logger).to receive(:error).with("Organisation merge failed with: Record invalid")
merge_organisations_service.call
absorbing_organisation.reload
expect(absorbing_organisation.sales_logs.count).to eq(0)
expect(sales_log.owning_organisation).to eq(merging_organisation)
end
end
context "and merging lettings logs" do
let(:owning_organisation) { create(:organisation, holds_own_stock: true) }
let!(:owned_lettings_log) { create(:lettings_log, startdate: Time.zone.today, owning_organisation: merging_organisation, created_by: merging_organisation_user) }
let!(:managed_lettings_log) { create(:lettings_log, startdate: Time.zone.today) }
before do
create(:organisation_relationship) { create(:organisation_relationship, parent_organisation: owning_organisation, child_organisation: merging_organisation) }
managed_lettings_log.update!(owning_organisation:, managing_organisation: merging_organisation, created_by: merging_organisation_user)
create(:lettings_log, startdate: Time.zone.today - 2.days, owning_organisation: merging_organisation, created_by: merging_organisation_user)
create(:lettings_log, startdate: Time.zone.today - 2.days, owning_organisation:, managing_organisation: merging_organisation, created_by: merging_organisation_user)
end
it "moves relevant logs" do
merge_organisations_service.call
absorbing_organisation.reload
expect(LettingsLog.filter_by_owning_organisation(absorbing_organisation).count).to eq(1)
expect(LettingsLog.filter_by_owning_organisation(absorbing_organisation).first).to eq(owned_lettings_log)
expect(LettingsLog.filter_by_managing_organisation(absorbing_organisation).count).to eq(2)
expect(LettingsLog.filter_by_managing_organisation(absorbing_organisation)).to include(managed_lettings_log)
expect(LettingsLog.filter_by_managing_organisation(absorbing_organisation)).to include(owned_lettings_log)
end
it "rolls back if there's an error" do
allow(Organisation).to receive(:find).with([merging_organisation_ids]).and_return(Organisation.find(merging_organisation_ids))
allow(Organisation).to receive(:find).with(absorbing_organisation.id).and_return(absorbing_organisation)
allow(absorbing_organisation).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
expect(Rails.logger).to receive(:error).with("Organisation merge failed with: Record invalid")
merge_organisations_service.call
absorbing_organisation.reload
expect(absorbing_organisation.lettings_logs.count).to eq(0)
expect(owned_lettings_log.owning_organisation).to eq(merging_organisation)
expect(managed_lettings_log.managing_organisation).to eq(merging_organisation)
end
end
context "and merging organisation schemes and locations" do
let!(:scheme) { create(:scheme, owning_organisation: merging_organisation) }
let!(:location) { create(:location, scheme:) }
let!(:deactivated_location) { create(:location, scheme:) }
let!(:deactivated_scheme) { create(:scheme, owning_organisation: merging_organisation) }
let!(:owned_lettings_log) { create(:lettings_log, :sh, scheme:, location:, startdate: Time.zone.tomorrow, owning_organisation: merging_organisation) }
let!(:owned_lettings_log_no_location) { create(:lettings_log, :sh, scheme:, startdate: Time.zone.tomorrow, owning_organisation: merging_organisation) }
before do
create(:location, scheme:, name: "fake location", postcode: "A1 1AA")
create(:location, scheme: deactivated_scheme)
create(:scheme_deactivation_period, scheme: deactivated_scheme, deactivation_date: Time.zone.today - 1.month)
create(:location_deactivation_period, location: deactivated_location, deactivation_date: Time.zone.today - 1.month)
create(:lettings_log, scheme:, location:, startdate: Time.zone.yesterday)
create(:lettings_log, startdate: Time.zone.tomorrow, managing_organisation: merging_organisation)
end
it "combines organisation schemes and locations" do
expect(Rails.logger).to receive(:info).with("Merged users from fake org:")
expect(Rails.logger).to receive(:info).with("\tDanny Rojas (#{merging_organisation.data_protection_officers.first.email})")
expect(Rails.logger).to receive(:info).with("\tfake name (fake@email.com)")
expect(Rails.logger).to receive(:info).with("New schemes from fake org:")
expect(Rails.logger).to receive(:info).with(/\t#{scheme.service_name} \(S/)
merge_organisations_service.call
absorbing_organisation.reload
expect(absorbing_organisation.owned_schemes.count).to eq(1)
expect(absorbing_organisation.owned_schemes.first.service_name).to eq(scheme.service_name)
expect(absorbing_organisation.owned_schemes.first.locations.count).to eq(2)
expect(absorbing_organisation.owned_schemes.first.locations.first.postcode).to eq(location.postcode)
expect(scheme.scheme_deactivation_periods.count).to eq(1)
expect(scheme.scheme_deactivation_periods.first.deactivation_date.to_date).to eq(Time.zone.yesterday)
end
it "moves relevant logs and assigns the new scheme" do
merge_organisations_service.call
absorbing_organisation.reload
merging_organisation.reload
expect(absorbing_organisation.owned_lettings_logs.count).to eq(2)
expect(absorbing_organisation.managed_lettings_logs.count).to eq(1)
expect(absorbing_organisation.owned_lettings_logs.find(owned_lettings_log.id).scheme).to eq(absorbing_organisation.owned_schemes.first)
expect(absorbing_organisation.owned_lettings_logs.find(owned_lettings_log.id).location).to eq(absorbing_organisation.owned_schemes.first.locations.first)
expect(absorbing_organisation.owned_lettings_logs.find(owned_lettings_log_no_location.id).scheme).to eq(absorbing_organisation.owned_schemes.first)
expect(absorbing_organisation.owned_lettings_logs.find(owned_lettings_log_no_location.id).location).to eq(nil)
end
it "rolls back if there's an error" do
allow(Organisation).to receive(:find).with([merging_organisation_ids]).and_return(Organisation.find(merging_organisation_ids))
allow(Organisation).to receive(:find).with(absorbing_organisation.id).and_return(absorbing_organisation)
allow(absorbing_organisation).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
expect(Rails.logger).to receive(:error).with("Organisation merge failed with: Record invalid")
merge_organisations_service.call
absorbing_organisation.reload
merging_organisation.reload
expect(absorbing_organisation.owned_schemes.count).to eq(0)
expect(scheme.scheme_deactivation_periods.count).to eq(0)
expect(owned_lettings_log.owning_organisation).to eq(merging_organisation)
expect(owned_lettings_log_no_location.owning_organisation).to eq(merging_organisation)
end
end
context "and absorbing_organisation_active_from_merge_date is true" do
subject(:merge_organisations_service) { described_class.new(absorbing_organisation_id: absorbing_organisation.id, merging_organisation_ids: [merging_organisation_ids], merge_date: Time.zone.yesterday, absorbing_organisation_active_from_merge_date: true) }
it "sets available from to merge_date for absorbing organisation" do
merge_organisations_service.call
absorbing_organisation.reload
expect(absorbing_organisation.available_from.to_date).to eq(Time.zone.yesterday)
end
end
end
context "and absorbing_organisation_active_from_merge_date is true" do
subject(:merge_organisations_service) { described_class.new(absorbing_organisation_id: absorbing_organisation.id, merging_organisation_ids: [merging_organisation_ids], absorbing_organisation_active_from_merge_date: true) }
it "sets available from to merge_date (today) for absorbing organisation" do
merge_organisations_service.call
absorbing_organisation.reload
expect(absorbing_organisation.available_from.to_date).to eq(Time.zone.today)
end
end
end end
context "when merging a multiple organisations into an existing organisation" do context "when merging a multiple organisations into an existing organisation" do
@ -318,6 +487,21 @@ RSpec.describe Merge::MergeOrganisationsService do
expect(absorbing_organisation.child_organisations).to include(absorbing_organisation_relationship.child_organisation) expect(absorbing_organisation.child_organisations).to include(absorbing_organisation_relationship.child_organisation)
end end
end end
context "and merge date is provided" do
subject(:merge_organisations_service) { described_class.new(absorbing_organisation_id: absorbing_organisation.id, merging_organisation_ids: [merging_organisation_ids], merge_date: Time.zone.yesterday) }
it "sets merge date and absorbing organisation on merged organisations" do
merge_organisations_service.call
merging_organisation.reload
merging_organisation_too.reload
expect(merging_organisation.merge_date.to_date).to eq(Time.zone.yesterday)
expect(merging_organisation.absorbing_organisation_id).to eq(absorbing_organisation.id)
expect(merging_organisation_too.merge_date.to_date).to eq(Time.zone.yesterday)
expect(merging_organisation_too.absorbing_organisation_id).to eq(absorbing_organisation.id)
end
end
end end
end end
end end

Loading…
Cancel
Save