cleanup: Commands are a lot less verbal and report better on success / failue

This commit is contained in:
James Cole
2023-06-02 07:36:17 +02:00
parent 1e1497ff4e
commit dcf71c6fdf
60 changed files with 1108 additions and 1698 deletions

View File

@@ -39,22 +39,10 @@ use Illuminate\Console\Command;
*/
class CorrectAmounts extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command makes sure positive and negative amounts are recorded correctly.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-amount-pos-neg';
protected $signature = 'firefly-iii:fix-amount-pos-neg';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int

View File

@@ -34,25 +34,14 @@ use Schema;
*/
class CorrectDatabase extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Will correct the integrity of your database, if necessary.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:correct-database';
protected $signature = 'firefly-iii:correct-database';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->line('Handle Firefly III database correction commands.');
// if table does not exist, return false
if (!Schema::hasTable('users')) {
$this->error('No "users"-table, will not continue.');

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
@@ -33,26 +32,15 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use JsonException;
use Illuminate\Support\Collection;
/**
* Class CorrectOpeningBalanceCurrencies
*/
class CorrectOpeningBalanceCurrencies extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Will make sure that opening balance transaction currencies match the account they\'re for.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-ob-currencies';
protected $signature = 'firefly-iii:fix-ob-currencies';
/**
* Execute the console command.
@@ -61,32 +49,22 @@ class CorrectOpeningBalanceCurrencies extends Command
*/
public function handle(): int
{
Log::debug(sprintf('Now in %s', __METHOD__));
// get all OB journals:
$set = TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereNull('transaction_journals.deleted_at')
->where('transaction_types.type', TransactionType::OPENING_BALANCE)->get(['transaction_journals.*']);
$this->line(sprintf('Going to verify %d opening balance transactions.', $set->count()));
$count = 0;
$journals = $this->getJournals();
$count = 0;
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
foreach ($journals as $journal) {
$count += $this->correctJournal($journal);
}
if ($count > 0) {
$message = sprintf('Corrected %d opening balance transaction(s).', $count);
Log::debug($message);
$this->line($message);
}
if (0 === $count) {
$message = 'There was nothing to fix in the opening balance transactions.';
Log::debug($message);
$message = 'Correct: There was nothing to fix in the opening balance transactions.';
$this->info($message);
}
Log::debug(sprintf('Done with %s', __METHOD__));
return 0;
}
@@ -94,24 +72,21 @@ class CorrectOpeningBalanceCurrencies extends Command
* @param TransactionJournal $journal
*
* @return int
* @throws FireflyException
* @throws JsonException
*/
private function correctJournal(TransactionJournal $journal): int
{
// get the asset account for this opening balance:
$account = $this->getAccount($journal);
if (null === $account) {
$message = sprintf('Transaction journal #%d has no valid account. Cant fix this line.', $journal->id);
$message = sprintf('Transaction journal #%d has no valid account. Can\'t fix this line.', $journal->id);
app('log')->warning($message);
$this->warn($message);
return 0;
}
$currency = $this->getCurrency($account);
// update journal and all transactions:
return $this->setCurrency($journal, $currency);
return $this->setCorrectCurrency($account, $journal);
}
/**
@@ -138,8 +113,6 @@ class CorrectOpeningBalanceCurrencies extends Command
* @param Account $account
*
* @return TransactionCurrency
* @throws JsonException
* @throws FireflyException
*/
private function getCurrency(Account $account): TransactionCurrency
{
@@ -151,14 +124,25 @@ class CorrectOpeningBalanceCurrencies extends Command
}
/**
* @return Collection
*/
private function getJournals(): Collection
{
/** @var Collection */
return TransactionJournal::leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->whereNull('transaction_journals.deleted_at')
->where('transaction_types.type', TransactionType::OPENING_BALANCE)->get(['transaction_journals.*']);
}
/**
* @param Account $account
* @param TransactionJournal $journal
* @param TransactionCurrency $currency
*
* @return int
*/
private function setCurrency(TransactionJournal $journal, TransactionCurrency $currency): int
private function setCorrectCurrency(Account $account, TransactionJournal $journal): int
{
$count = 0;
$currency = $this->getCurrency($account);
$count = 0;
if ((int)$journal->transaction_currency_id !== (int)$currency->id) {
$journal->transaction_currency_id = $currency->id;
$journal->save();

View File

@@ -58,7 +58,6 @@ class CreateAccessTokens extends Command
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
$start = microtime(true);
$count = 0;
$users = $repository->all();
/** @var User $user */
@@ -72,10 +71,8 @@ class CreateAccessTokens extends Command
}
}
if (0 === $count) {
$this->info('All access tokens OK!');
$this->info('Correct: Verified access tokens.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verify access tokens in %s seconds.', $end));
return 0;
}

View File

@@ -51,7 +51,6 @@ class CreateLinkTypes extends Command
*/
public function handle(): int
{
$start = microtime(true);
$count = 0;
$set = [
'Related' => ['relates to', 'relates to'],
@@ -74,11 +73,8 @@ class CreateLinkTypes extends Command
$link->save();
}
if (0 === $count) {
$this->info('All link types OK!');
$this->info('Correct: all link types are OK');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified link types in %s seconds', $end));
return 0;
}
}

View File

@@ -26,25 +26,14 @@ namespace FireflyIII\Console\Commands\Correction;
use Exception;
use FireflyIII\Models\TransactionGroup;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
/**
* Class DeleteEmptyGroups
*/
class DeleteEmptyGroups extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Delete empty transaction groups.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:delete-empty-groups';
protected $signature = 'firefly-iii:delete-empty-groups';
/**
* Execute the console command.
@@ -55,14 +44,11 @@ class DeleteEmptyGroups extends Command
*/
public function handle(): int
{
Log::debug(sprintf('Now in %s', __METHOD__));
$start = microtime(true);
$groupIds
= TransactionGroup::leftJoin('transaction_journals', 'transaction_groups.id', '=', 'transaction_journals.transaction_group_id')
->whereNull('transaction_journals.id')->get(['transaction_groups.id'])->pluck('id')->toArray();
= TransactionGroup::leftJoin('transaction_journals', 'transaction_groups.id', '=', 'transaction_journals.transaction_group_id')
->whereNull('transaction_journals.id')->get(['transaction_groups.id'])->pluck('id')->toArray();
$total = count($groupIds);
Log::debug(sprintf('Count is %d', $total));
if ($total > 0) {
$this->info(sprintf('Deleted %d empty transaction group(s).', $total));
@@ -72,8 +58,9 @@ class DeleteEmptyGroups extends Command
TransactionGroup::whereNull('deleted_at')->whereIn('id', $chunk)->delete();
}
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified empty groups in %s seconds', $end));
if (0 === $total) {
$this->info('Correct: verified empty groups.');
}
return 0;
}

View File

@@ -63,7 +63,6 @@ class DeleteEmptyJournals extends Command
private function deleteEmptyJournals(): void
{
$start = microtime(true);
$count = 0;
$set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->groupBy('transaction_journals.id')
@@ -82,10 +81,8 @@ class DeleteEmptyJournals extends Command
++$count;
}
if (0 === $count) {
$this->info('No empty transaction journals.');
$this->info('Correct: no empty transaction journals.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified empty journals in %s seconds', $end));
}
/**
@@ -115,7 +112,7 @@ class DeleteEmptyJournals extends Command
}
}
if (0 === $total) {
$this->info('No uneven transaction journals.');
$this->info('Correct: no uneven transaction journals.');
}
}
}

View File

@@ -55,12 +55,9 @@ class DeleteOrphanedTransactions extends Command
*/
public function handle(): int
{
$start = microtime(true);
$this->deleteOrphanedJournals();
$this->deleteOrphanedTransactions();
$this->deleteFromOrphanedAccounts();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified orphans in %s seconds', $end));
return 0;
}
@@ -93,7 +90,7 @@ class DeleteOrphanedTransactions extends Command
$count++;
}
if (0 === $count) {
$this->info('No orphaned accounts.');
$this->info('Correct: no orphaned accounts.');
}
}
@@ -105,7 +102,7 @@ class DeleteOrphanedTransactions extends Command
->get(['transaction_journals.id', 'transaction_journals.transaction_group_id']);
$count = $set->count();
if (0 === $count) {
$this->info('No orphaned journals.');
$this->info('Correct: no orphaned journals.');
}
if ($count > 0) {
$this->info(sprintf('Found %d orphaned journal(s).', $count));
@@ -157,7 +154,7 @@ class DeleteOrphanedTransactions extends Command
}
}
if (0 === $count) {
$this->info('No orphaned transactions.');
$this->info('Correct: no orphaned transactions.');
}
}
}

View File

@@ -52,7 +52,6 @@ class DeleteZeroAmount extends Command
*/
public function handle(): int
{
$start = microtime(true);
$set = Transaction::where('amount', 0)->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
$set = array_unique($set);
$journals = TransactionJournal::whereIn('id', $set)->get();
@@ -64,12 +63,9 @@ class DeleteZeroAmount extends Command
Transaction::where('transaction_journal_id', $journal->id)->delete();
}
if (0 === $journals->count()) {
$this->info('No zero-amount transaction journals.');
$this->info('Correct: no zero-amount transaction journals.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified zero-amount integrity in %s seconds', $end));
return 0;
}
}

View File

@@ -37,18 +37,8 @@ use Illuminate\Support\Facades\Log;
*/
class EnableCurrencies extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Enables all currencies in use.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:enable-currencies';
protected $signature = 'firefly-iii:enable-currencies';
/**
* Execute the console command.
@@ -57,7 +47,6 @@ class EnableCurrencies extends Command
*/
public function handle(): int
{
$start = microtime(true);
$found = [];
// get all meta entries
/** @var Collection $meta */
@@ -85,8 +74,8 @@ class EnableCurrencies extends Command
$found[] = (int)$entry->transaction_currency_id;
}
$found = array_values(array_unique($found));
$found = array_values(
$found = array_values(array_unique($found));
$found = array_values(
array_filter(
$found,
function (int $currencyId) {
@@ -94,22 +83,15 @@ class EnableCurrencies extends Command
}
)
);
$message = sprintf('%d different currencies are currently in use.', count($found));
$this->info($message);
Log::debug($message, $found);
$disabled = TransactionCurrency::whereIn('id', $found)->where('enabled', false)->count();
if ($disabled > 0) {
$this->info(sprintf('%d were (was) still disabled. This has been corrected.', $disabled));
}
if (0 === $disabled) {
$this->info('All currencies are correctly enabled or disabled.');
$this->info('Correct: All currencies are correctly enabled or disabled.');
}
TransactionCurrency::whereIn('id', $found)->update(['enabled' => true]);
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified currencies in %s seconds.', $end));
return 0;
}
}

View File

@@ -32,18 +32,8 @@ use Illuminate\Console\Command;
*/
class FixAccountOrder extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Make sure account order is correct.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-account-order';
protected $signature = 'firefly-iii:fix-account-order';
private AccountRepositoryInterface $repository;
@@ -55,7 +45,6 @@ class FixAccountOrder extends Command
public function handle(): int
{
$this->stupidLaravel();
$start = microtime(true);
$users = User::get();
foreach ($users as $user) {
@@ -63,8 +52,7 @@ class FixAccountOrder extends Command
$this->repository->resetAccountOrder();
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verifying account order took %s seconds', $end));
$this->info('Correct: All accounts are ordered correctly');
return 0;
}

View File

@@ -38,18 +38,8 @@ use Illuminate\Support\Facades\Log;
*/
class FixAccountTypes extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Make sure all journals have the correct from/to account types.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-account-types';
protected $signature = 'firefly-iii:fix-account-types';
private int $count;
private array $expected;
private AccountFactory $factory;
@@ -63,103 +53,23 @@ class FixAccountTypes extends Command
public function handle(): int
{
$this->stupidLaravel();
Log::debug('Now in fix-account-types');
$start = microtime(true);
$this->factory = app(AccountFactory::class);
$this->expected = config('firefly.source_dests');
$journals = TransactionJournal::with(['TransactionType', 'transactions', 'transactions.account', 'transactions.account.accounttype'])->get();
Log::debug(sprintf('Found %d journals to inspect.', $journals->count()));
foreach ($journals as $journal) {
$this->inspectJournal($journal);
}
if (0 === $this->count) {
Log::debug('No journals had to be fixed.');
$this->info('All account types are OK!');
$this->info('Correct: all account types are OK');
}
if (0 !== $this->count) {
Log::debug(sprintf('%d journals had to be fixed.', $this->count));
$this->info(sprintf('Acted on %d transaction(s)!', $this->count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verifying account types took %s seconds', $end));
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
}
/**
* @param TransactionJournal $journal
*
* @throws FireflyException
*/
private function inspectJournal(TransactionJournal $journal): void
{
$transactions = $journal->transactions()->count();
if (2 !== $transactions) {
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
return;
}
$type = $journal->transactionType->type;
$sourceTransaction = $this->getSourceTransaction($journal);
$destTransaction = $this->getDestinationTransaction($journal);
$sourceAccount = $sourceTransaction->account;
$sourceAccountType = $sourceAccount->accountType->type;
$destAccount = $destTransaction->account;
$destAccountType = $destAccount->accountType->type;
if (!array_key_exists($type, $this->expected)) {
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
return;
}
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
return;
}
$expectedTypes = $this->expected[$type][$sourceAccountType];
if (!in_array($destAccountType, $expectedTypes, true)) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
}
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getSourceTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '<', 0);
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getDestinationTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '>', 0);
}
/**
* @param TransactionJournal $journal
* @param string $type
@@ -254,4 +164,77 @@ class FixAccountTypes extends Command
break;
}
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getDestinationTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '>', 0);
}
/**
* @param TransactionJournal $journal
*
* @return Transaction
*/
private function getSourceTransaction(TransactionJournal $journal): Transaction
{
return $journal->transactions->firstWhere('amount', '<', 0);
}
/**
* @param TransactionJournal $journal
*
* @throws FireflyException
*/
private function inspectJournal(TransactionJournal $journal): void
{
$transactions = $journal->transactions()->count();
if (2 !== $transactions) {
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
return;
}
$type = $journal->transactionType->type;
$sourceTransaction = $this->getSourceTransaction($journal);
$destTransaction = $this->getDestinationTransaction($journal);
$sourceAccount = $sourceTransaction->account;
$sourceAccountType = $sourceAccount->accountType->type;
$destAccount = $destTransaction->account;
$destAccountType = $destAccount->accountType->type;
if (!array_key_exists($type, $this->expected)) {
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
return;
}
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
return;
}
$expectedTypes = $this->expected[$type][$sourceAccountType];
if (!in_array($destAccountType, $expectedTypes, true)) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
}
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
}
}

View File

@@ -36,18 +36,8 @@ use Illuminate\Console\Command;
*/
class FixFrontpageAccounts extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes a preference that may include deleted accounts or accounts of another type.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-frontpage-accounts';
protected $signature = 'firefly-iii:fix-frontpage-accounts';
/**
* Execute the console command.
@@ -56,8 +46,6 @@ class FixFrontpageAccounts extends Command
*/
public function handle(): int
{
$start = microtime(true);
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
@@ -66,8 +54,7 @@ class FixFrontpageAccounts extends Command
$this->fixPreference($preference);
}
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verifying account preferences took %s seconds', $end));
$this->info('Correct: account preferences are OK');
return 0;
}

View File

@@ -36,18 +36,8 @@ use Illuminate\Console\Command;
*/
class FixGroupAccounts extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Unify the source / destination accounts of split groups.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:unify-group-accounts';
protected $signature = 'firefly-iii:unify-group-accounts';
/**
* Execute the console command.
@@ -72,7 +62,7 @@ class FixGroupAccounts extends Command
$handler->unifyAccounts($event);
}
$this->line('Updated inconsistent transaction groups.');
$this->info('Correct: updated possible inconsistent transaction groups.');
return 0;
}

View File

@@ -34,18 +34,9 @@ use Illuminate\Support\Collection;
*/
class FixIbans extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Removes spaces from IBANs';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-ibans';
protected $signature = 'firefly-iii:fix-ibans';
private int $count = 0;
/**
* Execute the console command.
@@ -57,6 +48,9 @@ class FixIbans extends Command
$accounts = Account::whereNotNull('iban')->get();
$this->filterIbans($accounts);
$this->countAndCorrectIbans($accounts);
if (0 === $this->count) {
$this->info('Correct: All IBANs are valid.');
}
return 0;
}
@@ -99,6 +93,7 @@ class FixIbans extends Command
);
$account->iban = null;
$account->save();
$this->count++;
}
}
@@ -124,6 +119,7 @@ class FixIbans extends Command
$account->iban = $iban;
$account->save();
$this->line(sprintf('Removed spaces from IBAN of account #%d', $account->id));
$this->count++;
}
}
}

View File

@@ -34,18 +34,8 @@ use Illuminate\Console\Command;
class FixLongDescriptions extends Command
{
private const MAX_LENGTH = 1000;
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes long descriptions in journals and groups.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-long-descriptions';
protected $signature = 'firefly-iii:fix-long-descriptions';
/**
* Execute the console command.
@@ -54,14 +44,15 @@ class FixLongDescriptions extends Command
*/
public function handle(): int
{
$start = microtime(true);
$journals = TransactionJournal::get(['id', 'description']);
$count = 0;
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
if (strlen($journal->description) > self::MAX_LENGTH) {
$journal->description = substr($journal->description, 0, self::MAX_LENGTH);
$journal->save();
$this->line(sprintf('Truncated description of transaction journal #%d', $journal->id));
$count++;
}
}
@@ -72,11 +63,12 @@ class FixLongDescriptions extends Command
$group->title = substr($group->title, 0, self::MAX_LENGTH);
$group->save();
$this->line(sprintf('Truncated description of transaction group #%d', $group->id));
$count++;
}
}
$end = round(microtime(true) - $start, 2);
$this->info('Verified all transaction group and journal title lengths.');
$this->info(sprintf('Took %s seconds.', $end));
if (0 === $count) {
$this->info('Correct: all transaction group and journal title lengths are within bounds.');
}
return 0;
}

View File

@@ -34,18 +34,8 @@ use Illuminate\Console\Command;
*/
class FixPiggies extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes common issues with piggy banks.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-piggies';
protected $signature = 'firefly-iii:fix-piggies';
/**
* Execute the console command.
@@ -55,7 +45,6 @@ class FixPiggies extends Command
public function handle(): int
{
$count = 0;
$start = microtime(true);
$set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal'])->get();
/** @var PiggyBankEvent $event */
@@ -74,15 +63,12 @@ class FixPiggies extends Command
}
}
if (0 === $count) {
$this->line('All piggy bank events are correct.');
$this->info('Correct: all piggy bank events are OK.');
}
if (0 !== $count) {
$this->line(sprintf('Fixed %d piggy bank event(s).', $count));
}
$end = round(microtime(true) - $start, 2);
$this->line(sprintf('Verified the content of %d piggy bank events in %s seconds.', $set->count(), $end));
return 0;
}
}

View File

@@ -37,22 +37,11 @@ use Illuminate\Console\Command;
*/
class FixRecurringTransactions extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes recurring transactions with the wrong transaction type.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-recurring-transactions';
/** @var RecurringRepositoryInterface */
private $recurringRepos;
/** @var UserRepositoryInterface */
private $userRepos;
protected $description = 'Fixes recurring transactions with the wrong transaction type.';
protected $signature = 'firefly-iii:fix-recurring-transactions';
private int $count = 0;
private RecurringRepositoryInterface $recurringRepos;
private UserRepositoryInterface $userRepos;
/**
* Execute the console command.
@@ -61,11 +50,11 @@ class FixRecurringTransactions extends Command
*/
public function handle(): int
{
$start = microtime(true);
$this->stupidLaravel();
$this->correctTransactions();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Corrected recurring transactions in %s seconds.', $end));
if (0 === $this->count) {
$this->info('Correct: all recurring transactions are OK.');
}
return 0;
}
@@ -111,6 +100,7 @@ class FixRecurringTransactions extends Command
if (null !== $transactionType) {
$recurrence->transaction_type_id = $transactionType->id;
$recurrence->save();
$this->count++;
}
}
}

View File

@@ -37,18 +37,8 @@ use Illuminate\Support\Collection;
*/
class FixTransactionTypes extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Make sure all transactions are of the correct type, based on source + dest.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-transaction-types';
protected $signature = 'firefly-iii:fix-transaction-types';
/**
* Execute the console command.
@@ -57,7 +47,6 @@ class FixTransactionTypes extends Command
*/
public function handle(): int
{
$start = microtime(true);
$count = 0;
$journals = $this->collectJournals();
/** @var TransactionJournal $journal */
@@ -67,13 +56,12 @@ class FixTransactionTypes extends Command
$count++;
}
}
$end = round(microtime(true) - $start, 2);
if ($count > 0) {
$this->info(sprintf('Corrected transaction type of %d transaction journals in %s seconds.', $count, $end));
$this->info('Corrected transaction type of %d transaction journals.', $count);
return 0;
}
$this->line(sprintf('All transaction journals are of the correct transaction type (in %s seconds).', $end));
$this->info('Correct: all transaction journals are of the correct transaction type');
return 0;
}

View File

@@ -27,7 +27,6 @@ use DB;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use stdClass;
/**
@@ -35,18 +34,8 @@ use stdClass;
*/
class FixUnevenAmount extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fix journals with uneven amounts.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-uneven-amount';
protected $signature = 'firefly-iii:fix-uneven-amount';
/**
* Execute the console command.
@@ -55,10 +44,7 @@ class FixUnevenAmount extends Command
*/
public function handle(): int
{
Log::debug(sprintf('Now in %s', __METHOD__));
$start = microtime(true);
$count = 0;
// get invalid journals
$count = 0;
$journals = DB::table('transactions')
->groupBy('transaction_journal_id')
->whereNull('deleted_at')
@@ -74,12 +60,9 @@ class FixUnevenAmount extends Command
}
}
if (0 === $count) {
$this->info('Amount integrity OK!');
$this->info('Correct: Database amount integrity is OK');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified amount integrity in %s seconds', $end));
return 0;
}

View File

@@ -32,18 +32,8 @@ use Illuminate\Console\Command;
*/
class RemoveBills extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Remove bills from transactions that shouldn\'t have one.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:remove-bills';
protected $signature = 'firefly-iii:remove-bills';
/**
* Execute the console command.
@@ -52,7 +42,6 @@ class RemoveBills extends Command
*/
public function handle(): int
{
$start = microtime(true);
/** @var TransactionType|null $withdrawal */
$withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
if (null === $withdrawal) {
@@ -65,14 +54,10 @@ class RemoveBills extends Command
$journal->bill_id = null;
$journal->save();
}
if (0 === $journals->count()) {
$this->info('All transaction journals have correct bill information.');
}
if ($journals->count() > 0) {
$this->info('Fixed all transaction journals so they have correct bill information.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified bills / journals in %s seconds', $end));
$this->info('Correct: verified bills / journals in %s seconds');
return 0;
}

View File

@@ -31,18 +31,8 @@ use Illuminate\Console\Command;
*/
class RenameMetaFields extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Rename changed meta fields.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:rename-meta-fields';
protected $signature = 'firefly-iii:rename-meta-fields';
private int $count;
@@ -54,7 +44,6 @@ class RenameMetaFields extends Command
public function handle(): int
{
$this->count = 0;
$start = microtime(true);
$changes = [
'original-source' => 'original_source',
@@ -74,15 +63,11 @@ class RenameMetaFields extends Command
$this->rename($original, $update);
}
if (0 === $this->count) {
$this->line('All meta fields are correct.');
$this->info('Correct: all meta fields are correct.');
}
if (0 !== $this->count) {
$this->line(sprintf('Renamed %d meta field(s).', $this->count));
$this->info(sprintf('Renamed %d meta field(s).', $this->count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Renamed meta fields in %s seconds', $end));
return 0;
}

View File

@@ -33,18 +33,8 @@ use Illuminate\Support\Facades\Log;
*/
class TransferBudgets extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Removes budgets from transfers.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:fix-transfer-budgets';
protected $signature = 'firefly-iii:fix-transfer-budgets';
/**
* Execute the console command.
@@ -53,7 +43,6 @@ class TransferBudgets extends Command
*/
public function handle(): int
{
$start = microtime(true);
$set = TransactionJournal::distinct()
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('budget_transaction_journal', 'transaction_journals.id', '=', 'budget_transaction_journal.transaction_journal_id')
@@ -69,8 +58,7 @@ class TransferBudgets extends Command
$count++;
}
if (0 === $count) {
$message = 'No invalid budget/journal entries.';
Log::debug($message);
$message = 'Correct: no invalid budget/journal entries.';
$this->info($message);
}
if (0 !== $count) {
@@ -78,9 +66,6 @@ class TransferBudgets extends Command
Log::debug($message);
$this->line($message);
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified budget/journals in %s seconds.', $end));
return 0;
}
}

View File

@@ -15,18 +15,8 @@ use Illuminate\Support\Facades\Log;
*/
class TriggerCreditCalculation extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Triggers the credit recalculation service for liabilities.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:trigger-credit-recalculation';
protected $signature = 'firefly-iii:trigger-credit-recalculation';
/**
* Execute the console command.
@@ -59,7 +49,6 @@ class TriggerCreditCalculation extends Command
->whereIn('account_types.type', config('firefly.valid_liabilities'))
->get(['accounts.*']);
foreach ($accounts as $account) {
Log::debug(sprintf('Processing account #%d ("%s")', $account->id, $account->name));
$this->processAccount($account);
}
}

View File

@@ -38,18 +38,8 @@ use Illuminate\Support\Facades\Log;
class CreateGroupMemberships extends Command
{
public const CONFIG_NAME = '560_create_group_memberships';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update group memberships';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:create-group-memberships';
protected $signature = 'firefly-iii:create-group-memberships';
/**
* TODO move to helper.
@@ -64,7 +54,6 @@ class CreateGroupMemberships extends Command
$userGroup = UserGroup::where('title', $user->email)->first();
if (null === $userGroup) {
$userGroup = UserGroup::create(['title' => $user->email]);
Log::debug(sprintf('Created new user group #%d ("%s")', $userGroup->id, $userGroup->title));
}
$userRole = UserRole::where('title', UserRole::OWNER)->first();
@@ -83,15 +72,11 @@ class CreateGroupMemberships extends Command
'user_group_id' => $userGroup->id,
]
);
Log::debug('Created new membership.');
}
if (null === $user->user_group_id) {
$user->user_group_id = $userGroup->id;
$user->save();
Log::debug('Put user in default group.');
}
Log::debug(sprintf('User #%d now has main group.', $user->id));
}
/**
@@ -102,12 +87,8 @@ class CreateGroupMemberships extends Command
*/
public function handle(): int
{
$start = microtime(true);
$this->createGroupMemberships();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Validated group memberships in %s seconds.', $end));
$this->info('Correct: validated group memberships');
return 0;
}
@@ -121,9 +102,7 @@ class CreateGroupMemberships extends Command
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
Log::debug(sprintf('Manage group memberships for user #%d', $user->id));
self::createGroupMembership($user);
Log::debug(sprintf('Done with user #%d', $user->id));
}
}
}

View File

@@ -55,14 +55,11 @@ class ReportEmptyObjects extends Command
*/
public function handle(): int
{
$start = microtime(true);
$this->reportEmptyBudgets();
$this->reportEmptyCategories();
$this->reportEmptyTags();
$this->reportAccounts();
$this->reportBudgetLimits();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Report on empty objects finished in %s seconds', $end));
return 0;
}

View File

@@ -32,18 +32,8 @@ use Illuminate\Console\Command;
*/
class ReportSum extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Report on the total sum of transactions. Must be 0.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:report-sum';
protected $signature = 'firefly-iii:report-sum';
/**
* Execute the console command.
@@ -62,7 +52,6 @@ class ReportSum extends Command
*/
private function reportSum(): void
{
$start = microtime(true);
/** @var UserRepositoryInterface $userRepository */
$userRepository = app(UserRepositoryInterface::class);
@@ -74,10 +63,8 @@ class ReportSum extends Command
$this->error($message);
}
if (0 === bccomp($sum, '0')) {
$this->info(sprintf('Amount integrity OK for user #%d', $user->id));
$this->info(sprintf('Correct: Amount integrity OK for user #%d', $user->id));
}
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Report on total sum finished in %s seconds', $end));
}
}

View File

@@ -26,25 +26,14 @@ namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Support\System\OAuthKeys;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
/**
* Class RestoreOAuthKeys
*/
class RestoreOAuthKeys extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Will restore the OAuth keys generated for the system.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:restore-oauth-keys';
protected $signature = 'firefly-iii:restore-oauth-keys';
/**
* Execute the console command.
@@ -95,38 +84,33 @@ class RestoreOAuthKeys extends Command
*/
private function restoreOAuthKeys(): void
{
Log::debug('Going to restoreOAuthKeys()');
if (!$this->keysInDatabase() && !$this->keysOnDrive()) {
Log::debug('Keys are not in DB and keys are not on the drive.');
$this->generateKeys();
$this->storeKeysInDB();
$this->line('Generated and stored new keys.');
$this->line('Correct: generated and stored new keys.');
return;
}
if ($this->keysInDatabase() && !$this->keysOnDrive()) {
Log::debug('Keys are in DB and keys are not on the drive. Restore.');
$result = $this->restoreKeysFromDB();
if (true === $result) {
$this->line('Restored OAuth keys from database.');
$this->line('Correct: restored OAuth keys from database.');
return;
}
app('log')->warning('Could not restore keys. Will create new ones.');
$this->generateKeys();
$this->storeKeysInDB();
$this->line('Generated and stored new keys.');
$this->line('Correct: generated and stored new keys.');
return;
}
if (!$this->keysInDatabase() && $this->keysOnDrive()) {
Log::debug('Keys are not in DB and keys are on the drive. Save in DB.');
$this->storeKeysInDB();
$this->line('Stored OAuth keys in database.');
$this->line('Correct: stored OAuth keys in database.');
return;
}
$this->line('OAuth keys are OK');
$this->line('Correct: OAuth keys are OK');
}
/**

View File

@@ -48,18 +48,8 @@ use Illuminate\Database\QueryException;
*/
class UpdateGroupInformation extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Makes sure that every object is linked to a group';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:upgrade-group-information';
protected $signature = 'firefly-iii:upgrade-group-information';
/**
* Execute the console command.
@@ -126,7 +116,7 @@ class UpdateGroupInformation extends Command
return;
}
if (0 !== $result) {
$this->line(sprintf('Moved %d %s objects to the correct group.', $result, str_replace('FireflyIII\\Models\\', '', $className)));
$this->info(sprintf('Correct: Moved %d %s objects to the correct group.', $result, str_replace('FireflyIII\\Models\\', '', $className)));
}
}
}

View File

@@ -103,7 +103,6 @@ class ForceDecimalSize extends Command
$this->correctAmounts();
$this->updateDecimals();
}
$this->line('Done!');
return 0;
}

View File

@@ -83,12 +83,10 @@ class ForceMigration extends Command
$this->line('Dropping "migrations" table...');
sleep(2);
Schema::dropIfExists('migrations');
$this->line('Done!');
$this->line('Re-run all migrations...');
Artisan::call('migrate', ['--seed' => true]);
sleep(2);
$this->line('');
$this->info('Done!');
$this->line('There is a good chance you just saw a lot of error messages.');
$this->line('No need to panic yet. First try to access Firefly III (again).');
$this->line('The issue, whatever it was, may have been solved now.');

View File

@@ -43,54 +43,35 @@ use Psr\Container\NotFoundExceptionInterface;
class AccountCurrencies extends Command
{
public const CONFIG_NAME = '480_account_currencies';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Give all accounts proper currency info.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:account-currencies {--F|force : Force the execution of this command.}';
/** @var AccountRepositoryInterface */
private $accountRepos;
/** @var int */
private $count;
/** @var UserRepositoryInterface */
private $userRepos;
protected $signature = 'firefly-iii:account-currencies {--F|force : Force the execution of this command.}';
private AccountRepositoryInterface $accountRepos;
private int $count;
private UserRepositoryInterface $userRepos;
/**
* Each (asset) account must have a reference to a preferred currency. If the account does not have one, it's forced upon the account.
*
* @return int
* @throws ContainerExceptionInterface
* @throws FireflyException
* @throws NotFoundExceptionInterface
*/
public function handle(): int
{
Log::debug('Now in handle()');
$this->stupidLaravel();
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
$this->updateAccountCurrencies();
if (0 === $this->count) {
$this->line('All accounts are OK.');
$this->info('Correct: all account currencies are OK.');
}
if (0 !== $this->count) {
$this->line(sprintf('Corrected %d account(s).', $this->count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified and fixed account currencies in %s seconds.', $end));
$this->markAsExecuted();
return 0;
@@ -124,7 +105,6 @@ class AccountCurrencies extends Command
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
@@ -139,23 +119,16 @@ class AccountCurrencies extends Command
*/
private function updateAccount(Account $account, TransactionCurrency $currency): void
{
Log::debug(sprintf('Now in updateAccount(%d, %s)', $account->id, $currency->code));
$this->accountRepos->setUser($account->user);
$accountCurrency = (int)$this->accountRepos->getMetaValue($account, 'currency_id');
Log::debug(sprintf('Account currency is #%d', $accountCurrency));
$openingBalance = $this->accountRepos->getOpeningBalance($account);
$obCurrency = 0;
$openingBalance = $this->accountRepos->getOpeningBalance($account);
$obCurrency = 0;
if (null !== $openingBalance) {
$obCurrency = (int)$openingBalance->transaction_currency_id;
Log::debug('Account has opening balance.');
}
Log::debug(sprintf('Account OB currency is #%d.', $obCurrency));
// both 0? set to default currency:
if (0 === $accountCurrency && 0 === $obCurrency) {
Log::debug(sprintf('Both currencies are 0, so reset to #%d (%s)', $currency->id, $currency->code));
AccountMeta::where('account_id', $account->id)->where('name', 'currency_id')->forceDelete();
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $currency->id]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (%s).', $account->id, $account->name, $currency->code));
@@ -166,7 +139,6 @@ class AccountCurrencies extends Command
// account is set to 0, opening balance is not?
if (0 === $accountCurrency && $obCurrency > 0) {
Log::debug(sprintf('Account is #0, OB is #%d, so set account to OB as well', $obCurrency));
AccountMeta::create(['account_id' => $account->id, 'name' => 'currency_id', 'data' => $obCurrency]);
$this->line(sprintf('Account #%d ("%s") now has a currency setting (#%d).', $account->id, $account->name, $obCurrency));
$this->count++;
@@ -175,7 +147,6 @@ class AccountCurrencies extends Command
}
// do not match and opening balance id is not null.
if ($accountCurrency !== $obCurrency && null !== $openingBalance) {
Log::debug(sprintf('Account (#%d) and OB currency (#%d) are different. Overrule OB, set to account currency.', $accountCurrency, $obCurrency));
// update opening balance:
$openingBalance->transaction_currency_id = $accountCurrency;
$openingBalance->save();
@@ -190,7 +161,6 @@ class AccountCurrencies extends Command
return;
}
Log::debug('No changes necessary for this account.');
}
/**
@@ -198,10 +168,8 @@ class AccountCurrencies extends Command
*/
private function updateAccountCurrencies(): void
{
Log::debug('Now in updateAccountCurrencies()');
$users = $this->userRepos->all();
$defaultCurrencyCode = (string)config('firefly.default_currency', 'EUR');
Log::debug(sprintf('Default currency is %s', $defaultCurrencyCode));
foreach ($users as $user) {
$this->updateCurrenciesForUser($user, $defaultCurrencyCode);
}
@@ -215,7 +183,6 @@ class AccountCurrencies extends Command
*/
private function updateCurrenciesForUser(User $user, string $systemCurrencyCode): void
{
Log::debug(sprintf('Now in updateCurrenciesForUser(%s, %s)', $user->email, $systemCurrencyCode));
$this->accountRepos->setUser($user);
$accounts = $this->accountRepos->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
@@ -224,7 +191,6 @@ class AccountCurrencies extends Command
if (!is_string($defaultCurrencyCode)) {
$defaultCurrencyCode = $systemCurrencyCode;
}
Log::debug(sprintf('Users currency pref is %s', $defaultCurrencyCode));
/** @var TransactionCurrency|null $defaultCurrency */
$defaultCurrency = TransactionCurrency::where('code', $defaultCurrencyCode)->first();

View File

@@ -56,20 +56,15 @@ class AppendBudgetLimitPeriods extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
$this->theresNoLimit();
$this->markAsExecuted();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Fixed budget limits in %s seconds.', $end));
return 0;
}

View File

@@ -64,12 +64,11 @@ class BackToJournals extends Command
*/
public function handle(): int
{
$start = microtime(true);
if (!$this->isMigrated()) {
$this->error('Please run firefly-iii:migrate-to-groups first.');
}
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -79,8 +78,7 @@ class BackToJournals extends Command
$this->migrateAll();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Updated category and budget info for all transaction journals in %s seconds.', $end));
$this->info('Correct: updated category and budget info for all transaction journals');
$this->markAsExecuted();
return 0;
@@ -159,7 +157,6 @@ class BackToJournals extends Command
*/
private function migrateAll(): void
{
Log::debug('Now in migrateAll()');
$this->migrateBudgets();
$this->migrateCategories();
@@ -225,19 +222,15 @@ class BackToJournals extends Command
*/
private function migrateCategories(): void
{
Log::debug('Now in migrateCategories()');
$journals = new Collection();
$allIds = $this->getIdsForCategories();
Log::debug(sprintf('Total: %d', count($allIds)));
$chunks = array_chunk($allIds, 500);
foreach ($chunks as $chunk) {
Log::debug('Now doing a chunk.');
$collected = TransactionJournal::whereIn('id', $chunk)->with(['transactions', 'categories', 'transactions.categories'])->get();
$journals = $journals->merge($collected);
}
$this->line(sprintf('Check %d transaction journal(s) for category info.', count($journals)));
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$this->migrateCategoriesForJournal($journal);

View File

@@ -58,10 +58,8 @@ class BudgetLimitCurrency extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -88,11 +86,8 @@ class BudgetLimitCurrency extends Command
}
}
if (0 === $count) {
$this->info('All budget limits are correct.');
$this->info('Correct: all budget limits are OK.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified budget limits in %s seconds.', $end));
$this->markAsExecuted();
return 0;

View File

@@ -37,18 +37,8 @@ use Psr\Container\NotFoundExceptionInterface;
class CCLiabilities extends Command
{
public const CONFIG_NAME = '480_cc_liabilities';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Convert old credit card liabilities.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:cc-liabilities {--F|force : Force the execution of this command.}';
protected $signature = 'firefly-iii:cc-liabilities {--F|force : Force the execution of this command.}';
/**
* Execute the console command.
@@ -62,9 +52,8 @@ class CCLiabilities extends Command
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -73,7 +62,8 @@ class CCLiabilities extends Command
$ccType = AccountType::where('type', AccountType::CREDITCARD)->first();
$debtType = AccountType::where('type', AccountType::DEBT)->first();
if (null === $ccType || null === $debtType) {
$this->info('No incorrectly stored credit card liabilities.');
$this->info('Correct: no incorrectly stored credit card liabilities.');
$this->markAsExecuted();
return 0;
}
@@ -88,7 +78,7 @@ class CCLiabilities extends Command
$this->info('Credit card liability types are no longer supported and have been converted to generic debts. See: https://bit.ly/FF3-credit-cards');
}
if (0 === $accounts->count()) {
$this->info('No incorrectly stored credit card liabilities.');
$this->info('Correct: no incorrectly stored credit card liabilities.');
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified credit card liabilities in %s seconds', $end));

View File

@@ -41,18 +41,8 @@ use stdClass;
*/
class DecryptDatabase extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Decrypts the database.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:decrypt-all';
protected $signature = 'firefly-iii:decrypt-all';
/**
* Execute the console command.
@@ -61,7 +51,6 @@ class DecryptDatabase extends Command
*/
public function handle(): int
{
$this->line('Going to decrypt the database.');
$tables = [
'accounts' => ['name', 'iban'],
'attachments' => ['filename', 'mime', 'title', 'description'],
@@ -82,8 +71,6 @@ class DecryptDatabase extends Command
foreach ($tables as $table => $fields) {
$this->decryptTable($table, $fields);
}
$this->info('Done!');
return 0;
}
@@ -172,14 +159,14 @@ class DecryptDatabase extends Command
private function decryptTable(string $table, array $fields): void
{
if ($this->isDecrypted($table)) {
$this->info(sprintf('No decryption required for table "%s".', $table));
$this->info(sprintf('Correct: no decryption required for table "%s".', $table));
return;
}
foreach ($fields as $field) {
$this->decryptField($table, $field);
}
$this->line(sprintf('Decrypted the data in table "%s".', $table));
$this->line(sprintf('Correct: decrypted the data in table "%s".', $table));
// mark as decrypted:
$configName = sprintf('is_decrypted_%s', $table);
app('fireflyconfig')->set($configName, true);

View File

@@ -53,8 +53,6 @@ class FixPostgresSequences extends Command
public function handle(): int
{
if (DB::connection()->getName() !== 'pgsql') {
$this->info('Command executed successfully.');
return 0;
}
$this->line('Going to verify PostgreSQL table sequences.');

View File

@@ -62,7 +62,7 @@ class MigrateAttachments extends Command
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -94,7 +94,7 @@ class MigrateAttachments extends Command
}
}
if (0 === $count) {
$this->line('All attachments are OK.');
$this->info('Correct: all attachments are OK.');
}
if (0 !== $count) {
$this->line(sprintf('Updated %d attachment(s).', $count));

View File

@@ -63,7 +63,7 @@ class MigrateJournalNotes extends Command
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -88,7 +88,7 @@ class MigrateJournalNotes extends Command
}
if (0 === $count) {
$this->line('No notes to migrate.');
$this->info('Correct: No notes to migrate.');
}
if (0 !== $count) {
$this->line(sprintf('Migrated %d note(s).', $count));

View File

@@ -63,16 +63,15 @@ class MigrateRecurrenceMeta extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
$count = $this->migrateMetaData();
if (0 === $count) {
$this->line('No recurrence meta data migrated.');
$this->info('Correct: no recurrence meta data migrated.');
}
if ($count > 0) {
$this->line(sprintf('Migrated %d meta data entries', $count));
@@ -80,9 +79,6 @@ class MigrateRecurrenceMeta extends Command
$this->markAsExecuted();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Migrated recurrence meta data in %s seconds.', $end));
return 0;
}

View File

@@ -61,7 +61,6 @@ class MigrateRecurrenceType extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
@@ -69,11 +68,8 @@ class MigrateRecurrenceType extends Command
}
$this->migrateTypes();
$this->markAsExecuted();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Update recurring transaction types in %s seconds.', $end));
return 0;
}

View File

@@ -60,18 +60,14 @@ class MigrateTagLocations extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
$this->migrateTagLocations();
$this->markAsExecuted();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Migrated tag locations in %s seconds.', $end));
return 0;
}

View File

@@ -50,18 +50,8 @@ use Psr\Container\NotFoundExceptionInterface;
class MigrateToGroups extends Command
{
public const CONFIG_NAME = '480_migrated_to_groups';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Migrates a pre-4.7.8 transaction structure to the 4.7.8+ transaction structure.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:migrate-to-groups {--F|force : Force the migration, even if it fired before.}';
protected $signature = 'firefly-iii:migrate-to-groups {--F|force : Force the migration, even if it fired before.}';
private JournalCLIRepositoryInterface $cliRepository;
private int $count;
private TransactionGroupFactory $groupFactory;
@@ -72,17 +62,13 @@ class MigrateToGroups extends Command
* Execute the console command.
*
* @return int
* @throws ContainerExceptionInterface
* @throws FireflyException
* @throws NotFoundExceptionInterface
*/
public function handle(): int
{
$this->stupidLaravel();
$start = microtime(true);
if ($this->isMigrated() && true !== $this->option('force')) {
$this->info('Database already seems to be migrated.');
$this->info('Correct: database is already migrated.');
return 0;
}
@@ -92,22 +78,14 @@ class MigrateToGroups extends Command
}
Log::debug('---- start group migration ----');
$this->makeGroupsFromSplitJournals();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Migrate split journals to groups in %s seconds.', $end));
$start = microtime(true);
$this->makeGroupsFromAll();
Log::debug('---- end group migration ----');
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Migrate all journals to groups in %s seconds.', $end));
if (0 !== $this->count) {
$this->line(sprintf('Migrated %d transaction journal(s).', $this->count));
}
if (0 === $this->count) {
$this->line('No journals to migrate to groups.');
$this->info('Correct: no journals to migrate to groups.');
}
$this->markAsMigrated();
@@ -115,19 +93,122 @@ class MigrateToGroups extends Command
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
* @param TransactionJournal $journal
* @param Transaction $transaction
*
* @return Transaction|null
*/
private function stupidLaravel(): void
private function findOpposingTransaction(TransactionJournal $journal, Transaction $transaction): ?Transaction
{
$this->count = 0;
$this->journalRepository = app(JournalRepositoryInterface::class);
$this->service = app(JournalDestroyService::class);
$this->groupFactory = app(TransactionGroupFactory::class);
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
$set = $journal->transactions->filter(
static function (Transaction $subject) use ($transaction) {
$amount = (float)$transaction->amount * -1 === (float)$subject->amount; // intentional float
$identifier = $transaction->identifier === $subject->identifier;
Log::debug(sprintf('Amount the same? %s', var_export($amount, true)));
Log::debug(sprintf('ID the same? %s', var_export($identifier, true)));
return $amount && $identifier;
}
);
return $set->first();
}
/**
* @param TransactionJournal $journal
*
* @return Collection
*/
private function getDestinationTransactions(TransactionJournal $journal): Collection
{
return $journal->transactions->filter(
static function (Transaction $transaction) {
return $transaction->amount > 0;
}
);
}
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionBudget(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionBudget()');
// try to get a budget ID from the left transaction:
/** @var Budget|null $budget */
$budget = $left->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $left->id));
return (int)$budget->id;
}
// try to get a budget ID from the right transaction:
/** @var Budget|null $budget */
$budget = $right->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $right->id));
return (int)$budget->id;
}
Log::debug('Neither left or right have a budget, return NULL');
// if all fails, return NULL.
return null;
}
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionCategory(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionCategory()');
// try to get a category ID from the left transaction:
/** @var Category|null $category */
$category = $left->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $left->id));
return (int)$category->id;
}
// try to get a category ID from the left transaction:
/** @var Category|null $category */
$category = $right->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $category->id));
return (int)$category->id;
}
Log::debug('Neither left or right have a category, return NULL');
// if all fails, return NULL.
return null;
}
/**
* @param array $array
*/
private function giveGroup(array $array): void
{
$groupId = DB::table('transaction_groups')->insertGetId(
[
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
'title' => null,
'user_id' => $array['user_id'],
]
);
DB::table('transaction_journals')->where('id', $array['id'])->update(['transaction_group_id' => $groupId]);
$this->count++;
}
/**
@@ -145,6 +226,26 @@ class MigrateToGroups extends Command
return false;
}
/**
* Gives all journals without a group a group.
*/
private function makeGroupsFromAll(): void
{
$orphanedJournals = $this->cliRepository->getJournalsWithoutGroup();
$total = count($orphanedJournals);
if ($total > 0) {
Log::debug(sprintf('Going to convert %d transaction journals. Please hold..', $total));
$this->line(sprintf('Going to convert %d transaction journals. Please hold..', $total));
/** @var array $array */
foreach ($orphanedJournals as $array) {
$this->giveGroup($array);
}
}
if (0 === $total) {
$this->info('Correct: no need to convert transaction journals.');
}
}
/**
* @throws Exception
*/
@@ -158,9 +259,6 @@ class MigrateToGroups extends Command
$this->makeMultiGroup($journal);
}
}
if (0 === $splitJournals->count()) {
$this->info('Found no split transaction journals. Nothing to do.');
}
}
/**
@@ -305,145 +403,6 @@ class MigrateToGroups extends Command
);
}
/**
* @param TransactionJournal $journal
*
* @return Collection
*/
private function getDestinationTransactions(TransactionJournal $journal): Collection
{
return $journal->transactions->filter(
static function (Transaction $transaction) {
return $transaction->amount > 0;
}
);
}
/**
* @param TransactionJournal $journal
* @param Transaction $transaction
*
* @return Transaction|null
*/
private function findOpposingTransaction(TransactionJournal $journal, Transaction $transaction): ?Transaction
{
$set = $journal->transactions->filter(
static function (Transaction $subject) use ($transaction) {
$amount = (float)$transaction->amount * -1 === (float)$subject->amount; // intentional float
$identifier = $transaction->identifier === $subject->identifier;
Log::debug(sprintf('Amount the same? %s', var_export($amount, true)));
Log::debug(sprintf('ID the same? %s', var_export($identifier, true)));
return $amount && $identifier;
}
);
return $set->first();
}
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionBudget(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionBudget()');
// try to get a budget ID from the left transaction:
/** @var Budget|null $budget */
$budget = $left->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $left->id));
return (int)$budget->id;
}
// try to get a budget ID from the right transaction:
/** @var Budget|null $budget */
$budget = $right->budgets()->first();
if (null !== $budget) {
Log::debug(sprintf('Return budget #%d, from transaction #%d', $budget->id, $right->id));
return (int)$budget->id;
}
Log::debug('Neither left or right have a budget, return NULL');
// if all fails, return NULL.
return null;
}
/**
* @param Transaction $left
* @param Transaction $right
*
* @return int|null
*/
private function getTransactionCategory(Transaction $left, Transaction $right): ?int
{
Log::debug('Now in getTransactionCategory()');
// try to get a category ID from the left transaction:
/** @var Category|null $category */
$category = $left->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $left->id));
return (int)$category->id;
}
// try to get a category ID from the left transaction:
/** @var Category|null $category */
$category = $right->categories()->first();
if (null !== $category) {
Log::debug(sprintf('Return category #%d, from transaction #%d', $category->id, $category->id));
return (int)$category->id;
}
Log::debug('Neither left or right have a category, return NULL');
// if all fails, return NULL.
return null;
}
/**
* Gives all journals without a group a group.
*/
private function makeGroupsFromAll(): void
{
$orphanedJournals = $this->cliRepository->getJournalsWithoutGroup();
$total = count($orphanedJournals);
if ($total > 0) {
Log::debug(sprintf('Going to convert %d transaction journals. Please hold..', $total));
$this->line(sprintf('Going to convert %d transaction journals. Please hold..', $total));
/** @var array $array */
foreach ($orphanedJournals as $array) {
$this->giveGroup($array);
}
}
if (0 === $total) {
$this->info('No need to convert transaction journals.');
}
}
/**
* @param array $array
*/
private function giveGroup(array $array): void
{
$groupId = DB::table('transaction_groups')->insertGetId(
[
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
'title' => null,
'user_id' => $array['user_id'],
]
);
DB::table('transaction_journals')->where('id', $array['id'])->update(['transaction_group_id' => $groupId]);
$this->count++;
}
/**
*
*/
@@ -451,4 +410,20 @@ class MigrateToGroups extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->journalRepository = app(JournalRepositoryInterface::class);
$this->service = app(JournalDestroyService::class);
$this->groupFactory = app(TransactionGroupFactory::class);
$this->cliRepository = app(JournalCLIRepositoryInterface::class);
}
}

View File

@@ -79,7 +79,7 @@ class MigrateToRules extends Command
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -92,7 +92,7 @@ class MigrateToRules extends Command
}
if (0 === $this->count) {
$this->line('All bills are OK.');
$this->info('Correct: all bills are OK.');
}
if (0 !== $this->count) {
$this->line(sprintf('Verified and fixed %d bill(s).', $this->count));

View File

@@ -44,18 +44,8 @@ use Psr\Container\NotFoundExceptionInterface;
class OtherCurrenciesCorrections extends Command
{
public const CONFIG_NAME = '480_other_currencies';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update all journal currency information.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:other-currencies {--F|force : Force the execution of this command.}';
protected $signature = 'firefly-iii:other-currencies {--F|force : Force the execution of this command.}';
private array $accountCurrencies;
private AccountRepositoryInterface $accountRepos;
private JournalCLIRepositoryInterface $cliRepos;
@@ -74,10 +64,9 @@ class OtherCurrenciesCorrections extends Command
public function handle(): int
{
$this->stupidLaravel();
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -86,28 +75,78 @@ class OtherCurrenciesCorrections extends Command
$this->updateOtherJournalsCurrencies();
$this->markAsExecuted();
$this->line(sprintf('Verified %d transaction(s) and journal(s).', $this->count));
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified and fixed transaction currencies in %s seconds.', $end));
$this->info('Correct: verified and fixed transaction currencies.');
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
* @param Account $account
*
* @return TransactionCurrency|null
*/
private function stupidLaravel(): void
private function getCurrency(Account $account): ?TransactionCurrency
{
$this->count = 0;
$this->accountCurrencies = [];
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->journalRepos = app(JournalRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
$accountId = $account->id;
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
return null;
}
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
return $this->accountCurrencies[$accountId];
}
$currency = $this->accountRepos->getAccountCurrency($account);
if (null === $currency) {
$this->accountCurrencies[$accountId] = 0;
return null;
}
$this->accountCurrencies[$accountId] = $currency;
return $currency;
}
/**
* Gets the transaction that determines the transaction that "leads" and will determine
* the currency to be used by all transactions, and the journal itself.
*
* @param TransactionJournal $journal
*
* @return Transaction|null
*/
private function getLeadTransaction(TransactionJournal $journal): ?Transaction
{
/** @var Transaction $lead */
$lead = null;
switch ($journal->transactionType->type) {
default:
break;
case TransactionType::WITHDRAWAL:
$lead = $journal->transactions()->where('amount', '<', 0)->first();
break;
case TransactionType::DEPOSIT:
$lead = $journal->transactions()->where('amount', '>', 0)->first();
break;
case TransactionType::OPENING_BALANCE:
// whichever isn't an initial balance account:
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
'account_types',
'accounts.account_type_id',
'=',
'account_types.id'
)->where('account_types.type', '!=', AccountType::INITIAL_BALANCE)->first(['transactions.*']);
break;
case TransactionType::RECONCILIATION:
// whichever isn't the reconciliation account:
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
'account_types',
'accounts.account_type_id',
'=',
'account_types.id'
)->where('account_types.type', '!=', AccountType::RECONCILIATION)->first(['transactions.*']);
break;
}
return $lead;
}
/**
@@ -126,21 +165,28 @@ class OtherCurrenciesCorrections extends Command
}
/**
* This routine verifies that withdrawals, deposits and opening balances have the correct currency settings for
* the accounts they are linked to.
* Both source and destination must match the respective currency preference of the related asset account.
* So FF3 must verify all transactions.
*
*/
private function updateOtherJournalsCurrencies(): void
private function markAsExecuted(): void
{
$set = $this->cliRepos->getAllJournals(
[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]
);
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
$this->updateJournalCurrency($journal);
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->accountCurrencies = [];
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->journalRepos = app(JournalRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
}
/**
@@ -200,79 +246,20 @@ class OtherCurrenciesCorrections extends Command
}
/**
* Gets the transaction that determines the transaction that "leads" and will determine
* the currency to be used by all transactions, and the journal itself.
*
* @param TransactionJournal $journal
*
* @return Transaction|null
* This routine verifies that withdrawals, deposits and opening balances have the correct currency settings for
* the accounts they are linked to.
* Both source and destination must match the respective currency preference of the related asset account.
* So FF3 must verify all transactions.
*/
private function getLeadTransaction(TransactionJournal $journal): ?Transaction
private function updateOtherJournalsCurrencies(): void
{
/** @var Transaction $lead */
$lead = null;
switch ($journal->transactionType->type) {
default:
break;
case TransactionType::WITHDRAWAL:
$lead = $journal->transactions()->where('amount', '<', 0)->first();
break;
case TransactionType::DEPOSIT:
$lead = $journal->transactions()->where('amount', '>', 0)->first();
break;
case TransactionType::OPENING_BALANCE:
// whichever isn't an initial balance account:
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
'account_types',
'accounts.account_type_id',
'=',
'account_types.id'
)->where('account_types.type', '!=', AccountType::INITIAL_BALANCE)->first(['transactions.*']);
break;
case TransactionType::RECONCILIATION:
// whichever isn't the reconciliation account:
$lead = $journal->transactions()->leftJoin('accounts', 'transactions.account_id', '=', 'accounts.id')->leftJoin(
'account_types',
'accounts.account_type_id',
'=',
'account_types.id'
)->where('account_types.type', '!=', AccountType::RECONCILIATION)->first(['transactions.*']);
break;
$set = $this->cliRepos->getAllJournals(
[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]
);
/** @var TransactionJournal $journal */
foreach ($set as $journal) {
$this->updateJournalCurrency($journal);
}
return $lead;
}
/**
* @param Account $account
*
* @return TransactionCurrency|null
*/
private function getCurrency(Account $account): ?TransactionCurrency
{
$accountId = $account->id;
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
return null;
}
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
return $this->accountCurrencies[$accountId];
}
$currency = $this->accountRepos->getAccountCurrency($account);
if (null === $currency) {
$this->accountCurrencies[$accountId] = 0;
return null;
}
$this->accountCurrencies[$accountId] = $currency;
return $currency;
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@@ -58,10 +58,8 @@ class RenameAccountMeta extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -88,15 +86,12 @@ class RenameAccountMeta extends Command
$this->markAsExecuted();
if (0 === $count) {
$this->line('All account meta is OK.');
$this->info('Correct: all account meta is OK.');
}
if (0 !== $count) {
$this->line(sprintf('Renamed %d account meta entries (entry).', $count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Fixed account meta data in %s seconds.', $end));
return 0;
}

View File

@@ -40,22 +40,10 @@ use Schema;
class TransactionIdentifier extends Command
{
public const CONFIG_NAME = '480_transaction_identifier';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes transaction identifiers.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:transaction-identifiers {--F|force : Force the execution of this command.}';
/** @var JournalCLIRepositoryInterface */
private $cliRepository;
/** @var int */
private $count;
protected $signature = 'firefly-iii:transaction-identifiers {--F|force : Force the execution of this command.}';
private JournalCLIRepositoryInterface $cliRepository;
private int $count;
/**
* This method gives all transactions which are part of a split journal (so more than 2) a sort of "order" so they are easier
@@ -74,10 +62,9 @@ class TransactionIdentifier extends Command
public function handle(): int
{
$this->stupidLaravel();
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -94,14 +81,12 @@ class TransactionIdentifier extends Command
}
if (0 === $this->count) {
$this->line('All split journal transaction identifiers are correct.');
$this->line('Correct: all split journal transaction identifiers are OK.');
}
if (0 !== $this->count) {
$this->line(sprintf('Fixed %d split journal transaction identifier(s).', $this->count));
$this->line(sprintf('Correct: fixed %d split journal transaction identifier(s).', $this->count));
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified and fixed transaction identifiers in %s seconds.', $end));
$this->markAsExecuted();
return 0;

View File

@@ -42,18 +42,8 @@ use Psr\Container\NotFoundExceptionInterface;
class TransferCurrenciesCorrections extends Command
{
public const CONFIG_NAME = '480_transfer_currencies';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Updates transfer currency information.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:transfer-currencies {--F|force : Force the execution of this command.}';
protected $signature = 'firefly-iii:transfer-currencies {--F|force : Force the execution of this command.}';
private array $accountCurrencies;
private AccountRepositoryInterface $accountRepos;
private JournalCLIRepositoryInterface $cliRepos;
@@ -70,17 +60,13 @@ class TransferCurrenciesCorrections extends Command
* Execute the console command.
*
* @return int
* @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function handle(): int
{
$this->stupidLaravel();
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}
@@ -90,50 +76,292 @@ class TransferCurrenciesCorrections extends Command
$this->markAsExecuted();
if (0 === $this->count) {
$message = 'All transfers have correct currency information.';
$this->line($message);
Log::debug($message);
$message = 'Correct: all transfers have correct currency information.';
$this->info($message);
}
if (0 !== $this->count) {
$message = sprintf('Verified currency information of %d transfer(s).', $this->count);
$this->line($message);
Log::debug($message);
}
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified and fixed currency information for transfers in %s seconds.', $end));
return 0;
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* The destination transaction must have a currency. If not, it will be added by
* taking it from the destination account's preference.
*/
private function stupidLaravel(): void
private function fixDestNoCurrency(): void
{
$this->count = 0;
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
$this->accountCurrencies = [];
$this->resetInformation();
if (null === $this->destinationTransaction->transaction_currency_id && null !== $this->destinationCurrency) {
$this->destinationTransaction
->transaction_currency_id
= (int)$this->destinationCurrency->id;
$message = sprintf(
'Transaction #%d has no currency setting, now set to %s.',
$this->destinationTransaction->id,
$this->destinationCurrency->code
);
$this->line($message);
$this->count++;
$this->destinationTransaction->save();
}
}
/**
* Reset all the class fields for the current transfer.
* If the foreign amount of the destination transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixDestNullForeignAmount(): void
{
if (null === $this->destinationTransaction->foreign_amount && null !== $this->sourceTransaction->foreign_amount) {
$this->destinationTransaction->foreign_amount = bcmul((string)$this->sourceTransaction->foreign_amount, '-1');
$this->destinationTransaction->save();
$this->count++;
$this->line(
sprintf(
'Restored foreign amount of destination transaction #%d to %s',
$this->destinationTransaction->id,
$this->destinationTransaction->foreign_amount
)
);
}
}
/**
* The destination transaction must have the correct currency. If not, it will be set by
* taking it from the destination account's preference.
*/
private function fixDestinationUnmatchedCurrency(): void
{
if (null !== $this->destinationCurrency
&& null === $this->destinationTransaction->foreign_amount
&& (int)$this->destinationTransaction->transaction_currency_id !== (int)$this->destinationCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->destinationTransaction->id,
$this->destinationTransaction->transaction_currency_id,
$this->destinationAccount->id,
$this->destinationTransaction->amount
);
$this->line($message);
$this->count++;
$this->destinationTransaction->transaction_currency_id = (int)$this->destinationCurrency->id;
$this->destinationTransaction->save();
}
}
/**
* If the destination account currency is the same as the source currency,
* both foreign_amount and foreign_currency_id fields must be NULL
* for both transactions (because foreign currency info would not make sense)
*/
private function fixInvalidForeignCurrency(): void
{
if ((int)$this->destinationCurrency->id === (int)$this->sourceCurrency->id) {
// update both transactions to match:
$this->sourceTransaction->foreign_amount = null;
$this->sourceTransaction->foreign_currency_id = null;
$this->destinationTransaction->foreign_amount = null;
$this->destinationTransaction->foreign_currency_id = null;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
}
}
/**
* If destination account currency is different from source account currency,
* then both transactions must get the source account's currency as normal currency
* and the opposing account's currency as foreign currency.
*/
private function fixMismatchedForeignCurrency(): void
{
if ((int)$this->sourceCurrency->id !== (int)$this->destinationCurrency->id) {
$this->sourceTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->sourceTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->destinationTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->destinationTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
$this->count++;
$this->line(sprintf('Verified foreign currency ID of transaction #%d and #%d', $this->sourceTransaction->id, $this->destinationTransaction->id));
}
}
/**
* The source transaction must have a currency. If not, it will be added by
* taking it from the source account's preference.
*/
private function fixSourceNoCurrency(): void
{
if (null === $this->sourceTransaction->transaction_currency_id && null !== $this->sourceCurrency) {
$this->sourceTransaction
->transaction_currency_id
= (int)$this->sourceCurrency->id;
$message = sprintf(
'Transaction #%d has no currency setting, now set to %s.',
$this->sourceTransaction->id,
$this->sourceCurrency->code
);
$this->line($message);
$this->count++;
$this->sourceTransaction->save();
}
}
/**
* If the foreign amount of the source transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixSourceNullForeignAmount(): void
{
if (null === $this->sourceTransaction->foreign_amount && null !== $this->destinationTransaction->foreign_amount) {
$this->sourceTransaction->foreign_amount = bcmul((string)$this->destinationTransaction->foreign_amount, '-1');
$this->sourceTransaction->save();
$this->count++;
$this->line(
sprintf(
'Restored foreign amount of source transaction #%d to %s',
$this->sourceTransaction->id,
$this->sourceTransaction->foreign_amount
)
);
}
}
/**
* The source transaction must have the correct currency. If not, it will be set by
* taking it from the source account's preference.
*/
private function fixSourceUnmatchedCurrency(): void
{
if (null !== $this->sourceCurrency
&& null === $this->sourceTransaction->foreign_amount
&& (int)$this->sourceTransaction->transaction_currency_id !== (int)$this->sourceCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->sourceTransaction->id,
$this->sourceTransaction->transaction_currency_id,
$this->sourceAccount->id,
$this->sourceTransaction->amount
);
$this->line($message);
$this->count++;
$this->sourceTransaction->transaction_currency_id = (int)$this->sourceCurrency->id;
$this->sourceTransaction->save();
}
}
/**
* This method makes sure that the transaction journal uses the currency given in the source transaction.
*
* @param TransactionJournal $journal
*/
private function fixTransactionJournalCurrency(TransactionJournal $journal): void
{
if ((int)$journal->transaction_currency_id !== (int)$this->sourceCurrency->id) {
$oldCurrencyCode = $journal->transactionCurrency->code ?? '(nothing)';
$journal->transaction_currency_id = $this->sourceCurrency->id;
$message = sprintf(
'Transfer #%d ("%s") has been updated to use %s instead of %s.',
$journal->id,
$journal->description,
$this->sourceCurrency->code,
$oldCurrencyCode
);
$this->count++;
$this->line($message);
$journal->save();
}
}
/**
* @param Account $account
*
* @return TransactionCurrency|null
*/
private function getCurrency(Account $account): ?TransactionCurrency
{
$accountId = $account->id;
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
return null;
}
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
return $this->accountCurrencies[$accountId];
}
$currency = $this->accountRepos->getAccountCurrency($account);
if (null === $currency) {
$this->accountCurrencies[$accountId] = 0;
return null;
}
$this->accountCurrencies[$accountId] = $currency;
return $currency;
}
/**
* Extract destination transaction, destination account + destination account currency from the journal.
*
* @param TransactionJournal $journal
*
*/
private function resetInformation(): void
private function getDestinationInformation(TransactionJournal $journal): void
{
$this->sourceTransaction = null;
$this->sourceAccount = null;
$this->sourceCurrency = null;
$this->destinationTransaction = null;
$this->destinationAccount = null;
$this->destinationCurrency = null;
$this->destinationTransaction = $this->getDestinationTransaction($journal);
$this->destinationAccount = $this->destinationTransaction?->account;
$this->destinationCurrency = null === $this->destinationAccount ? null : $this->getCurrency($this->destinationAccount);
}
/**
* @param TransactionJournal $transfer
*
* @return Transaction|null
*/
private function getDestinationTransaction(TransactionJournal $transfer): ?Transaction
{
return $transfer->transactions()->where('amount', '>', 0)->first();
}
/**
* Extract source transaction, source account + source account currency from the journal.
*
* @param TransactionJournal $journal
*
*/
private function getSourceInformation(TransactionJournal $journal): void
{
$this->sourceTransaction = $this->getSourceTransaction($journal);
$this->sourceAccount = $this->sourceTransaction?->account;
$this->sourceCurrency = null === $this->sourceAccount ? null : $this->getCurrency($this->sourceAccount);
}
/**
* @param TransactionJournal $transfer
*
* @return Transaction|null
*/
private function getSourceTransaction(TransactionJournal $transfer): ?Transaction
{
return $transfer->transactions()->where('amount', '<', 0)->first();
}
/**
* Is either the source or destination transaction NULL?
*
* @return bool
*/
private function isEmptyTransactions(): bool
{
return null === $this->sourceTransaction || null === $this->destinationTransaction
|| null === $this->sourceAccount
|| null === $this->destinationAccount;
}
/**
@@ -151,6 +379,71 @@ class TransferCurrenciesCorrections extends Command
return false;
}
/**
* @return bool
*/
private function isNoCurrencyPresent(): bool
{
// source account must have a currency preference.
if (null === $this->sourceCurrency) {
$message = sprintf('Account #%d ("%s") must have currency preference but has none.', $this->sourceAccount->id, $this->sourceAccount->name);
Log::error($message);
$this->error($message);
return true;
}
// destination account must have a currency preference.
if (null === $this->destinationCurrency) {
$message = sprintf(
'Account #%d ("%s") must have currency preference but has none.',
$this->destinationAccount->id,
$this->destinationAccount->name
);
Log::error($message);
$this->error($message);
return true;
}
return false;
}
/**
* Is this a split transaction journal?
*
* @param TransactionJournal $transfer
*
* @return bool
*/
private function isSplitJournal(TransactionJournal $transfer): bool
{
return $transfer->transactions->count() > 2;
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
/**
* Reset all the class fields for the current transfer.
*
*/
private function resetInformation(): void
{
$this->sourceTransaction = null;
$this->sourceAccount = null;
$this->sourceCurrency = null;
$this->destinationTransaction = null;
$this->destinationAccount = null;
$this->destinationCurrency = null;
}
/**
* This routine verifies that transfers have the correct currency settings for the accounts they are linked to.
* For transfers, this is can be a destructive routine since we FORCE them into a currency setting whether they
@@ -168,6 +461,22 @@ class TransferCurrenciesCorrections extends Command
}
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
*/
private function stupidLaravel(): void
{
$this->count = 0;
$this->accountRepos = app(AccountRepositoryInterface::class);
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
$this->accountCurrencies = [];
$this->resetInformation();
}
/**
* @param TransactionJournal $transfer
*/
@@ -230,351 +539,4 @@ class TransferCurrenciesCorrections extends Command
// fix journal itself:
$this->fixTransactionJournalCurrency($transfer);
}
/**
* Is this a split transaction journal?
*
* @param TransactionJournal $transfer
*
* @return bool
*/
private function isSplitJournal(TransactionJournal $transfer): bool
{
return $transfer->transactions->count() > 2;
}
/**
* Extract source transaction, source account + source account currency from the journal.
*
* @param TransactionJournal $journal
*
*/
private function getSourceInformation(TransactionJournal $journal): void
{
$this->sourceTransaction = $this->getSourceTransaction($journal);
$this->sourceAccount = $this->sourceTransaction?->account;
$this->sourceCurrency = null === $this->sourceAccount ? null : $this->getCurrency($this->sourceAccount);
}
/**
* @param TransactionJournal $transfer
*
* @return Transaction|null
*/
private function getSourceTransaction(TransactionJournal $transfer): ?Transaction
{
return $transfer->transactions()->where('amount', '<', 0)->first();
}
/**
* @param Account $account
*
* @return TransactionCurrency|null
*/
private function getCurrency(Account $account): ?TransactionCurrency
{
$accountId = $account->id;
if (array_key_exists($accountId, $this->accountCurrencies) && 0 === $this->accountCurrencies[$accountId]) {
return null;
}
if (array_key_exists($accountId, $this->accountCurrencies) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
return $this->accountCurrencies[$accountId];
}
$currency = $this->accountRepos->getAccountCurrency($account);
if (null === $currency) {
$this->accountCurrencies[$accountId] = 0;
return null;
}
$this->accountCurrencies[$accountId] = $currency;
return $currency;
}
/**
* Extract destination transaction, destination account + destination account currency from the journal.
*
* @param TransactionJournal $journal
*
*/
private function getDestinationInformation(TransactionJournal $journal): void
{
$this->destinationTransaction = $this->getDestinationTransaction($journal);
$this->destinationAccount = $this->destinationTransaction?->account;
$this->destinationCurrency = null === $this->destinationAccount ? null : $this->getCurrency($this->destinationAccount);
}
/**
* @param TransactionJournal $transfer
*
* @return Transaction|null
*/
private function getDestinationTransaction(TransactionJournal $transfer): ?Transaction
{
return $transfer->transactions()->where('amount', '>', 0)->first();
}
/**
* Is either the source or destination transaction NULL?
*
* @return bool
*/
private function isEmptyTransactions(): bool
{
return null === $this->sourceTransaction || null === $this->destinationTransaction
|| null === $this->sourceAccount
|| null === $this->destinationAccount;
}
/**
* @return bool
*/
private function isNoCurrencyPresent(): bool
{
// source account must have a currency preference.
if (null === $this->sourceCurrency) {
$message = sprintf('Account #%d ("%s") must have currency preference but has none.', $this->sourceAccount->id, $this->sourceAccount->name);
Log::error($message);
$this->error($message);
return true;
}
// destination account must have a currency preference.
if (null === $this->destinationCurrency) {
$message = sprintf(
'Account #%d ("%s") must have currency preference but has none.',
$this->destinationAccount->id,
$this->destinationAccount->name
);
Log::error($message);
$this->error($message);
return true;
}
return false;
}
/**
* The source transaction must have a currency. If not, it will be added by
* taking it from the source account's preference.
*/
private function fixSourceNoCurrency(): void
{
if (null === $this->sourceTransaction->transaction_currency_id && null !== $this->sourceCurrency) {
$this->sourceTransaction
->transaction_currency_id
= (int)$this->sourceCurrency->id;
$message = sprintf(
'Transaction #%d has no currency setting, now set to %s.',
$this->sourceTransaction->id,
$this->sourceCurrency->code
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->sourceTransaction->save();
}
}
/**
* The source transaction must have the correct currency. If not, it will be set by
* taking it from the source account's preference.
*/
private function fixSourceUnmatchedCurrency(): void
{
if (null !== $this->sourceCurrency
&& null === $this->sourceTransaction->foreign_amount
&& (int)$this->sourceTransaction->transaction_currency_id !== (int)$this->sourceCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->sourceTransaction->id,
$this->sourceTransaction->transaction_currency_id,
$this->sourceAccount->id,
$this->sourceTransaction->amount
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->sourceTransaction->transaction_currency_id = (int)$this->sourceCurrency->id;
$this->sourceTransaction->save();
}
}
/**
* The destination transaction must have a currency. If not, it will be added by
* taking it from the destination account's preference.
*/
private function fixDestNoCurrency(): void
{
if (null === $this->destinationTransaction->transaction_currency_id && null !== $this->destinationCurrency) {
$this->destinationTransaction
->transaction_currency_id
= (int)$this->destinationCurrency->id;
$message = sprintf(
'Transaction #%d has no currency setting, now set to %s.',
$this->destinationTransaction->id,
$this->destinationCurrency->code
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->destinationTransaction->save();
}
}
/**
* The destination transaction must have the correct currency. If not, it will be set by
* taking it from the destination account's preference.
*/
private function fixDestinationUnmatchedCurrency(): void
{
if (null !== $this->destinationCurrency
&& null === $this->destinationTransaction->foreign_amount
&& (int)$this->destinationTransaction->transaction_currency_id !== (int)$this->destinationCurrency->id
) {
$message = sprintf(
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
$this->destinationTransaction->id,
$this->destinationTransaction->transaction_currency_id,
$this->destinationAccount->id,
$this->destinationTransaction->amount
);
Log::debug($message);
$this->line($message);
$this->count++;
$this->destinationTransaction->transaction_currency_id = (int)$this->destinationCurrency->id;
$this->destinationTransaction->save();
}
}
/**
* If the destination account currency is the same as the source currency,
* both foreign_amount and foreign_currency_id fields must be NULL
* for both transactions (because foreign currency info would not make sense)
*/
private function fixInvalidForeignCurrency(): void
{
if ((int)$this->destinationCurrency->id === (int)$this->sourceCurrency->id) {
// update both transactions to match:
$this->sourceTransaction->foreign_amount = null;
$this->sourceTransaction->foreign_currency_id = null;
$this->destinationTransaction->foreign_amount = null;
$this->destinationTransaction->foreign_currency_id = null;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
Log::debug(
sprintf(
'Currency for account "%s" is %s, and currency for account "%s" is also
%s, so transactions #%d and #%d has been verified to be to %s exclusively.',
$this->destinationAccount->name,
$this->destinationCurrency->code,
$this->sourceAccount->name,
$this->sourceCurrency->code,
$this->sourceTransaction->id,
$this->destinationTransaction->id,
$this->sourceCurrency->code
)
);
}
}
/**
* If destination account currency is different from source account currency,
* then both transactions must get the source account's currency as normal currency
* and the opposing account's currency as foreign currency.
*/
private function fixMismatchedForeignCurrency(): void
{
if ((int)$this->sourceCurrency->id !== (int)$this->destinationCurrency->id) {
$this->sourceTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->sourceTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->destinationTransaction->transaction_currency_id = $this->sourceCurrency->id;
$this->destinationTransaction->foreign_currency_id = $this->destinationCurrency->id;
$this->sourceTransaction->save();
$this->destinationTransaction->save();
$this->count++;
Log::debug(sprintf('Verified foreign currency ID of transaction #%d and #%d', $this->sourceTransaction->id, $this->destinationTransaction->id));
}
}
/**
* If the foreign amount of the source transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixSourceNullForeignAmount(): void
{
if (null === $this->sourceTransaction->foreign_amount && null !== $this->destinationTransaction->foreign_amount) {
$this->sourceTransaction->foreign_amount = bcmul((string)$this->destinationTransaction->foreign_amount, '-1');
$this->sourceTransaction->save();
$this->count++;
Log::debug(
sprintf(
'Restored foreign amount of source transaction #%d to %s',
$this->sourceTransaction->id,
$this->sourceTransaction->foreign_amount
)
);
}
}
/**
* If the foreign amount of the destination transaction is null, but that of the other isn't, use this piece of code
* to restore it.
*/
private function fixDestNullForeignAmount(): void
{
if (null === $this->destinationTransaction->foreign_amount && null !== $this->sourceTransaction->foreign_amount) {
$this->destinationTransaction->foreign_amount = bcmul((string)$this->sourceTransaction->foreign_amount, '-1');
$this->destinationTransaction->save();
$this->count++;
Log::debug(
sprintf(
'Restored foreign amount of destination transaction #%d to %s',
$this->destinationTransaction->id,
$this->destinationTransaction->foreign_amount
)
);
}
}
/**
* This method makes sure that the transaction journal uses the currency given in the source transaction.
*
* @param TransactionJournal $journal
*/
private function fixTransactionJournalCurrency(TransactionJournal $journal): void
{
if ((int)$journal->transaction_currency_id !== (int)$this->sourceCurrency->id) {
$oldCurrencyCode = $journal->transactionCurrency->code ?? '(nothing)';
$journal->transaction_currency_id = $this->sourceCurrency->id;
$message = sprintf(
'Transfer #%d ("%s") has been updated to use %s instead of %s.',
$journal->id,
$journal->description,
$this->sourceCurrency->code,
$oldCurrencyCode
);
$this->count++;
$this->line($message);
Log::debug($message);
$journal->save();
}
}
/**
*
*/
private function markAsExecuted(): void
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}

View File

@@ -35,18 +35,8 @@ use Illuminate\Console\Command;
*/
class UpgradeDatabase extends Command
{
/**
* The console command description.
*
* @var string
*/
protected $description = 'Upgrades the database to the latest version.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:upgrade-database {--F|force : Force all upgrades.}';
protected $signature = 'firefly-iii:upgrade-database {--F|force : Force all upgrades.}';
/**
* Execute the console command.
@@ -97,15 +87,8 @@ class UpgradeDatabase extends Command
*/
private function callInitialCommands(): void
{
$this->line('Now seeding the database...');
$this->call('migrate', ['--seed' => true, '--force' => true, '--no-interaction' => true]);
$this->line('Fix PostgreSQL sequences.');
$this->call('firefly-iii:fix-pgsql-sequences');
$this->line('Now decrypting the database (if necessary)...');
$this->call('firefly-iii:decrypt-all');
$this->line('Done!');
}
}

View File

@@ -43,18 +43,8 @@ use Psr\Container\NotFoundExceptionInterface;
class UpgradeLiabilities extends Command
{
public const CONFIG_NAME = '560_upgrade_liabilities';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Upgrade liabilities to new 5.6.0 structure.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:upgrade-liabilities {--F|force : Force the execution of this command.}';
protected $signature = 'firefly-iii:upgrade-liabilities {--F|force : Force the execution of this command.}';
/**
* Execute the console command.
@@ -66,7 +56,6 @@ class UpgradeLiabilities extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
@@ -75,10 +64,6 @@ class UpgradeLiabilities extends Command
$this->upgradeLiabilities();
$this->markAsExecuted();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Upgraded liabilities in %s seconds.', $end));
return 0;
}
@@ -95,15 +80,12 @@ class UpgradeLiabilities extends Command
}
// source MUST be the liability.
if ((int)$destination->account_id === (int)$account->id) {
Log::debug(sprintf('Must switch around, because account #%d is the destination.', $destination->account_id));
// so if not, switch things around:
$sourceAccountId = (int)$source->account_id;
$source->account_id = $destination->account_id;
$destination->account_id = $sourceAccountId;
$source->save();
$destination->save();
Log::debug(sprintf('Source transaction #%d now has account #%d', $source->id, $source->account_id));
Log::debug(sprintf('Dest transaction #%d now has account #%d', $destination->id, $destination->account_id));
}
}
@@ -155,7 +137,6 @@ class UpgradeLiabilities extends Command
*/
private function upgradeForUser(User $user): void
{
Log::debug(sprintf('Upgrading liabilities for user #%d', $user->id));
$accounts = $user->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
@@ -174,7 +155,6 @@ class UpgradeLiabilities extends Command
*/
private function upgradeLiabilities(): void
{
Log::debug('Upgrading liabilities.');
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
@@ -190,7 +170,6 @@ class UpgradeLiabilities extends Command
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
Log::debug(sprintf('Upgrade liability #%d', $account->id));
// get opening balance, and correct if necessary.
$openingBalance = $repository->getOpeningBalance($account);

View File

@@ -45,18 +45,8 @@ use Psr\Container\NotFoundExceptionInterface;
class UpgradeLiabilitiesEight extends Command
{
public const CONFIG_NAME = '600_upgrade_liabilities';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Upgrade liabilities to new 6.0.0 structure.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:liabilities-600 {--F|force : Force the execution of this command.}';
protected $signature = 'firefly-iii:liabilities-600 {--F|force : Force the execution of this command.}';
/**
* Execute the console command.
@@ -68,7 +58,6 @@ class UpgradeLiabilitiesEight extends Command
*/
public function handle(): int
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
@@ -77,9 +66,6 @@ class UpgradeLiabilitiesEight extends Command
$this->upgradeLiabilities();
$this->markAsExecuted();
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Upgraded liabilities for 6.0.0 in %s seconds.', $end));
return 0;
}
@@ -90,7 +76,6 @@ class UpgradeLiabilitiesEight extends Command
*/
private function deleteCreditTransaction(Account $account): void
{
Log::debug('Will delete credit transaction.');
$liabilityType = TransactionType::whereType(TransactionType::LIABILITY_CREDIT)->first();
$liabilityJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
@@ -100,11 +85,9 @@ class UpgradeLiabilitiesEight extends Command
$group = $liabilityJournal->transactionGroup;
$service = new TransactionGroupDestroyService();
$service->destroy($group);
Log::debug(sprintf('Deleted liability credit group #%d', $group->id));
return;
}
Log::debug('No liability credit journal found.');
}
/**
@@ -117,7 +100,6 @@ class UpgradeLiabilitiesEight extends Command
$count = 0;
$journals = TransactionJournal::leftJoin('transactions', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->where('transactions.account_id', $account->id)->get(['transaction_journals.*']);
Log::debug(sprintf('Found %d journals to analyse.', $journals->count()));
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$delete = false;
@@ -140,16 +122,6 @@ class UpgradeLiabilitiesEight extends Command
$delete = false;
if ($delete) {
Log::debug(
sprintf(
'Deleted %s journal #%d ("%s") (%s %s).',
$journal->transactionType->type,
$journal->id,
$journal->description,
$journal->transactionCurrency->code,
$dest->amount
)
);
$service = app(TransactionGroupDestroyService::class);
$service->destroy($journal->transactionGroup);
$count++;
@@ -173,8 +145,6 @@ class UpgradeLiabilitiesEight extends Command
->where('transaction_journals.transaction_type_id', $openingBalanceType->id)
->first(['transaction_journals.*']);
if (null === $openingJournal) {
Log::debug('Account has no opening balance and can be skipped.');
return false;
}
$liabilityJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
@@ -182,16 +152,11 @@ class UpgradeLiabilitiesEight extends Command
->where('transaction_journals.transaction_type_id', $liabilityType->id)
->first(['transaction_journals.*']);
if (null === $liabilityJournal) {
Log::debug('Account has no liability credit and can be skipped.');
return false;
}
if (!$openingJournal->date->isSameDay($liabilityJournal->date)) {
Log::debug('Account has opening/credit not on the same day.');
return false;
}
Log::debug('Account has bad opening balance data.');
return true;
}
@@ -243,7 +208,6 @@ class UpgradeLiabilitiesEight extends Command
$source->account_id = $destId;
$source->save();
$dest->save();
Log::debug(sprintf('Opening balance transaction journal #%d reversed.', $openingJournal->id));
return;
}
@@ -255,7 +219,6 @@ class UpgradeLiabilitiesEight extends Command
*/
private function upgradeForUser(User $user): void
{
Log::debug(sprintf('Upgrading liabilities for user #%d', $user->id));
$accounts = $user->accounts()
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
->whereIn('account_types.type', config('firefly.valid_liabilities'))
@@ -274,7 +237,6 @@ class UpgradeLiabilitiesEight extends Command
*/
private function upgradeLiabilities(): void
{
Log::debug('Upgrading liabilities.');
$users = User::get();
/** @var User $user */
foreach ($users as $user) {
@@ -287,16 +249,11 @@ class UpgradeLiabilitiesEight extends Command
*/
private function upgradeLiability(Account $account): void
{
Log::debug(sprintf('Upgrade liability #%d ("%s")', $account->id, $account->name));
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser($account->user);
$direction = $repository->getMetaValue($account, 'liability_direction');
if ('debit' === $direction) {
Log::debug('Direction is debit ("I owe this amount"), so no need to upgrade.');
}
if ('credit' === $direction && $this->hasBadOpening($account)) {
$this->deleteCreditTransaction($account);
$this->reverseOpeningBalance($account);
@@ -308,6 +265,5 @@ class UpgradeLiabilitiesEight extends Command
$this->line(sprintf('Removed %d old format transaction(s) for liability #%d ("%s")', $count, $account->id, $account->name));
}
}
Log::debug(sprintf('Done upgrading liability #%d ("%s")', $account->id, $account->name));
}
}

View File

@@ -33,7 +33,7 @@ class UpgradeSkeleton extends Command
{
$start = microtime(true);
if ($this->isExecuted() && true !== $this->option('force')) {
$this->warn('This command has already been executed.');
$this->warn('Correct: this command has already been executed.');
return 0;
}

View File

@@ -60,15 +60,12 @@ class AccountMetaFactory
if ('' !== $value) {
// if $data has field and $entry is null, create new one:
if (null === $entry) {
Log::debug(sprintf('Created meta-field "%s":"%s" for account #%d ("%s") ', $field, $value, $account->id, $account->name));
return $this->create(['account_id' => $account->id, 'name' => $field, 'data' => $value]);
}
// if $data has field and $entry is not null, update $entry:
$entry->data = $value;
$entry->save();
Log::debug(sprintf('Updated meta-field "%s":"%s" for #%d ("%s") ', $field, $value, $account->id, $account->name));
}
if ('' === $value && null !== $entry) {
$entry->delete();

View File

@@ -102,7 +102,6 @@ class DebugController extends Controller
Log::debug('Call view:clear...');
Artisan::call('view:clear');
Log::debug('Done! Redirecting...');
return redirect(route('index'));
}

View File

@@ -667,7 +667,6 @@ class AccountRepository implements AccountRepositoryInterface
//[AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION],
];
foreach ($sets as $set) {
Log::debug('Now in resetAccountOrder', $set);
$list = $this->getAccountsByType($set);
$index = 1;
foreach ($list as $account) {

View File

@@ -57,25 +57,18 @@ class CreditRecalculateService
public function recalculate(): void
{
if (true !== config('firefly.feature_flags.handle_debts')) {
Log::debug('handle_debts is disabled.');
return;
}
if (null !== $this->group && null === $this->account) {
Log::debug('Have to handle a group.');
$this->processGroup();
}
if (null !== $this->account && null === $this->group) {
Log::debug('Have to handle an account.');
// work based on account.
$this->processAccount();
}
if (0 === count($this->work)) {
Log::debug('No work accounts, do not do CreditRecalculationService');
return;
}
Log::debug('Will now do CreditRecalculationService');
$this->processWork();
}
@@ -108,11 +101,9 @@ class CreditRecalculateService
// destination or source must be liability.
$valid = config('firefly.valid_liabilities');
if (in_array($destination->accountType->type, $valid, true)) {
Log::debug(sprintf('Dest account type is "%s", include it.', $destination->accountType->type));
$this->work[] = $destination;
}
if (in_array($source->accountType->type, $valid, true)) {
Log::debug(sprintf('Src account type is "%s", include it.', $source->accountType->type));
$this->work[] = $source;
}
}
@@ -168,7 +159,6 @@ class CreditRecalculateService
{
$valid = config('firefly.valid_liabilities');
if (in_array($this->account->accountType->type, $valid, true)) {
Log::debug(sprintf('Account type is "%s", include it.', $this->account->accountType->type));
$this->work[] = $this->account;
}
}
@@ -187,7 +177,6 @@ class CreditRecalculateService
Log::error(sprintf('Could not find work account for transaction group #%d.', $this->group->id));
}
}
Log::debug(sprintf('Done with %s', __METHOD__));
}
/**
@@ -200,7 +189,6 @@ class CreditRecalculateService
*/
private function processTransaction(Account $account, string $direction, Transaction $transaction, string $leftOfDebt): string
{
Log::debug(sprintf('Now in processTransaction(#%d, %s)', $transaction->id, $leftOfDebt));
$journal = $transaction->transactionJournal;
$foreignCurrency = $transaction->foreignCurrency;
$accountCurrency = $this->repository->getAccountCurrency($account);
@@ -212,12 +200,9 @@ class CreditRecalculateService
$sourceTransaction = $journal->transactions()->where('amount', '<', '0')->first();
if ('' === $direction) {
Log::debug('Since direction is "", do nothing.');
return $leftOfDebt;
}
if (TransactionType::LIABILITY_CREDIT === $type || TransactionType::OPENING_BALANCE === $type) {
Log::debug(sprintf('Skip group #%d, journal #%d of type "%s"', $journal->id, $groupId, $type));
return $leftOfDebt;
}
@@ -225,11 +210,8 @@ class CreditRecalculateService
$usedAmount = $transaction->amount;
if (null !== $foreignCurrency && $foreignCurrency->id === $accountCurrency->id) {
$usedAmount = $transaction->foreign_amount;
Log::debug('Will use foreign amount to match account currency.');
}
Log::debug(sprintf('Processing group #%d, journal #%d of type "%s"', $journal->id, $groupId, $type));
// Case 1
// it's a withdrawal into this liability (from asset).
// if it's a credit ("I am owed"), this increases the amount due,
@@ -240,9 +222,7 @@ class CreditRecalculateService
&& 1 === bccomp($usedAmount, '0')
&& 'credit' === $direction
) {
$newLeftOfDebt = bcadd($leftOfDebt, app('steam')->positive($usedAmount));
Log::debug(sprintf('[1] Is withdrawal (%s) into liability, left of debt = %s.', $usedAmount, $newLeftOfDebt));
return $newLeftOfDebt;
return bcadd($leftOfDebt, app('steam')->positive($usedAmount));
}
// Case 2
@@ -255,15 +235,7 @@ class CreditRecalculateService
&& -1 === bccomp($usedAmount, '0')
&& 'credit' === $direction
) {
$newLeftOfDebt = bcsub($leftOfDebt, app('steam')->positive($usedAmount));
Log::debug(
sprintf(
'[2] Is withdrawal (%s) away from liability, left of debt = %s.',
$usedAmount,
$newLeftOfDebt
)
);
return $newLeftOfDebt;
return bcsub($leftOfDebt, app('steam')->positive($usedAmount));
}
// case 3
@@ -276,9 +248,7 @@ class CreditRecalculateService
&& -1 === bccomp($usedAmount, '0')
&& 'credit' === $direction
) {
$newLeftOfDebt = bcsub($leftOfDebt, app('steam')->positive($usedAmount));
Log::debug(sprintf('[3] Is deposit (%s) away from liability, left of debt = %s.', $usedAmount, $newLeftOfDebt));
return $newLeftOfDebt;
return bcsub($leftOfDebt, app('steam')->positive($usedAmount));
}
// case 4
@@ -292,16 +262,12 @@ class CreditRecalculateService
&& 'credit' === $direction
) {
$newLeftOfDebt = bcadd($leftOfDebt, app('steam')->positive($usedAmount));
Log::debug(sprintf('[4] Is deposit (%s) into liability, left of debt = %s.', $usedAmount, $newLeftOfDebt));
return $newLeftOfDebt;
}
// in any other case, remove amount from left of debt.
if (in_array($type, [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER], true)) {
$newLeftOfDebt = bcadd($leftOfDebt, bcmul($usedAmount, '-1'));
Log::debug(
sprintf('[5] Fallback: transaction is withdrawal/deposit/transfer, remove amount %s from left of debt, = %s.', $usedAmount, $newLeftOfDebt)
);
return $newLeftOfDebt;
}
@@ -319,7 +285,6 @@ class CreditRecalculateService
foreach ($this->work as $account) {
$this->processWorkAccount($account);
}
Log::debug(sprintf('Done with %s', __METHOD__));
}
/**
@@ -327,8 +292,6 @@ class CreditRecalculateService
*/
private function processWorkAccount(Account $account): void
{
Log::debug(sprintf('Now in %s(#%d)', __METHOD__, $account->id));
// get opening balance (if present)
$this->repository->setUser($account->user);
$startOfDebt = $this->repository->getOpeningBalanceAmount($account) ?? '0';
@@ -345,14 +308,10 @@ class CreditRecalculateService
// now loop all transactions (except opening balance and credit thing)
$transactions = $account->transactions()->get();
Log::debug(sprintf('Going to process %d transaction(s)', $transactions->count()));
Log::debug(sprintf('Account currency is #%d (%s)', $account->id, $this->repository->getAccountCurrency($account)?->code));
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$leftOfDebt = $this->processTransaction($account, $direction, $transaction, $leftOfDebt);
}
$factory->crud($account, 'current_debt', $leftOfDebt);
Log::debug(sprintf('Done with %s(#%d)', __METHOD__, $account->id));
}
}

View File

@@ -265,7 +265,6 @@ trait JournalServiceTrait
Log::debug('End of loop.');
Log::debug(sprintf('Total nr. of tags: %d', count($tags)), $tags);
$journal->tags()->sync($set);
Log::debug('Done!');
}
/**

521
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -39,8 +39,6 @@ class ConfigSeeder extends Seeder
{
$entry = Configuration::where('name', 'db_version')->first();
if (null === $entry) {
Log::warning('No database version entry is present. Database is assumed to be OLD (version 1).');
// FF old or no version present. Put at 1:
Configuration::create(
[
'name' => 'db_version',
@@ -52,8 +50,6 @@ class ConfigSeeder extends Seeder
$version = (int)config('firefly.db_version');
$entry->data = $version;
$entry->save();
Log::warning(sprintf('Database entry exists. Update to latest version (%d)', $version));
}
}
}