diff --git a/app/models/duplicate_log_reference.rb b/app/models/duplicate_log_reference.rb new file mode 100644 index 000000000..a8ef83444 --- /dev/null +++ b/app/models/duplicate_log_reference.rb @@ -0,0 +1,18 @@ +class DuplicateLogReference < ApplicationRecord + belongs_to :log, polymorphic: true + + before_create :set_default_duplicate_log_reference_id + +private + + def set_default_duplicate_log_reference_id + self.duplicate_log_reference_id ||= generate_new_id + end + + def generate_new_id + loop do + duplicate_log_reference_id = SecureRandom.random_number(1_000_000) + return duplicate_log_reference_id unless DuplicateLogReference.exists?(duplicate_log_reference_id:) + end + end +end diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index 3eda732d1..854acd79d 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -631,6 +631,10 @@ class LettingsLog < Log renttype == 1 || renttype == 2 end + def duplicates + LettingsLog.joins(:duplicate_log_references).where(duplicate_log_references: { duplicate_log_reference_id: duplicate_log_references&.first&.duplicate_log_reference_id }).where.not(id:) + end + private def reset_invalid_unresolved_log_fields! diff --git a/app/models/log.rb b/app/models/log.rb index 8814e771d..91964c43e 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -7,6 +7,7 @@ class Log < ApplicationRecord belongs_to :created_by, class_name: "User", optional: true belongs_to :updated_by, class_name: "User", optional: true belongs_to :bulk_upload, optional: true + has_many :duplicate_log_references, as: :log before_save :update_status! diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index cff497ae4..422e328d0 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -448,4 +448,8 @@ class SalesLog < Log form.start_date.year < 2023 || uprn.blank? ? "postcode_full" : nil, form.start_date.year >= 2023 && uprn.present? ? "uprn" : nil].compact end + + def duplicates + SalesLog.joins(:duplicate_log_references).where(duplicate_log_references: { duplicate_log_reference_id: duplicate_log_references&.first&.duplicate_log_reference_id }).where.not(id:) + end end diff --git a/db/migrate/20240110101500_create_duplicate_log_references.rb b/db/migrate/20240110101500_create_duplicate_log_references.rb new file mode 100644 index 000000000..1edae4a38 --- /dev/null +++ b/db/migrate/20240110101500_create_duplicate_log_references.rb @@ -0,0 +1,11 @@ +class CreateDuplicateLogReferences < ActiveRecord::Migration[7.0] + def change + create_table :duplicate_log_references do |t| + t.integer :duplicate_log_reference_id + t.integer :log_id + t.string :log_type + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 22d67bb9f..58ebd5d95 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_12_18_105226) do +ActiveRecord::Schema[7.0].define(version: 2024_01_10_101500) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -63,6 +63,14 @@ ActiveRecord::Schema[7.0].define(version: 2023_12_18_105226) do t.index ["organisation_id"], name: "index_data_protection_confirmations_on_organisation_id" end + create_table "duplicate_log_references", force: :cascade do |t| + t.integer "duplicate_log_reference_id" + t.integer "log_id" + t.string "log_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "la_rent_ranges", force: :cascade do |t| t.integer "ranges_rent_id" t.integer "lettype" diff --git a/spec/models/duplicate_log_reference_spec.rb b/spec/models/duplicate_log_reference_spec.rb new file mode 100644 index 000000000..a92ce7d26 --- /dev/null +++ b/spec/models/duplicate_log_reference_spec.rb @@ -0,0 +1,89 @@ +require "rails_helper" + +RSpec.describe DuplicateLogReference, type: :model do + context "when adding a new duplicate log" do + context "and duplicate_log_reference_id is not given" do + let(:sales_log) { create(:sales_log) } + + it "generates a new random duplicate_log_reference_id" do + duplicate_log = described_class.create!(log_id: sales_log.id, log_type: "SalesLog") + expect(duplicate_log.duplicate_log_reference_id).to be_a(Integer) + end + end + + context "and duplicate_log_reference_id is given" do + let(:sales_log) { create(:sales_log) } + + it "adds correct duplicate_log_reference_id" do + duplicate_log = described_class.create!(log_id: sales_log.id, log_type: "SalesLog", duplicate_log_reference_id: 123_456) + expect(duplicate_log.duplicate_log_reference_id).to eq(123_456) + end + end + + context "and log does not exist" do + it "raises an error" do + expect { described_class.create!(log_id: 1, log_type: "SalesLog") }.to raise_error(ActiveRecord::RecordInvalid) + end + end + + context "and log_type is invalid" do + let(:sales_log) { create(:sales_log) } + + it "raises an error" do + expect { described_class.create!(log_id: sales_log.id, log_type: "SomethingElse") }.to raise_error(NameError) + end + end + end + + context "when accessing all duplicates for a sales log" do + let(:sales_log) { create(:sales_log) } + + context "and there are no duplicates" do + it "returns an empty array" do + expect(sales_log.duplicates).to eq([]) + end + end + + context "and there are duplicates" do + let(:other_sales_log) { create(:sales_log) } + + before do + duplicate_log = described_class.create!(log_id: sales_log.id, log_type: "SalesLog") + described_class.create!(log_id: other_sales_log.id, log_type: "SalesLog", duplicate_log_reference_id: duplicate_log.duplicate_log_reference_id) + create(:sales_log) + create(:sales_log) + end + + it "returns the correct duplicates" do + expect(sales_log.duplicates.count).to eq(1) + expect(sales_log.duplicates).to include(other_sales_log) + end + end + end + + context "when accessing all duplicates for a lettings log" do + let(:lettings_log) { create(:lettings_log) } + + context "and there are no duplicates" do + it "returns an empty array" do + expect(lettings_log.duplicates).to eq([]) + end + end + + context "and there are duplicates" do + let(:other_lettings_log) { create(:lettings_log) } + + before do + duplicate_log = described_class.create!(log_id: lettings_log.id, log_type: "LettingsLog") + described_class.create!(log_id: other_lettings_log.id, log_type: "LettingsLog", duplicate_log_reference_id: duplicate_log.duplicate_log_reference_id) + create(:lettings_log) + create(:lettings_log) + end + + it "returns the correct duplicates" do + expect(lettings_log.duplicates.count).to eq(1) + expect(lettings_log.duplicates).to include(other_lettings_log) + end + end + end +end