diff --git a/.env.example b/.env.example index 0a7bd1b7ff..159b802948 100644 --- a/.env.example +++ b/.env.example @@ -3,7 +3,7 @@ APP_DEBUG=false APP_NAME=FireflyIII APP_KEY=SomeRandomStringOf32CharsExactly APP_LOG=daily -APP_LOG_LEVEL=warning +APP_LOG_LEVEL=notice APP_URL=http://localhost TRUSTED_PROXIES= diff --git a/app/Console/Commands/VerifyDatabase.php b/app/Console/Commands/VerifyDatabase.php index 79e07b02ea..570d323af8 100644 --- a/app/Console/Commands/VerifyDatabase.php +++ b/app/Console/Commands/VerifyDatabase.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace FireflyIII\Console\Commands; use Crypt; +use DB; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\Budget; @@ -93,6 +94,7 @@ class VerifyDatabase extends Command $this->repairPiggyBanks(); $this->createLinkTypes(); $this->createAccessTokens(); + $this->fixDoubleAmounts(); } /** @@ -100,6 +102,7 @@ class VerifyDatabase extends Command */ private function createAccessTokens() { + $count = 0; $users = User::get(); /** @var User $user */ foreach ($users as $user) { @@ -108,8 +111,12 @@ class VerifyDatabase extends Command $token = $user->generateAccessToken(); Preferences::setForUser($user, 'access_token', $token); $this->line(sprintf('Generated access token for user %s', $user->email)); + $count++; } } + if ($count === 0) { + $this->info('All access tokens OK!'); + } } /** @@ -117,7 +124,8 @@ class VerifyDatabase extends Command */ private function createLinkTypes() { - $set = [ + $count = 0; + $set = [ 'Related' => ['relates to', 'relates to'], 'Refund' => ['(partially) refunds', 'is (partially) refunded by'], 'Paid' => ['(partially) pays for', 'is (partially) paid for by'], @@ -130,10 +138,61 @@ class VerifyDatabase extends Command $link->name = $name; $link->outward = $values[0]; $link->inward = $values[1]; + $count++; } $link->editable = false; $link->save(); } + if ($count === 0) { + $this->info('All link types OK!'); + } + } + + private function fixDoubleAmounts() + { + $count = 0; + // get invalid journals + $errored = []; + $journals = DB::table('transactions') + ->groupBy('transaction_journal_id') + ->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')]); + /** @var stdClass $entry */ + foreach ($journals as $entry) { + if (bccomp(strval($entry->the_sum), '0') !== 0) { + $errored[] = $entry->transaction_journal_id; + } + } + foreach ($errored as $journalId) { + // select and update: + $res = Transaction::where('transaction_journal_id', $journalId)->groupBy('amount')->get([DB::raw('MIN(id) as first_id')]); + $ids = $res->pluck('first_id')->toArray(); + DB::table('transactions')->whereIn('id', $ids)->update(['amount' => DB::raw('amount * -1')]); + $count++; + // report about it + /** @var TransactionJournal $journal */ + $journal = TransactionJournal::find($journalId); + if ($journal->transactionType->type === TransactionType::OPENING_BALANCE) { + $this->error( + sprintf( + 'Transaction #%d was stored incorrectly. One of your asset accounts may show the wrong balance. Please visit /transactions/show/%d to verify the opening balance.', + $journalId, $journalId + ) + ); + } + if ($journal->transactionType->type !== TransactionType::OPENING_BALANCE) { + $this->error( + sprintf( + 'Transaction #%d was stored incorrectly. Could be that the transaction shows the wrong amount. Please visit /transactions/show/%d to verify the opening balance.', + $journalId, $journalId + ) + ); + } + } + if ($count === 0) { + $this->info('Amount integrity OK!'); + } + + return; } /** @@ -141,7 +200,7 @@ class VerifyDatabase extends Command */ private function repairPiggyBanks(): void { - $set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal', 'TransactionJournal.TransactionType'])->get(); + $set = PiggyBankEvent::with(['PiggyBank', 'TransactionJournal', 'TransactionJournal.TransactionType'])->get(); $set->each( function (PiggyBankEvent $event) { if (null === $event->transaction_journal_id) { @@ -290,6 +349,7 @@ class VerifyDatabase extends Command */ private function reportJournals() { + $count = 0; $set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->whereNotNull('transaction_journals.deleted_at')// USE THIS ->whereNull('transactions.deleted_at') @@ -308,6 +368,10 @@ class VerifyDatabase extends Command 'Error: Transaction #' . $entry->transaction_id . ' should have been deleted, but has not.' . ' Find it in the table called "transactions" and change the "deleted_at" field to: "' . $entry->journal_deleted . '"' ); + $count++; + } + if($count === 0) { + $this->info('No orphaned transactions!'); } } @@ -316,6 +380,7 @@ class VerifyDatabase extends Command */ private function reportNoTransactions() { + $count = 0; $set = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id') ->groupBy('transaction_journals.id') ->whereNull('transactions.transaction_journal_id') @@ -325,6 +390,10 @@ class VerifyDatabase extends Command $this->error( 'Error: Journal #' . $entry->id . ' has zero transactions. Open table "transaction_journals" and delete the entry with id #' . $entry->id ); + $count++; + } + if($count === 0) { + $this->info('No orphaned journals!'); } } @@ -379,6 +448,8 @@ class VerifyDatabase extends Command $sum = strval($user->transactions()->sum('amount')); if (0 !== bccomp($sum, '0')) { $this->error('Error: Transactions for user #' . $user->id . ' (' . $user->email . ') are off by ' . $sum . '!'); + } else { + $this->info(sprintf('Amount integrity OK for user #%d', $user->id)); } } } diff --git a/app/Http/Controllers/NewUserController.php b/app/Http/Controllers/NewUserController.php index efa5ae5ab7..b8a88a0289 100644 --- a/app/Http/Controllers/NewUserController.php +++ b/app/Http/Controllers/NewUserController.php @@ -114,7 +114,7 @@ class NewUserController extends Controller 'virtualBalance' => 0, 'active' => true, 'accountRole' => 'defaultAsset', - 'openingBalance' => round($request->input('bank_balance'), 12), + 'openingBalance' => $request->input('bank_balance'), 'openingBalanceDate' => new Carbon, 'currency_id' => intval($request->input('amount_currency_id_bank_balance')), ]; @@ -139,7 +139,7 @@ class NewUserController extends Controller 'virtualBalance' => 0, 'active' => true, 'accountRole' => 'savingAsset', - 'openingBalance' => round($request->input('savings_balance'), 12), + 'openingBalance' => $request->input('savings_balance'), 'openingBalanceDate' => new Carbon, 'currency_id' => intval($request->input('amount_currency_id_bank_balance')), ];