mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-29 06:34:37 +00:00 
			
		
		
		
	Expand test coverage
This commit is contained in:
		| @@ -71,6 +71,7 @@ class OtherCurrenciesCorrections extends Command | |||||||
|     { |     { | ||||||
|         parent::__construct(); |         parent::__construct(); | ||||||
|         $this->count             = 0; |         $this->count             = 0; | ||||||
|  |         $this->accountCurrencies = []; | ||||||
|         $this->accountRepos      = app(AccountRepositoryInterface::class); |         $this->accountRepos      = app(AccountRepositoryInterface::class); | ||||||
|         $this->currencyRepos     = app(CurrencyRepositoryInterface::class); |         $this->currencyRepos     = app(CurrencyRepositoryInterface::class); | ||||||
|         $this->journalRepos      = app(JournalRepositoryInterface::class); |         $this->journalRepos      = app(JournalRepositoryInterface::class); | ||||||
| @@ -83,9 +84,6 @@ class OtherCurrenciesCorrections extends Command | |||||||
|      */ |      */ | ||||||
|     public function handle(): int |     public function handle(): int | ||||||
|     { |     { | ||||||
|         $this->accountCurrencies = []; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         $start = microtime(true); |         $start = microtime(true); | ||||||
|         // @codeCoverageIgnoreStart |         // @codeCoverageIgnoreStart | ||||||
|         if ($this->isExecuted() && true !== $this->option('force')) { |         if ($this->isExecuted() && true !== $this->option('force')) { | ||||||
| @@ -98,12 +96,7 @@ class OtherCurrenciesCorrections extends Command | |||||||
|         $this->updateOtherJournalsCurrencies(); |         $this->updateOtherJournalsCurrencies(); | ||||||
|         $this->markAsExecuted(); |         $this->markAsExecuted(); | ||||||
|  |  | ||||||
|         if (0 === $this->count) { |  | ||||||
|             $this->line('All transactions are correct.'); |  | ||||||
|         } |  | ||||||
|         if (0 !== $this->count) { |  | ||||||
|         $this->line(sprintf('Verified %d transaction(s) and journal(s).', $this->count)); |         $this->line(sprintf('Verified %d transaction(s) and journal(s).', $this->count)); | ||||||
|         } |  | ||||||
|         $end = round(microtime(true) - $start, 2); |         $end = round(microtime(true) - $start, 2); | ||||||
|         $this->info(sprintf('Verified and fixed transaction currencies in %s seconds.', $end)); |         $this->info(sprintf('Verified and fixed transaction currencies in %s seconds.', $end)); | ||||||
|  |  | ||||||
| @@ -119,7 +112,7 @@ class OtherCurrenciesCorrections extends Command | |||||||
|     { |     { | ||||||
|         $accountId = $account->id; |         $accountId = $account->id; | ||||||
|         if (isset($this->accountCurrencies[$accountId]) && 0 === $this->accountCurrencies[$accountId]) { |         if (isset($this->accountCurrencies[$accountId]) && 0 === $this->accountCurrencies[$accountId]) { | ||||||
|             return null; |             return null; // @codeCoverageIgnore | ||||||
|         } |         } | ||||||
|         if (isset($this->accountCurrencies[$accountId]) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) { |         if (isset($this->accountCurrencies[$accountId]) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) { | ||||||
|             return $this->accountCurrencies[$accountId]; |             return $this->accountCurrencies[$accountId]; | ||||||
| @@ -127,9 +120,11 @@ class OtherCurrenciesCorrections extends Command | |||||||
|         $currencyId = (int)$this->accountRepos->getMetaValue($account, 'currency_id'); |         $currencyId = (int)$this->accountRepos->getMetaValue($account, 'currency_id'); | ||||||
|         $result     = $this->currencyRepos->findNull($currencyId); |         $result     = $this->currencyRepos->findNull($currencyId); | ||||||
|         if (null === $result) { |         if (null === $result) { | ||||||
|  |             // @codeCoverageIgnoreStart | ||||||
|             $this->accountCurrencies[$accountId] = 0; |             $this->accountCurrencies[$accountId] = 0; | ||||||
|  |  | ||||||
|             return null; |             return null; | ||||||
|  |             // @codeCoverageIgnoreEnd | ||||||
|         } |         } | ||||||
|         $this->accountCurrencies[$accountId] = $result; |         $this->accountCurrencies[$accountId] = $result; | ||||||
|  |  | ||||||
| @@ -138,24 +133,6 @@ class OtherCurrenciesCorrections extends Command | |||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * @param TransactionJournal $journal |  | ||||||
|      * |  | ||||||
|      * @return Transaction|null |  | ||||||
|      */ |  | ||||||
|     private function getFirstAssetTransaction(TransactionJournal $journal): ?Transaction |  | ||||||
|     { |  | ||||||
|         $result = $journal->transactions->first( |  | ||||||
|             static function (Transaction $transaction) { |  | ||||||
|                 // type can also be liability. |  | ||||||
|                 return AccountType::ASSET === $transaction->account->accountType->type; |  | ||||||
|             } |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         return $result; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @return bool |      * @return bool | ||||||
|      */ |      */ | ||||||
| @@ -182,22 +159,31 @@ class OtherCurrenciesCorrections extends Command | |||||||
|      */ |      */ | ||||||
|     private function updateJournalCurrency(TransactionJournal $journal): void |     private function updateJournalCurrency(TransactionJournal $journal): void | ||||||
|     { |     { | ||||||
|  |         $this->accountRepos->setUser($journal->user); | ||||||
|  |         $this->journalRepos->setUser($journal->user); | ||||||
|  |         $this->currencyRepos->setUser($journal->user); | ||||||
|  |  | ||||||
|         $leadTransaction = $this->getLeadTransaction($journal); |         $leadTransaction = $this->getLeadTransaction($journal); | ||||||
|  |  | ||||||
|         if (null === $leadTransaction) { |         if (null === $leadTransaction) { | ||||||
|  |             // @codeCoverageIgnoreStart | ||||||
|             $this->error(sprintf('Could not reliably determine which transaction is in the lead for transaction journal #%d.', $journal->id)); |             $this->error(sprintf('Could not reliably determine which transaction is in the lead for transaction journal #%d.', $journal->id)); | ||||||
|  |  | ||||||
|             return; |             return; | ||||||
|  |             // @codeCoverageIgnoreEnd | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /** @var Account $account */ |         /** @var Account $account */ | ||||||
|         $account  = $leadTransaction->account; |         $account  = $leadTransaction->account; | ||||||
|         $currency = $this->getCurrency($account); |         $currency = $this->getCurrency($account); | ||||||
|         if (null === $currency) { |         if (null === $currency) { | ||||||
|  |             // @codeCoverageIgnoreStart | ||||||
|             $this->error(sprintf('Account #%d ("%s") has no currency preference, so transaction journal #%d can\'t be corrected', |             $this->error(sprintf('Account #%d ("%s") has no currency preference, so transaction journal #%d can\'t be corrected', | ||||||
|                                  $account->id, $account->name, $journal->id)); |                                  $account->id, $account->name, $journal->id)); | ||||||
|  |             $this->count++; | ||||||
|  |  | ||||||
|             return; |             return; | ||||||
|  |             // @codeCoverageIgnoreEnd | ||||||
|         } |         } | ||||||
|         // fix each transaction: |         // fix each transaction: | ||||||
|         $journal->transactions->each( |         $journal->transactions->each( | ||||||
| @@ -205,7 +191,6 @@ class OtherCurrenciesCorrections extends Command | |||||||
|                 if (null === $transaction->transaction_currency_id) { |                 if (null === $transaction->transaction_currency_id) { | ||||||
|                     $transaction->transaction_currency_id = $currency->id; |                     $transaction->transaction_currency_id = $currency->id; | ||||||
|                     $transaction->save(); |                     $transaction->save(); | ||||||
|                     //$this->count++; |  | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // when mismatch in transaction: |                 // when mismatch in transaction: | ||||||
| @@ -214,7 +199,6 @@ class OtherCurrenciesCorrections extends Command | |||||||
|                     $transaction->foreign_amount          = $transaction->amount; |                     $transaction->foreign_amount          = $transaction->amount; | ||||||
|                     $transaction->transaction_currency_id = $currency->id; |                     $transaction->transaction_currency_id = $currency->id; | ||||||
|                     $transaction->save(); |                     $transaction->save(); | ||||||
|                     //$this->count++; |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
| @@ -231,8 +215,6 @@ class OtherCurrenciesCorrections extends Command | |||||||
|      * Both source and destination must match the respective currency preference of the related asset account. |      * Both source and destination must match the respective currency preference of the related asset account. | ||||||
|      * So FF3 must verify all transactions. |      * So FF3 must verify all transactions. | ||||||
|      * |      * | ||||||
|      * @SuppressWarnings(PHPMD.CyclomaticComplexity) |  | ||||||
|      * @SuppressWarnings(PHPMD.ExcessiveMethodLength) |  | ||||||
|      */ |      */ | ||||||
|     private function updateOtherJournalsCurrencies(): void |     private function updateOtherJournalsCurrencies(): void | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -21,9 +21,9 @@ | |||||||
|  |  | ||||||
| namespace FireflyIII\Console\Commands\Upgrade; | namespace FireflyIII\Console\Commands\Upgrade; | ||||||
|  |  | ||||||
| use DB; |  | ||||||
| use FireflyIII\Models\Transaction; | use FireflyIII\Models\Transaction; | ||||||
| use FireflyIII\Models\TransactionJournal; | use FireflyIII\Models\TransactionJournal; | ||||||
|  | use FireflyIII\Repositories\Journal\JournalRepositoryInterface; | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
| use Illuminate\Database\QueryException; | use Illuminate\Database\QueryException; | ||||||
| use Log; | use Log; | ||||||
| @@ -48,6 +48,19 @@ class TransactionIdentifier extends Command | |||||||
|      */ |      */ | ||||||
|     protected $signature = 'firefly-iii:transaction-identifiers {--F|force : Force the execution of this command.}'; |     protected $signature = 'firefly-iii:transaction-identifiers {--F|force : Force the execution of this command.}'; | ||||||
|  |  | ||||||
|  |     /** @var JournalRepositoryInterface */ | ||||||
|  |     private $journalRepository; | ||||||
|  |  | ||||||
|  |     /** @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 |      * 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. |      * to easier to match to their counterpart. When a journal is split, it has two or three transactions: -3, -4 and -5 for example. | ||||||
| @@ -62,6 +75,7 @@ class TransactionIdentifier extends Command | |||||||
|     public function handle(): int |     public function handle(): int | ||||||
|     { |     { | ||||||
|         $start = microtime(true); |         $start = microtime(true); | ||||||
|  |         // @codeCoverageIgnoreStart | ||||||
|         if ($this->isExecuted() && true !== $this->option('force')) { |         if ($this->isExecuted() && true !== $this->option('force')) { | ||||||
|             $this->warn('This command has already been executed.'); |             $this->warn('This command has already been executed.'); | ||||||
|  |  | ||||||
| @@ -72,24 +86,22 @@ class TransactionIdentifier extends Command | |||||||
|         if (!Schema::hasTable('transaction_journals')) { |         if (!Schema::hasTable('transaction_journals')) { | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
|         $subQuery = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') |         // @codeCoverageIgnoreEnd | ||||||
|                                       ->whereNull('transaction_journals.deleted_at') |         $journals = $this->journalRepository->getSplitJournals(); | ||||||
|                                       ->whereNull('transactions.deleted_at') |         /** @var TransactionJournal $journal */ | ||||||
|                                       ->groupBy(['transaction_journals.id']) |         foreach ($journals as $journal) { | ||||||
|                                       ->select(['transaction_journals.id', DB::raw('COUNT(transactions.id) AS t_count')]); |             $this->updateJournalIdentifiers($journal); | ||||||
|         /** @noinspection PhpStrictTypeCheckingInspection */ |  | ||||||
|         $result     = DB::table(DB::raw('(' . $subQuery->toSql() . ') AS derived')) |  | ||||||
|                         ->mergeBindings($subQuery->getQuery()) |  | ||||||
|                         ->where('t_count', '>', 2) |  | ||||||
|                         ->select(['id', 't_count']); |  | ||||||
|         $journalIds = array_unique($result->pluck('id')->toArray()); |  | ||||||
|         $count= 0; |  | ||||||
|         foreach ($journalIds as $journalId) { |  | ||||||
|             $this->updateJournalIdentifiers((int)$journalId); |  | ||||||
|             $count++; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (0 === $this->count) { | ||||||
|  |             $this->line('All split journal transaction identifiers are correct.'); | ||||||
|  |         } | ||||||
|  |         if (0 !== $this->count) { | ||||||
|  |             $this->line(sprintf('Fixed %d split journal transaction identifier(s).', $this->count)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $end = round(microtime(true) - $start, 2); |         $end = round(microtime(true) - $start, 2); | ||||||
|         $this->info(sprintf('Verified and fixed %d transaction identifiers in %s seconds.', $count, $end)); |         $this->info(sprintf('Verified and fixed transaction identifiers in %s seconds.', $end)); | ||||||
|         $this->markAsExecuted(); |         $this->markAsExecuted(); | ||||||
|  |  | ||||||
|         return 0; |         return 0; | ||||||
| @@ -117,27 +129,52 @@ class TransactionIdentifier extends Command | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * grab all positive transactions from this journal that are not deleted. for each one, grab the negative opposing one |      * Grab all positive transactions from this journal that are not deleted. for each one, grab the negative opposing one | ||||||
|      * which has 0 as an identifier and give it the same identifier. |      * which has 0 as an identifier and give it the same identifier. | ||||||
|      * |      * | ||||||
|      * @param int $journalId |      * @param TransactionJournal $transactionJournal | ||||||
|      */ |      */ | ||||||
|     private function updateJournalIdentifiers(int $journalId): void |     private function updateJournalIdentifiers(TransactionJournal $transactionJournal): void | ||||||
|     { |     { | ||||||
|         $identifier   = 0; |         $identifier   = 0; | ||||||
|         $processed    = []; |         $exclude      = []; // transactions already processed. | ||||||
|         $transactions = Transaction::where('transaction_journal_id', $journalId)->where('amount', '>', 0)->get(); |         $transactions = $transactionJournal->transactions()->where('amount', '>', 0)->get(); | ||||||
|  |  | ||||||
|         /** @var Transaction $transaction */ |         /** @var Transaction $transaction */ | ||||||
|         foreach ($transactions as $transaction) { |         foreach ($transactions as $transaction) { | ||||||
|  |             $opposing = $this->findOpposing($transaction, $exclude); | ||||||
|  |             if (null !== $opposing) { | ||||||
|  |                 // give both a new identifier: | ||||||
|  |                 $transaction->identifier = $identifier; | ||||||
|  |                 $opposing->identifier    = $identifier; | ||||||
|  |                 $transaction->save(); | ||||||
|  |                 $opposing->save(); | ||||||
|  |                 $exclude[] = $transaction->id; | ||||||
|  |                 $exclude[] = $opposing->id; | ||||||
|  |                 $this->count++; | ||||||
|  |             } | ||||||
|  |             ++$identifier; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param Transaction $transaction | ||||||
|  |      * @param array $exclude | ||||||
|  |      * @return Transaction|null | ||||||
|  |      */ | ||||||
|  |     private function findOpposing(Transaction $transaction, array $exclude): ?Transaction | ||||||
|  |     { | ||||||
|         // find opposing: |         // find opposing: | ||||||
|         $amount = bcmul((string)$transaction->amount, '-1'); |         $amount = bcmul((string)$transaction->amount, '-1'); | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             /** @var Transaction $opposing */ |             /** @var Transaction $opposing */ | ||||||
|                 $opposing = Transaction::where('transaction_journal_id', $journalId) |             $opposing = Transaction::where('transaction_journal_id', $transaction->transaction_journal_id) | ||||||
|                                    ->where('amount', $amount)->where('identifier', '=', 0) |                                    ->where('amount', $amount)->where('identifier', '=', 0) | ||||||
|                                        ->whereNotIn('id', $processed) |                                    ->whereNotIn('id', $exclude) | ||||||
|                                    ->first(); |                                    ->first(); | ||||||
|  |             // @codeCoverageIgnoreStart | ||||||
|         } catch (QueryException $e) { |         } catch (QueryException $e) { | ||||||
|             Log::error($e->getMessage()); |             Log::error($e->getMessage()); | ||||||
|             $this->error('Firefly III could not find the "identifier" field in the "transactions" table.'); |             $this->error('Firefly III could not find the "identifier" field in the "transactions" table.'); | ||||||
| @@ -145,19 +182,10 @@ class TransactionIdentifier extends Command | |||||||
|             $this->error('Please run "php artisan migrate" to add this field to the table.'); |             $this->error('Please run "php artisan migrate" to add this field to the table.'); | ||||||
|             $this->info('Then, run "php artisan firefly:upgrade-database" to try again.'); |             $this->info('Then, run "php artisan firefly:upgrade-database" to try again.'); | ||||||
|  |  | ||||||
|                 return; |             return null; | ||||||
|             } |  | ||||||
|             if (null !== $opposing) { |  | ||||||
|                 // give both a new identifier: |  | ||||||
|                 $transaction->identifier = $identifier; |  | ||||||
|                 $opposing->identifier    = $identifier; |  | ||||||
|                 $transaction->save(); |  | ||||||
|                 $opposing->save(); |  | ||||||
|                 $processed[] = $transaction->id; |  | ||||||
|                 $processed[] = $opposing->id; |  | ||||||
|             } |  | ||||||
|             ++$identifier; |  | ||||||
|         } |         } | ||||||
|  |         // @codeCoverageIgnoreEnd | ||||||
|  |  | ||||||
|  |         return $opposing; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,6 +28,7 @@ use Illuminate\Console\Command; | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Class UpgradeDatabase |  * Class UpgradeDatabase | ||||||
|  |  * @codeCoverageIgnore | ||||||
|  */ |  */ | ||||||
| class UpgradeDatabase extends Command | class UpgradeDatabase extends Command | ||||||
| { | { | ||||||
| @@ -62,6 +63,7 @@ class UpgradeDatabase extends Command | |||||||
|     public function handle(): int |     public function handle(): int | ||||||
|     { |     { | ||||||
|         $commands = [ |         $commands = [ | ||||||
|  |             // there are 11 upgrade commands. | ||||||
|             'firefly-iii:transaction-identifiers', |             'firefly-iii:transaction-identifiers', | ||||||
|             'firefly-iii:account-currencies', |             'firefly-iii:account-currencies', | ||||||
|             'firefly-iii:transfer-currencies', |             'firefly-iii:transfer-currencies', | ||||||
|   | |||||||
| @@ -65,12 +65,12 @@ class InstallController extends Controller | |||||||
|     { |     { | ||||||
|         // empty on purpose. |         // empty on purpose. | ||||||
|         $this->upgradeCommands = [ |         $this->upgradeCommands = [ | ||||||
|             // there are x initial commands |             // there are 3 initial commands | ||||||
|             'migrate'                                  => ['--seed' => true, '--force' => true], |             'migrate'                                  => ['--seed' => true, '--force' => true], | ||||||
|             'firefly-iii:decrypt-all'                  => [], |             'firefly-iii:decrypt-all'                  => [], | ||||||
|             'generate-keys'                            => [], // an exception :( |             'generate-keys'                            => [], // an exception :( | ||||||
|  |  | ||||||
|             // there are 10 upgrade commands. |             // there are 11 upgrade commands. | ||||||
|             'firefly-iii:transaction-identifiers'      => [], |             'firefly-iii:transaction-identifiers'      => [], | ||||||
|             'firefly-iii:account-currencies'           => [], |             'firefly-iii:account-currencies'           => [], | ||||||
|             'firefly-iii:transfer-currencies'          => [], |             'firefly-iii:transfer-currencies'          => [], | ||||||
|   | |||||||
| @@ -149,6 +149,18 @@ abstract class TestCase extends BaseTestCase | |||||||
|         return $this->getRandomAccount(AccountType::EXPENSE, null); |         return $this->getRandomAccount(AccountType::EXPENSE, null); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return Account | ||||||
|  |      */ | ||||||
|  |     public function getRandomInitialBalance(): Account | ||||||
|  |     { | ||||||
|  |         return $this->getRandomAccount(AccountType::INITIAL_BALANCE, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getRandomReconciliation(): Account { | ||||||
|  |         return $this->getRandomAccount(AccountType::RECONCILIATION, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @return Account |      * @return Account | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -0,0 +1,263 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * OtherCurrenciesCorrectionsTest.php | ||||||
|  |  * Copyright (c) 2019 thegrumpydictator@gmail.com | ||||||
|  |  * | ||||||
|  |  * This file is part of Firefly III. | ||||||
|  |  * | ||||||
|  |  * Firefly III is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * Firefly III is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with Firefly III. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | 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 OtherCurrenciesCorrectionsTest | ||||||
|  |  */ | ||||||
|  | class OtherCurrenciesCorrectionsTest extends TestCase | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |     public function setUp(): void | ||||||
|  |     { | ||||||
|  |         parent::setUp(); | ||||||
|  |         Log::info(sprintf('Now in %s.', get_class($this))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Basic test. Assume nothing is wrong. Submit a withdrawal and a deposit. | ||||||
|  |      * | ||||||
|  |      * @covers \FireflyIII\Console\Commands\Upgrade\OtherCurrenciesCorrections | ||||||
|  |      */ | ||||||
|  |     public function testHandle(): void | ||||||
|  |     { | ||||||
|  |         // mock classes: | ||||||
|  |         $accountRepos  = $this->mock(AccountRepositoryInterface::class); | ||||||
|  |         $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); | ||||||
|  |         $journalRepos  = $this->mock(JournalRepositoryInterface::class); | ||||||
|  |         $withdrawal    = $this->getRandomWithdrawal(); | ||||||
|  |         $deposit       = $this->getRandomDeposit(); | ||||||
|  |         $euro          = $this->getEuro(); | ||||||
|  |  | ||||||
|  |         // collect all journals: | ||||||
|  |         $journalRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $journalRepos->shouldReceive('getAllJournals') | ||||||
|  |                      ->atLeast()->once() | ||||||
|  |                      ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) | ||||||
|  |                      ->andReturn(new Collection([$withdrawal, $deposit])); | ||||||
|  |  | ||||||
|  |         // account repos | ||||||
|  |         $accountRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $accountRepos->shouldReceive('getMetaValue')->atLeast()->once() | ||||||
|  |                      ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); | ||||||
|  |  | ||||||
|  |         // collect currency | ||||||
|  |         $currencyRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $currencyRepos->shouldReceive('findNull')->atLeast()->once() | ||||||
|  |                       ->withArgs([1])->andReturn($euro); | ||||||
|  |  | ||||||
|  |         // configuration | ||||||
|  |         $false       = new Configuration; | ||||||
|  |         $false->data = false; | ||||||
|  |         FireflyConfig::shouldReceive('get')->withArgs(['4780_other_currencies', false])->andReturn($false); | ||||||
|  |         FireflyConfig::shouldReceive('set')->withArgs(['4780_other_currencies', true]); | ||||||
|  |  | ||||||
|  |         // assume all is well. | ||||||
|  |         $this->artisan('firefly-iii:other-currencies') | ||||||
|  |              ->expectsOutput('Verified 2 transaction(s) and journal(s).') | ||||||
|  |              ->assertExitCode(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Basic test. Assume nothing is wrong. Submit an opening balance. | ||||||
|  |      * Also fixes transaction currency ID. | ||||||
|  |      * | ||||||
|  |      * @covers \FireflyIII\Console\Commands\Upgrade\OtherCurrenciesCorrections | ||||||
|  |      */ | ||||||
|  |     public function testHandleOB(): void | ||||||
|  |     { | ||||||
|  |         $type    = TransactionType::where('type', TransactionType::OPENING_BALANCE)->first(); | ||||||
|  |         $asset   = $this->getRandomAsset(); | ||||||
|  |         $initial = $this->getRandomInitialBalance(); | ||||||
|  |         $journal = TransactionJournal::create( | ||||||
|  |             [ | ||||||
|  |                 'user_id'                 => 1, | ||||||
|  |                 'transaction_currency_id' => 1, | ||||||
|  |                 'transaction_type_id'     => $type->id, | ||||||
|  |                 'description'             => 'Test', | ||||||
|  |                 'tag_count'               => 0, | ||||||
|  |                 'date'                    => '2019-01-01', | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $one     = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id' => $journal->id, | ||||||
|  |                 'account_id'             => $asset->id, | ||||||
|  |                 'amount'                 => '-10', | ||||||
|  |                 'identifier'             => 1, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $two     = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id' => $journal->id, | ||||||
|  |                 'account_id'             => $initial->id, | ||||||
|  |                 'amount'                 => '10', | ||||||
|  |                 'identifier'             => 1, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // mock classes: | ||||||
|  |         $accountRepos  = $this->mock(AccountRepositoryInterface::class); | ||||||
|  |         $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); | ||||||
|  |         $journalRepos  = $this->mock(JournalRepositoryInterface::class); | ||||||
|  |         $euro          = $this->getEuro(); | ||||||
|  |  | ||||||
|  |         // collect all journals: | ||||||
|  |         $journalRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $journalRepos->shouldReceive('getAllJournals') | ||||||
|  |                      ->atLeast()->once() | ||||||
|  |                      ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) | ||||||
|  |                      ->andReturn(new Collection([$journal])); | ||||||
|  |  | ||||||
|  |         // account repos | ||||||
|  |         $accountRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $accountRepos->shouldReceive('getMetaValue')->atLeast()->once() | ||||||
|  |                      ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); | ||||||
|  |  | ||||||
|  |         // collect currency | ||||||
|  |         $currencyRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $currencyRepos->shouldReceive('findNull')->atLeast()->once() | ||||||
|  |                       ->withArgs([1])->andReturn($euro); | ||||||
|  |  | ||||||
|  |         // configuration | ||||||
|  |         $false       = new Configuration; | ||||||
|  |         $false->data = false; | ||||||
|  |         FireflyConfig::shouldReceive('get')->withArgs(['4780_other_currencies', false])->andReturn($false); | ||||||
|  |         FireflyConfig::shouldReceive('set')->withArgs(['4780_other_currencies', true]); | ||||||
|  |  | ||||||
|  |         $this->artisan('firefly-iii:other-currencies') | ||||||
|  |              ->expectsOutput('Verified 1 transaction(s) and journal(s).') | ||||||
|  |              ->assertExitCode(0); | ||||||
|  |  | ||||||
|  |         // assume currency has been fixed for both transactions: | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $one->id)->where('transaction_currency_id', $euro->id)->get()); | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $two->id)->where('transaction_currency_id', $euro->id)->get()); | ||||||
|  |  | ||||||
|  |         $one->forceDelete(); | ||||||
|  |         $two->forceDelete(); | ||||||
|  |         $journal->forceDelete(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Basic test. Assume nothing is wrong. Submit an opening balance. | ||||||
|  |      * Also fixes bad transaction currency ID. | ||||||
|  |      * | ||||||
|  |      * @covers \FireflyIII\Console\Commands\Upgrade\OtherCurrenciesCorrections | ||||||
|  |      */ | ||||||
|  |     public function testHandleReconciliation(): void | ||||||
|  |     { | ||||||
|  |         $type           = TransactionType::where('type', TransactionType::RECONCILIATION)->first(); | ||||||
|  |         $asset          = $this->getRandomAsset(); | ||||||
|  |         $reconciliation = $this->getRandomReconciliation(); | ||||||
|  |         $journal        = TransactionJournal::create( | ||||||
|  |             [ | ||||||
|  |                 'user_id'                 => 1, | ||||||
|  |                 'transaction_currency_id' => 1, | ||||||
|  |                 'transaction_type_id'     => $type->id, | ||||||
|  |                 'description'             => 'Test', | ||||||
|  |                 'tag_count'               => 0, | ||||||
|  |                 'date'                    => '2019-01-01', | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $one            = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id'  => $journal->id, | ||||||
|  |                 'account_id'              => $asset->id, | ||||||
|  |                 'amount'                  => '-10', | ||||||
|  |                 'identifier'              => 1, | ||||||
|  |                 'transaction_currency_id' => 2, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $two            = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id'  => $journal->id, | ||||||
|  |                 'account_id'              => $reconciliation->id, | ||||||
|  |                 'amount'                  => '10', | ||||||
|  |                 'identifier'              => 1, | ||||||
|  |                 'transaction_currency_id' => 2, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // mock classes: | ||||||
|  |         $accountRepos  = $this->mock(AccountRepositoryInterface::class); | ||||||
|  |         $currencyRepos = $this->mock(CurrencyRepositoryInterface::class); | ||||||
|  |         $journalRepos  = $this->mock(JournalRepositoryInterface::class); | ||||||
|  |         $euro          = $this->getEuro(); | ||||||
|  |  | ||||||
|  |         // collect all journals: | ||||||
|  |         $journalRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $journalRepos->shouldReceive('getAllJournals') | ||||||
|  |                      ->atLeast()->once() | ||||||
|  |                      ->withArgs([[TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::OPENING_BALANCE, TransactionType::RECONCILIATION,]]) | ||||||
|  |                      ->andReturn(new Collection([$journal])); | ||||||
|  |  | ||||||
|  |         // account repos | ||||||
|  |         $accountRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $accountRepos->shouldReceive('getMetaValue')->atLeast()->once() | ||||||
|  |                      ->withArgs([Mockery::any(), 'currency_id'])->andReturn('1'); | ||||||
|  |  | ||||||
|  |         // collect currency | ||||||
|  |         $currencyRepos->shouldReceive('setUser')->atLeast()->once(); | ||||||
|  |         $currencyRepos->shouldReceive('findNull')->atLeast()->once() | ||||||
|  |                       ->withArgs([1])->andReturn($euro); | ||||||
|  |  | ||||||
|  |         // configuration | ||||||
|  |         $false       = new Configuration; | ||||||
|  |         $false->data = false; | ||||||
|  |         FireflyConfig::shouldReceive('get')->withArgs(['4780_other_currencies', false])->andReturn($false); | ||||||
|  |         FireflyConfig::shouldReceive('set')->withArgs(['4780_other_currencies', true]); | ||||||
|  |  | ||||||
|  |         $this->artisan('firefly-iii:other-currencies') | ||||||
|  |              ->expectsOutput('Verified 1 transaction(s) and journal(s).') | ||||||
|  |              ->assertExitCode(0); | ||||||
|  |  | ||||||
|  |         // assume currency has been fixed for both transactions: | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $one->id)->where('transaction_currency_id', $euro->id)->get()); | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $two->id)->where('transaction_currency_id', $euro->id)->get()); | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $one->id)->where('foreign_currency_id', 2)->get()); | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $two->id)->where('foreign_currency_id', 2)->get()); | ||||||
|  |  | ||||||
|  |         $one->forceDelete(); | ||||||
|  |         $two->forceDelete(); | ||||||
|  |         $journal->forceDelete(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,152 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * TransactionIdentifierTest.php | ||||||
|  |  * Copyright (c) 2019 thegrumpydictator@gmail.com | ||||||
|  |  * | ||||||
|  |  * This file is part of Firefly III. | ||||||
|  |  * | ||||||
|  |  * Firefly III is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * Firefly III is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with Firefly III. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | namespace Tests\Unit\Console\Commands\Upgrade; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | use FireflyConfig; | ||||||
|  | use FireflyIII\Models\Configuration; | ||||||
|  | use FireflyIII\Models\Transaction; | ||||||
|  | use FireflyIII\Models\TransactionJournal; | ||||||
|  | use FireflyIII\Repositories\Journal\JournalRepositoryInterface; | ||||||
|  | use Illuminate\Support\Collection; | ||||||
|  | use Log; | ||||||
|  | use Tests\TestCase; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class TransactionIdentifierTest | ||||||
|  |  */ | ||||||
|  | class TransactionIdentifierTest 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\TransactionIdentifier | ||||||
|  |      */ | ||||||
|  |     public function testHandle(): void | ||||||
|  |     { | ||||||
|  |         // mock classes: | ||||||
|  |         $journalRepos = $this->mock(JournalRepositoryInterface::class); | ||||||
|  |  | ||||||
|  |         // commands: | ||||||
|  |         $journalRepos->shouldReceive('getSplitJournals')->andReturn(new Collection) | ||||||
|  |                      ->atLeast()->once(); | ||||||
|  |  | ||||||
|  |         // configuration | ||||||
|  |         $false       = new Configuration; | ||||||
|  |         $false->data = false; | ||||||
|  |         FireflyConfig::shouldReceive('get')->withArgs(['4780_transaction_identifier', false])->andReturn($false); | ||||||
|  |         FireflyConfig::shouldReceive('set')->withArgs(['4780_transaction_identifier', true]); | ||||||
|  |  | ||||||
|  |         // assume all is well. | ||||||
|  |         $this->artisan('firefly-iii:transaction-identifiers') | ||||||
|  |              ->expectsOutput('All split journal transaction identifiers are correct.') | ||||||
|  |              ->assertExitCode(0); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Basic test. Assume nothing is wrong. | ||||||
|  |      * | ||||||
|  |      * @covers \FireflyIII\Console\Commands\Upgrade\TransactionIdentifier | ||||||
|  |      */ | ||||||
|  |     public function testHandleSplit(): void | ||||||
|  |     { | ||||||
|  |         // create a split journal: | ||||||
|  |         $asset   = $this->getRandomAsset(); | ||||||
|  |         $expense = $this->getRandomExpense(); | ||||||
|  |         $journal = TransactionJournal::create( | ||||||
|  |             [ | ||||||
|  |                 'user_id'                 => 1, | ||||||
|  |                 'transaction_currency_id' => 1, | ||||||
|  |                 'transaction_type_id'     => 1, | ||||||
|  |                 'description'             => 'Test', | ||||||
|  |                 'tag_count'               => 0, | ||||||
|  |                 'date'                    => '2019-01-01', | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $one     = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id' => $journal->id, | ||||||
|  |                 'account_id'             => $asset->id, | ||||||
|  |                 'amount'                 => '-10', | ||||||
|  |                 'identifier'             => 0, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $two     = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id' => $journal->id, | ||||||
|  |                 'account_id'             => $expense->id, | ||||||
|  |                 'amount'                 => '10', | ||||||
|  |                 'identifier'             => 0, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $three   = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id' => $journal->id, | ||||||
|  |                 'account_id'             => $asset->id, | ||||||
|  |                 'amount'                 => '-12', | ||||||
|  |                 'identifier'             => 0, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |         $four    = Transaction::create( | ||||||
|  |             [ | ||||||
|  |                 'transaction_journal_id' => $journal->id, | ||||||
|  |                 'account_id'             => $expense->id, | ||||||
|  |                 'amount'                 => '12', | ||||||
|  |                 'identifier'             => 0, | ||||||
|  |             ] | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         // mock classes: | ||||||
|  |         $journalRepos = $this->mock(JournalRepositoryInterface::class); | ||||||
|  |  | ||||||
|  |         // commands: | ||||||
|  |         $journalRepos->shouldReceive('getSplitJournals')->andReturn(new Collection([$journal])) | ||||||
|  |                      ->atLeast()->once(); | ||||||
|  |  | ||||||
|  |         // configuration | ||||||
|  |         $false       = new Configuration; | ||||||
|  |         $false->data = false; | ||||||
|  |         FireflyConfig::shouldReceive('get')->withArgs(['4780_transaction_identifier', false])->andReturn($false); | ||||||
|  |         FireflyConfig::shouldReceive('set')->withArgs(['4780_transaction_identifier', true]); | ||||||
|  |  | ||||||
|  |         // assume all is well. | ||||||
|  |         $this->artisan('firefly-iii:transaction-identifiers') | ||||||
|  |             ->expectsOutput('Fixed 2 split journal transaction identifier(s).') | ||||||
|  |              ->assertExitCode(0); | ||||||
|  |  | ||||||
|  |         // see results: | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $one->id)->where('identifier', 0)->get()); | ||||||
|  |         $this->assertCount(1, Transaction::where('id', $three->id)->where('identifier', 1)->get()); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user