From 5fea35d5b19bd4166b606e32392cbd0a65730104 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 23 Nov 2025 08:44:01 +0100 Subject: [PATCH] Allow command to be forced. --- .../Commands/System/ForcesDecimalSize.php | 180 +++++++++--------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/app/Console/Commands/System/ForcesDecimalSize.php b/app/Console/Commands/System/ForcesDecimalSize.php index e3a644e2bc..0a39fedf78 100644 --- a/app/Console/Commands/System/ForcesDecimalSize.php +++ b/app/Console/Commands/System/ForcesDecimalSize.php @@ -42,7 +42,6 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; - use function Safe\json_encode; use function Safe\mb_regex_encoding; @@ -55,11 +54,11 @@ class ForcesDecimalSize extends Command { use ShowsFriendlyMessages; - protected $description = 'This command resizes DECIMAL columns in MySQL or PostgreSQL and correct amounts (only MySQL).'; - protected $signature = 'firefly-iii:force-decimal-size'; + protected $description = 'This command resizes DECIMAL columns in MySQL or PostgreSQL and correct amounts (only MySQL).'; + protected $signature = 'firefly-iii:force-decimal-size {--force}'; private string $cast; private array $classes - = [ + = [ 'accounts' => Account::class, 'auto_budgets' => AutoBudget::class, 'available_budgets' => AvailableBudget::class, @@ -75,7 +74,7 @@ class ForcesDecimalSize extends Command private string $operator; private string $regularExpression; private array $tables - = [ + = [ 'accounts' => ['virtual_balance'], 'auto_budgets' => ['amount'], 'available_budgets' => ['amount'], @@ -98,9 +97,14 @@ class ForcesDecimalSize extends Command Log::debug('Now in ForceDecimalSize::handle()'); $this->determineDatabaseType(); - $this->friendlyError('Running this command is dangerous and can cause data loss.'); - $this->friendlyError('Please do not continue.'); - $question = $this->confirm('Do you want to continue?'); + $force = $this->option('force'); + $question = true; + if (false === $force) { + $this->friendlyError('Running this command is dangerous and can cause data loss.'); + $this->friendlyError('Please make sure you have a backup.'); + $question = $this->confirm('Do you want to continue?'); + } + if (true === $question) { $this->correctAmounts(); $this->updateDecimals(); @@ -131,17 +135,17 @@ class ForcesDecimalSize extends Command private function correctAmounts(): void { // if sqlite, add function? - if ('sqlite' === (string) config('database.default')) { + if ('sqlite' === (string)config('database.default')) { DB::connection()->getPdo()->sqliteCreateFunction('REGEXP', static function ($pattern, $value): int { mb_regex_encoding('UTF-8'); $pattern = trim($pattern, '"'); - return (mb_ereg($pattern, (string) $value)) ? 1 : 0; + return (mb_ereg($pattern, (string)$value)) ? 1 : 0; }); } - if (!in_array((string) config('database.default'), ['mysql', 'pgsql', 'sqlite'], true)) { - $this->friendlyWarning(sprintf('Skip correcting amounts, does not support "%s"...', (string) config('database.default'))); + if (!in_array((string)config('database.default'), ['mysql', 'pgsql', 'sqlite'], true)) { + $this->friendlyWarning(sprintf('Skip correcting amounts, does not support "%s"...', (string)config('database.default'))); return; } @@ -234,10 +238,9 @@ class ForcesDecimalSize extends Command $regularExpression = $this->regularExpression; /** @var Builder $query */ - $query = Account::leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') - ->where('account_meta.name', 'currency_id') - ->where('account_meta.data', json_encode((string) $currency->id)) - ; + $query = Account::leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') + ->where('account_meta.name', 'currency_id') + ->where('account_meta.data', json_encode((string)$currency->id)); $query->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { foreach ($fields as $field) { $q->orWhere( @@ -247,7 +250,7 @@ class ForcesDecimalSize extends Command ); } }); - $result = $query->get(['accounts.*']); + $result = $query->get(['accounts.*']); if (0 === $result->count()) { $this->friendlyPositive(sprintf('All accounts in %s are OK', $currency->code)); @@ -258,13 +261,13 @@ class ForcesDecimalSize extends Command foreach ($result as $account) { /** @var string $field */ foreach ($fields as $field) { - $value = $account->{$field}; + $value = $account->{$field}; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10 ** $currency->decimal_places; - $correct = bcdiv((string) round($value * $pow), (string) $pow, 12); + $pow = 10 ** $currency->decimal_places; + $correct = bcdiv((string)round($value * $pow), (string)$pow, 12); $this->friendlyInfo(sprintf('Account #%d has %s with value "%s", this has been corrected to "%s".', $account->id, $field, $value, $correct)); /** @var null|Account $updateAccount */ @@ -286,7 +289,7 @@ class ForcesDecimalSize extends Command $regularExpression = $this->regularExpression; /** @var Builder $query */ - $query = $class::where('transaction_currency_id', $currency->id)->where( + $query = $class::where('transaction_currency_id', $currency->id)->where( static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { /** @var string $field */ foreach ($fields as $field) { @@ -299,7 +302,7 @@ class ForcesDecimalSize extends Command } ); - $result = $query->get(); + $result = $query->get(); if (0 === $result->count()) { $this->friendlyPositive(sprintf('All %s in %s are OK', $table, $currency->code)); @@ -310,17 +313,17 @@ class ForcesDecimalSize extends Command foreach ($result as $item) { /** @var string $field */ foreach ($fields as $field) { - $value = $item->{$field}; + $value = $item->{$field}; if (null === $value || '' === $value) { continue; } // fix $field by rounding it down correctly. $pow = 10 ** $currency->decimal_places; - $correct = bcdiv((string) round($value * $pow), (string) $pow, 12); + $correct = bcdiv((string)round($value * $pow), (string)$pow, 12); $this->friendlyWarning(sprintf('%s #%d has %s with value "%s", this has been corrected to "%s".', $table, $item->id, $field, $value, $correct)); /** @var null|Model $model */ - $model = $class::find($item->id); + $model = $class::find($item->id); $model?->update([$field => $correct]); } } @@ -336,23 +339,22 @@ class ForcesDecimalSize extends Command $regularExpression = $this->regularExpression; /** @var Builder $query */ - $query = PiggyBankEvent::leftJoin('piggy_banks', 'piggy_bank_events.piggy_bank_id', '=', 'piggy_banks.id') - ->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') - ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') - ->where('account_meta.name', 'currency_id') - ->where('account_meta.data', json_encode((string) $currency->id)) - ->where(static function (Builder $q) use ($fields, $currency, $cast, $operator, $regularExpression): void { - foreach ($fields as $field) { - $q->orWhere( - DB::raw(sprintf('CAST(piggy_bank_events.%s AS %s)', $field, $cast)), - $operator, - DB::raw(sprintf($regularExpression, $currency->decimal_places)) - ); - } - }) - ; + $query = PiggyBankEvent::leftJoin('piggy_banks', 'piggy_bank_events.piggy_bank_id', '=', 'piggy_banks.id') + ->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') + ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') + ->where('account_meta.name', 'currency_id') + ->where('account_meta.data', json_encode((string)$currency->id)) + ->where(static function (Builder $q) use ($fields, $currency, $cast, $operator, $regularExpression): void { + foreach ($fields as $field) { + $q->orWhere( + DB::raw(sprintf('CAST(piggy_bank_events.%s AS %s)', $field, $cast)), + $operator, + DB::raw(sprintf($regularExpression, $currency->decimal_places)) + ); + } + }); - $result = $query->get(['piggy_bank_events.*']); + $result = $query->get(['piggy_bank_events.*']); if (0 === $result->count()) { $this->friendlyPositive(sprintf('All piggy bank events in %s are OK', $currency->code)); @@ -363,19 +365,19 @@ class ForcesDecimalSize extends Command foreach ($result as $item) { /** @var string $field */ foreach ($fields as $field) { - $value = $item->{$field}; + $value = $item->{$field}; if (null === $value) { continue; } // fix $field by rounding it down correctly. $pow = 10 ** $currency->decimal_places; - $correct = bcdiv((string) round($value * $pow), (string) $pow, 12); + $correct = bcdiv((string)round($value * $pow), (string)$pow, 12); $this->friendlyWarning( sprintf('Piggy bank event #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct) ); /** @var null|PiggyBankEvent $event */ - $event = PiggyBankEvent::find($item->id); + $event = PiggyBankEvent::find($item->id); $event?->update([$field => $correct]); } } @@ -392,23 +394,22 @@ class ForcesDecimalSize extends Command // select all piggy bank repetitions with this currency and issue. /** @var Builder $query */ - $query = PiggyBankRepetition::leftJoin('piggy_banks', 'piggy_bank_repetitions.piggy_bank_id', '=', 'piggy_banks.id') - ->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') - ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') - ->where('account_meta.name', 'currency_id') - ->where('account_meta.data', json_encode((string) $currency->id)) - ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { - foreach ($fields as $field) { - $q->orWhere( - DB::raw(sprintf('CAST(piggy_bank_repetitions.%s AS %s)', $field, $cast)), - $operator, - DB::raw(sprintf($regularExpression, $currency->decimal_places)) - ); - } - }) - ; + $query = PiggyBankRepetition::leftJoin('piggy_banks', 'piggy_bank_repetitions.piggy_bank_id', '=', 'piggy_banks.id') + ->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') + ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') + ->where('account_meta.name', 'currency_id') + ->where('account_meta.data', json_encode((string)$currency->id)) + ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { + foreach ($fields as $field) { + $q->orWhere( + DB::raw(sprintf('CAST(piggy_bank_repetitions.%s AS %s)', $field, $cast)), + $operator, + DB::raw(sprintf($regularExpression, $currency->decimal_places)) + ); + } + }); - $result = $query->get(['piggy_bank_repetitions.*']); + $result = $query->get(['piggy_bank_repetitions.*']); if (0 === $result->count()) { $this->friendlyPositive(sprintf('All piggy bank repetitions in %s', $currency->code)); @@ -419,13 +420,13 @@ class ForcesDecimalSize extends Command foreach ($result as $item) { /** @var string $field */ foreach ($fields as $field) { - $value = $item->{$field}; + $value = $item->{$field}; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10 ** $currency->decimal_places; - $correct = bcdiv((string) round($value * $pow), (string) $pow, 12); + $pow = 10 ** $currency->decimal_places; + $correct = bcdiv((string)round($value * $pow), (string)$pow, 12); $this->friendlyWarning( sprintf('Piggy bank repetition #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct) ); @@ -447,22 +448,21 @@ class ForcesDecimalSize extends Command $regularExpression = $this->regularExpression; /** @var Builder $query */ - $query = PiggyBank::leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') - ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') - ->where('account_meta.name', 'currency_id') - ->where('account_meta.data', json_encode((string) $currency->id)) - ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { - foreach ($fields as $field) { - $q->orWhere( - DB::raw(sprintf('CAST(piggy_banks.%s AS %s)', $field, $cast)), - $operator, - DB::raw(sprintf($regularExpression, $currency->decimal_places)) - ); - } - }) - ; + $query = PiggyBank::leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') + ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') + ->where('account_meta.name', 'currency_id') + ->where('account_meta.data', json_encode((string)$currency->id)) + ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { + foreach ($fields as $field) { + $q->orWhere( + DB::raw(sprintf('CAST(piggy_banks.%s AS %s)', $field, $cast)), + $operator, + DB::raw(sprintf($regularExpression, $currency->decimal_places)) + ); + } + }); - $result = $query->get(['piggy_banks.*']); + $result = $query->get(['piggy_banks.*']); if (0 === $result->count()) { $this->friendlyPositive(sprintf('All piggy banks in %s are OK', $currency->code)); @@ -473,13 +473,13 @@ class ForcesDecimalSize extends Command foreach ($result as $item) { /** @var string $field */ foreach ($fields as $field) { - $value = $item->{$field}; + $value = $item->{$field}; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10 ** $currency->decimal_places; - $correct = bcdiv((string) round($value * $pow), (string) $pow, 12); + $pow = 10 ** $currency->decimal_places; + $correct = bcdiv((string)round($value * $pow), (string)$pow, 12); $this->friendlyWarning(sprintf('Piggy bank #%d has %s with value "%s", this has been corrected to "%s".', $item->id, $field, $value, $correct)); /** @var null|PiggyBank $piggyBank */ @@ -496,7 +496,7 @@ class ForcesDecimalSize extends Command { // select all transactions with this currency and issue. /** @var Builder $query */ - $query = Transaction::where('transaction_currency_id', $currency->id)->where( + $query = Transaction::where('transaction_currency_id', $currency->id)->where( DB::raw(sprintf('CAST(amount as %s)', $this->cast)), $this->operator, DB::raw(sprintf($this->regularExpression, $currency->decimal_places)) @@ -509,13 +509,13 @@ class ForcesDecimalSize extends Command /** @var Transaction $item */ foreach ($result as $item) { - $value = $item->amount; + $value = $item->amount; if ('' === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10.0 ** $currency->decimal_places; - $correct = bcdiv((string) round((float) $value * $pow), (string) $pow, 12); + $pow = 10.0 ** $currency->decimal_places; + $correct = bcdiv((string)round((float)$value * $pow), (string)$pow, 12); $this->friendlyWarning(sprintf('Transaction #%d has amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct)); /** @var null|Transaction $transaction */ @@ -525,7 +525,7 @@ class ForcesDecimalSize extends Command // select all transactions with this FOREIGN currency and issue. /** @var Builder $query */ - $query = Transaction::where('foreign_currency_id', $currency->id)->where( + $query = Transaction::where('foreign_currency_id', $currency->id)->where( DB::raw(sprintf('CAST(foreign_amount as %s)', $this->cast)), $this->operator, DB::raw(sprintf($this->regularExpression, $currency->decimal_places)) @@ -540,13 +540,13 @@ class ForcesDecimalSize extends Command /** @var Transaction $item */ foreach ($result as $item) { - $value = $item->foreign_amount; + $value = $item->foreign_amount; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10.0 ** $currency->decimal_places; - $correct = bcdiv((string) round((float) $value * $pow), (string) $pow, 12); + $pow = 10.0 ** $currency->decimal_places; + $correct = bcdiv((string)round((float)$value * $pow), (string)$pow, 12); $this->friendlyWarning( sprintf('Transaction #%d has foreign amount with value "%s", this has been corrected to "%s".', $item->id, $value, $correct) ); @@ -560,7 +560,7 @@ class ForcesDecimalSize extends Command private function updateDecimals(): void { $this->friendlyInfo('Going to force the size of DECIMAL columns. Please hold.'); - $type = (string) config('database.default'); + $type = (string)config('database.default'); /** * @var string $name