From 9d350a87e8b16d16f1babf2c29cfec1d819b1fca Mon Sep 17 00:00:00 2001 From: Manny Dinssa <44172848+Dinssa@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:42:10 +0100 Subject: [PATCH] CLDC-3015: Remove duplicate rent periods (#2685) --- lib/tasks/duplicate_rent_periods.rake | 52 ++++++++++++++++++++ spec/lib/tasks/dupicate_rent_periods_spec.rb | 49 ++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 lib/tasks/duplicate_rent_periods.rake create mode 100644 spec/lib/tasks/dupicate_rent_periods_spec.rb diff --git a/lib/tasks/duplicate_rent_periods.rake b/lib/tasks/duplicate_rent_periods.rake new file mode 100644 index 000000000..a5cedbfbe --- /dev/null +++ b/lib/tasks/duplicate_rent_periods.rake @@ -0,0 +1,52 @@ +def process_duplicate_rent_periods(log_groups: true) + duplicate_groups = OrganisationRentPeriod + .select("organisation_id, rent_period") + .group("organisation_id, rent_period") + .having("COUNT(*) > 1") + + affected_records = OrganisationRentPeriod + .where(organisation_id: duplicate_groups.map(&:organisation_id), rent_period: duplicate_groups.map(&:rent_period)) + + if log_groups + duplicate_groups.each do |group| + group_records = affected_records.where(organisation_id: group.organisation_id, rent_period: group.rent_period) + group_records.each do |record| + Rails.logger.info "ID: #{record.id}, Organisation ID: #{record.organisation_id}, Rent Period: #{record.rent_period}" + end + Rails.logger.info "----------------------" + end + end + + to_keep_ids = OrganisationRentPeriod + .select("MIN(id) as id") + .group("organisation_id, rent_period") + .having("COUNT(*) > 1") + .map(&:id) + + duplicate_ids = affected_records.pluck(:id) - to_keep_ids + + { + affected_records:, + to_keep_ids:, + duplicate_ids:, + } +end + +desc "Find and output each group of duplicate rent periods with counts" +task find_duplicate_rent_periods: :environment do + result = process_duplicate_rent_periods(log_groups: true) + + Rails.logger.info "Total number of records: #{OrganisationRentPeriod.count}" + Rails.logger.info "Number of affected records: #{result[:affected_records].size}" + Rails.logger.info "Number of affected records to delete: #{result[:duplicate_ids].size}" + Rails.logger.info "Number of affected records to keep: #{result[:to_keep_ids].size}" +end + +desc "Delete duplicate rent periods" +task delete_duplicate_rent_periods: :environment do + result = process_duplicate_rent_periods(log_groups: false) + + OrganisationRentPeriod.where(id: result[:duplicate_ids]).delete_all + + Rails.logger.info "Number of deleted duplicate records: #{result[:duplicate_ids].size}" +end diff --git a/spec/lib/tasks/dupicate_rent_periods_spec.rb b/spec/lib/tasks/dupicate_rent_periods_spec.rb new file mode 100644 index 000000000..58d29ba28 --- /dev/null +++ b/spec/lib/tasks/dupicate_rent_periods_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" +require "rake" + +RSpec.describe "duplicate_rent_periods" do + before do + Rake.application.rake_require("tasks/duplicate_rent_periods") + Rake::Task.define_task(:environment) + allow(Rails.logger).to receive(:info) + organisation = create(:organisation, rent_periods: (2..11).to_a) + + [2, 4, 6, 11, 2, 11, 11].each do |rent_period| + org_rent_period = build(:organisation_rent_period, organisation:, rent_period:) + org_rent_period.save!(validate: false) + end + end + + describe "find_duplicate_rent_periods" do + let(:task) { Rake::Task["find_duplicate_rent_periods"] } + + before do + task.reenable + end + + it "logs the correct information about duplicate rent periods" do + task.invoke + + expect(Rails.logger).to have_received(:info).with(include("Total number of records: 17")) + expect(Rails.logger).to have_received(:info).with(include("Number of affected records: 11")) + expect(Rails.logger).to have_received(:info).with(include("Number of affected records to delete: 7")) + expect(Rails.logger).to have_received(:info).with(include("Number of affected records to keep: 4")) + end + end + + describe "delete_duplicate_rent_periods" do + let(:task) { Rake::Task["delete_duplicate_rent_periods"] } + + before do + task.reenable + end + + it "deletes redundant rent periods" do + expect { task.invoke }.to change(OrganisationRentPeriod, :count).by(-7) + expect(Rails.logger).to have_received(:info).with(include("Number of deleted duplicate records: 7")) + + remaining_rent_periods = OrganisationRentPeriod.pluck(:rent_period) + expect(remaining_rent_periods).to match_array((2..11).to_a) + end + end +end