diff --git a/app/Api/V2/Controllers/Chart/AccountController.php b/app/Api/V2/Controllers/Chart/AccountController.php index 15442e4d84..29c0cf1523 100644 --- a/app/Api/V2/Controllers/Chart/AccountController.php +++ b/app/Api/V2/Controllers/Chart/AccountController.php @@ -125,7 +125,7 @@ class AccountController extends Controller 'native_id' => (string)$default->id, 'native_code' => $default->code, 'native_symbol' => $default->symbol, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, 'start' => $start->toAtomString(), 'end' => $end->toAtomString(), 'period' => '1D', diff --git a/app/Api/V2/Controllers/Chart/BalanceController.php b/app/Api/V2/Controllers/Chart/BalanceController.php index e11952ae1c..23aeecf431 100644 --- a/app/Api/V2/Controllers/Chart/BalanceController.php +++ b/app/Api/V2/Controllers/Chart/BalanceController.php @@ -100,12 +100,12 @@ class BalanceController extends Controller 'currency_symbol' => $default->symbol, 'currency_code' => $default->code, 'currency_name' => $default->name, - 'currency_decimal_places' => (int)$default->decimal_places, + 'currency_decimal_places' => $default->decimal_places, 'native_id' => (string)$defaultCurrencyId, 'native_symbol' => $default->symbol, 'native_code' => $default->code, 'native_name' => $default->name, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, ]; @@ -131,7 +131,7 @@ class BalanceController extends Controller 'native_id' => (string)$default->id, 'native_code' => $default->code, 'native_symbol' => $default->symbol, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, ]; // set the array (in monetary info) with spent/earned in this $period, if it does not exist. diff --git a/app/Api/V2/Controllers/Chart/BudgetController.php b/app/Api/V2/Controllers/Chart/BudgetController.php index 2171576a35..e3d2d38f91 100644 --- a/app/Api/V2/Controllers/Chart/BudgetController.php +++ b/app/Api/V2/Controllers/Chart/BudgetController.php @@ -209,7 +209,7 @@ class BudgetController extends Controller 'native_code' => $this->currency->code, 'native_name' => $this->currency->name, 'native_symbol' => $this->currency->symbol, - 'native_decimal_places' => (int)$this->currency->decimal_places, + 'native_decimal_places' => $this->currency->decimal_places, 'start' => $start->toAtomString(), 'end' => $end->toAtomString(), 'spent' => '0', diff --git a/app/Api/V2/Controllers/Chart/CategoryController.php b/app/Api/V2/Controllers/Chart/CategoryController.php index a5eccfcdaa..d1443822a7 100644 --- a/app/Api/V2/Controllers/Chart/CategoryController.php +++ b/app/Api/V2/Controllers/Chart/CategoryController.php @@ -114,12 +114,12 @@ class CategoryController extends Controller 'currency_code' => $currency->code, 'currency_name' => $currency->name, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'native_id' => (string)$default->id, 'native_code' => $default->code, 'native_name' => $default->name, 'native_symbol' => $default->symbol, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, 'period' => null, 'start' => $start->toAtomString(), 'end' => $end->toAtomString(), diff --git a/app/Api/V2/Controllers/Summary/BasicController.php b/app/Api/V2/Controllers/Summary/BasicController.php index e6489fc17d..d5fc39c078 100644 --- a/app/Api/V2/Controllers/Summary/BasicController.php +++ b/app/Api/V2/Controllers/Summary/BasicController.php @@ -376,7 +376,7 @@ class BasicController extends Controller 'currency_id' => (string)$default->id, 'currency_code' => $default->code, 'currency_symbol' => $default->symbol, - 'currency_decimal_places' => (int)$default->decimal_places, + 'currency_decimal_places' => $default->decimal_places, ]; $nativePerDay = [ 'key' => 'left-per-day-to-spend-in-native', @@ -384,7 +384,7 @@ class BasicController extends Controller 'currency_id' => (string)$default->id, 'currency_code' => $default->code, 'currency_symbol' => $default->symbol, - 'currency_decimal_places' => (int)$default->decimal_places, + 'currency_decimal_places' => $default->decimal_places, ]; /** diff --git a/app/Console/Commands/Correction/DeleteEmptyJournals.php b/app/Console/Commands/Correction/DeleteEmptyJournals.php index e340250d4c..065fbe0f0a 100644 --- a/app/Console/Commands/Correction/DeleteEmptyJournals.php +++ b/app/Console/Commands/Correction/DeleteEmptyJournals.php @@ -61,7 +61,7 @@ class DeleteEmptyJournals extends Command { $set = Transaction::whereNull('deleted_at') ->groupBy('transactions.transaction_journal_id') - ->get([DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']); + ->get([DB::raw('COUNT(transactions.transaction_journal_id) as the_count'), 'transaction_journal_id']); // @phpstan-ignore-line $total = 0; /** @var Transaction $row */ foreach ($set as $row) { diff --git a/app/Console/Commands/Correction/FixGroupAccounts.php b/app/Console/Commands/Correction/FixGroupAccounts.php index 9ddb1cddf6..9575de2807 100644 --- a/app/Console/Commands/Correction/FixGroupAccounts.php +++ b/app/Console/Commands/Correction/FixGroupAccounts.php @@ -51,7 +51,7 @@ class FixGroupAccounts extends Command { $groups = []; $res = TransactionJournal::groupBy('transaction_group_id') - ->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]); + ->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);// @phpstan-ignore-line /** @var TransactionJournal $journal */ foreach ($res as $journal) { if ((int)$journal->the_count > 1) { diff --git a/app/Console/Commands/Export/ExportData.php b/app/Console/Commands/Export/ExportData.php index 64043db366..b191cb48e3 100644 --- a/app/Console/Commands/Export/ExportData.php +++ b/app/Console/Commands/Export/ExportData.php @@ -51,7 +51,7 @@ class ExportData extends Command protected $description = 'Command to export data from Firefly III.'; - protected $signature = 'firefly-iii:export-data + protected $signature = 'firefly-iii:export-data {--user=1 : The user ID that the export should run for.} {--token= : The user\'s access token.} {--start= : First transaction to export. Defaults to your very first transaction. Only applies to transaction export.} @@ -190,7 +190,12 @@ class ExportData extends Command { $date = today(config('app.timezone'))->subYear(); $error = false; - if (null !== $this->option($field)) { + + if (!in_array($field, ['start', 'end'], true)) { + throw new FireflyException(sprintf('Invalid field "%s" given, can only be "start" or "end".', $field)); + } + + if (is_string($this->option($field))) { try { $date = Carbon::createFromFormat('!Y-m-d', $this->option($field)); } catch (InvalidArgumentException $e) { @@ -198,6 +203,10 @@ class ExportData extends Command $this->friendlyError(sprintf('%s date "%s" must be formatted YYYY-MM-DD. Field will be ignored.', $field, $this->option('start'))); $error = true; } + if (false === $date) { + $this->friendlyError(sprintf('%s date "%s" must be formatted YYYY-MM-DD.', $field, $this->option('start'))); + throw new FireflyException(sprintf('%s date "%s" must be formatted YYYY-MM-DD.', $field, $this->option('start'))); + } } if (null === $this->option($field)) { app('log')->info(sprintf('No date given in field "%s"', $field)); @@ -208,12 +217,15 @@ class ExportData extends Command $journal = $this->journalRepository->firstNull(); $date = null === $journal ? today(config('app.timezone'))->subYear() : $journal->date; $date->startOfDay(); + return $date; } - - if (true === $error && 'end' === $field) { + // field can only be 'end' at this point, so no need to include it in the check. + if (true === $error) { $date = today(config('app.timezone')); $date->endOfDay(); + return $date; } + if ('end' === $field) { $date->endOfDay(); } diff --git a/app/Console/Commands/System/CreateDatabase.php b/app/Console/Commands/System/CreateDatabase.php index 268aea277b..9d1142d7de 100644 --- a/app/Console/Commands/System/CreateDatabase.php +++ b/app/Console/Commands/System/CreateDatabase.php @@ -79,6 +79,7 @@ class CreateDatabase extends Command // only continue when no error. // with PDO, try to list DB's ( + /** @var array $stmt */ $stmt = $pdo->query('SHOW DATABASES;'); // slightly more complex but less error-prone. foreach ($stmt as $row) { diff --git a/app/Console/Commands/System/ForceDecimalSize.php b/app/Console/Commands/System/ForceDecimalSize.php index 3b03731de9..e2f05c907b 100644 --- a/app/Console/Commands/System/ForceDecimalSize.php +++ b/app/Console/Commands/System/ForceDecimalSize.php @@ -253,13 +253,14 @@ class ForceDecimalSize extends Command } /** @var Account $account */ foreach ($result as $account) { + /** @var string $field */ foreach ($fields as $field) { $value = $account->$field; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10** (int)$currency->decimal_places; + $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)); Account::find($account->id)->update([$field => $correct]); @@ -286,6 +287,7 @@ class ForceDecimalSize extends Command /** @var Builder $query */ $query = $class::where('transaction_currency_id', $currency->id)->where( static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression) { + /** @var string $field */ foreach ($fields as $field) { $q->orWhere( DB::raw(sprintf('CAST(%s AS %s)', $field, $cast)), // @phpstan-ignore-line @@ -304,13 +306,14 @@ class ForceDecimalSize extends Command } /** @var Model $item */ foreach ($result as $item) { + /** @var string $field */ foreach ($fields as $field) { $value = $item->$field; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10** (int)$currency->decimal_places; + $pow = 10** $currency->decimal_places; $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)); $class::find($item->id)->update([$field => $correct]); @@ -356,13 +359,14 @@ class ForceDecimalSize extends Command } /** @var PiggyBankEvent $item */ foreach ($result as $item) { + /** @var string $field */ foreach ($fields as $field) { $value = $item->$field; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10** (int)$currency->decimal_places; + $pow = 10** $currency->decimal_places; $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) @@ -410,13 +414,14 @@ class ForceDecimalSize extends Command } /** @var PiggyBankRepetition $item */ foreach ($result as $item) { + /** @var string $field */ foreach ($fields as $field) { $value = $item->$field; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10** (int)$currency->decimal_places; + $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) @@ -463,13 +468,14 @@ class ForceDecimalSize extends Command } /** @var PiggyBank $item */ foreach ($result as $item) { + /** @var string $field */ foreach ($fields as $field) { $value = $item->$field; if (null === $value) { continue; } // fix $field by rounding it down correctly. - $pow = 10** (int)$currency->decimal_places; + $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)); PiggyBank::find($item->id)->update([$field => $correct]); @@ -506,7 +512,7 @@ class ForceDecimalSize extends Command continue; } // fix $field by rounding it down correctly. - $pow = (float)10** (int)$currency->decimal_places; + $pow = (float)10** $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)); Transaction::find($item->id)->update(['amount' => $correct]); @@ -533,7 +539,7 @@ class ForceDecimalSize extends Command continue; } // fix $field by rounding it down correctly. - $pow = (float)10** (int)$currency->decimal_places; + $pow = (float)10** $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) diff --git a/app/Console/Commands/System/ScanAttachments.php b/app/Console/Commands/System/ScanAttachments.php index a8a99375c5..6c964fd021 100644 --- a/app/Console/Commands/System/ScanAttachments.php +++ b/app/Console/Commands/System/ScanAttachments.php @@ -67,11 +67,13 @@ class ScanAttachments extends Command $decryptedContent = $encryptedContent; } $tempFileName = tempnam(sys_get_temp_dir(), 'FireflyIII'); + if(false === $tempFileName) { + app('log')->error(sprintf('Could not create temporary file for attachment #%d', $attachment->id)); + exit(1); + } file_put_contents($tempFileName, $decryptedContent); - $md5 = md5_file($tempFileName); - $mime = mime_content_type($tempFileName); - $attachment->md5 = $md5; - $attachment->mime = $mime; + $attachment->md5 = (string) md5_file($tempFileName); + $attachment->mime = (string) mime_content_type($tempFileName); $attachment->save(); $this->friendlyInfo(sprintf('Fixed attachment #%d', $attachment->id)); } diff --git a/app/Console/Commands/System/UpgradeFireflyInstructions.php b/app/Console/Commands/System/UpgradeFireflyInstructions.php index 061e526b10..86fe14fac8 100644 --- a/app/Console/Commands/System/UpgradeFireflyInstructions.php +++ b/app/Console/Commands/System/UpgradeFireflyInstructions.php @@ -61,14 +61,15 @@ class UpgradeFireflyInstructions extends Command */ private function updateInstructions(): void { - /** @var string $version */ - $version = config('firefly.version'); + $version = (string) config('firefly.version'); + /** @var array $config */ $config = config('upgrade.text.upgrade'); $text = ''; + /** @var string $compare */ foreach (array_keys($config) as $compare) { // if string starts with: if (str_starts_with($version, $compare)) { - $text = $config[$compare]; + $text = (string) $config[$compare]; } } @@ -78,7 +79,7 @@ class UpgradeFireflyInstructions extends Command $this->showLine(); $this->boxed(''); - if (null === $text || '' === $text) { + if ('' === $text) { $this->boxed(sprintf('Thank you for updating to Firefly III, v%s', $version)); $this->boxedInfo('There are no extra upgrade instructions.'); $this->boxed('Firefly III should be ready for use.'); @@ -174,14 +175,15 @@ class UpgradeFireflyInstructions extends Command */ private function installInstructions(): void { - /** @var string $version */ - $version = config('firefly.version'); + $version = (string) config('firefly.version'); + /** @var array $config */ $config = config('upgrade.text.install'); $text = ''; + /** @var string $compare */ foreach (array_keys($config) as $compare) { // if string starts with: if (str_starts_with($version, $compare)) { - $text = $config[$compare]; + $text = (string) $config[$compare]; } } $this->newLine(); @@ -189,7 +191,7 @@ class UpgradeFireflyInstructions extends Command $this->newLine(); $this->showLine(); $this->boxed(''); - if (null === $text || '' === $text) { + if ('' === $text) { $this->boxed(sprintf('Thank you for installing Firefly III, v%s!', $version)); $this->boxedInfo('There are no extra installation instructions.'); $this->boxed('Firefly III should be ready for use.'); diff --git a/app/Console/Commands/Tools/ApplyRules.php b/app/Console/Commands/Tools/ApplyRules.php index 9f1fc9d5aa..b340585ffe 100644 --- a/app/Console/Commands/Tools/ApplyRules.php +++ b/app/Console/Commands/Tools/ApplyRules.php @@ -37,6 +37,7 @@ use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\TransactionRules\Engine\RuleEngineInterface; use Illuminate\Console\Command; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Log; /** * Class ApplyRules @@ -296,6 +297,10 @@ class ApplyRules extends Command if (null !== $endString && '' !== $endString) { $inputEnd = Carbon::createFromFormat('Y-m-d', $endString); } + if(false === $inputEnd || false === $inputStart) { + Log::error('Could not parse start or end date in verifyInputDate().'); + return; + } if ($inputStart > $inputEnd) { [$inputEnd, $inputStart] = [$inputStart, $inputEnd]; diff --git a/app/Console/Commands/Upgrade/FixPostgresSequences.php b/app/Console/Commands/Upgrade/FixPostgresSequences.php index 8abe8b981e..520cc36963 100644 --- a/app/Console/Commands/Upgrade/FixPostgresSequences.php +++ b/app/Console/Commands/Upgrade/FixPostgresSequences.php @@ -120,11 +120,11 @@ class FixPostgresSequences extends Command continue; } - if ($nextId->nextval < $highestId->max) { + if ($nextId->nextval < $highestId->max) { // @phpstan-ignore-line DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max)); $highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first(); $nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first(); - if ($nextId->nextval > $highestId->max) { + if ($nextId->nextval > $highestId->max) { // @phpstan-ignore-line $this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck)); } if ($nextId->nextval <= $highestId->max) { diff --git a/app/Console/Commands/Upgrade/MigrateToRules.php b/app/Console/Commands/Upgrade/MigrateToRules.php index 937021f53a..a8eb5a3188 100644 --- a/app/Console/Commands/Upgrade/MigrateToRules.php +++ b/app/Console/Commands/Upgrade/MigrateToRules.php @@ -48,7 +48,7 @@ class MigrateToRules extends Command protected $description = 'Migrate bills to rules.'; - protected $signature = 'firefly-iii:bills-to-rules {--F|force : Force the execution of this command.}'; + protected $signature = 'firefly-iii:bills-to-rules {--F|force : Force the execution of this command.}'; private BillRepositoryInterface $billRepository; private int $count; private RuleGroupRepositoryInterface $ruleGroupRepository; @@ -138,14 +138,15 @@ class MigrateToRules extends Command /** @var Preference $lang */ $lang = app('preferences')->getForUser($user, 'language', 'en_US'); - $groupTitle = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data); + $language = null !== $lang->data && !is_array($lang->data) ? (string)$lang->data : 'en_US'; + $groupTitle = (string)trans('firefly.rulegroup_for_bills_title', [], $language); $ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle); if (null === $ruleGroup) { $ruleGroup = $this->ruleGroupRepository->store( [ - 'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data), - 'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $lang->data), + 'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $language), + 'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $language), 'active' => true, ] ); @@ -168,6 +169,7 @@ class MigrateToRules extends Command if ('MIGRATED_TO_RULES' === $bill->match) { return; } + $languageString = null !== $language->data && !is_array($language->data) ? (string)$language->data : 'en_US'; // get match thing: $match = implode(' ', explode(',', $bill->match)); @@ -176,8 +178,8 @@ class MigrateToRules extends Command 'active' => true, 'strict' => false, 'stop_processing' => false, // field is no longer used. - 'title' => (string)trans('firefly.rule_for_bill_title', ['name' => $bill->name], $language->data), - 'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $language->data), + 'title' => (string)trans('firefly.rule_for_bill_title', ['name' => $bill->name], $languageString), + 'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $languageString), 'trigger' => 'store-journal', 'triggers' => [ [ diff --git a/app/Console/Commands/Upgrade/UpgradeCurrencyPreferences.php b/app/Console/Commands/Upgrade/UpgradeCurrencyPreferences.php index cf55d9efbb..4a6c94c121 100644 --- a/app/Console/Commands/Upgrade/UpgradeCurrencyPreferences.php +++ b/app/Console/Commands/Upgrade/UpgradeCurrencyPreferences.php @@ -150,7 +150,7 @@ class UpgradeCurrencyPreferences extends Command { $preference = Preference::where('user_id', $user->id)->where('name', 'currencyPreference')->first(['id', 'user_id', 'name', 'data', 'updated_at', 'created_at']); - if (null !== $preference) { + if (null !== $preference->data && !is_array($preference->data)) { return (string)$preference->data; } return 'EUR'; diff --git a/app/Exceptions/GracefulNotFoundHandler.php b/app/Exceptions/GracefulNotFoundHandler.php index 3261c54b95..ed5c931340 100644 --- a/app/Exceptions/GracefulNotFoundHandler.php +++ b/app/Exceptions/GracefulNotFoundHandler.php @@ -143,10 +143,11 @@ class GracefulNotFoundHandler extends ExceptionHandler $user = auth()->user(); $route = $request->route(); $param = $route->parameter('account'); + $accountId = 0; if ($param instanceof Account) { $accountId = $param->id; } - if (!($param instanceof Account)) { + if (!($param instanceof Account) && !is_object($param)) { $accountId = (int)$param; } /** @var Account|null $account */ @@ -176,7 +177,8 @@ class GracefulNotFoundHandler extends ExceptionHandler /** @var User $user */ $user = auth()->user(); $route = $request->route(); - $groupId = (int)$route->parameter('transactionGroup'); + $param = $route->parameter('transactionGroup'); + $groupId = !is_object($param) ? (int)$param : 0; /** @var TransactionGroup|null $group */ $group = $user->transactionGroups()->withTrashed()->find($groupId); @@ -215,7 +217,8 @@ class GracefulNotFoundHandler extends ExceptionHandler /** @var User $user */ $user = auth()->user(); $route = $request->route(); - $attachmentId = (int)$route->parameter('attachment'); + $param = $route->parameter('attachment'); + $attachmentId = is_object($param) ? 0 : (int)$param; /** @var Attachment|null $attachment */ $attachment = $user->attachments()->withTrashed()->find($attachmentId); if (null === $attachment) { diff --git a/app/Factory/TransactionJournalFactory.php b/app/Factory/TransactionJournalFactory.php index d7fae5f385..dd072ab721 100644 --- a/app/Factory/TransactionJournalFactory.php +++ b/app/Factory/TransactionJournalFactory.php @@ -474,7 +474,7 @@ class TransactionJournalFactory private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency { app('log')->debug('Now in getCurrency()'); - /** @var Preference|null $preference */ + /** @var TransactionCurrency|null $preference */ $preference = $this->accountRepository->getAccountCurrency($account); if (null === $preference && null === $currency) { // return user's default: diff --git a/app/Handlers/Events/Model/BudgetLimitHandler.php b/app/Handlers/Events/Model/BudgetLimitHandler.php index 06bdc69a80..77bcba63bc 100644 --- a/app/Handlers/Events/Model/BudgetLimitHandler.php +++ b/app/Handlers/Events/Model/BudgetLimitHandler.php @@ -92,6 +92,11 @@ class BudgetLimitHandler app('log')->error($e->getMessage()); $viewRange = '1M'; } + // safety catch + if(null === $viewRange || is_array($viewRange)){ + $viewRange = '1M'; + } + $viewRange = (string)$viewRange; $start = app('navigation')->startOfPeriod($budgetLimit->start_date, $viewRange); $end = app('navigation')->startOfPeriod($budgetLimit->end_date, $viewRange); diff --git a/app/Handlers/Events/UserEventHandler.php b/app/Handlers/Events/UserEventHandler.php index 2689d53840..6001e1f8b3 100644 --- a/app/Handlers/Events/UserEventHandler.php +++ b/app/Handlers/Events/UserEventHandler.php @@ -197,6 +197,9 @@ class UserEventHandler } $list = app('preferences')->getForUser($user, 'login_ip_history', [])->data; + if(!is_array($list)) { + $list = []; + } /** @var array $entry */ foreach ($list as $index => $entry) { @@ -415,7 +418,7 @@ class UserEventHandler } // clean up old entries (6 months) $carbon = Carbon::createFromFormat('Y-m-d H:i:s', $preference[$index]['time']); - if ($carbon->diffInMonths(today()) > 6) { + if (false !== $carbon && $carbon->diffInMonths(today()) > 6) { app('log')->debug(sprintf('Entry for %s is very old, remove it.', $row['ip'])); unset($preference[$index]); } diff --git a/app/Helpers/Attachments/AttachmentHelper.php b/app/Helpers/Attachments/AttachmentHelper.php index b2ea13bd3a..b828c1e886 100644 --- a/app/Helpers/Attachments/AttachmentHelper.php +++ b/app/Helpers/Attachments/AttachmentHelper.php @@ -155,13 +155,18 @@ class AttachmentHelper implements AttachmentHelperInterface $path = stream_get_meta_data($resource)['uri']; Log::debug(sprintf('Path is %s', $path)); $result = fwrite($resource, $content); - if(false === $result) { + if (false === $result) { Log::error('Could not write temp file.'); return false; } Log::debug(sprintf('Wrote %d bytes to temp file.', $result)); - $finfo = finfo_open(FILEINFO_MIME_TYPE); - $mime = finfo_file($finfo, $path); + $finfo = finfo_open(FILEINFO_MIME_TYPE); + if (false === $finfo) { + Log::error('Could not open finfo.'); + fclose($resource); + return false; + } + $mime = (string) finfo_file($finfo, $path); $allowedMime = config('firefly.allowedMimes'); if (!in_array($mime, $allowedMime, true)) { Log::error(sprintf('Mime type %s is not allowed for API file upload.', $mime)); @@ -177,7 +182,7 @@ class AttachmentHelper implements AttachmentHelperInterface $this->uploadDisk->put($file, $content); // update attachment. - $attachment->md5 = md5_file($path); + $attachment->md5 = (string) md5_file($path); $attachment->mime = $mime; $attachment->size = strlen($content); $attachment->uploaded = true; @@ -246,7 +251,7 @@ class AttachmentHelper implements AttachmentHelperInterface $attachment = new Attachment(); // create Attachment object. $attachment->user()->associate($user); $attachment->attachable()->associate($model); - $attachment->md5 = md5_file($file->getRealPath()); + $attachment->md5 = (string) md5_file($file->getRealPath()); $attachment->filename = $file->getClientOriginalName(); $attachment->mime = $file->getMimeType(); $attachment->size = $file->getSize(); @@ -261,7 +266,7 @@ class AttachmentHelper implements AttachmentHelperInterface throw new FireflyException('Cannot upload empty or non-existent file.'); } - $content = $fileObject->fread($file->getSize()); + $content = (string) $fileObject->fread($file->getSize()); Log::debug(sprintf('Full file length is %d and upload size is %d.', strlen($content), $file->getSize())); // store it without encryption. diff --git a/app/Helpers/Collector/Extensions/MetaCollection.php b/app/Helpers/Collector/Extensions/MetaCollection.php index c593e856a6..636e98a522 100644 --- a/app/Helpers/Collector/Extensions/MetaCollection.php +++ b/app/Helpers/Collector/Extensions/MetaCollection.php @@ -226,7 +226,7 @@ trait MetaCollection */ public function excludeInternalReference(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -253,7 +253,7 @@ trait MetaCollection */ public function externalIdContains(string $externalId): GroupCollectorInterface { - $externalId = json_encode($externalId); + $externalId = (string) json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -268,7 +268,7 @@ trait MetaCollection */ public function externalIdDoesNotContain(string $externalId): GroupCollectorInterface { - $externalId = json_encode($externalId); + $externalId = (string) json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -283,7 +283,7 @@ trait MetaCollection */ public function externalIdDoesNotEnd(string $externalId): GroupCollectorInterface { - $externalId = json_encode($externalId); + $externalId = (string) json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -298,7 +298,7 @@ trait MetaCollection */ public function externalIdDoesNotStart(string $externalId): GroupCollectorInterface { - $externalId = json_encode($externalId); + $externalId = (string) json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -313,7 +313,7 @@ trait MetaCollection */ public function externalIdEnds(string $externalId): GroupCollectorInterface { - $externalId = json_encode($externalId); + $externalId = (string) json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -328,7 +328,7 @@ trait MetaCollection */ public function externalIdStarts(string $externalId): GroupCollectorInterface { - $externalId = json_encode($externalId); + $externalId = (string) json_encode($externalId); $externalId = str_replace('\\', '\\\\', trim($externalId, '"')); $this->joinMetaDataTables(); @@ -346,7 +346,7 @@ trait MetaCollection public function externalUrlContains(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = json_encode($url); + $url = (string) json_encode($url); $url = str_replace('\\', '\\\\', trim($url, '"')); $this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $url)); @@ -362,7 +362,7 @@ trait MetaCollection public function externalUrlDoesNotContain(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = json_encode($url); + $url = (string) json_encode($url); $url = str_replace('\\', '\\\\', trim($url, '"')); $this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s%%', $url)); @@ -378,7 +378,7 @@ trait MetaCollection public function externalUrlDoesNotEnd(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = json_encode($url); + $url = (string) json_encode($url); $url = str_replace('\\', '\\\\', ltrim($url, '"')); $this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.data', 'NOT LIKE', sprintf('%%%s', $url)); @@ -394,7 +394,7 @@ trait MetaCollection public function externalUrlDoesNotStart(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = json_encode($url); + $url = (string) json_encode($url); $url = str_replace('\\', '\\\\', rtrim($url, '"')); //var_dump($url); @@ -412,7 +412,7 @@ trait MetaCollection public function externalUrlEnds(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = json_encode($url); + $url = (string) json_encode($url); $url = str_replace('\\', '\\\\', ltrim($url, '"')); $this->query->where('journal_meta.name', '=', 'external_url'); $this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s', $url)); @@ -428,7 +428,7 @@ trait MetaCollection public function externalUrlStarts(string $url): GroupCollectorInterface { $this->joinMetaDataTables(); - $url = json_encode($url); + $url = (string) json_encode($url); $url = str_replace('\\', '\\\\', rtrim($url, '"')); //var_dump($url); @@ -487,7 +487,7 @@ trait MetaCollection */ public function internalReferenceContains(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); //var_dump($internalReference); //exit; @@ -504,7 +504,7 @@ trait MetaCollection */ public function internalReferenceDoesNotContain(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -519,7 +519,7 @@ trait MetaCollection */ public function internalReferenceDoesNotEnd(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -534,7 +534,7 @@ trait MetaCollection */ public function internalReferenceDoesNotStart(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -549,7 +549,7 @@ trait MetaCollection */ public function internalReferenceEnds(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -564,7 +564,7 @@ trait MetaCollection */ public function internalReferenceStarts(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); @@ -836,7 +836,7 @@ trait MetaCollection */ public function setInternalReference(string $internalReference): GroupCollectorInterface { - $internalReference = json_encode($internalReference); + $internalReference = (string) json_encode($internalReference); $internalReference = str_replace('\\', '\\\\', trim($internalReference, '"')); $this->joinMetaDataTables(); diff --git a/app/Helpers/Fiscal/FiscalHelper.php b/app/Helpers/Fiscal/FiscalHelper.php index b0e5209f6f..05d1fb453e 100644 --- a/app/Helpers/Fiscal/FiscalHelper.php +++ b/app/Helpers/Fiscal/FiscalHelper.php @@ -80,6 +80,10 @@ class FiscalHelper implements FiscalHelperInterface $startDate = clone $date; if (true === $this->useCustomFiscalYear) { $prefStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data; + if(is_array($prefStartStr)) { + $prefStartStr = '01-01'; + } + $prefStartStr = (string) $prefStartStr; [$mth, $day] = explode('-', $prefStartStr); $startDate->day((int)$day)->month((int)$mth); diff --git a/app/Helpers/Report/NetWorth.php b/app/Helpers/Report/NetWorth.php index fba187e7cd..4961d15ecb 100644 --- a/app/Helpers/Report/NetWorth.php +++ b/app/Helpers/Report/NetWorth.php @@ -89,12 +89,12 @@ class NetWorth implements NetWorthInterface 'currency_code' => $default->code, 'currency_name' => $default->name, 'currency_symbol' => $default->symbol, - 'currency_decimal_places' => (int)$default->decimal_places, + 'currency_decimal_places' => $default->decimal_places, 'native_id' => $default->id, 'native_code' => $default->code, 'native_name' => $default->name, 'native_symbol' => $default->symbol, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, ], ]; $balances = app('steam')->balancesByAccountsConverted($accounts, $date); @@ -125,12 +125,12 @@ class NetWorth implements NetWorthInterface 'currency_code' => $currency->code, 'currency_name' => $currency->name, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'native_id' => $default->id, 'native_code' => $default->code, 'native_name' => $default->name, 'native_symbol' => $default->symbol, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, ]; $netWorth[$currencyId]['balance'] = bcadd($balance, $netWorth[$currencyId]['balance']); diff --git a/app/Http/Controllers/Account/CreateController.php b/app/Http/Controllers/Account/CreateController.php index 169df67b86..a590844c11 100644 --- a/app/Http/Controllers/Account/CreateController.php +++ b/app/Http/Controllers/Account/CreateController.php @@ -152,6 +152,9 @@ class CreateController extends Controller // update preferences if necessary: $frontPage = app('preferences')->get('frontPageAccounts', [])->data; + if(!is_array($frontPage)) { + $frontPage = []; + } if (AccountType::ASSET === $account->accountType->type) { $frontPage[] = $account->id; app('preferences')->set('frontPageAccounts', $frontPage); diff --git a/app/Http/Controllers/Account/EditController.php b/app/Http/Controllers/Account/EditController.php index 384a6a2318..8a7b4f820e 100644 --- a/app/Http/Controllers/Account/EditController.php +++ b/app/Http/Controllers/Account/EditController.php @@ -195,7 +195,7 @@ class EditController extends Controller $request->session()->flash('success', (string)trans('firefly.updated_account', ['name' => $account->name])); // store new attachment(s): - + /** @var array|null $files */ $files = $request->hasFile('attachments') ? $request->file('attachments') : null; if (null !== $files && !auth()->user()->hasRole('demo')) { $this->attachments->saveAttachmentsForModel($account, $files); diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php index b75d9ca6b4..9ebe1c0d09 100644 --- a/app/Http/Controllers/Account/ReconcileController.php +++ b/app/Http/Controllers/Account/ReconcileController.php @@ -207,14 +207,14 @@ class ReconcileController extends Controller * @param Carbon $end * @param string $difference * - * @return RedirectResponse|Redirector|string + * @return string * @throws DuplicateTransactionException * @throws JsonException */ - private function createReconciliation(Account $account, Carbon $start, Carbon $end, string $difference) + private function createReconciliation(Account $account, Carbon $start, Carbon $end, string $difference): string { if (!$this->isEditableAccount($account)) { - return $this->redirectAccountToAccount($account); + return 'not-editable'; } $reconciliation = $this->accountRepos->getReconciliation($account); diff --git a/app/Http/Controllers/Auth/TwoFactorController.php b/app/Http/Controllers/Auth/TwoFactorController.php index a023cade15..dc43499cda 100644 --- a/app/Http/Controllers/Auth/TwoFactorController.php +++ b/app/Http/Controllers/Auth/TwoFactorController.php @@ -170,6 +170,9 @@ class TwoFactorController extends Controller private function isBackupCode(string $mfaCode): bool { $list = app('preferences')->get('mfa_recovery', [])->data; + if(!is_array($list)) { + $list = []; + } if (in_array($mfaCode, $list, true)) { return true; } @@ -185,6 +188,9 @@ class TwoFactorController extends Controller private function removeFromBackupCodes(string $mfaCode): void { $list = app('preferences')->get('mfa_recovery', [])->data; + if(!is_array($list)) { + $list = []; + } $newList = array_values(array_diff($list, [$mfaCode])); app('preferences')->set('mfa_recovery', $newList); } diff --git a/app/Http/Controllers/Budget/BudgetLimitController.php b/app/Http/Controllers/Budget/BudgetLimitController.php index e3a48740b8..18696c7156 100644 --- a/app/Http/Controllers/Budget/BudgetLimitController.php +++ b/app/Http/Controllers/Budget/BudgetLimitController.php @@ -138,6 +138,11 @@ class BudgetLimitController extends Controller } $start = Carbon::createFromFormat('Y-m-d', $request->get('start')); $end = Carbon::createFromFormat('Y-m-d', $request->get('end')); + + if (false === $start || false === $end) { + return response()->json([]); + } + $amount = (string)$request->get('amount'); $start->startOfDay(); $end->startOfDay(); diff --git a/app/Http/Controllers/Budget/CreateController.php b/app/Http/Controllers/Budget/CreateController.php index da18c84c23..451da6fe52 100644 --- a/app/Http/Controllers/Budget/CreateController.php +++ b/app/Http/Controllers/Budget/CreateController.php @@ -125,6 +125,7 @@ class CreateController extends Controller app('preferences')->mark(); // store attachment(s): + /** @var array|null $files */ $files = $request->hasFile('attachments') ? $request->file('attachments') : null; if (null !== $files && !auth()->user()->hasRole('demo')) { $this->attachments->saveAttachmentsForModel($budget, $files); diff --git a/app/Http/Controllers/Budget/EditController.php b/app/Http/Controllers/Budget/EditController.php index cba15a857d..1d0c009ddb 100644 --- a/app/Http/Controllers/Budget/EditController.php +++ b/app/Http/Controllers/Budget/EditController.php @@ -101,7 +101,11 @@ class EditController extends Controller 'auto_budget_currency_id' => $hasOldInput ? (int)$request->old('auto_budget_currency_id') : $currency->id, ]; if (null !== $autoBudget) { - $amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount; + $amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount; + if (is_array($amount)) { + $amount = '0'; + } + $amount = (string)$amount; $preFilled['auto_budget_amount'] = app('steam')->bcround($amount, $autoBudget->transactionCurrency->decimal_places); } @@ -135,6 +139,7 @@ class EditController extends Controller $redirect = redirect($this->getPreviousUrl('budgets.edit.url')); // store new attachment(s): + /** @var array|null $files */ $files = $request->hasFile('attachments') ? $request->file('attachments') : null; if (null !== $files && !auth()->user()->hasRole('demo')) { $this->attachments->saveAttachmentsForModel($budget, $files); diff --git a/app/Http/Controllers/Category/CreateController.php b/app/Http/Controllers/Category/CreateController.php index 77e2b7ea83..dbd2ed4322 100644 --- a/app/Http/Controllers/Category/CreateController.php +++ b/app/Http/Controllers/Category/CreateController.php @@ -98,6 +98,7 @@ class CreateController extends Controller app('preferences')->mark(); // store attachment(s): + /** @var array|null $files */ $files = $request->hasFile('attachments') ? $request->file('attachments') : null; if (null !== $files && !auth()->user()->hasRole('demo')) { $this->attachments->saveAttachmentsForModel($category, $files); diff --git a/app/Http/Controllers/Category/EditController.php b/app/Http/Controllers/Category/EditController.php index ba3c591c9d..c5abab1bcc 100644 --- a/app/Http/Controllers/Category/EditController.php +++ b/app/Http/Controllers/Category/EditController.php @@ -105,6 +105,7 @@ class EditController extends Controller app('preferences')->mark(); // store new attachment(s): + /** @var array|null $files */ $files = $request->hasFile('attachments') ? $request->file('attachments') : null; if (null !== $files && !auth()->user()->hasRole('demo')) { $this->attachments->saveAttachmentsForModel($category, $files); diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index b105b29db4..adf12be4cd 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -335,13 +335,14 @@ class AccountController extends Controller $end = clone session('end', today(config('app.timezone'))->endOfMonth()); $defaultSet = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET])->pluck('id')->toArray(); app('log')->debug('Default set is ', $defaultSet); - $frontPage = app('preferences')->get('frontPageAccounts', $defaultSet); - app('log')->debug('Frontpage preference set is ', $frontPage->data); - if (0 === count($frontPage->data)) { + $frontPage = app('preferences')->get('frontPageAccounts', $defaultSet); + $frontPageArray = !is_array($frontPage->data) ? [] : $frontPage->data; + app('log')->debug('Frontpage preference set is ', $frontPageArray); + if (0 === count($frontPageArray)) { app('preferences')->set('frontPageAccounts', $defaultSet); app('log')->debug('frontpage set is empty!'); } - $accounts = $repository->getAccountsById($frontPage->data); + $accounts = $repository->getAccountsById($frontPageArray); return response()->json($this->accountBalanceChart($accounts, $start, $end)); } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 6b89c0464b..8b5236f4b5 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -74,8 +74,8 @@ abstract class Controller extends BaseController app('view')->share('logoutUrl', $logoutUrl); // upload size - $maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize')); - $maxPostSize = app('steam')->phpBytes(ini_get('post_max_size')); + $maxFileSize = app('steam')->phpBytes((string)ini_get('upload_max_filesize')); + $maxPostSize = app('steam')->phpBytes((string)ini_get('post_max_size')); $uploadSize = min($maxFileSize, $maxPostSize); app('view')->share('uploadSize', $uploadSize); diff --git a/app/Http/Controllers/DebugController.php b/app/Http/Controllers/DebugController.php index 3badb00404..126b19a845 100644 --- a/app/Http/Controllers/DebugController.php +++ b/app/Http/Controllers/DebugController.php @@ -141,7 +141,7 @@ class DebugController extends Controller } if ('' !== $logContent) { // last few lines - $logContent = 'Truncated from this point <----|' . substr($logContent, -16384); + $logContent = 'Truncated from this point <----|' . substr((string)$logContent, -16384); } return view('debug', compact('table', 'now', 'logContent')); @@ -166,8 +166,8 @@ class DebugController extends Controller */ private function getSystemInformation(): array { - $maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize')); - $maxPostSize = app('steam')->phpBytes(ini_get('post_max_size')); + $maxFileSize = app('steam')->phpBytes((string)ini_get('upload_max_filesize')); + $maxPostSize = app('steam')->phpBytes((string)ini_get('post_max_size')); $drivers = DB::availableDrivers(); $currentDriver = DB::getDriverName(); return [ @@ -199,7 +199,7 @@ class DebugController extends Controller ]; try { if (file_exists('/var/www/counter-main.txt')) { - $return['build'] = trim(file_get_contents('/var/www/counter-main.txt')); + $return['build'] = trim((string)file_get_contents('/var/www/counter-main.txt')); } } catch (Exception $e) { // @phpstan-ignore-line app('log')->debug('Could not check build counter, but thats ok.'); @@ -207,7 +207,7 @@ class DebugController extends Controller } try { if (file_exists('/var/www/build-date-main.txt')) { - $return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt')); + $return['build_date'] = trim((string)file_get_contents('/var/www/build-date-main.txt')); } } catch (Exception $e) { // @phpstan-ignore-line app('log')->debug('Could not check build date, but thats ok.'); @@ -236,7 +236,7 @@ class DebugController extends Controller if ($lastTime > 0) { $carbon = Carbon::createFromTimestamp($lastTime); $lastCronjob = $carbon->format('Y-m-d H:i:s'); - $lastCronjobAgo = $carbon->locale('en')->diffForHumans(); + $lastCronjobAgo = $carbon->locale('en')->diffForHumans(); // @phpstan-ignore-line } return [ @@ -279,7 +279,7 @@ class DebugController extends Controller $result = setlocale(LC_ALL, $code); $localeAttempts[$code] = $result === $code; } - setlocale(LC_ALL, $original); + setlocale(LC_ALL, (string) $original); return [ 'user_id' => auth()->user()->id, diff --git a/app/Models/TransactionCurrency.php b/app/Models/TransactionCurrency.php index 6cfbe7dd70..cfbd363700 100644 --- a/app/Models/TransactionCurrency.php +++ b/app/Models/TransactionCurrency.php @@ -25,7 +25,9 @@ namespace FireflyIII\Models; use Carbon\Carbon; use Eloquent; +use FireflyIII\Support\Models\ReturnsIntegerIdTrait; use FireflyIII\User; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; @@ -33,7 +35,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Query\Builder; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use FireflyIII\Support\Models\ReturnsIntegerIdTrait; + /** * FireflyIII\Models\TransactionCurrency * @@ -47,7 +49,7 @@ use FireflyIII\Support\Models\ReturnsIntegerIdTrait; * @property string $code * @property string $name * @property string $symbol - * @property int|string $decimal_places + * @property int $decimal_places * @property-read Collection|BudgetLimit[] $budgetLimits * @property-read int|null $budget_limits_count * @property-read Collection|TransactionJournal[] $transactionJournals @@ -82,7 +84,7 @@ class TransactionCurrency extends Model public ?bool $userDefault; public ?bool $userEnabled; - protected $casts + protected $casts = [ 'created_at' => 'datetime', 'updated_at' => 'datetime', @@ -170,4 +172,14 @@ class TransactionCurrency extends Model { return $this->belongsToMany(User::class)->withTimestamps()->withPivot('user_default'); } + + /** + * @return Attribute + */ + protected function decimalPlaces(): Attribute + { + return Attribute::make( + get: static fn($value) => (int)$value, + ); + } } diff --git a/app/Repositories/UserGroups/Bill/BillRepository.php b/app/Repositories/UserGroups/Bill/BillRepository.php index dd4c1cf098..a691452393 100644 --- a/app/Repositories/UserGroups/Bill/BillRepository.php +++ b/app/Repositories/UserGroups/Bill/BillRepository.php @@ -88,12 +88,12 @@ class BillRepository implements BillRepositoryInterface 'currency_name' => $currency->name, 'currency_symbol' => $currency->symbol, 'currency_code' => $currency->code, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'native_id' => (string)$default->id, 'native_name' => $default->name, 'native_symbol' => $default->symbol, 'native_code' => $default->code, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, 'sum' => '0', 'native_sum' => '0', ]; @@ -162,12 +162,12 @@ class BillRepository implements BillRepositoryInterface 'currency_name' => $currency->name, 'currency_symbol' => $currency->symbol, 'currency_code' => $currency->code, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'native_id' => (string)$default->id, 'native_name' => $default->name, 'native_symbol' => $default->symbol, 'native_code' => $default->code, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, 'sum' => '0', 'native_sum' => '0', ]; diff --git a/app/Repositories/UserGroups/Budget/AvailableBudgetRepository.php b/app/Repositories/UserGroups/Budget/AvailableBudgetRepository.php index f32da21d50..40555a096a 100644 --- a/app/Repositories/UserGroups/Budget/AvailableBudgetRepository.php +++ b/app/Repositories/UserGroups/Budget/AvailableBudgetRepository.php @@ -64,7 +64,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface 'native_code' => $default->code, 'native_symbol' => $default->symbol, 'native_name' => $default->name, - 'native_decimal_places' => (int)$default->decimal_places, + 'native_decimal_places' => $default->decimal_places, 'amount' => '0', 'native_amount' => '0', ]; diff --git a/app/Support/Twig/TransactionGroupTwig.php b/app/Support/Twig/TransactionGroupTwig.php index 14761dfb79..69219785c9 100644 --- a/app/Support/Twig/TransactionGroupTwig.php +++ b/app/Support/Twig/TransactionGroupTwig.php @@ -200,7 +200,7 @@ class TransactionGroupTwig extends AbstractExtension if ($type === TransactionType::TRANSFER) { $colored = false; } - $result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored); + $result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored); if ($type === TransactionType::TRANSFER) { $result = sprintf('%s', $result); } @@ -243,7 +243,7 @@ class TransactionGroupTwig extends AbstractExtension if ($type === TransactionType::TRANSFER) { $colored = false; } - $result = app('amount')->formatFlat($currency->symbol, (int)$currency->decimal_places, $amount, $colored); + $result = app('amount')->formatFlat($currency->symbol, $currency->decimal_places, $amount, $colored); if ($type === TransactionType::TRANSFER) { $result = sprintf('%s', $result); } diff --git a/app/Transformers/AvailableBudgetTransformer.php b/app/Transformers/AvailableBudgetTransformer.php index 5f24686e0f..5ffe94fab9 100644 --- a/app/Transformers/AvailableBudgetTransformer.php +++ b/app/Transformers/AvailableBudgetTransformer.php @@ -68,7 +68,7 @@ class AvailableBudgetTransformer extends AbstractTransformer 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'amount' => app('steam')->bcround($availableBudget->amount, $currency->decimal_places), 'start' => $availableBudget->start_date->toAtomString(), 'end' => $availableBudget->end_date->endOfDay()->toAtomString(), diff --git a/app/Transformers/BillTransformer.php b/app/Transformers/BillTransformer.php index cd431bee09..d688db79b7 100644 --- a/app/Transformers/BillTransformer.php +++ b/app/Transformers/BillTransformer.php @@ -128,7 +128,7 @@ class BillTransformer extends AbstractTransformer 'currency_id' => (string)$bill->transaction_currency_id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'name' => $bill->name, 'amount_min' => app('steam')->bcround($bill->amount_min, $currency->decimal_places), 'amount_max' => app('steam')->bcround($bill->amount_max, $currency->decimal_places), diff --git a/app/Transformers/CurrencyTransformer.php b/app/Transformers/CurrencyTransformer.php index d1ad7299eb..771f881c8b 100644 --- a/app/Transformers/CurrencyTransformer.php +++ b/app/Transformers/CurrencyTransformer.php @@ -48,7 +48,7 @@ class CurrencyTransformer extends AbstractTransformer 'name' => $currency->name, 'code' => $currency->code, 'symbol' => $currency->symbol, - 'decimal_places' => (int)$currency->decimal_places, + 'decimal_places' => $currency->decimal_places, 'links' => [ [ 'rel' => 'self', diff --git a/app/Transformers/PiggyBankEventTransformer.php b/app/Transformers/PiggyBankEventTransformer.php index f1e8511e4b..3137e76269 100644 --- a/app/Transformers/PiggyBankEventTransformer.php +++ b/app/Transformers/PiggyBankEventTransformer.php @@ -85,7 +85,7 @@ class PiggyBankEventTransformer extends AbstractTransformer 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'transaction_journal_id' => null !== $journalId ? (string)$journalId : null, 'transaction_group_id' => null !== $groupId ? (string)$groupId : null, 'links' => [ diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index 6c2bd4736d..f098bba34d 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -112,7 +112,7 @@ class PiggyBankTransformer extends AbstractTransformer 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'target_amount' => $targetAmount, 'percentage' => $percentage, 'current_amount' => $currentAmount, diff --git a/app/Transformers/TransactionGroupTransformer.php b/app/Transformers/TransactionGroupTransformer.php index 39e277185c..50f21901b7 100644 --- a/app/Transformers/TransactionGroupTransformer.php +++ b/app/Transformers/TransactionGroupTransformer.php @@ -415,7 +415,7 @@ class TransactionGroupTransformer extends AbstractTransformer 'currency_id' => $currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'foreign_currency_id' => $foreignCurrency['id'], 'foreign_currency_code' => $foreignCurrency['code'], @@ -592,7 +592,7 @@ class TransactionGroupTransformer extends AbstractTransformer $array['id'] = $currency->id; $array['code'] = $currency->code; $array['symbol'] = $currency->symbol; - $array['decimal_places'] = (int)$currency->decimal_places; + $array['decimal_places'] = $currency->decimal_places; return $array; } diff --git a/app/Transformers/V2/AccountTransformer.php b/app/Transformers/V2/AccountTransformer.php index f117a41df7..f8aab9b8ac 100644 --- a/app/Transformers/V2/AccountTransformer.php +++ b/app/Transformers/V2/AccountTransformer.php @@ -144,7 +144,7 @@ class AccountTransformer extends AbstractTransformer 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'native_currency_id' => (string)$this->default->id, 'native_currency_code' => $this->default->code, diff --git a/app/Transformers/V2/BillTransformer.php b/app/Transformers/V2/BillTransformer.php index 82cd4ba63a..d5119483f5 100644 --- a/app/Transformers/V2/BillTransformer.php +++ b/app/Transformers/V2/BillTransformer.php @@ -207,7 +207,7 @@ class BillTransformer extends AbstractTransformer 'currency_code' => $currency->code, 'currency_name' => $currency->name, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'native_currency_id' => $this->default->id, 'native_currency_code' => $this->default->code, 'native_currency_name' => $this->default->name, diff --git a/app/Transformers/V2/CurrencyTransformer.php b/app/Transformers/V2/CurrencyTransformer.php index b3973b6f09..446d4083fa 100644 --- a/app/Transformers/V2/CurrencyTransformer.php +++ b/app/Transformers/V2/CurrencyTransformer.php @@ -56,7 +56,7 @@ class CurrencyTransformer extends AbstractTransformer 'name' => $currency->name, 'code' => $currency->code, 'symbol' => $currency->symbol, - 'decimal_places' => (int)$currency->decimal_places, + 'decimal_places' => $currency->decimal_places, 'links' => [ [ 'rel' => 'self', diff --git a/app/Transformers/V2/PiggyBankTransformer.php b/app/Transformers/V2/PiggyBankTransformer.php index 329448e9af..98dceed838 100644 --- a/app/Transformers/V2/PiggyBankTransformer.php +++ b/app/Transformers/V2/PiggyBankTransformer.php @@ -208,7 +208,7 @@ class PiggyBankTransformer extends AbstractTransformer 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int)$currency->decimal_places, + 'currency_decimal_places' => $currency->decimal_places, 'native_currency_id' => (string)$this->default->id, 'native_currency_code' => $this->default->code, 'native_currency_symbol' => $this->default->symbol, diff --git a/phpunit.xml b/phpunit.xml index 0c9c6a3a42..5979cacc3f 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -14,6 +14,7 @@ stopOnFailure="true"> + diff --git a/resources/views/bills/show.twig b/resources/views/bills/show.twig index 763055be63..7edc47d58d 100644 --- a/resources/views/bills/show.twig +++ b/resources/views/bills/show.twig @@ -46,8 +46,9 @@ {{ 'next_expected_match'|_ }} - {% if object.data.next_expected_match|length > 0 %} - {{ formatDate(object.data.next_expected_match, monthAndDayFormat) }} + + {% if object.data.pay_dates|length > 0 %} + {{ formatDate(object.data.pay_dates[0], monthAndDayFormat) }} {% else %} {{ 'unknown'|_ }} {% endif %} diff --git a/tests/integration/Support/Models/BillDateCalculatorTest.php b/tests/integration/Support/Models/BillDateCalculatorTest.php index f4a3c66c79..b6ec63097e 100644 --- a/tests/integration/Support/Models/BillDateCalculatorTest.php +++ b/tests/integration/Support/Models/BillDateCalculatorTest.php @@ -45,7 +45,14 @@ class BillDateCalculatorTest extends TestCase // Carbon $earliest, Carbon $latest, Carbon $billStart, string $period, int $skip, ?Carbon $lastPaid return [ // basic monthly bill. - '1M' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => null, 'expected' => ['2023-11-01']], + '1Ma' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => null, 'expected' => ['2023-11-01']], + // already paid on the first, expect it next month. + '1Mb' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => Carbon::parse('2023-11-01'), 'expected' => ['2023-12-01']], + // already paid on the 12th, expect it next month. + '1Mc' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2023-01-01'), 'period' => 'monthly', 'skip' => 0, 'lastPaid' => Carbon::parse('2023-11-12'), 'expected' => ['2023-12-01']], + + // yearly not due this month. Should jump to next year. + '1Ya' => ['earliest' => Carbon::parse('2023-11-01'), 'latest' => Carbon::parse('2023-11-30'), 'billStart' => Carbon::parse('2021-05-01'), 'period' => 'yearly', 'skip' => 0, 'lastPaid' => Carbon::parse('2023-05-02'), 'expected' => ['2024-05-01']], ]; }