2018-02-21 18:42:15 +01:00
< ? php
2024-11-25 04:18:55 +01:00
2018-02-21 18:42:15 +01:00
/**
* AccountDestroyService . php
2020-02-16 13:56:35 +01:00
* Copyright ( c ) 2019 james @ firefly - iii . org
2018-02-21 18:42:15 +01:00
*
2019-10-02 06:37:26 +02:00
* This file is part of Firefly III ( https :// github . com / firefly - iii ) .
2018-02-21 18:42:15 +01:00
*
2019-10-02 06:37:26 +02:00
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
2018-02-21 18:42:15 +01:00
*
2019-10-02 06:37:26 +02:00
* This program is distributed in the hope that it will be useful ,
2018-02-21 18:42:15 +01:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2019-10-02 06:37:26 +02:00
* GNU Affero General Public License for more details .
2018-02-21 18:42:15 +01:00
*
2019-10-02 06:37:26 +02:00
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2018-02-21 18:42:15 +01:00
*/
declare ( strict_types = 1 );
namespace FireflyIII\Services\Internal\Destroy ;
2025-01-03 09:11:20 +01:00
use FireflyIII\Enums\TransactionTypeEnum ;
2018-02-21 18:42:15 +01:00
use FireflyIII\Models\Account ;
2018-10-17 05:04:26 +02:00
use FireflyIII\Models\PiggyBank ;
2018-08-11 19:21:58 +02:00
use FireflyIII\Models\RecurrenceTransaction ;
2018-02-21 18:42:15 +01:00
use FireflyIII\Models\Transaction ;
2018-03-02 16:31:02 +01:00
use FireflyIII\Models\TransactionJournal ;
2018-08-11 19:21:58 +02:00
use Illuminate\Database\Eloquent\Builder ;
2025-02-16 19:30:40 +01:00
use Illuminate\Support\Facades\DB ;
2025-05-27 16:57:36 +02:00
use stdClass ;
2018-02-21 18:42:15 +01:00
/**
* Class AccountDestroyService
*/
class AccountDestroyService
{
2018-03-25 09:01:43 +02:00
public function destroy ( Account $account , ? Account $moveTo ) : void
2018-02-21 18:42:15 +01:00
{
2019-08-18 09:00:15 +02:00
// find and delete opening balance journal + opposing account
$this -> destroyOpeningBalance ( $account );
2025-05-27 17:06:15 +02:00
if ( $moveTo instanceof Account ) {
2019-07-31 16:53:09 +02:00
$this -> moveTransactions ( $account , $moveTo );
$this -> updateRecurrences ( $account , $moveTo );
}
// delete recurring transactions with this account:
2025-05-27 17:06:15 +02:00
if ( ! $moveTo instanceof Account ) {
2019-07-31 16:53:09 +02:00
$this -> destroyRecurrences ( $account );
}
// delete piggy banks:
PiggyBank :: where ( 'account_id' , $account -> id ) -> delete ();
2019-08-18 09:00:15 +02:00
// delete account meta:
$account -> accountMeta () -> delete ();
2019-07-31 16:53:09 +02:00
// delete account.
2025-02-16 19:30:40 +01:00
// at this point the account observer interferes and deletes most of the other stuff.
2022-12-30 20:25:04 +01:00
$account -> delete ();
2019-07-31 16:53:09 +02:00
}
2023-06-21 12:34:58 +02:00
private function destroyOpeningBalance ( Account $account ) : void
{
2023-10-29 06:33:43 +01:00
app ( 'log' ) -> debug ( sprintf ( 'Searching for opening balance for account #%d "%s"' , $account -> id , $account -> name ));
2023-06-21 12:34:58 +02:00
$set = $account -> transactions ()
2023-12-20 19:35:52 +01:00
-> leftJoin ( 'transaction_journals' , 'transaction_journals.id' , '=' , 'transactions.transaction_journal_id' )
-> leftJoin ( 'transaction_types' , 'transaction_types.id' , '=' , 'transaction_journals.transaction_type_id' )
2025-01-03 09:11:20 +01:00
-> where ( 'transaction_types.type' , TransactionTypeEnum :: OPENING_BALANCE -> value )
2023-12-20 19:35:52 +01:00
-> get ([ 'transactions.transaction_journal_id' ])
;
2023-06-21 12:34:58 +02:00
if ( $set -> count () > 0 ) {
2024-01-01 14:43:56 +01:00
$journalId = $set -> first () -> transaction_journal_id ;
2023-10-29 06:33:43 +01:00
app ( 'log' ) -> debug ( sprintf ( 'Found opening balance journal with ID #%d' , $journalId ));
2023-06-21 12:34:58 +02:00
// get transactions with this journal (should be just one):
$transactions = Transaction :: where ( 'transaction_journal_id' , $journalId )
2023-12-20 19:35:52 +01:00
-> where ( 'account_id' , '!=' , $account -> id )
-> get ()
;
2023-06-21 12:34:58 +02:00
/** @var Transaction $transaction */
foreach ( $transactions as $transaction ) {
2023-10-29 06:33:43 +01:00
app ( 'log' ) -> debug ( sprintf ( 'Found transaction with ID #%d' , $transaction -> id ));
2023-06-21 12:34:58 +02:00
$ibAccount = $transaction -> account ;
2023-10-29 06:33:43 +01:00
app ( 'log' ) -> debug ( sprintf ( 'Connected to account #%d "%s"' , $ibAccount -> id , $ibAccount -> name ));
2023-06-21 12:34:58 +02:00
$ibAccount -> accountMeta () -> delete ();
$transaction -> delete ();
$ibAccount -> delete ();
}
2025-01-05 07:31:26 +01:00
/** @var null|TransactionJournal $journal */
2024-01-01 14:43:56 +01:00
$journal = TransactionJournal :: find ( $journalId );
2023-10-11 07:42:38 +02:00
if ( null !== $journal ) {
/** @var JournalDestroyService $service */
$service = app ( JournalDestroyService :: class );
$service -> destroy ( $journal );
}
2023-06-21 12:34:58 +02:00
}
}
2024-02-22 20:11:09 +01:00
public function moveTransactions ( Account $account , Account $moveTo ) : void
{
app ( 'log' ) -> debug ( sprintf ( 'Move from account #%d to #%d' , $account -> id , $moveTo -> id ));
2025-02-23 12:47:04 +01:00
DB :: table ( 'transactions' ) -> where ( 'account_id' , $account -> id ) -> update ([ 'account_id' => $moveTo -> id ]);
2024-02-22 20:11:09 +01:00
2025-09-07 07:31:00 +02:00
$collection = Transaction :: groupBy ( 'transaction_journal_id' , 'account_id' ) -> where ( 'account_id' , $moveTo -> id ) -> get ([ 'transaction_journal_id' , 'account_id' , DB :: raw ( 'count(*) as the_count' )]);
2024-02-22 20:11:09 +01:00
if ( 0 === $collection -> count ()) {
return ;
}
/** @var JournalDestroyService $service */
$service = app ( JournalDestroyService :: class );
$user = $account -> user ;
2025-05-27 16:57:36 +02:00
/** @var stdClass $row */
2024-02-22 20:11:09 +01:00
foreach ( $collection as $row ) {
2024-12-22 08:43:12 +01:00
if (( int ) $row -> the_count > 1 ) {
2024-02-22 20:11:09 +01:00
$journalId = $row -> transaction_journal_id ;
$journal = $user -> transactionJournals () -> find ( $journalId );
if ( null !== $journal ) {
app ( 'log' ) -> debug ( sprintf ( 'Deleted journal #%d because it has the same source as destination.' , $journal -> id ));
$service -> destroy ( $journal );
}
}
}
}
2023-06-21 12:34:58 +02:00
private function updateRecurrences ( Account $account , Account $moveTo ) : void
{
2025-02-16 19:30:40 +01:00
DB :: table ( 'recurrences_transactions' ) -> where ( 'source_id' , $account -> id ) -> update ([ 'source_id' => $moveTo -> id ]);
DB :: table ( 'recurrences_transactions' ) -> where ( 'destination_id' , $account -> id ) -> update ([ 'destination_id' => $moveTo -> id ]);
2023-06-21 12:34:58 +02:00
}
2019-07-31 16:53:09 +02:00
private function destroyRecurrences ( Account $account ) : void
{
2024-01-01 14:43:56 +01:00
$recurrences = RecurrenceTransaction :: where (
2023-12-21 05:07:26 +01:00
static function ( Builder $q ) use ( $account ) : void {
2019-07-31 16:53:09 +02:00
$q -> where ( 'source_id' , $account -> id );
$q -> orWhere ( 'destination_id' , $account -> id );
2018-08-11 19:21:58 +02:00
}
2019-07-31 16:53:09 +02:00
) -> get ([ 'recurrence_id' ]) -> pluck ( 'recurrence_id' ) -> toArray ();
/** @var RecurrenceDestroyService $destroyService */
$destroyService = app ( RecurrenceDestroyService :: class );
foreach ( $recurrences as $recurrenceId ) {
2024-12-22 08:43:12 +01:00
$destroyService -> destroyById (( int ) $recurrenceId );
2018-08-11 19:21:58 +02:00
}
2019-07-31 16:53:09 +02:00
}
2018-03-05 19:35:58 +01:00
}