Do not try to correct transactions between asset / liability with foreign amount info.

This commit is contained in:
James Cole
2025-05-11 07:09:48 +02:00
parent 899d374222
commit 0545826d57

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction; namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
@@ -47,7 +48,10 @@ class CorrectsUnevenAmount extends Command
public function handle(): int public function handle(): int
{ {
$this->count = 0; $this->count = 0;
// convert transfers with foreign currency info where the amount is NOT uneven (it should be)
$this->convertOldStyleTransfers(); $this->convertOldStyleTransfers();
$this->fixUnevenAmounts(); $this->fixUnevenAmounts();
$this->matchCurrencies(); $this->matchCurrencies();
if (true === config('firefly.feature_flags.running_balance_column')) { if (true === config('firefly.feature_flags.running_balance_column')) {
@@ -68,8 +72,7 @@ class CorrectsUnevenAmount extends Command
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id') ->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->where('transaction_types.type', TransactionTypeEnum::TRANSFER->value) ->where('transaction_types.type', TransactionTypeEnum::TRANSFER->value)
->whereNotNull('foreign_currency_id') ->whereNotNull('foreign_currency_id')
->whereNotNull('foreign_amount')->get(['transactions.transaction_journal_id']) ->whereNotNull('foreign_amount')->get(['transactions.transaction_journal_id']);
;
$count = 0; $count = 0;
Log::debug(sprintf('Found %d potential journal(s)', $transactions->count())); Log::debug(sprintf('Found %d potential journal(s)', $transactions->count()));
@@ -119,11 +122,11 @@ class CorrectsUnevenAmount extends Command
private function fixUnevenAmounts(): void private function fixUnevenAmounts(): void
{ {
Log::debug('fixUnevenAmounts()');
$journals = DB::table('transactions') $journals = DB::table('transactions')
->groupBy('transaction_journal_id') ->groupBy('transaction_journal_id')
->whereNull('deleted_at') ->whereNull('deleted_at')
->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')]) ->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')]);
;
/** @var \stdClass $entry */ /** @var \stdClass $entry */
foreach ($journals as $entry) { foreach ($journals as $entry) {
@@ -207,7 +210,7 @@ class CorrectsUnevenAmount extends Command
} }
// may still be able to salvage this journal if it is a transfer with foreign currency info // may still be able to salvage this journal if it is a transfer with foreign currency info
if ($this->isForeignCurrencyTransfer($journal)) { if ($this->isForeignCurrencyTransfer($journal) || $this->isBetweenAssetAndLiability($journal)) {
Log::debug(sprintf('Can skip foreign currency transfer #%d.', $journal->id)); Log::debug(sprintf('Can skip foreign currency transfer #%d.', $journal->id));
return; return;
@@ -264,8 +267,7 @@ class CorrectsUnevenAmount extends Command
{ {
$journals = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', 'transactions.transaction_journal_id') $journals = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', 'transactions.transaction_journal_id')
->where('transactions.transaction_currency_id', '!=', DB::raw('transaction_journals.transaction_currency_id')) ->where('transactions.transaction_currency_id', '!=', DB::raw('transaction_journals.transaction_currency_id'))
->get(['transaction_journals.*']) ->get(['transaction_journals.*']);
;
$count = 0; $count = 0;
@@ -285,4 +287,42 @@ class CorrectsUnevenAmount extends Command
$this->friendlyPositive(sprintf('Fixed %d journal(s) with mismatched currencies.', $journals->count())); $this->friendlyPositive(sprintf('Fixed %d journal(s) with mismatched currencies.', $journals->count()));
} }
private function isBetweenAssetAndLiability(TransactionJournal $journal): bool
{
/** @var Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
/** @var Transaction $destinationTransaction */
$destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first();
if (null === $sourceTransaction || null === $destinationTransaction) {
Log::warning('Either transaction is false, stop.');
return false;
}
if (null === $sourceTransaction->foreign_amount || null === $destinationTransaction->foreign_amount) {
Log::warning('Either foreign amount is false, stop.');
return false;
}
$source = $sourceTransaction->account;
$destination = $destinationTransaction->account;
if (null === $source || null === $destination) {
Log::warning('Either is false, stop.');
return false;
}
$sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
// source is liability, destination is asset
if (in_array($source->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $destination->accountType->type) {
Log::debug('Source is a liability account, destination is an asset account, return TRUE.');
return true;
}
// source is asset, destination is liability
if (in_array($destination->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $source->accountType->type) {
Log::debug('Destination is a liability account, source is an asset account, return TRUE.');
return true;
}
Log::debug('Not between asset and liability, return FALSE');
return false;
}
} }