From eca8c6ce1f2391efe2294fcd255b35d2f6426fd3 Mon Sep 17 00:00:00 2001 From: arumaio <108123468+arumaio@users.noreply.github.com> Date: Sun, 24 May 2026 13:27:27 +0200 Subject: [PATCH] =?UTF-8?q?fix=20:=20account=20destroyed=20cascade=20trans?= =?UTF-8?q?fer=20destruction=20then=20=E2=80=A6=20(#1795)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: cascade destroy transfers and reset transaction kind on account destruction. * Add rescue no method to transfer transaction reset --------- Co-authored-by: arumaio --- app/models/account.rb | 11 +++++++++++ app/models/transfer.rb | 12 ++++++++++-- test/models/account_test.rb | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index b0595d308..6e11de9c4 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -2,7 +2,10 @@ class Account < ApplicationRecord include AASM, Syncable, Monetizable, Chartable, Linkable, Enrichable, Anchorable, Reconcileable, TaxTreatable before_validation :assign_default_owner, if: -> { owner_id.blank? } + before_destroy :capture_account_statement_ids_to_move + before_destroy :cleanup_transfers + after_destroy_commit :move_account_statements_to_inbox validates :name, :balance, :currency, presence: true @@ -543,4 +546,12 @@ class Account < ApplicationRecord updated_at: Time.current ) end + + def cleanup_transfers + transaction_ids = entries.where(entryable_type: "Transaction").pluck(:entryable_id) + + transfers = Transfer.where(inflow_transaction_id: transaction_ids).or(Transfer.where(outflow_transaction_id: transaction_ids)) + + transfers.find_each(&:destroy!) + end end diff --git a/app/models/transfer.rb b/app/models/transfer.rb index 878e899be..9b39d0f7d 100644 --- a/app/models/transfer.rb +++ b/app/models/transfer.rb @@ -38,8 +38,16 @@ class Transfer < ApplicationRecord # Once transfer is destroyed, we need to mark the denormalized kind fields on the transactions def destroy! Transfer.transaction do - inflow_transaction.update!(kind: "standard") - outflow_transaction.update!(kind: "standard") + [ inflow_transaction, outflow_transaction ].each do |transaction| + next if transaction.nil? + next unless Transaction.exists?(transaction.id) + begin + transaction.update!(kind: "standard") + rescue ActiveRecord::RecordNotFound + rescue NoMethodError + next + end + end super end end diff --git a/test/models/account_test.rb b/test/models/account_test.rb index 6b1507159..de44d90cb 100644 --- a/test/models/account_test.rb +++ b/test/models/account_test.rb @@ -382,4 +382,41 @@ class AccountTest < ActiveSupport::TestCase assert_equal [ provider_holding.id, second_provider_holding.id ].sort, account.current_holdings.pluck(:id).sort assert_equal %w[CHF EUR], account.current_holdings.pluck(:currency).sort end + + test "on account destroyed cascade transfer destroyed" do + outflow_account = @family.accounts.create!({ + owner: @admin, + name: "test_account_outflow", + balance: 100, + currency: "USD", + accountable_type: "Depository", + accountable_attributes: {} + }) + inflow_account = @family.accounts.create!({ + owner: @admin, + name: "test_account_inflow", + balance: 100, + currency: "USD", + accountable_type: "Depository", + accountable_attributes: {} + }) + + transfer = create_transfer( + from_account: outflow_account, + to_account: inflow_account, + amount: 50 + ) + + outflow_transaction = transfer.outflow_transaction + + outflow_transaction.reload + assert_equal "funds_movement", outflow_transaction.kind + + inflow_account.destroy! + + assert_raises(ActiveRecord::RecordNotFound) { transfer.reload } + + outflow_transaction.reload + assert_equal "standard", outflow_transaction.kind + end end