diff --git a/app/Console/Commands/Correction/CorrectDatabase.php b/app/Console/Commands/Correction/CorrectDatabase.php index 6bcb3dc278..c95b7b9db7 100644 --- a/app/Console/Commands/Correction/CorrectDatabase.php +++ b/app/Console/Commands/Correction/CorrectDatabase.php @@ -69,7 +69,7 @@ class CorrectDatabase extends Command 'firefly-iii:delete-empty-journals', 'firefly-iii:delete-empty-groups', 'firefly-iii:fix-account-types', - 'firefly-iii:rename-meta-fields' + 'firefly-iii:rename-meta-fields', ]; foreach ($commands as $command) { $this->line(sprintf('Now executing %s', $command)); diff --git a/app/Console/Commands/Correction/CreateAccessTokens.php b/app/Console/Commands/Correction/CreateAccessTokens.php index 9d2ce023dd..d2f8602d21 100644 --- a/app/Console/Commands/Correction/CreateAccessTokens.php +++ b/app/Console/Commands/Correction/CreateAccessTokens.php @@ -58,7 +58,7 @@ class CreateAccessTokens extends Command $start = microtime(true); $count = 0; - $users= $repository->all(); + $users = $repository->all(); /** @var User $user */ foreach ($users as $user) { $pref = app('preferences')->getForUser($user, 'access_token', null); diff --git a/app/Console/Commands/Correction/DeleteEmptyGroups.php b/app/Console/Commands/Correction/DeleteEmptyGroups.php index 4db1945866..2a45cab77b 100644 --- a/app/Console/Commands/Correction/DeleteEmptyGroups.php +++ b/app/Console/Commands/Correction/DeleteEmptyGroups.php @@ -47,12 +47,12 @@ class DeleteEmptyGroups extends Command /** * Execute the console command. * - * @throws Exception; * @return mixed + * @throws Exception; */ public function handle(): int { - $start = microtime(true); + $start = microtime(true); $groups = array_unique(TransactionJournal::get(['transaction_group_id'])->pluck('transaction_group_id')->toArray()); $count = TransactionGroup::whereNull('deleted_at')->whereNotIn('id', $groups)->count(); if (0 === $count) { diff --git a/app/Console/Commands/Correction/DeleteEmptyJournals.php b/app/Console/Commands/Correction/DeleteEmptyJournals.php index 0932efe932..54bd7fd05f 100644 --- a/app/Console/Commands/Correction/DeleteEmptyJournals.php +++ b/app/Console/Commands/Correction/DeleteEmptyJournals.php @@ -22,10 +22,10 @@ namespace FireflyIII\Console\Commands\Correction; use DB; +use Exception; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use Illuminate\Console\Command; -use Exception; use Log; /** @@ -105,7 +105,7 @@ class DeleteEmptyJournals extends Command try { TransactionJournal::find((int)$row->transaction_journal_id)->delete(); // @codeCoverageIgnoreStart - } catch(Exception $e) { + } catch (Exception $e) { Log::info(sprintf('Could not delete journal: %s', $e->getMessage())); } // @codeCoverageIgnoreEnd diff --git a/app/Console/Commands/Correction/DeleteZeroAmount.php b/app/Console/Commands/Correction/DeleteZeroAmount.php index e55b413f1d..c71d0443f3 100644 --- a/app/Console/Commands/Correction/DeleteZeroAmount.php +++ b/app/Console/Commands/Correction/DeleteZeroAmount.php @@ -21,11 +21,11 @@ namespace FireflyIII\Console\Commands\Correction; -use FireflyIII\Models\TransactionJournal; +use Exception; use FireflyIII\Models\Transaction; +use FireflyIII\Models\TransactionJournal; use Illuminate\Console\Command; use Illuminate\Support\Collection; -use Exception; /** * Class DeleteZeroAmount @@ -52,8 +52,8 @@ 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); + $set = Transaction::where('amount', 0)->get(['transaction_journal_id'])->pluck('transaction_journal_id')->toArray(); + $set = array_unique($set); /** @var Collection $journals */ $journals = TransactionJournal::whereIn('id', $set)->get(); /** @var TransactionJournal $journal */ @@ -74,6 +74,7 @@ class DeleteZeroAmount extends Command $end = round(microtime(true) - $start, 2); $this->info(sprintf('Verified zero-amount integrity in %s seconds', $end)); + return 0; } } diff --git a/app/Console/Commands/Correction/FixAccountTypes.php b/app/Console/Commands/Correction/FixAccountTypes.php index ed936a1900..0fd0b16af7 100644 --- a/app/Console/Commands/Correction/FixAccountTypes.php +++ b/app/Console/Commands/Correction/FixAccountTypes.php @@ -55,15 +55,6 @@ class FixAccountTypes extends Command /** @var int */ private $count; - /** - * FixAccountTypes constructor. - */ - public function __construct() - { - parent::__construct(); - $this->count = 0; - } - /** * Execute the console command. * @@ -72,6 +63,7 @@ class FixAccountTypes extends Command */ public function handle(): int { + $this->stupidLaravel(); $start = microtime(true); $this->factory = app(AccountFactory::class); // some combinations can be fixed by this script: @@ -110,6 +102,18 @@ class FixAccountTypes extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->count = 0; + } + /** * @param TransactionJournal $journal * @param string $type diff --git a/app/Console/Commands/Correction/FixUnevenAmount.php b/app/Console/Commands/Correction/FixUnevenAmount.php index 7b72aeef8b..251d22bca4 100644 --- a/app/Console/Commands/Correction/FixUnevenAmount.php +++ b/app/Console/Commands/Correction/FixUnevenAmount.php @@ -22,7 +22,6 @@ namespace FireflyIII\Console\Commands\Correction; use DB; -use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use Illuminate\Console\Command; @@ -93,7 +92,7 @@ class FixUnevenAmount extends Command // fix amount of destination: /** @var Transaction $destination */ - $destination = $journal->transactions()->where('amount', '>', 0)->first(); + $destination = $journal->transactions()->where('amount', '>', 0)->first(); $destination->amount = $amount; $destination->save(); diff --git a/app/Console/Commands/Correction/TransferBudgets.php b/app/Console/Commands/Correction/TransferBudgets.php index 8598acc6fc..533192c96c 100644 --- a/app/Console/Commands/Correction/TransferBudgets.php +++ b/app/Console/Commands/Correction/TransferBudgets.php @@ -66,7 +66,7 @@ class TransferBudgets extends Command if (0 === $count) { $this->info('No invalid budget/journal entries.'); } - if(0 !== $count) { + if (0 !== $count) { $this->line(sprintf('Corrected %d invalid budget/journal entries (entry).', $count)); } $end = round(microtime(true) - $start, 2); diff --git a/app/Console/Commands/Import/CreateCSVImport.php b/app/Console/Commands/Import/CreateCSVImport.php index ad64c742db..27909afafe 100644 --- a/app/Console/Commands/Import/CreateCSVImport.php +++ b/app/Console/Commands/Import/CreateCSVImport.php @@ -67,22 +67,12 @@ class CreateCSVImport extends Command /** @var ImportJob */ private $importJob; - /** - * CreateCSVImport constructor. - */ - public function __construct() - { - parent::__construct(); - $this->userRepository = app(UserRepositoryInterface::class); - $this->importRepository = app(ImportJobRepositoryInterface::class); - - } - /** * Run the command. */ public function handle(): int { + $this->stupidLaravel(); // @codeCoverageIgnoreStart if (!$this->verifyAccessToken()) { $this->errorLine('Invalid access token.'); @@ -156,6 +146,19 @@ class CreateCSVImport extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->userRepository = app(UserRepositoryInterface::class); + $this->importRepository = app(ImportJobRepositoryInterface::class); + } + /** * @param string $message * @param array|null $data diff --git a/app/Console/Commands/Integrity/ReportEmptyObjects.php b/app/Console/Commands/Integrity/ReportEmptyObjects.php index 69ab4b8848..8c368b3037 100644 --- a/app/Console/Commands/Integrity/ReportEmptyObjects.php +++ b/app/Console/Commands/Integrity/ReportEmptyObjects.php @@ -124,7 +124,7 @@ class ReportEmptyObjects extends Command /** @var stdClass $entry */ foreach ($set as $entry) { - $line = sprintf( + $line = sprintf( 'User #%d (%s) has budget #%d ("%s") which has no transaction journals.', $entry->user_id, $entry->email, diff --git a/app/Console/Commands/Integrity/ReportIntegrity.php b/app/Console/Commands/Integrity/ReportIntegrity.php index 541418c67e..4384a62e5c 100644 --- a/app/Console/Commands/Integrity/ReportIntegrity.php +++ b/app/Console/Commands/Integrity/ReportIntegrity.php @@ -24,9 +24,9 @@ declare(strict_types=1); namespace FireflyIII\Console\Commands\Integrity; +use Artisan; use Illuminate\Console\Command; use Schema; -use Artisan; /** * Class ReportIntegrity diff --git a/app/Console/Commands/Tools/ApplyRules.php b/app/Console/Commands/Tools/ApplyRules.php index 3eb4019a85..11d9c9dfdb 100644 --- a/app/Console/Commands/Tools/ApplyRules.php +++ b/app/Console/Commands/Tools/ApplyRules.php @@ -92,24 +92,6 @@ class ApplyRules extends Command /** @var RuleGroupRepositoryInterface */ private $ruleGroupRepository; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->allRules = false; - $this->accounts = new Collection; - $this->ruleSelection = []; - $this->ruleGroupSelection = []; - $this->ruleRepository = app(RuleRepositoryInterface::class); - $this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class); - $this->acceptedAccounts = [AccountType::DEFAULT, AccountType::DEBT, AccountType::ASSET, AccountType::LOAN, AccountType::MORTGAGE]; - $this->groups = new Collection; - } - /** * Execute the console command. * @@ -118,6 +100,7 @@ class ApplyRules extends Command */ public function handle(): int { + $this->stupidLaravel(); // @codeCoverageIgnoreStart if (!$this->verifyAccessToken()) { $this->error('Invalid access token.'); @@ -183,6 +166,25 @@ class ApplyRules extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->allRules = false; + $this->accounts = new Collection; + $this->ruleSelection = []; + $this->ruleGroupSelection = []; + $this->ruleRepository = app(RuleRepositoryInterface::class); + $this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class); + $this->acceptedAccounts = [AccountType::DEFAULT, AccountType::DEBT, AccountType::ASSET, AccountType::LOAN, AccountType::MORTGAGE]; + $this->groups = new Collection; + } + /** * @return bool * @throws FireflyException diff --git a/app/Console/Commands/Upgrade/AccountCurrencies.php b/app/Console/Commands/Upgrade/AccountCurrencies.php index 14ee979839..1ae44be61f 100644 --- a/app/Console/Commands/Upgrade/AccountCurrencies.php +++ b/app/Console/Commands/Upgrade/AccountCurrencies.php @@ -57,17 +57,6 @@ class AccountCurrencies extends Command /** @var int */ private $count; - /** - * AccountCurrencies constructor. - */ - public function __construct() - { - parent::__construct(); - $this->accountRepos = app(AccountRepositoryInterface::class); - $this->userRepos = app(UserRepositoryInterface::class); - $this->count = 0; - } - /** * Each (asset) account must have a reference to a preferred currency. If the account does not have one, it's forced upon the account. * @@ -75,6 +64,7 @@ class AccountCurrencies 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.'); @@ -98,6 +88,20 @@ class AccountCurrencies extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->accountRepos = app(AccountRepositoryInterface::class); + $this->userRepos = app(UserRepositoryInterface::class); + $this->count = 0; + } + /** * @return bool */ @@ -141,6 +145,7 @@ class AccountCurrencies extends Command 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)); $this->count++; + return; } diff --git a/app/Console/Commands/Upgrade/BudgetLimitCurrency.php b/app/Console/Commands/Upgrade/BudgetLimitCurrency.php index 99a0068d49..dd37b5fc59 100644 --- a/app/Console/Commands/Upgrade/BudgetLimitCurrency.php +++ b/app/Console/Commands/Upgrade/BudgetLimitCurrency.php @@ -54,7 +54,7 @@ class BudgetLimitCurrency extends Command */ public function handle(): int { - $start = microtime(true); + $start = microtime(true); // @codeCoverageIgnoreStart if ($this->isExecuted() && true !== $this->option('force')) { $this->warn('This command has already been executed.'); diff --git a/app/Console/Commands/Upgrade/CCLiabilities.php b/app/Console/Commands/Upgrade/CCLiabilities.php index b09a172446..e53bfafaa9 100644 --- a/app/Console/Commands/Upgrade/CCLiabilities.php +++ b/app/Console/Commands/Upgrade/CCLiabilities.php @@ -71,6 +71,7 @@ class CCLiabilities extends Command $debtType = AccountType::where('type', AccountType::DEBT)->first(); if (null === $ccType || null === $debtType) { $this->info('No incorrectly stored credit card liabilities.'); + return 0; } /** @var Collection $accounts */ diff --git a/app/Console/Commands/Upgrade/MigrateAttachments.php b/app/Console/Commands/Upgrade/MigrateAttachments.php index 375d80bf16..4e4df1caa8 100644 --- a/app/Console/Commands/Upgrade/MigrateAttachments.php +++ b/app/Console/Commands/Upgrade/MigrateAttachments.php @@ -95,7 +95,7 @@ class MigrateAttachments extends Command $this->line('All attachments are OK.'); } if (0 !== $count) { - $this->line(sprintf('Updated %d attachment(s).',$count)); + $this->line(sprintf('Updated %d attachment(s).', $count)); } $end = round(microtime(true) - $start, 2); $this->info(sprintf('Migrated attachment notes in %s seconds.', $end)); diff --git a/app/Console/Commands/Upgrade/MigrateToGroups.php b/app/Console/Commands/Upgrade/MigrateToGroups.php index 385ce73ffe..35c8053305 100644 --- a/app/Console/Commands/Upgrade/MigrateToGroups.php +++ b/app/Console/Commands/Upgrade/MigrateToGroups.php @@ -62,20 +62,6 @@ class MigrateToGroups extends Command private $service; private $count; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->count = 0; - $this->journalRepository = app(JournalRepositoryInterface::class); - $this->service = app(JournalDestroyService::class); - $this->groupFactory = app(TransactionGroupFactory::class); - } - /** * Execute the console command. * @@ -84,6 +70,7 @@ class MigrateToGroups extends Command */ public function handle(): int { + $this->stupidLaravel(); $start = microtime(true); // @codeCoverageIgnoreStart if ($this->isMigrated() && true !== $this->option('force')) { @@ -122,6 +109,21 @@ class MigrateToGroups extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->count = 0; + $this->journalRepository = app(JournalRepositoryInterface::class); + $this->service = app(JournalDestroyService::class); + $this->groupFactory = app(TransactionGroupFactory::class); + } + /** * @param TransactionJournal $journal * @param Transaction $transaction diff --git a/app/Console/Commands/Upgrade/MigrateToRules.php b/app/Console/Commands/Upgrade/MigrateToRules.php index 014cb595d9..cd7ee995a1 100644 --- a/app/Console/Commands/Upgrade/MigrateToRules.php +++ b/app/Console/Commands/Upgrade/MigrateToRules.php @@ -64,19 +64,6 @@ class MigrateToRules extends Command private $ruleRepository; private $count; - /** - * MigrateToRules constructor. - */ - public function __construct() - { - parent::__construct(); - $this->count = 0; - $this->userRepository = app(UserRepositoryInterface::class); - $this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class); - $this->billRepository = app(BillRepositoryInterface::class); - $this->ruleRepository = app(RuleRepositoryInterface::class); - } - /** * Execute the console command. * @@ -85,6 +72,7 @@ class MigrateToRules extends Command */ public function handle(): int { + $this->stupidLaravel(); $start = microtime(true); // @codeCoverageIgnoreStart @@ -115,6 +103,22 @@ class MigrateToRules extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->count = 0; + $this->userRepository = app(UserRepositoryInterface::class); + $this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class); + $this->billRepository = app(BillRepositoryInterface::class); + $this->ruleRepository = app(RuleRepositoryInterface::class); + } + /** * @return bool */ diff --git a/app/Console/Commands/Upgrade/OtherCurrenciesCorrections.php b/app/Console/Commands/Upgrade/OtherCurrenciesCorrections.php index 650e4885f5..1ce062030b 100644 --- a/app/Console/Commands/Upgrade/OtherCurrenciesCorrections.php +++ b/app/Console/Commands/Upgrade/OtherCurrenciesCorrections.php @@ -64,19 +64,6 @@ class OtherCurrenciesCorrections extends Command /** @var int */ private $count; - /** - * JournalCurrencies constructor. - */ - public function __construct() - { - parent::__construct(); - $this->count = 0; - $this->accountCurrencies = []; - $this->accountRepos = app(AccountRepositoryInterface::class); - $this->currencyRepos = app(CurrencyRepositoryInterface::class); - $this->journalRepos = app(JournalRepositoryInterface::class); - } - /** * Execute the console command. * @@ -84,6 +71,7 @@ class OtherCurrenciesCorrections extends Command */ public function handle(): int { + $this->stupidLaravel(); $start = microtime(true); // @codeCoverageIgnoreStart if ($this->isExecuted() && true !== $this->option('force')) { @@ -103,6 +91,22 @@ class OtherCurrenciesCorrections extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->count = 0; + $this->accountCurrencies = []; + $this->accountRepos = app(AccountRepositoryInterface::class); + $this->currencyRepos = app(CurrencyRepositoryInterface::class); + $this->journalRepos = app(JournalRepositoryInterface::class); + } + /** * @param Account $account * diff --git a/app/Console/Commands/Upgrade/TransactionIdentifier.php b/app/Console/Commands/Upgrade/TransactionIdentifier.php index 9e124b9ead..fcbde7e17a 100644 --- a/app/Console/Commands/Upgrade/TransactionIdentifier.php +++ b/app/Console/Commands/Upgrade/TransactionIdentifier.php @@ -54,13 +54,6 @@ class TransactionIdentifier extends Command /** @var int */ private $count; - public function __construct() - { - parent::__construct(); - $this->journalRepository = app(JournalRepositoryInterface::class); - $this->count = 0; - } - /** * This method gives all transactions which are part of a split journal (so more than 2) a sort of "order" so they are easier * to easier to match to their counterpart. When a journal is split, it has two or three transactions: -3, -4 and -5 for example. @@ -74,6 +67,7 @@ class TransactionIdentifier extends Command */ public function handle(): int { + $this->stupidLaravel(); $start = microtime(true); // @codeCoverageIgnoreStart if ($this->isExecuted() && true !== $this->option('force')) { @@ -107,6 +101,19 @@ class TransactionIdentifier extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->journalRepository = app(JournalRepositoryInterface::class); + $this->count = 0; + } + /** * @return bool */ @@ -184,6 +191,7 @@ class TransactionIdentifier extends Command return null; } + // @codeCoverageIgnoreEnd return $opposing; diff --git a/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php b/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php index 710a202725..e1a72e6a93 100644 --- a/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php +++ b/app/Console/Commands/Upgrade/TransferCurrenciesCorrections.php @@ -76,21 +76,6 @@ class TransferCurrenciesCorrections extends Command /** @var TransactionCurrency The currency preference of the destination account of the current journal. */ private $destinationCurrency; - - /** - * JournalCurrencies constructor. - */ - public function __construct() - { - parent::__construct(); - $this->count = 0; - $this->accountRepos = app(AccountRepositoryInterface::class); - $this->currencyRepos = app(CurrencyRepositoryInterface::class); - $this->journalRepos = app(JournalRepositoryInterface::class); - $this->accountCurrencies = []; - $this->resetInformation(); - } - /** * Execute the console command. * @@ -98,6 +83,7 @@ class TransferCurrenciesCorrections extends Command */ public function handle(): int { + $this->stupidLaravel(); $start = microtime(true); // @codeCoverageIgnoreStart if ($this->isExecuted() && true !== $this->option('force')) { @@ -111,10 +97,14 @@ class TransferCurrenciesCorrections extends Command $this->markAsExecuted(); if (0 === $this->count) { - $this->line('All transfers have correct currency information.'); + $message = 'All transfers have correct currency information.'; + $this->line($message); + Log::debug($message); } if (0 !== $this->count) { - $this->line(sprintf('Verified currency information of %d transfer(s).', $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)); @@ -122,6 +112,23 @@ class TransferCurrenciesCorrections extends Command 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. + * + * @codeCoverageIgnore + */ + private function stupidLaravel(): void + { + $this->count = 0; + $this->accountRepos = app(AccountRepositoryInterface::class); + $this->currencyRepos = app(CurrencyRepositoryInterface::class); + $this->journalRepos = app(JournalRepositoryInterface::class); + $this->accountCurrencies = []; + $this->resetInformation(); + } + /** * @param Account $account * @@ -131,17 +138,19 @@ class TransferCurrenciesCorrections extends Command { $accountId = $account->id; if (isset($this->accountCurrencies[$accountId]) && 0 === $this->accountCurrencies[$accountId]) { - return null; + return null; // @codeCoverageIgnore } if (isset($this->accountCurrencies[$accountId]) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) { - return $this->accountCurrencies[$accountId]; + return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore } $currencyId = (int)$this->accountRepos->getMetaValue($account, 'currency_id'); $result = $this->currencyRepos->findNull($currencyId); if (null === $result) { + // @codeCoverageIgnoreStart $this->accountCurrencies[$accountId] = 0; return null; + // @codeCoverageIgnoreEnd } $this->accountCurrencies[$accountId] = $result; @@ -154,20 +163,22 @@ class TransferCurrenciesCorrections extends Command * @param TransactionJournal $transfer * * @return Transaction|null + * @codeCoverageIgnore */ private function getDestinationTransaction(TransactionJournal $transfer): ?Transaction { - return $transfer->transactions->firstWhere('amount', '>', 0); + return $transfer->transactions()->where('amount', '>', 0)->first(); } /** * @param TransactionJournal $transfer * * @return Transaction|null + * @codeCoverageIgnore */ private function getSourceTransaction(TransactionJournal $transfer): ?Transaction { - return $transfer->transactions->firstWhere('amount', '<', 0); + return $transfer->transactions()->where('amount', '<', 0)->first(); } /** @@ -198,19 +209,19 @@ class TransferCurrenciesCorrections extends Command */ private function fixTransactionJournalCurrency(TransactionJournal $journal): void { - if ($journal->transaction_currency_id !== $this->sourceCurrency->id) { + if ((int)$journal->transaction_currency_id !== (int)$this->sourceCurrency->id) { $oldCurrencyCode = $journal->transactionCurrency->code ?? '(nothing)'; $journal->transaction_currency_id = $this->sourceCurrency->id; - $this->count++; - $this->line( - sprintf( - 'Transfer #%d ("%s") has been updated to use %s instead of %s.', - $journal->id, - $journal->description, - $this->sourceCurrency->code, - $oldCurrencyCode - ) + $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(); } } @@ -235,7 +246,8 @@ class TransferCurrenciesCorrections extends Command } /** - * Reset all the class fields for the current transfer + * Reset all the class fields for the current transfer. + * @codeCoverageIgnore */ private function resetInformation(): void { @@ -249,7 +261,9 @@ class TransferCurrenciesCorrections extends Command /** * Extract source transaction, source account + source account currency from the journal. + * * @param TransactionJournal $journal + * @codeCoverageIgnore */ private function getSourceInformation(TransactionJournal $journal): void { @@ -260,7 +274,9 @@ class TransferCurrenciesCorrections extends Command /** * Extract destination transaction, destination account + destination account currency from the journal. + * * @param TransactionJournal $journal + * @codeCoverageIgnore */ private function getDestinationInformation(TransactionJournal $journal): void { @@ -276,26 +292,37 @@ class TransferCurrenciesCorrections extends Command */ private function updateTransferCurrency(TransactionJournal $transfer): void { + $this->resetInformation(); + // @codeCoverageIgnoreStart if ($this->isSplitJournal($transfer)) { $this->line(sprintf(sprintf('Transaction journal #%d is a split journal. Cannot continue.', $transfer->id))); + + return; } + // @codeCoverageIgnoreEnd $this->getSourceInformation($transfer); $this->getDestinationInformation($transfer); // unexpectedly, either one is null: + // @codeCoverageIgnoreStart if ($this->isEmptyTransactions()) { $this->error(sprintf('Source or destination information for transaction journal #%d is null. Cannot fix this one.', $transfer->id)); return; } + // @codeCoverageIgnoreEnd + // both accounts must have currency preference: + // @codeCoverageIgnoreStart if ($this->isNoCurrencyPresent()) { return; } + // @codeCoverageIgnoreEnd + // fix source transaction having no currency. $this->fixSourceNoCurrency(); @@ -311,16 +338,17 @@ class TransferCurrenciesCorrections extends Command // remove foreign currency information if not necessary. $this->fixInvalidForeignCurrency(); - // correct foreign currency info if necessary. $this->fixMismatchedForeignCurrency(); // restore missing foreign currency amount. $this->fixSourceNullForeignAmount(); + $this->fixDestNullForeignAmount(); // fix journal itself: $this->fixTransactionJournalCurrency($transfer); + } /** @@ -416,6 +444,7 @@ class TransferCurrenciesCorrections extends Command * * @param TransactionJournal $transfer * @return bool + * @codeCoverageIgnore */ private function isSplitJournal(TransactionJournal $transfer): bool { @@ -425,6 +454,7 @@ class TransferCurrenciesCorrections extends Command /** * Is either the source or destination transaction NULL? * @return bool + * @codeCoverageIgnore */ private function isEmptyTransactions(): bool { @@ -436,6 +466,7 @@ class TransferCurrenciesCorrections extends Command * 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 { @@ -459,21 +490,21 @@ class TransferCurrenciesCorrections extends Command $this->sourceTransaction->id, $this->destinationTransaction->id, $this->sourceCurrency->code ) ); - $this->count++; - - return; } } /** - * If destination account currency is different from source account currency, then - * both transactions must have each others currency as foreign currency id. + * 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->foreign_currency_id = $this->destinationCurrency->id; - $this->destinationTransaction->foreign_currency_id = $this->sourceCurrency->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(); @@ -514,6 +545,7 @@ class TransferCurrenciesCorrections extends Command /** * @return bool + * @codeCoverageIgnore */ private function isNoCurrencyPresent(): bool { @@ -523,7 +555,7 @@ class TransferCurrenciesCorrections extends Command Log::error($message); $this->error($message); - return false; + return true; } // destination account must have a currency preference. @@ -533,10 +565,10 @@ class TransferCurrenciesCorrections extends Command Log::error($message); $this->error($message); - return false; + return true; } - return true; + return false; } } \ No newline at end of file diff --git a/app/Console/Commands/Upgrade/UpgradeDatabase.php b/app/Console/Commands/Upgrade/UpgradeDatabase.php index 2eec509c3b..73ed7727a8 100644 --- a/app/Console/Commands/Upgrade/UpgradeDatabase.php +++ b/app/Console/Commands/Upgrade/UpgradeDatabase.php @@ -45,16 +45,6 @@ class UpgradeDatabase extends Command */ protected $signature = 'firefly-iii:upgrade-database {--F|force : Force all upgrades.}'; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - parent::__construct(); - } - /** * Execute the console command. * diff --git a/routes/console.php b/routes/console.php index f5cebdaa32..3ff8a14920 100644 --- a/routes/console.php +++ b/routes/console.php @@ -41,8 +41,6 @@ declare(strict_types=1); * along with Firefly III. If not, see . */ -use Illuminate\Foundation\Inspiring; - /* |-------------------------------------------------------------------------- | Console Routes @@ -53,9 +51,3 @@ use Illuminate\Foundation\Inspiring; | simple approach to interacting with each command's IO methods. | */ - -Artisan::command( - 'inspire', function () { - $this->comment(Inspiring::quote()); -} -)->describe('Display an inspiring quote'); diff --git a/tests/Api/V1/Controllers/CurrencyControllerTest.php b/tests/Api/V1/Controllers/CurrencyControllerTest.php index 1cf178a9b4..e3b535ca26 100644 --- a/tests/Api/V1/Controllers/CurrencyControllerTest.php +++ b/tests/Api/V1/Controllers/CurrencyControllerTest.php @@ -28,6 +28,7 @@ use FireflyIII\Helpers\Collector\TransactionCollectorInterface; use FireflyIII\Models\Preference; use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\User\UserRepositoryInterface; use FireflyIII\Transformers\CurrencyTransformer; use Laravel\Passport\Passport; use Log; @@ -64,6 +65,7 @@ class CurrencyControllerTest extends TestCase $currency = TransactionCurrency::first(); $repository = $this->mock(CurrencyRepositoryInterface::class); $transformer = $this->mock(CurrencyTransformer::class); + $userRepository = $this->mock(UserRepositoryInterface::class); // mock transformer $transformer->shouldReceive('setParameters')->withAnyArgs()->atLeast()->once(); @@ -103,6 +105,7 @@ class CurrencyControllerTest extends TestCase $currency = TransactionCurrency::first(); $repository = $this->mock(CurrencyRepositoryInterface::class); $transformer = $this->mock(CurrencyTransformer::class); + $userRepository = $this->mock(UserRepositoryInterface::class); // mock transformer $transformer->shouldReceive('setParameters')->withAnyArgs()->atLeast()->once(); @@ -148,6 +151,7 @@ class CurrencyControllerTest extends TestCase $currency = TransactionCurrency::first(); $repository = $this->mock(CurrencyRepositoryInterface::class); $transformer = $this->mock(CurrencyTransformer::class); + $this->mock(UserRepositoryInterface::class); // mock transformer $transformer->shouldReceive('setParameters')->withAnyArgs()->atLeast()->once(); @@ -187,6 +191,7 @@ class CurrencyControllerTest extends TestCase $currency = TransactionCurrency::first(); $repository = $this->mock(CurrencyRepositoryInterface::class); $transformer = $this->mock(CurrencyTransformer::class); + $this->mock(UserRepositoryInterface::class); $preference = new Preference; $preference->data = 'EUR'; diff --git a/tests/Api/V1/Controllers/LinkTypeControllerTest.php b/tests/Api/V1/Controllers/LinkTypeControllerTest.php index a7557f0a53..23e4ebb49a 100644 --- a/tests/Api/V1/Controllers/LinkTypeControllerTest.php +++ b/tests/Api/V1/Controllers/LinkTypeControllerTest.php @@ -181,6 +181,7 @@ class LinkTypeControllerTest extends TestCase { // mock stuff: $repository = $this->mock(LinkTypeRepositoryInterface::class); + $userRepository = $this->mock(UserRepositoryInterface::class); // create editable link type: $linkType = LinkType::create( diff --git a/tests/Api/V1/Controllers/PreferencesControllerTest.php b/tests/Api/V1/Controllers/PreferencesControllerTest.php index c8950708fc..386f1d9cad 100644 --- a/tests/Api/V1/Controllers/PreferencesControllerTest.php +++ b/tests/Api/V1/Controllers/PreferencesControllerTest.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace Tests\Api\V1\Controllers; use FireflyIII\Models\Preference; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Transformers\PreferenceTransformer; use Laravel\Passport\Passport; use Log; @@ -56,6 +57,7 @@ class PreferencesControllerTest extends TestCase public function testUpdateArray(): void { $transformer = $this->mock(PreferenceTransformer::class); + $accountRepos = $this->mock(AccountRepositoryInterface::class); // mock calls to transformer: $transformer->shouldReceive('setParameters')->withAnyArgs()->atLeast()->once(); @@ -63,6 +65,7 @@ class PreferencesControllerTest extends TestCase $transformer->shouldReceive('getDefaultIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('getAvailableIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('transform')->atLeast()->once()->andReturn(['id' => 5]); + $accountRepos->shouldReceive('setUser')->atLeast()->once(); /** @var Preference $preference */ $preference = Preferences::setForUser($this->user(), 'frontPageAccounts', [1, 2, 3]); @@ -78,6 +81,7 @@ class PreferencesControllerTest extends TestCase public function testUpdateBoolean(): void { $transformer = $this->mock(PreferenceTransformer::class); + $accountRepos = $this->mock(AccountRepositoryInterface::class); // mock calls to transformer: $transformer->shouldReceive('setParameters')->withAnyArgs()->atLeast()->once(); @@ -85,6 +89,7 @@ class PreferencesControllerTest extends TestCase $transformer->shouldReceive('getDefaultIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('getAvailableIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('transform')->atLeast()->once()->andReturn(['id' => 5]); + $accountRepos->shouldReceive('setUser')->atLeast()->once(); /** @var Preference $preference */ $preference = Preferences::setForUser($this->user(), 'twoFactorAuthEnabled', false); @@ -101,6 +106,7 @@ class PreferencesControllerTest extends TestCase public function testUpdateDefault(): void { $transformer = $this->mock(PreferenceTransformer::class); + $accountRepos = $this->mock(AccountRepositoryInterface::class); // mock calls to transformer: $transformer->shouldReceive('setParameters')->withAnyArgs()->atLeast()->once(); @@ -108,6 +114,7 @@ class PreferencesControllerTest extends TestCase $transformer->shouldReceive('getDefaultIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('getAvailableIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('transform')->atLeast()->once()->andReturn(['id' => 5]); + $accountRepos->shouldReceive('setUser')->atLeast()->once(); /** @var Preference $preference */ $preference = Preferences::setForUser($this->user(), 'currencyPreference', false); @@ -123,6 +130,7 @@ class PreferencesControllerTest extends TestCase public function testUpdateInteger(): void { $transformer = $this->mock(PreferenceTransformer::class); + $accountRepos = $this->mock(AccountRepositoryInterface::class); // mock calls to transformer: $transformer->shouldReceive('setParameters')->withAnyArgs()->atLeast()->once(); @@ -130,6 +138,7 @@ class PreferencesControllerTest extends TestCase $transformer->shouldReceive('getDefaultIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('getAvailableIncludes')->withAnyArgs()->atLeast()->once()->andReturn([]); $transformer->shouldReceive('transform')->atLeast()->once()->andReturn(['id' => 5]); + $accountRepos->shouldReceive('setUser')->atLeast()->once(); /** @var Preference $preference */ $preference = Preferences::setForUser($this->user(), 'listPageSize', 13); diff --git a/tests/TestCase.php b/tests/TestCase.php index 33829c5bbe..11ad4115c0 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -157,7 +157,8 @@ abstract class TestCase extends BaseTestCase return $this->getRandomAccount(AccountType::INITIAL_BALANCE, null); } - public function getRandomReconciliation(): Account { + public function getRandomReconciliation(): Account + { return $this->getRandomAccount(AccountType::RECONCILIATION, null); } @@ -233,6 +234,14 @@ abstract class TestCase extends BaseTestCase return TransactionCurrency::find(1); } + /** + * @return TransactionCurrency + */ + protected function getDollar(): TransactionCurrency + { + return TransactionCurrency::where('code', 'USD')->first(); + } + /** * @return TransactionGroup */ @@ -257,7 +266,7 @@ abstract class TestCase extends BaseTestCase if (in_array($class, $deprecated, true)) { throw new RuntimeException(strtoupper('Must not be mocking the transaction collector or transformer.')); } - Log::debug(sprintf('Will now mock %s', $class)); + //Log::debug(sprintf('Will now mock %s', $class)); $object = Mockery::mock($class); $this->app->instance($class, $object); @@ -345,7 +354,7 @@ abstract class TestCase extends BaseTestCase DB::raw('COUNT(transaction_journal_id) as ct'), ] )->first(); - if(null === $result) { + if (null === $result) { throw new FireflyException(sprintf('Cannot find suitable %s to use.', $type)); } diff --git a/tests/Unit/Console/Commands/Upgrade/JournalCurrenciesTest.php b/tests/Unit/Console/Commands/Upgrade/JournalCurrenciesTest.php deleted file mode 100644 index c4e867f193..0000000000 --- a/tests/Unit/Console/Commands/Upgrade/JournalCurrenciesTest.php +++ /dev/null @@ -1,354 +0,0 @@ -. - */ - -namespace Tests\Unit\Console\Commands\Upgrade; - - -use FireflyConfig; -use FireflyIII\Models\Account; -use FireflyIII\Models\Configuration; -use FireflyIII\Models\Transaction; -use FireflyIII\Models\TransactionCurrency; -use FireflyIII\Models\TransactionType; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; -use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; -use FireflyIII\Repositories\Journal\JournalRepositoryInterface; -use Illuminate\Support\Collection; -use Log; -use Mockery; -use Tests\TestCase; - -/** - * Class JournalCurrenciesTest - */ -class JournalCurrenciesTest extends TestCase -{ - /** - * - */ - public function setUp(): void - { - parent::setUp(); - Log::info(sprintf('Now in %s.', get_class($this))); - } -// -// /** -// * Basic run. Would not change anything. -// * -// * @covers \FireflyIII\Console\Commands\Upgrade\JournalCurrencies -// */ -// public function testHandle(): void -// { -// // mock classes -// $accountRepos = $this->mock(AccountRepositoryInterface::class); -// $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); -// $journalRepos = $this->mock(JournalRepositoryInterface::class); -// $euro = TransactionCurrency::find(1); -// -// // update transfer if necessary for the test: -// $false = new Configuration; -// $false->data = false; -// FireflyConfig::shouldReceive('get')->withArgs(['4780_journal_currencies', false])->andReturn($false); -// FireflyConfig::shouldReceive('set')->withArgs(['4780_journal_currencies', true]); -// -// // mock stuff -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::TRANSFER]]) -// ->andReturn(new Collection); -// -// // for the "other journals" check, return nothing. -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) -// ->andReturn(new Collection); -// -// // transaction would be verified, nothing more. -// $this->artisan('firefly-iii:journal-currencies') -// ->expectsOutput('All transactions are correct.') -// ->assertExitCode(0); -// // nothing changed, so no verification. -// -// } -// -// /** -// * Submit a single transfer which has no issues. -// * -// * @covers \FireflyIII\Console\Commands\Upgrade\JournalCurrencies -// */ -// public function testHandleTransfer(): void -// { -// // mock classes -// $accountRepos = $this->mock(AccountRepositoryInterface::class); -// $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); -// $journalRepos = $this->mock(JournalRepositoryInterface::class); -// $euro = TransactionCurrency::find(1); -// $transfer = $this->getRandomTransfer(); -// -// // update transfer if necessary for the test: -// $collection = new Collection([$transfer]); -// $false = new Configuration; -// $false->data = false; -// FireflyConfig::shouldReceive('get')->withArgs(['4780_journal_currencies', false])->andReturn($false); -// FireflyConfig::shouldReceive('set')->withArgs(['4780_journal_currencies', true]); -// -// // mock stuff -// $accountRepos->shouldReceive('setUser')->atLeast()->once(); -// $journalRepos->shouldReceive('setUser')->atLeast()->once(); -// $currencyRepos->shouldReceive('setUser')->atLeast()->once(); -// -// // return single tranfer -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::TRANSFER]]) -// ->andReturn($collection); -// -// // for the "other journals" check, return nothing. -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) -// ->andReturn(new Collection); -// -// $accountRepos->shouldReceive('getMetaValue')->atLeast()->once()->withArgs([Mockery::any(), 'currency_id'])->andReturn($euro->id); -// $currencyRepos->shouldReceive('findNull')->atLeast()->once()->andReturn($euro); -// -// // transaction would be verified, nothing more. -// $this->artisan('firefly-iii:journal-currencies') -// ->expectsOutput('Verified 1 transaction(s) and journal(s).') -// ->assertExitCode(0); -// // nothing changed, so no verification. -// } -// -// /** -// * Submit a single transfer where the source account has no currency preference. -// * -// * @covers \FireflyIII\Console\Commands\Upgrade\JournalCurrencies -// */ -// public function testHandleTransferSourceNoPref(): void -// { -// // mock classes -// $accountRepos = $this->mock(AccountRepositoryInterface::class); -// $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); -// $journalRepos = $this->mock(JournalRepositoryInterface::class); -// $euro = TransactionCurrency::find(1); -// $transfer = $this->getRandomTransfer(); -// -// // edit source to remove currency preference: -// /** @var Account $source */ -// $source = $transfer->transactions()->where('amount', '<', 0)->first()->account; -//// AccountMeta::where('account_id', $source->id)->where('name', 'currency_id')->delete(); -// -// // update transfer if necessary for the test: -// $collection = new Collection([$transfer]); -// $false = new Configuration; -// $false->data = false; -// FireflyConfig::shouldReceive('get')->withArgs(['4780_journal_currencies', false])->andReturn($false); -// FireflyConfig::shouldReceive('set')->withArgs(['4780_journal_currencies', true]); -// -// // mock stuff -// $accountRepos->shouldReceive('setUser')->atLeast()->once(); -// $journalRepos->shouldReceive('setUser')->atLeast()->once(); -// $currencyRepos->shouldReceive('setUser')->atLeast()->once(); -// -// // return single transfer -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::TRANSFER]]) -// ->andReturn($collection); -// -// // for the "other journals" check, return nothing. -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) -// ->andReturn(new Collection); -// -// // return NULL for first currency ID and currency. -// $accountRepos->shouldReceive('getMetaValue')->atLeast()->once()->withArgs([Mockery::any(), 'currency_id'])->andReturnNull(); -// $currencyRepos->shouldReceive('findNull')->atLeast()->once()->andReturnNull(); -// -// // transaction would be verified, nothing more. -// $this->artisan('firefly-iii:journal-currencies') -// ->expectsOutput(sprintf('Account #%d ("%s") must have currency preference but has none.', $source->id, $source->name)) -// ->assertExitCode(0); -// // nothing changed, so no verification. -// -// } -// -// /** -// * Submit a single transfer where the source transaction has no currency set. -// * Because this is not done over repositories, we must edit the DB. -// * -// * @covers \FireflyIII\Console\Commands\Upgrade\JournalCurrencies -// */ -// public function testHandleTransferSourceNoCurrency(): void -// { -// // mock classes -// $accountRepos = $this->mock(AccountRepositoryInterface::class); -// $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); -// $journalRepos = $this->mock(JournalRepositoryInterface::class); -// $euro = TransactionCurrency::find(1); -// $transfer = $this->getRandomTransfer(); -// /** @var Transaction $source */ -// $source = $transfer->transactions()->where('amount', '<', 0)->first(); -// $source->transaction_currency_id = null; -// $source->save(); -// -// // update transfer if necessary for the test: -// $collection = new Collection([$transfer]); -// $false = new Configuration; -// $false->data = false; -// FireflyConfig::shouldReceive('get')->withArgs(['4780_journal_currencies', false])->andReturn($false); -// FireflyConfig::shouldReceive('set')->withArgs(['4780_journal_currencies', true]); -// -// // mock stuff -// $accountRepos->shouldReceive('setUser')->atLeast()->once(); -// $journalRepos->shouldReceive('setUser')->atLeast()->once(); -// $currencyRepos->shouldReceive('setUser')->atLeast()->once(); -// -// // return single tranfer -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::TRANSFER]]) -// ->andReturn($collection); -// -// // for the "other journals" check, return nothing. -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) -// ->andReturn(new Collection); -// -// $accountRepos->shouldReceive('getMetaValue')->atLeast()->once()->withArgs([Mockery::any(), 'currency_id'])->andReturn($euro->id); -// $currencyRepos->shouldReceive('findNull')->atLeast()->once()->andReturn($euro); -// -// // transaction would be verified, nothing more. -// $this->artisan('firefly-iii:journal-currencies') -// ->expectsOutput(sprintf('Transaction #%d has no currency setting, now set to %s.', $source->id, $euro->code)) -// ->expectsOutput('Verified 2 transaction(s) and journal(s).') -// ->assertExitCode(0); -// -// // check transaction -// $this->assertCount(1, Transaction::where('id', $source->id)->where('transaction_currency_id', $euro->id)->get()); -// } -// -// /** -// * Submit a single transfer where the source transaction has a different currency than the source account does. -// * -// * @covers \FireflyIII\Console\Commands\Upgrade\JournalCurrencies -// */ -// public function testHandleMismatchedTransfer(): void -// { -// // mock classes -// $accountRepos = $this->mock(AccountRepositoryInterface::class); -// $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); -// $journalRepos = $this->mock(JournalRepositoryInterface::class); -// $euro = TransactionCurrency::find(1); -// $usd = TransactionCurrency::where('code', 'USD')->first(); -// $transfer = $this->getRandomTransfer(); -// -// /** @var Transaction $source */ -// $source = $transfer->transactions()->where('amount', '<', 0)->first(); -// $source->transaction_currency_id = $usd->id; -// $source->save(); -// -// // update transfer if necessary for the test: -// $collection = new Collection([$transfer]); -// $false = new Configuration; -// $false->data = false; -// FireflyConfig::shouldReceive('get')->withArgs(['4780_journal_currencies', false])->andReturn($false); -// FireflyConfig::shouldReceive('set')->withArgs(['4780_journal_currencies', true]); -// -// // mock stuff -// $accountRepos->shouldReceive('setUser')->atLeast()->once(); -// $journalRepos->shouldReceive('setUser')->atLeast()->once(); -// $currencyRepos->shouldReceive('setUser')->atLeast()->once(); -// -// // return single tranfer -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::TRANSFER]]) -// ->andReturn($collection); -// -// // for the "other journals" check, return nothing. -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) -// ->andReturn(new Collection); -// -// $accountRepos->shouldReceive('getMetaValue')->atLeast()->once()->withArgs([Mockery::any(), 'currency_id'])->andReturn($euro->id); -// $currencyRepos->shouldReceive('findNull')->atLeast()->once()->andReturn($euro); -// -// // transaction would be verified, nothing more. -// $this->artisan('firefly-iii:journal-currencies') -// ->expectsOutput( -// sprintf( -// 'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.', -// $source->id, -// $source->transaction_currency_id, -// $euro->id, -// $source->amount -// ) -// ) -// ->expectsOutput('Verified 2 transaction(s) and journal(s).') -// ->assertExitCode(0); -// // nothing changed, so no verification. -// } -// -// /** -// * Submit a single transfer where the destination account has no currency preference. -// * -// * @covers \FireflyIII\Console\Commands\Upgrade\JournalCurrencies -// */ -// public function testHandleTransferNoDestinationCurrency(): void -// { -// // mock classes -// $accountRepos = $this->mock(AccountRepositoryInterface::class); -// $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); -// $journalRepos = $this->mock(JournalRepositoryInterface::class); -// $euro = TransactionCurrency::find(1); -// $transfer = $this->getRandomTransfer(); -// -// /** @var Account $destination */ -// $destination = $transfer->transactions()->where('amount', '>', 0)->first()->account; -// -// // update transfer if necessary for the test: -// $collection = new Collection([$transfer]); -// $false = new Configuration; -// $false->data = false; -// FireflyConfig::shouldReceive('get')->withArgs(['4780_journal_currencies', false])->andReturn($false); -// FireflyConfig::shouldReceive('set')->withArgs(['4780_journal_currencies', true]); -// -// // mock stuff -// $accountRepos->shouldReceive('setUser')->atLeast()->once(); -// $journalRepos->shouldReceive('setUser')->atLeast()->once(); -// $currencyRepos->shouldReceive('setUser')->atLeast()->once(); -// -// // return single tranfer -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::TRANSFER]]) -// ->andReturn($collection); -// -// // for the "other journals" check, return nothing. -// $journalRepos->shouldReceive('getAllJournals')->atLeast()->once() -// ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) -// ->andReturn(new Collection); -// -// $accountRepos->shouldReceive('getMetaValue')->atLeast()->once()->withArgs([Mockery::any(), 'currency_id'])->andReturn($euro->id, 0); -// $currencyRepos->shouldReceive('findNull')->atLeast()->once()->andReturn($euro, null); -// -// // transaction would be verified, nothing more. -// $this->artisan('firefly-iii:journal-currencies') -// ->expectsOutput(sprintf('Account #%d ("%s") must have currency preference but has none.', $destination->id, $destination->name)) -// ->assertExitCode(0); -// // nothing changed, so no verification. -// } - - -} \ No newline at end of file diff --git a/tests/Unit/Console/Commands/Upgrade/TransferCurrenciesCorrectionsTest.php b/tests/Unit/Console/Commands/Upgrade/TransferCurrenciesCorrectionsTest.php new file mode 100644 index 0000000000..8c08eca164 --- /dev/null +++ b/tests/Unit/Console/Commands/Upgrade/TransferCurrenciesCorrectionsTest.php @@ -0,0 +1,535 @@ +. + */ + +namespace Tests\Unit\Console\Commands\Upgrade; + + +use FireflyConfig; +use FireflyIII\Models\Configuration; +use FireflyIII\Models\Transaction; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Models\TransactionType; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use Illuminate\Support\Collection; +use Log; +use Mockery; +use Tests\TestCase; + +/** + * Class TransferCurrenciesCorrectionsTest + */ +class TransferCurrenciesCorrectionsTest extends TestCase +{ + /** + * + */ + public function setUp(): void + { + parent::setUp(); + Log::info(sprintf('Now in %s.', get_class($this))); + } + + /** + * Basic test. Assume nothing is wrong. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandle(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + // assume all is well. + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('All transfers have correct currency information.') + ->assertExitCode(0); + } + + /** + * Basic test. Assume the transfer is OK. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleCorrectTransfer(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + // assume all is well. + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('All transfers have correct currency information.') + ->assertExitCode(0); + } + + /** + * Journal has bad currency info. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleInvalidJournalCurrency(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + $dollar = $this->getDollar(); + $transfer->transaction_currency_id = $dollar->id; + $transfer->save(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 1 transfer(s).') + ->assertExitCode(0); + + $this->assertCount(1, TransactionJournal::where('id', $transfer->id)->where('transaction_currency_id', 1)->get()); + } + + /** + * Missing source foreign amount information. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleMissingSourceForeignAmount(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + $dollar = $this->getDollar(); + + /** @var Transaction $destination */ + $destination = $transfer->transactions()->where('amount', '>', 0)->first(); + $destination->foreign_amount = '100'; + $destination->save(); + + /** @var Transaction $destination */ + $source = $transfer->transactions()->where('amount', '<', 0)->first(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1', $dollar->id); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([$dollar->id])->andReturn($dollar); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 2 transfer(s).') + ->assertExitCode(0); + + $this->assertCount(1, Transaction::where('id', $source->id) + ->where('foreign_amount', '-100')->get() + ); + } + + + /** + * Missing source foreign amount information. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleMissingDestForeignAmount(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + $dollar = $this->getDollar(); + + /** @var Transaction $destination */ + $destination = $transfer->transactions()->where('amount', '>', 0)->first(); + $destination->foreign_amount = null; + $destination->save(); + + /** @var Transaction $destination */ + $source = $transfer->transactions()->where('amount', '<', 0)->first(); + $source->foreign_amount = '-100'; + $source->save(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1', $dollar->id); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([$dollar->id])->andReturn($dollar); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 3 transfer(s).') + ->assertExitCode(0); + + $this->assertCount(1, Transaction::where('id', $destination->id) + ->where('foreign_amount', '100')->get() + ); + } + + + /** + * Basic test. The foreign currency is broken and should be corrected. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleMismatchedForeignCurrency(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + $dollar = $this->getDollar(); + + $source = $transfer->transactions()->where('amount', '<', 0)->first(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1', $dollar->id); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([$dollar->id])->andReturn($dollar); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 2 transfer(s).') + ->assertExitCode(0); + + // source and destination transaction should be corrected: + $this->assertCount(1, Transaction::where('id', $source->id) + ->where('transaction_currency_id', $euro->id) + ->where('foreign_currency_id', $dollar->id) + ->get()); + } + + + /** + * Basic test. Source transaction has no currency. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleTransferNoSourceCurrency(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + + // get source transaction and remove currency: + /** @var Transaction $source */ + $source = $transfer->transactions()->where('amount', '<', 0)->first(); + $source->transaction_currency_id = null; + $source->save(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 1 transfer(s).') + ->assertExitCode(0); + + // assume problem is fixed: + $this->assertCount(1, Transaction::where('id', $source->id)->where('transaction_currency_id', 1)->get()); + } + + /** + * Basic test. Destination transaction has no currency. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleTransferNoDestCurrency(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + + // get source transaction and remove currency: + /** @var Transaction $destination */ + $destination = $transfer->transactions()->where('amount', '>', 0)->first(); + $destination->transaction_currency_id = null; + $destination->save(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 1 transfer(s).') + ->assertExitCode(0); + + // assume problem is fixed: + $this->assertCount(1, Transaction::where('id', $destination->id)->where('transaction_currency_id', 1)->get()); + } + + /** + * Basic test. Source transaction has bad currency. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleTransferBadSourceCurrency(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + + // get source transaction and remove currency: + /** @var Transaction $source */ + $source = $transfer->transactions()->where('amount', '<', 0)->first(); + $source->transaction_currency_id = 2; + $source->save(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 1 transfer(s).') + ->assertExitCode(0); + + // assume problem is fixed: + $this->assertCount(1, Transaction::where('id', $source->id)->where('transaction_currency_id', 1)->get()); + } + + /** + * Basic test. Source transaction has bad currency. + * + * @covers \FireflyIII\Console\Commands\Upgrade\TransferCurrenciesCorrections + */ + public function testHandleTransferBadDestCurrency(): void + { + + $accountRepos = $this->mock(AccountRepositoryInterface::class); + $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); + $journalRepos = $this->mock(JournalRepositoryInterface::class); + $transfer = $this->getRandomTransfer(); + $euro = $this->getEuro(); + + // get destination transaction and remove currency: + /** @var Transaction $destination */ + $destination = $transfer->transactions()->where('amount', '>', 0)->first(); + $destination->transaction_currency_id = 2; + $destination->save(); + + // mock calls: + $journalRepos->shouldReceive('getAllJournals') + ->withArgs([[TransactionType::TRANSFER]]) + ->atLeast()->once()->andReturn(new Collection([$transfer])); + + // account repos + $accountRepos->shouldReceive('getMetaValue') + ->atLeast()->once() + ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); + + // currency repos + $currencyRepos->shouldReceive('findNull') + ->atLeast()->once() + ->withArgs([1])->andReturn($euro); + + // configuration + $false = new Configuration; + $false->data = false; + FireflyConfig::shouldReceive('get')->withArgs(['4780_transfer_currencies', false])->andReturn($false); + FireflyConfig::shouldReceive('set')->withArgs(['4780_transfer_currencies', true]); + + $this->artisan('firefly-iii:transfer-currencies') + ->expectsOutput('Verified currency information of 1 transfer(s).') + ->assertExitCode(0); + + // assume problem is fixed: + $this->assertCount(1, Transaction::where('id', $destination->id)->where('transaction_currency_id', 1)->get()); + } + +} \ No newline at end of file