Merge pull request #10345 from firefly-iii/develop

🤖 Automatically merge the PR into the main branch.
This commit is contained in:
github-actions[bot]
2025-05-24 06:31:42 +02:00
committed by GitHub
547 changed files with 5510 additions and 5506 deletions

View File

@@ -61,7 +61,7 @@ return $config->setRules(
'comment_to_phpdoc' => false, // breaks phpstan lines in combination with PHPStorm. 'comment_to_phpdoc' => false, // breaks phpstan lines in combination with PHPStorm.
'type_declaration_spaces' => false, 'type_declaration_spaces' => false,
'cast_spaces' => false, 'cast_spaces' => false,
'phpdoc_to_comment' => false, // do not overrule single line comment style, breaks phpstan. 'phpdoc_to_comment' => false, // do not overrule single line comment style, breaks phpstan.
// complex rules // complex rules
'array_syntax' => ['syntax' => 'short'], 'array_syntax' => ['syntax' => 'short'],

View File

@@ -1256,16 +1256,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v7.2.5", "version": "v7.2.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "e51498ea18570c062e7df29d05a7003585b19b88" "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88", "url": "https://api.github.com/repos/symfony/console/zipball/0e2e3f38c192e93e622e41ec37f4ca70cfedf218",
"reference": "e51498ea18570c062e7df29d05a7003585b19b88", "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1329,7 +1329,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v7.2.5" "source": "https://github.com/symfony/console/tree/v7.2.6"
}, },
"funding": [ "funding": [
{ {
@@ -1345,7 +1345,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-03-12T08:11:12+00:00" "time": "2025-04-07T19:09:28+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -1769,7 +1769,7 @@
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.31.0", "version": "v1.32.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
@@ -1828,7 +1828,7 @@
"portable" "portable"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
}, },
"funding": [ "funding": [
{ {
@@ -1848,7 +1848,7 @@
}, },
{ {
"name": "symfony/polyfill-intl-grapheme", "name": "symfony/polyfill-intl-grapheme",
"version": "v1.31.0", "version": "v1.32.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
@@ -1906,7 +1906,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
}, },
"funding": [ "funding": [
{ {
@@ -1926,7 +1926,7 @@
}, },
{ {
"name": "symfony/polyfill-intl-normalizer", "name": "symfony/polyfill-intl-normalizer",
"version": "v1.31.0", "version": "v1.32.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -1987,7 +1987,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
}, },
"funding": [ "funding": [
{ {
@@ -2007,19 +2007,20 @@
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.31.0", "version": "v1.32.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-iconv": "*",
"php": ">=7.2" "php": ">=7.2"
}, },
"provide": { "provide": {
@@ -2067,7 +2068,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
}, },
"funding": [ "funding": [
{ {
@@ -2083,20 +2084,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-09T11:45:10+00:00" "time": "2024-12-23T08:48:59+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.31.0", "version": "v1.32.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2147,7 +2148,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
}, },
"funding": [ "funding": [
{ {
@@ -2163,11 +2164,11 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-09T11:45:10+00:00" "time": "2025-01-02T08:10:11+00:00"
}, },
{ {
"name": "symfony/polyfill-php81", "name": "symfony/polyfill-php81",
"version": "v1.31.0", "version": "v1.32.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php81.git", "url": "https://github.com/symfony/polyfill-php81.git",
@@ -2223,7 +2224,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0"
}, },
"funding": [ "funding": [
{ {
@@ -2449,16 +2450,16 @@
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v7.2.0", "version": "v7.2.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", "url": "https://api.github.com/repos/symfony/string/zipball/a214fe7d62bd4df2a76447c67c6b26e1d5e74931",
"reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2516,7 +2517,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v7.2.0" "source": "https://github.com/symfony/string/tree/v7.2.6"
}, },
"funding": [ "funding": [
{ {
@@ -2532,7 +2533,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-13T13:31:26+00:00" "time": "2025-04-20T20:18:16+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],

69
.ci/rector.php Normal file
View File

@@ -0,0 +1,69 @@
<?php
/*
* rector.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector;
return RectorConfig::configure()
->withSkip([
ChangeOrIfContinueToMultiContinueRector::class,
])
->withPaths([
// __DIR__ . '/../app',
__DIR__ . '/../app/Http',
// __DIR__ . '/../bootstrap',
// __DIR__ . '/../config',
// __DIR__ . '/../public',
// __DIR__ . '/../resources',
// __DIR__ . '/../routes',
// __DIR__ . '/../tests',
])
// uncomment to reach your current PHP version
->withPhpSets()
->withPreparedSets(
codingStyle : false, // leave false
privatization: false, // leave false.
naming : false, // leave false
instanceOf : true,
earlyReturn : true,
strictBooleans : true,
carbon : true,
rectorPreset : true,
phpunitCodeQuality : true,
doctrineCodeQuality: true,
symfonyCodeQuality : true,
symfonyConfigs : true
)
->withComposerBased(
twig: true,
doctrine: true,
phpunit: true,
symfony: true)
->withTypeCoverageLevel(0)
->withDeadCodeLevel(0)
->withCodeQualityLevel(0)
->withImportNames(removeUnusedImports: true);// import statements instead of full classes.

28
.ci/rector.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
#
# phpstan.sh
# Copyright (c) 2021 james@firefly-iii.org
#
# This file is part of Firefly III (https://github.com/firefly-iii).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Install composer packages
#composer install --no-scripts --no-ansi
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
$SCRIPT_DIR/../vendor/bin/rector --config $SCRIPT_DIR/rector.php

View File

@@ -289,20 +289,13 @@ ALLOW_WEBHOOKS=false
# #
# You can set this variable from a file by appending it with _FILE # You can set this variable from a file by appending it with _FILE
# #
STATIC_CRON_TOKEN= STATIC_CRON_TOKEN=PLEASE_REPLACE_WITH_32_CHAR_CODE
# You can fine tune the start-up of a Docker container by editing these environment variables. # You can fine tune the start-up of a Docker container by editing these environment variables.
# Use this at your own risk. Disabling certain checks and features may result in lots of inconsistent data. # Use this at your own risk. Disabling certain checks and features may result in lots of inconsistent data.
# However if you know what you're doing you can significantly speed up container start times. # However if you know what you're doing you can significantly speed up container start times.
# Set each value to true to enable, or false to disable. # Set each value to true to enable, or false to disable.
# Set this to true to build all locales supported by Firefly III.
# This may take quite some time (several minutes) and is generally not recommended.
# If you wish to change or alter the list of locales, start your Docker container with
# `docker run -v locale.gen:/etc/locale.gen -e DKR_BUILD_LOCALE=true`
# and make sure your preferred locales are in your own locale.gen.
DKR_BUILD_LOCALE=false
# Check if the SQLite database exists. Can be skipped if you're not using SQLite. # Check if the SQLite database exists. Can be skipped if you're not using SQLite.
# Won't significantly speed up things. # Won't significantly speed up things.
DKR_CHECK_SQLITE=true DKR_CHECK_SQLITE=true

View File

@@ -21,5 +21,3 @@ Changes in this pull request:
- -
- -
- -
@JC5

View File

@@ -4,6 +4,7 @@ Over time, many people have contributed to Firefly III. Their efforts are not al
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution. Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2025 ## 2025
- Denis Iskandarov
- = - =
- Lompi - Lompi
- Jose Diaz-Gonzalez - Jose Diaz-Gonzalez

View File

@@ -43,6 +43,7 @@ use Illuminate\Support\Facades\Log;
class AccountController extends Controller class AccountController extends Controller
{ {
use AccountFilter; use AccountFilter;
// this array only exists to test if the constructor will use it properly. // this array only exists to test if the constructor will use it properly.
protected array $accepts = ['application/json', 'application/vnd.api+json']; protected array $accepts = ['application/json', 'application/vnd.api+json'];

View File

@@ -65,13 +65,11 @@ class BillController extends Controller
$data = $request->getData(); $data = $request->getData();
$result = $this->repository->searchBill($data['query'], $this->parameters->get('limit')); $result = $this->repository->searchBill($data['query'], $this->parameters->get('limit'));
$filtered = $result->map( $filtered = $result->map(
static function (Bill $item) { static fn (Bill $item) => [
return [ 'id' => (string) $item->id,
'id' => (string) $item->id, 'name' => $item->name,
'name' => $item->name, 'active' => $item->active,
'active' => $item->active, ]
];
}
); );
return response()->api($filtered->toArray()); return response()->api($filtered->toArray());

View File

@@ -65,12 +65,10 @@ class BudgetController extends Controller
$data = $request->getData(); $data = $request->getData();
$result = $this->repository->searchBudget($data['query'], $this->parameters->get('limit')); $result = $this->repository->searchBudget($data['query'], $this->parameters->get('limit'));
$filtered = $result->map( $filtered = $result->map(
static function (Budget $item) { static fn (Budget $item) => [
return [ 'id' => (string) $item->id,
'id' => (string) $item->id, 'name' => $item->name,
'name' => $item->name, ]
];
}
); );
return response()->api($filtered->toArray()); return response()->api($filtered->toArray());

View File

@@ -65,12 +65,10 @@ class CategoryController extends Controller
$data = $request->getData(); $data = $request->getData();
$result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit')); $result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit'));
$filtered = $result->map( $filtered = $result->map(
static function (Category $item) { static fn (Category $item) => [
return [ 'id' => (string) $item->id,
'id' => (string) $item->id, 'name' => $item->name,
'name' => $item->name, ]
];
}
); );
return response()->api($filtered->toArray()); return response()->api($filtered->toArray());

View File

@@ -39,11 +39,10 @@ use Illuminate\Support\Collection;
*/ */
class TransactionController extends Controller class TransactionController extends Controller
{ {
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
private TransactionGroupRepositoryInterface $groupRepository; private TransactionGroupRepositoryInterface $groupRepository;
private JournalRepositoryInterface $repository; private JournalRepositoryInterface $repository;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/** /**
* TransactionController constructor. * TransactionController constructor.
*/ */

View File

@@ -26,8 +26,8 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Api\V1\Requests\Chart\ChartRequest; use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
use FireflyIII\Api\V1\Requests\Data\DateRequest;
use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
@@ -48,8 +48,8 @@ class AccountController extends Controller
use ApiSupport; use ApiSupport;
use CollectsAccountsFromFilter; use CollectsAccountsFromFilter;
private AccountRepositoryInterface $repository;
private ChartData $chartData; private ChartData $chartData;
private AccountRepositoryInterface $repository;
/** /**
* AccountController constructor. * AccountController constructor.
@@ -93,6 +93,47 @@ class AccountController extends Controller
return response()->json($this->chartData->render()); return response()->json($this->chartData->render());
} }
/**
* @throws FireflyException
*/
private function renderAccountData(array $params, Account $account): void
{
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $this->default;
}
$currentSet = [
'label' => $account->name,
// the currency that belongs to the account.
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
// the default currency of the user (could be the same!)
'date' => $params['start']->toAtomString(),
'start' => $params['start']->toAtomString(),
'end' => $params['end']->toAtomString(),
'period' => '1D',
'entries' => [],
];
$currentStart = clone $params['start'];
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
$previous = array_values($range)[0]['balance'];
while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$previous = $balance;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance;
}
$this->chartData->add($currentSet);
}
/** /**
* This endpoint is documented at: * This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/charts/getChartAccountOverview * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/charts/getChartAccountOverview
@@ -162,45 +203,4 @@ class AccountController extends Controller
return response()->json($chartData); return response()->json($chartData);
} }
/**
* @throws FireflyException
*/
private function renderAccountData(array $params, Account $account): void
{
$currency = $this->repository->getAccountCurrency($account);
if (null === $currency) {
$currency = $this->default;
}
$currentSet = [
'label' => $account->name,
// the currency that belongs to the account.
'currency_id' => (string) $currency->id,
'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
// the default currency of the user (could be the same!)
'date' => $params['start']->toAtomString(),
'start' => $params['start']->toAtomString(),
'end' => $params['end']->toAtomString(),
'period' => '1D',
'entries' => [],
];
$currentStart = clone $params['start'];
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
$previous = array_values($range)[0]['balance'];
while ($currentStart <= $params['end']) {
$format = $currentStart->format('Y-m-d');
$label = $currentStart->toAtomString();
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
$previous = $balance;
$currentStart->addDay();
$currentSet['entries'][$label] = $balance;
}
$this->chartData->add($currentSet);
}
} }

View File

@@ -193,7 +193,7 @@ class BudgetController extends Controller
// var_dump($return); // var_dump($return);
/** @var array $journal */ /** @var array $journal */
foreach ($currentBudgetArray['transaction_journals'] as $journal) { foreach ($currentBudgetArray['transaction_journals'] as $journal) {
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $journal['amount']); $return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string) $journal['amount']);
} }
} }
@@ -245,13 +245,13 @@ class BudgetController extends Controller
} }
$result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end); $result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end);
if (1 === count($result)) { if (1 === count($result)) {
$compare = bccomp($limit->amount, app('steam')->positive($result[$limitCurrencyId]['spent'])); $compare = bccomp($limit->amount, (string) app('steam')->positive($result[$limitCurrencyId]['spent']));
if (1 === $compare) { if (1 === $compare) {
// convert this amount into the native currency: // convert this amount into the native currency:
$result[$limitCurrencyId]['left'] = bcadd($limit->amount, $result[$limitCurrencyId]['spent']); $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent']);
} }
if ($compare <= 0) { if ($compare <= 0) {
$result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, $result[$limitCurrencyId]['spent'])); $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent']));
} }
} }

View File

@@ -96,7 +96,7 @@ class CategoryController extends Controller
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId); $currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
$currencies[$currencyId] = $currency; $currencies[$currencyId] = $currency;
$categoryName = null === $journal['category_name'] ? (string) trans('firefly.no_category') : $journal['category_name']; $categoryName = $journal['category_name'] ?? (string) trans('firefly.no_category');
$amount = app('steam')->positive($journal['amount']); $amount = app('steam')->positive($journal['amount']);
$key = sprintf('%s-%s', $categoryName, $currency->code); $key = sprintf('%s-%s', $categoryName, $currency->code);
// create arrays // create arrays
@@ -114,14 +114,12 @@ class CategoryController extends Controller
]; ];
// add monies // add monies
$return[$key]['amount'] = bcadd($return[$key]['amount'], $amount); $return[$key]['amount'] = bcadd($return[$key]['amount'], (string) $amount);
} }
$return = array_values($return); $return = array_values($return);
// order by amount // order by amount
usort($return, static function (array $a, array $b) { usort($return, static fn (array $a, array $b) => (float) $a['amount'] < (float) $b['amount'] ? 1 : -1);
return (float) $a['amount'] < (float) $b['amount'] ? 1 : -1;
});
return response()->json($this->clean($return)); return response()->json($this->clean($return));
} }

View File

@@ -40,7 +40,6 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Routing\Controller as BaseController; use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Collection;
use League\Fractal\Manager; use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection; use League\Fractal\Resource\Collection as FractalCollection;
@@ -62,15 +61,15 @@ abstract class Controller extends BaseController
use ValidatesRequests; use ValidatesRequests;
use ValidatesUserGroupTrait; use ValidatesUserGroupTrait;
protected const string CONTENT_TYPE = 'application/vnd.api+json'; protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected const string JSON_CONTENT_TYPE = 'application/json'; protected const string JSON_CONTENT_TYPE = 'application/json';
protected array $accepts = ['application/json', 'application/vnd.api+json'];
/** @var array<int, string> */ /** @var array<int, string> */
protected array $allowedSort; protected array $allowedSort;
protected ParameterBag $parameters; protected bool $convertToNative = false;
protected bool $convertToNative = false;
protected array $accepts = ['application/json', 'application/vnd.api+json'];
protected TransactionCurrency $nativeCurrency; protected TransactionCurrency $nativeCurrency;
protected ParameterBag $parameters;
/** /**
* Controller constructor. * Controller constructor.

View File

@@ -30,6 +30,8 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Support\Export\ExportDataGenerator; use FireflyIII\Support\Export\ExportDataGenerator;
use Illuminate\Http\Response as LaravelResponse; use Illuminate\Http\Response as LaravelResponse;
use function Safe\date;
/** /**
* Class ExportController * Class ExportController
*/ */
@@ -88,7 +90,7 @@ class ExportController extends Controller
->header('Expires', '0') ->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') ->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public') ->header('Pragma', 'public')
->header('Content-Length', (string) strlen($data[$key])) ->header('Content-Length', (string) strlen((string) $data[$key]))
; ;
return $response; return $response;

View File

@@ -160,7 +160,7 @@ class TagController extends Controller
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
]; ];
$response[$key]['difference'] = bcadd($response[$key]['difference'], $journal['amount']); $response[$key]['difference'] = bcadd((string) $response[$key]['difference'], (string) $journal['amount']);
$response[$key]['difference_float'] = (float) $response[$key]['difference']; // float but on purpose. $response[$key]['difference_float'] = (float) $response[$key]['difference']; // float but on purpose.
} }
@@ -172,7 +172,7 @@ class TagController extends Controller
'currency_id' => (string) $foreignCurrencyId, 'currency_id' => (string) $foreignCurrencyId,
'currency_code' => $journal['foreign_currency_code'], 'currency_code' => $journal['foreign_currency_code'],
]; ];
$response[$foreignKey]['difference'] = bcadd($response[$foreignKey]['difference'], $journal['foreign_amount']); $response[$foreignKey]['difference'] = bcadd((string) $response[$foreignKey]['difference'], (string) $journal['foreign_amount']);
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // float but on purpose. $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // float but on purpose.
} }
} }

View File

@@ -75,7 +75,7 @@ class PeriodController extends Controller
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], (string) app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose. $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; // float but on purpose.
} }

View File

@@ -100,7 +100,7 @@ class TagController extends Controller
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], (string) app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
} }
@@ -154,7 +154,7 @@ class TagController extends Controller
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
]; ];
$response[$key]['difference'] = bcadd($response[$key]['difference'], app('steam')->positive($journal['amount'])); $response[$key]['difference'] = bcadd((string) $response[$key]['difference'], (string) app('steam')->positive($journal['amount']));
$response[$key]['difference_float'] = (float) $response[$key]['difference']; $response[$key]['difference_float'] = (float) $response[$key]['difference'];
} }
@@ -167,8 +167,8 @@ class TagController extends Controller
'currency_code' => $journal['foreign_currency_code'], 'currency_code' => $journal['foreign_currency_code'],
]; ];
$response[$foreignKey]['difference'] = bcadd( $response[$foreignKey]['difference'] = bcadd(
$response[$foreignKey]['difference'], (string) $response[$foreignKey]['difference'],
app('steam')->positive($journal['foreign_amount']) (string) app('steam')->positive($journal['foreign_amount'])
); );
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference'];
} }

View File

@@ -75,7 +75,7 @@ class PeriodController extends Controller
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], (string) app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
} }

View File

@@ -99,7 +99,7 @@ class TagController extends Controller
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $currencyCode, 'currency_code' => $currencyCode,
]; ];
$response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], app('steam')->positive($journal[$field])); $response[$currencyId]['difference'] = bcadd($response[$currencyId]['difference'], (string) app('steam')->positive($journal[$field]));
$response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference']; $response[$currencyId]['difference_float'] = (float) $response[$currencyId]['difference'];
} }
@@ -153,7 +153,7 @@ class TagController extends Controller
'currency_id' => (string) $currencyId, 'currency_id' => (string) $currencyId,
'currency_code' => $journal['currency_code'], 'currency_code' => $journal['currency_code'],
]; ];
$response[$key]['difference'] = bcadd($response[$key]['difference'], app('steam')->positive($journal['amount'])); $response[$key]['difference'] = bcadd((string) $response[$key]['difference'], (string) app('steam')->positive($journal['amount']));
$response[$key]['difference_float'] = (float) $response[$key]['difference']; $response[$key]['difference_float'] = (float) $response[$key]['difference'];
} }
@@ -166,8 +166,8 @@ class TagController extends Controller
'currency_code' => $journal['foreign_currency_code'], 'currency_code' => $journal['foreign_currency_code'],
]; ];
$response[$foreignKey]['difference'] = bcadd( $response[$foreignKey]['difference'] = bcadd(
$response[$foreignKey]['difference'], (string) $response[$foreignKey]['difference'],
app('steam')->positive($journal['foreign_amount']) (string) app('steam')->positive($journal['foreign_amount'])
); );
$response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float $response[$foreignKey]['difference_float'] = (float) $response[$foreignKey]['difference']; // intentional float
} }

View File

@@ -39,10 +39,8 @@ class DestroyController extends Controller
{ {
use ValidatesUserGroupTrait; use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::OWNER];
public const string RESOURCE_KEY = 'exchange-rates'; public const string RESOURCE_KEY = 'exchange-rates';
protected array $acceptedRoles = [UserRoleEnum::OWNER];
private ExchangeRateRepositoryInterface $repository; private ExchangeRateRepositoryInterface $repository;
public function __construct() public function __construct()

View File

@@ -50,9 +50,8 @@ class StoreController extends Controller
{ {
use TransactionFilter; use TransactionFilter;
private TransactionGroupRepositoryInterface $groupRepository;
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS]; protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
private TransactionGroupRepositoryInterface $groupRepository;
/** /**
* TransactionController constructor. * TransactionController constructor.

View File

@@ -27,8 +27,8 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionCurrency;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;

View File

@@ -177,9 +177,7 @@ class ListController extends Controller
// filter and paginate list: // filter and paginate list:
$collection = $unfiltered->filter( $collection = $unfiltered->filter(
static function (Bill $bill) use ($currency) { static fn (Bill $bill) => $bill->transaction_currency_id === $currency->id
return $bill->transaction_currency_id === $currency->id;
}
); );
$count = $collection->count(); $count = $collection->count();
$bills = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $bills = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@@ -43,6 +43,7 @@ use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer; use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
@@ -104,10 +105,10 @@ class BasicController extends Controller
$billData = $this->getSubscriptionInformation($start, $end); $billData = $this->getSubscriptionInformation($start, $end);
$spentData = $this->getLeftToSpendInfo($start, $end); $spentData = $this->getLeftToSpendInfo($start, $end);
$netWorthData = $this->getNetWorthInfo($end); $netWorthData = $this->getNetWorthInfo($end);
// $balanceData = []; // $balanceData = [];
// $billData = []; // $billData = [];
// $spentData = []; // $spentData = [];
// $netWorthData = []; // $netWorthData = [];
$total = array_merge($balanceData, $billData, $spentData, $netWorthData); $total = array_merge($balanceData, $billData, $spentData, $netWorthData);
// give new keys // give new keys
@@ -190,14 +191,14 @@ class BasicController extends Controller
// if it is the native currency already. // if it is the native currency already.
if ($entry['currency_id'] === $default->id) { if ($entry['currency_id'] === $default->id) {
$sums[$default->id]['sum'] = bcadd($entry['sum'], $sums[$default->id]['sum']); $sums[$default->id]['sum'] = bcadd((string) $entry['sum'], $sums[$default->id]['sum']);
// don't forget to add it to newExpenses and newIncome // don't forget to add it to newExpenses and newIncome
if (0 === $index) { if (0 === $index) {
$newExpenses[$default->id]['sum'] = bcadd($newExpenses[$default->id]['sum'], $entry['sum']); $newExpenses[$default->id]['sum'] = bcadd($newExpenses[$default->id]['sum'], (string) $entry['sum']);
} }
if (1 === $index) { if (1 === $index) {
$newIncomes[$default->id]['sum'] = bcadd($newIncomes[$default->id]['sum'], $entry['sum']); $newIncomes[$default->id]['sum'] = bcadd($newIncomes[$default->id]['sum'], (string) $entry['sum']);
} }
continue; continue;
@@ -228,7 +229,7 @@ class BasicController extends Controller
'currency_decimal_places' => $entry['currency_decimal_places'], 'currency_decimal_places' => $entry['currency_decimal_places'],
'sum' => '0', 'sum' => '0',
]; ];
$sums[$currencyId]['sum'] = bcadd($sums[$currencyId]['sum'], $entry['sum']); $sums[$currencyId]['sum'] = bcadd($sums[$currencyId]['sum'], (string) $entry['sum']);
} }
} }
} }
@@ -361,7 +362,7 @@ class BasicController extends Controller
if (0 === $index) { if (0 === $index) {
// paid amount // paid amount
if ($currencyId === $this->nativeCurrency->id) { if ($currencyId === $this->nativeCurrency->id) {
$newPaidAmount[0]['sum'] = bcadd($newPaidAmount[0]['sum'], $item['sum']); $newPaidAmount[0]['sum'] = bcadd($newPaidAmount[0]['sum'], (string) $item['sum']);
continue; continue;
} }
@@ -373,7 +374,7 @@ class BasicController extends Controller
} }
// unpaid amount // unpaid amount
if ($currencyId === $this->nativeCurrency->id) { if ($currencyId === $this->nativeCurrency->id) {
$newUnpaidAmount[0]['sum'] = bcadd($newUnpaidAmount[0]['sum'], $item['sum']); $newUnpaidAmount[0]['sum'] = bcadd($newUnpaidAmount[0]['sum'], (string) $item['sum']);
continue; continue;
} }
@@ -396,7 +397,7 @@ class BasicController extends Controller
* @var array $info * @var array $info
*/ */
foreach ($paidAmount as $info) { foreach ($paidAmount as $info) {
$amount = bcmul($info['sum'], '-1'); $amount = bcmul((string) $info['sum'], '-1');
$return[] = [ $return[] = [
'key' => sprintf('bills-paid-in-%s', $info['code']), 'key' => sprintf('bills-paid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_paid_in_currency', ['currency' => $info['symbol']]),
@@ -415,7 +416,7 @@ class BasicController extends Controller
* @var array $info * @var array $info
*/ */
foreach ($unpaidAmount as $info) { foreach ($unpaidAmount as $info) {
$amount = bcmul($info['sum'], '-1'); $amount = bcmul((string) $info['sum'], '-1');
$return[] = [ $return[] = [
'key' => sprintf('bills-unpaid-in-%s', $info['code']), 'key' => sprintf('bills-unpaid-in-%s', $info['code']),
'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]), 'title' => trans('firefly.box_bill_unpaid_in_currency', ['currency' => $info['symbol']]),
@@ -482,7 +483,7 @@ class BasicController extends Controller
// first, create an entry for each entry in the "available" array. // first, create an entry for each entry in the "available" array.
/** @var array $availableBudget */ /** @var array $availableBudget */
foreach ($available as $currencyId => $availableBudget) { foreach ($available as $currencyId => $availableBudget) {
$currencies[$currencyId] ??= $this->currencyRepos->find($currencyId); $currencies[$currencyId] ??= $this->currencyRepos->find($currencyId);
$return[$currencyId] = [ $return[$currencyId] = [
'key' => sprintf('left-to-spend-in-%s', $currencies[$currencyId]->code), 'key' => sprintf('left-to-spend-in-%s', $currencies[$currencyId]->code),
@@ -512,7 +513,7 @@ class BasicController extends Controller
continue; continue;
} }
$spentInCurrency = $row['sum']; $spentInCurrency = $row['sum'];
$leftToSpend = bcadd($amount, $spentInCurrency); $leftToSpend = bcadd($amount, (string) $spentInCurrency);
$perDay = '0'; $perDay = '0';
if (0 !== $days && bccomp($leftToSpend, '0') > -1) { if (0 !== $days && bccomp($leftToSpend, '0') > -1) {
$perDay = bcdiv($leftToSpend, (string) $days); $perDay = bcdiv($leftToSpend, (string) $days);
@@ -539,26 +540,63 @@ class BasicController extends Controller
), ),
]; ];
} }
unset($leftToSpend);
if (0 === count($return)) { if (0 === count($return)) {
$currency = $this->nativeCurrency; // a small trick to get every expense in this period, regardless of budget.
$return[$currency->id] = [ $spent = $this->opsRepository->sumExpenses($start, $end, null, new Collection());
'key' => sprintf('left-to-spend-in-%s', $currency->code), foreach ($spent as $row) {
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currency->symbol]), // either an amount was budgeted or 0 is available.
'monetary_value' => '0', $currencyId = (int) $row['currency_id'];
'no_available_budgets' => true, $spentInCurrency = $row['sum'];
'currency_id' => (string) $currency->id, $perDay = '0';
'currency_code' => $currency->code, if (0 !== $days && -1 === bccomp((string) $spentInCurrency, '0')) {
'currency_symbol' => $currency->symbol, $perDay = bcdiv((string) $spentInCurrency, (string) $days);
'currency_decimal_places' => $currency->decimal_places, }
'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
'local_icon' => 'money', Log::debug(sprintf('Spent %s %s', $row['currency_code'], $row['sum']));
'sub_title' => app('amount')->formatFlat(
$currency->symbol, $return[$currencyId] = [
$currency->decimal_places, 'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
'0', 'title' => trans('firefly.spent'),
false 'no_available_budgets' => true,
), 'monetary_value' => $spentInCurrency,
]; 'currency_id' => (string) $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'],
'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $spentInCurrency, false),
'local_icon' => 'money',
'sub_title' => app('amount')->formatFlat(
$row['currency_symbol'],
$row['currency_decimal_places'],
$perDay,
false
),
];
}
// $amount = '0';
// // $days
// // fill in by money spent, just count it.
// $currency = $this->nativeCurrency;
// $return[$currency->id] = [
// 'key' => sprintf('left-to-spend-in-%s', $currency->code),
// 'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $currency->symbol]),
// 'monetary_value' => '0',
// 'no_available_budgets' => true,
// 'currency_id' => (string) $currency->id,
// 'currency_code' => $currency->code,
// 'currency_symbol' => $currency->symbol,
// 'currency_decimal_places' => $currency->decimal_places,
// 'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
// 'local_icon' => 'money',
// 'sub_title' => app('amount')->formatFlat(
// $currency->symbol,
// $currency->decimal_places,
// '0',
// false
// ),
// ];
} }
return array_values($return); return array_values($return);
@@ -593,7 +631,7 @@ class BasicController extends Controller
continue; continue;
} }
$amount = $data['balance']; $amount = $data['balance'];
if (0 === bccomp($amount, '0')) { if (0 === bccomp((string) $amount, '0')) {
continue; continue;
} }
// return stuff // return stuff

View File

@@ -85,7 +85,7 @@ class ChartRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -74,7 +74,7 @@ class MoveTransactionsRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }

View File

@@ -33,6 +33,8 @@ use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
use function Safe\json_decode;
/** /**
* Class TransactionRequest * Class TransactionRequest
*/ */
@@ -74,7 +76,7 @@ class TransactionRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -144,7 +144,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -58,9 +58,7 @@ class StoreRequest extends FormRequest
{ {
$models = config('firefly.valid_attachment_models'); $models = config('firefly.valid_attachment_models');
$models = array_map( $models = array_map(
static function (string $className) { static fn (string $className) => str_replace('FireflyIII\Models\\', '', $className),
return str_replace('FireflyIII\Models\\', '', $className);
},
$models $models
); );
$models = implode(',', $models); $models = implode(',', $models);

View File

@@ -60,9 +60,7 @@ class UpdateRequest extends FormRequest
{ {
$models = config('firefly.valid_attachment_models'); $models = config('firefly.valid_attachment_models');
$models = array_map( $models = array_map(
static function (string $className) { static fn (string $className) => str_replace('FireflyIII\Models\\', '', $className),
return str_replace('FireflyIII\Models\\', '', $className);
},
$models $models
); );
$models = implode(',', $models); $models = implode(',', $models);

View File

@@ -90,7 +90,7 @@ class Request extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -129,7 +129,7 @@ class StoreRequest extends FormRequest
$failed = false; $failed = false;
} }
if ($failed) { if ($failed) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -110,7 +110,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -94,7 +94,7 @@ class StoreRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -106,7 +106,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -96,7 +96,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -45,7 +45,7 @@ class DestroyRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'required|date|after:1900-01-01|before:2099-12-31', 'date' => 'required|date|after:1900-01-01|before:2099-12-31',
]; ];
} }
} }

View File

@@ -40,16 +40,16 @@ class StoreRequest extends FormRequest
return $this->getCarbonDate('date'); return $this->getCarbonDate('date');
} }
public function getRate(): string
{
return (string) $this->get('rate');
}
public function getFromCurrency(): TransactionCurrency public function getFromCurrency(): TransactionCurrency
{ {
return TransactionCurrency::where('code', $this->get('from'))->first(); return TransactionCurrency::where('code', $this->get('from'))->first();
} }
public function getRate(): string
{
return (string) $this->get('rate');
}
public function getToCurrency(): TransactionCurrency public function getToCurrency(): TransactionCurrency
{ {
return TransactionCurrency::where('code', $this->get('to'))->first(); return TransactionCurrency::where('code', $this->get('to'))->first();

View File

@@ -50,8 +50,8 @@ class UpdateRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'date|after:1900-01-01|before:2099-12-31', 'date' => 'date|after:1900-01-01|before:2099-12-31',
'rate' => 'required|numeric|gt:0', 'rate' => 'required|numeric|gt:0',
]; ];
} }
} }

View File

@@ -126,7 +126,7 @@ class StoreRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }

View File

@@ -193,7 +193,7 @@ class StoreRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -208,7 +208,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -148,7 +148,7 @@ class StoreRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }

View File

@@ -168,7 +168,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }

View File

@@ -83,87 +83,87 @@ class StoreRequest extends FormRequest
foreach ($this->get('transactions') as $transaction) { foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction); $object = new NullArrayObject($transaction);
$return[] = [ $return[] = [
'type' => $this->clearString($object['type']), 'type' => $this->clearString($object['type']),
'date' => $this->dateFromValue($object['date']), 'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string) $object['order']), 'order' => $this->integerFromValue((string) $object['order']),
'currency_id' => $this->integerFromValue((string) $object['currency_id']), 'currency_id' => $this->integerFromValue((string) $object['currency_id']),
'currency_code' => $this->clearString((string) $object['currency_code']), 'currency_code' => $this->clearString((string) $object['currency_code']),
// location // location
'latitude' => $this->floatFromValue((string) $object['latitude']), 'latitude' => $this->floatFromValue((string) $object['latitude']),
'longitude' => $this->floatFromValue((string) $object['longitude']), 'longitude' => $this->floatFromValue((string) $object['longitude']),
'zoom_level' => $this->integerFromValue((string) $object['zoom_level']), 'zoom_level' => $this->integerFromValue((string) $object['zoom_level']),
// foreign currency info: // foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string) $object['foreign_currency_id']), 'foreign_currency_id' => $this->integerFromValue((string) $object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string) $object['foreign_currency_code']), 'foreign_currency_code' => $this->clearString((string) $object['foreign_currency_code']),
// amount and foreign amount. Cannot be 0. // amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string) $object['amount']), 'amount' => $this->clearString((string) $object['amount']),
'foreign_amount' => $this->clearString((string) $object['foreign_amount']), 'foreign_amount' => $this->clearString((string) $object['foreign_amount']),
// description. // description.
'description' => $this->clearString($object['description']), 'description' => $this->clearString($object['description']),
// source of transaction. If everything is null, assume cash account. // source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string) $object['source_id']), 'source_id' => $this->integerFromValue((string) $object['source_id']),
'source_name' => $this->clearString((string) $object['source_name']), 'source_name' => $this->clearString((string) $object['source_name']),
'source_iban' => $this->clearIban((string) $object['source_iban']), 'source_iban' => $this->clearIban((string) $object['source_iban']),
'source_number' => $this->clearString((string) $object['source_number']), 'source_number' => $this->clearString((string) $object['source_number']),
'source_bic' => $this->clearString((string) $object['source_bic']), 'source_bic' => $this->clearString((string) $object['source_bic']),
// destination of transaction. If everything is null, assume cash account. // destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string) $object['destination_id']), 'destination_id' => $this->integerFromValue((string) $object['destination_id']),
'destination_name' => $this->clearString((string) $object['destination_name']), 'destination_name' => $this->clearString((string) $object['destination_name']),
'destination_iban' => $this->clearIban((string) $object['destination_iban']), 'destination_iban' => $this->clearIban((string) $object['destination_iban']),
'destination_number' => $this->clearString((string) $object['destination_number']), 'destination_number' => $this->clearString((string) $object['destination_number']),
'destination_bic' => $this->clearString((string) $object['destination_bic']), 'destination_bic' => $this->clearString((string) $object['destination_bic']),
// budget info // budget info
'budget_id' => $this->integerFromValue((string) $object['budget_id']), 'budget_id' => $this->integerFromValue((string) $object['budget_id']),
'budget_name' => $this->clearString((string) $object['budget_name']), 'budget_name' => $this->clearString((string) $object['budget_name']),
// category info // category info
'category_id' => $this->integerFromValue((string) $object['category_id']), 'category_id' => $this->integerFromValue((string) $object['category_id']),
'category_name' => $this->clearString((string) $object['category_name']), 'category_name' => $this->clearString((string) $object['category_name']),
// journal bill reference. Optional. Will only work for withdrawals // journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string) $object['bill_id']), 'bill_id' => $this->integerFromValue((string) $object['bill_id']),
'bill_name' => $this->clearString((string) $object['bill_name']), 'bill_name' => $this->clearString((string) $object['bill_name']),
// piggy bank reference. Optional. Will only work for transfers // piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string) $object['piggy_bank_id']), 'piggy_bank_id' => $this->integerFromValue((string) $object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string) $object['piggy_bank_name']), 'piggy_bank_name' => $this->clearString((string) $object['piggy_bank_name']),
// some other interesting properties // some other interesting properties
'reconciled' => $this->convertBoolean((string) $object['reconciled']), 'reconciled' => $this->convertBoolean((string) $object['reconciled']),
'notes' => $this->clearStringKeepNewlines((string) $object['notes']), 'notes' => $this->clearStringKeepNewlines((string) $object['notes']),
'tags' => $this->arrayFromValue($object['tags']), 'tags' => $this->arrayFromValue($object['tags']),
// all custom fields: // all custom fields:
'internal_reference' => $this->clearString((string) $object['internal_reference']), 'internal_reference' => $this->clearString((string) $object['internal_reference']),
'external_id' => $this->clearString((string) $object['external_id']), 'external_id' => $this->clearString((string) $object['external_id']),
'original_source' => sprintf('ff3-v%s', config('firefly.version')), 'original_source' => sprintf('ff3-v%s', config('firefly.version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']), 'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string) $object['bunq_payment_id']), 'bunq_payment_id' => $this->clearString((string) $object['bunq_payment_id']),
'external_url' => $this->clearString((string) $object['external_url']), 'external_url' => $this->clearString((string) $object['external_url']),
'sepa_cc' => $this->clearString((string) $object['sepa_cc']), 'sepa_cc' => $this->clearString((string) $object['sepa_cc']),
'sepa_ct_op' => $this->clearString((string) $object['sepa_ct_op']), 'sepa_ct_op' => $this->clearString((string) $object['sepa_ct_op']),
'sepa_ct_id' => $this->clearString((string) $object['sepa_ct_id']), 'sepa_ct_id' => $this->clearString((string) $object['sepa_ct_id']),
'sepa_db' => $this->clearString((string) $object['sepa_db']), 'sepa_db' => $this->clearString((string) $object['sepa_db']),
'sepa_country' => $this->clearString((string) $object['sepa_country']), 'sepa_country' => $this->clearString((string) $object['sepa_country']),
'sepa_ep' => $this->clearString((string) $object['sepa_ep']), 'sepa_ep' => $this->clearString((string) $object['sepa_ep']),
'sepa_ci' => $this->clearString((string) $object['sepa_ci']), 'sepa_ci' => $this->clearString((string) $object['sepa_ci']),
'sepa_batch_id' => $this->clearString((string) $object['sepa_batch_id']), 'sepa_batch_id' => $this->clearString((string) $object['sepa_batch_id']),
// custom date fields. Must be Carbon objects. Presence is optional. // custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']), 'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']), 'book_date' => $this->dateFromValue($object['book_date']),
'process_date' => $this->dateFromValue($object['process_date']), 'process_date' => $this->dateFromValue($object['process_date']),
'due_date' => $this->dateFromValue($object['due_date']), 'due_date' => $this->dateFromValue($object['due_date']),
'payment_date' => $this->dateFromValue($object['payment_date']), 'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']), 'invoice_date' => $this->dateFromValue($object['invoice_date']),
]; ];
} }
@@ -300,7 +300,7 @@ class StoreRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -359,7 +359,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -80,7 +80,7 @@ class StoreRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }

View File

@@ -80,7 +80,7 @@ class UpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }

View File

@@ -99,7 +99,7 @@ class UserUpdateRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -61,13 +61,11 @@ class CategoryController extends Controller
$queryParameters = $request->getParameters(); $queryParameters = $request->getParameters();
$result = $this->repository->searchCategory($queryParameters['query'], $queryParameters['size']); $result = $this->repository->searchCategory($queryParameters['query'], $queryParameters['size']);
$filtered = $result->map( $filtered = $result->map(
static function (Category $item) { static fn (Category $item) => [
return [ 'id' => (string) $item->id,
'id' => (string) $item->id, 'title' => $item->name,
'title' => $item->name, 'meta' => [],
'meta' => [], ]
];
}
); );
return response()->json($filtered); return response()->json($filtered);

View File

@@ -61,15 +61,13 @@ class TagController extends Controller
$queryParameters = $request->getParameters(); $queryParameters = $request->getParameters();
$result = $this->repository->searchTag($queryParameters['query']); $result = $this->repository->searchTag($queryParameters['query']);
$filtered = $result->map( $filtered = $result->map(
static function (Tag $item) { static fn (Tag $item) => [
return [ 'id' => (string) $item->id,
'id' => (string) $item->id, 'title' => $item->tag,
'title' => $item->tag, 'value' => (string) $item->id,
'value' => (string) $item->id, 'label' => $item->tag,
'label' => $item->tag, 'meta' => [],
'meta' => [], ]
];
}
); );
return response()->json($filtered); return response()->json($filtered);

View File

@@ -212,13 +212,13 @@ class BudgetController extends Controller
foreach ($currentBudgetArray['transaction_journals'] as $journal) { foreach ($currentBudgetArray['transaction_journals'] as $journal) {
// convert the amount to the native currency. // convert the amount to the native currency.
$rate = $converter->getCurrencyRate($this->currencies[$currencyId], $this->currency, $journal['date']); $rate = $converter->getCurrencyRate($this->currencies[$currencyId], $this->currency, $journal['date']);
$convertedAmount = bcmul($journal['amount'], $rate); $convertedAmount = bcmul((string) $journal['amount'], $rate);
if ($journal['foreign_currency_id'] === $this->currency->id) { if ($journal['foreign_currency_id'] === $this->currency->id) {
$convertedAmount = $journal['foreign_amount']; $convertedAmount = $journal['foreign_amount'];
} }
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $journal['amount']); $return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], (string) $journal['amount']);
$return[$currencyId]['native_spent'] = bcadd($return[$currencyId]['native_spent'], $convertedAmount); $return[$currencyId]['native_spent'] = bcadd($return[$currencyId]['native_spent'], (string) $convertedAmount);
} }
} }
$converter->summarize(); $converter->summarize();
@@ -275,15 +275,15 @@ class BudgetController extends Controller
} }
$result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end); $result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end);
if (1 === count($result)) { if (1 === count($result)) {
$compare = bccomp($limit->amount, app('steam')->positive($result[$limitCurrencyId]['spent'])); $compare = bccomp($limit->amount, (string) app('steam')->positive($result[$limitCurrencyId]['spent']));
if (1 === $compare) { if (1 === $compare) {
// convert this amount into the native currency: // convert this amount into the native currency:
$result[$limitCurrencyId]['left'] = bcadd($limit->amount, $result[$limitCurrencyId]['spent']); $result[$limitCurrencyId]['left'] = bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent']);
$result[$limitCurrencyId]['native_left'] = bcadd($convertedLimitAmount, $result[$limitCurrencyId]['native_spent']); $result[$limitCurrencyId]['native_left'] = bcadd($convertedLimitAmount, (string) $result[$limitCurrencyId]['native_spent']);
} }
if ($compare <= 0) { if ($compare <= 0) {
$result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, $result[$limitCurrencyId]['spent'])); $result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, (string) $result[$limitCurrencyId]['spent']));
$result[$limitCurrencyId]['native_overspent'] = app('steam')->positive(bcadd($convertedLimitAmount, $result[$limitCurrencyId]['native_spent'])); $result[$limitCurrencyId]['native_overspent'] = app('steam')->positive(bcadd($convertedLimitAmount, (string) $result[$limitCurrencyId]['native_spent']));
} }
} }
$converter->summarize(); $converter->summarize();

View File

@@ -100,7 +100,7 @@ class CategoryController extends Controller
$currencyId = (int) $journal['currency_id']; $currencyId = (int) $journal['currency_id'];
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId); $currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
$currencies[$currencyId] = $currency; $currencies[$currencyId] = $currency;
$categoryName = null === $journal['category_name'] ? (string) trans('firefly.no_category') : $journal['category_name']; $categoryName = $journal['category_name'] ?? (string) trans('firefly.no_category');
$amount = app('steam')->positive($journal['amount']); $amount = app('steam')->positive($journal['amount']);
$nativeAmount = $converter->convert($default, $currency, $journal['date'], $amount); $nativeAmount = $converter->convert($default, $currency, $journal['date'], $amount);
$key = sprintf('%s-%s', $categoryName, $currency->code); $key = sprintf('%s-%s', $categoryName, $currency->code);
@@ -128,15 +128,13 @@ class CategoryController extends Controller
]; ];
// add monies // add monies
$return[$key]['amount'] = bcadd($return[$key]['amount'], $amount); $return[$key]['amount'] = bcadd($return[$key]['amount'], (string) $amount);
$return[$key]['native_amount'] = bcadd($return[$key]['native_amount'], $nativeAmount); $return[$key]['native_amount'] = bcadd($return[$key]['native_amount'], (string) $nativeAmount);
} }
$return = array_values($return); $return = array_values($return);
// order by native amount // order by native amount
usort($return, static function (array $a, array $b) { usort($return, static fn (array $a, array $b) => (float) $a['native_amount'] < (float) $b['native_amount'] ? 1 : -1);
return (float) $a['native_amount'] < (float) $b['native_amount'] ? 1 : -1;
});
$converter->summarize(); $converter->summarize();
return response()->json($this->clean($return)); return response()->json($this->clean($return));

View File

@@ -33,7 +33,6 @@ use FireflyIII\Transformers\AbstractTransformer;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Routing\Controller as BaseController; use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Collection;
use League\Fractal\Manager; use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection; use League\Fractal\Resource\Collection as FractalCollection;
@@ -56,8 +55,8 @@ class Controller extends BaseController
protected const string CONTENT_TYPE = 'application/vnd.api+json'; protected const string CONTENT_TYPE = 'application/vnd.api+json';
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY]; protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
protected ParameterBag $parameters;
protected bool $convertToNative = false; protected bool $convertToNative = false;
protected ParameterBag $parameters;
public function __construct() public function __construct()
{ {

View File

@@ -174,8 +174,8 @@ class BasicController extends Controller
* @var array $info * @var array $info
*/ */
foreach ($paidAmount as $info) { foreach ($paidAmount as $info) {
$amount = bcmul($info['sum'], '-1'); $amount = bcmul((string) $info['sum'], '-1');
$nativeAmount = bcmul($info['native_sum'], '-1'); $nativeAmount = bcmul((string) $info['native_sum'], '-1');
$return[] = [ $return[] = [
'key' => sprintf('bills-paid-in-%s', $info['currency_code']), 'key' => sprintf('bills-paid-in-%s', $info['currency_code']),
'value' => $amount, 'value' => $amount,
@@ -198,8 +198,8 @@ class BasicController extends Controller
* @var array $info * @var array $info
*/ */
foreach ($unpaidAmount as $info) { foreach ($unpaidAmount as $info) {
$amount = bcmul($info['sum'], '-1'); $amount = bcmul((string) $info['sum'], '-1');
$nativeAmount = bcmul($info['native_sum'], '-1'); $nativeAmount = bcmul((string) $info['native_sum'], '-1');
$return[] = [ $return[] = [
'key' => sprintf('bills-unpaid-in-%s', $info['currency_code']), 'key' => sprintf('bills-unpaid-in-%s', $info['currency_code']),
'value' => $amount, 'value' => $amount,
@@ -279,8 +279,8 @@ class BasicController extends Controller
if ((int) $journal['foreign_currency_id'] === $default->id) { if ((int) $journal['foreign_currency_id'] === $default->id) {
$amountNative = $journal['foreign_amount']; $amountNative = $journal['foreign_amount'];
} }
$spent = bcadd($spent, $amount); $spent = bcadd($spent, (string) $amount);
$spentNative = bcadd($spentNative, $amountNative); $spentNative = bcadd($spentNative, (string) $amountNative);
} }
app('log')->debug(sprintf('Total spent in budget "%s" is %s', $budget['name'], $spent)); app('log')->debug(sprintf('Total spent in budget "%s" is %s', $budget['name'], $spent));
} }

View File

@@ -84,7 +84,7 @@ class BalanceChartRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -86,7 +86,7 @@ class ChartRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -83,7 +83,7 @@ class DashboardChartRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -311,7 +311,7 @@ class StoreRequest extends FormRequest
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -64,6 +64,7 @@ class UpdateRequest extends Request
* *
* @throws FireflyException * @throws FireflyException
*/ */
#[\Override]
public function getAll(): array public function getAll(): array
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
@@ -247,6 +248,7 @@ class UpdateRequest extends Request
/** /**
* The rules that the incoming request must be matched against. * The rules that the incoming request must be matched against.
*/ */
#[\Override]
public function rules(): array public function rules(): array
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
@@ -330,6 +332,7 @@ class UpdateRequest extends Request
/** /**
* Configure the validator instance. * Configure the validator instance.
*/ */
#[\Override]
public function withValidator(Validator $validator): void public function withValidator(Validator $validator): void
{ {
app('log')->debug('Now in withValidator'); app('log')->debug('Now in withValidator');
@@ -361,7 +364,7 @@ class UpdateRequest extends Request
} }
); );
if ($validator->fails()) { if ($validator->fails()) {
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); Log::channel('audit')->error(sprintf('Validation errors in %s', self::class), $validator->errors()->toArray());
} }
} }
} }

View File

@@ -75,6 +75,65 @@ class CorrectsAmounts extends Command
return 0; return 0;
} }
private function correctTransfers(): void
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$type = TransactionType::where('type', TransactionTypeEnum::TRANSFER->value)->first();
$journals = TransactionJournal::where('transaction_type_id', $type->id)->get();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$repository->setUser($journal->user);
$native = Amount::getNativeCurrencyByUserGroup($journal->userGroup);
/** @var null|Transaction $source */
$source = $journal->transactions()->where('amount', '<', 0)->first();
/** @var null|Transaction $destination */
$destination = $journal->transactions()->where('amount', '>', 0)->first();
if (null === $source || null === $destination) {
continue;
}
if (null === $source->foreign_currency_id || null === $destination->foreign_currency_id) {
continue;
}
$sourceAccount = $source->account;
$destAccount = $destination->account;
if (null === $sourceAccount || null === $destAccount) {
continue;
}
$sourceCurrency = $repository->getAccountCurrency($sourceAccount) ?? $native;
$destCurrency = $repository->getAccountCurrency($destAccount) ?? $native;
if ($sourceCurrency->id === $destCurrency->id) {
Log::debug('Both accounts have the same currency. Removing foreign currency info.');
$source->foreign_currency_id = null;
$source->foreign_amount = null;
$source->save();
$destination->foreign_currency_id = null;
$destination->foreign_amount = null;
$destination->save();
continue;
}
// validate source
if ($destCurrency->id !== $source->foreign_currency_id) {
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $source->id, $source->foreignCurrency->code, $destCurrency->code));
$source->foreign_currency_id = $destCurrency->id;
$source->save();
}
// validate destination:
if ($sourceCurrency->id !== $destination->foreign_currency_id) {
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $destination->id, $destination->foreignCurrency->code, $sourceCurrency->code));
$destination->foreign_currency_id = $sourceCurrency->id;
$destination->save();
}
}
}
private function fixAutoBudgets(): void private function fixAutoBudgets(): void
{ {
$count = AutoBudget::where('amount', '<', 0)->update(['amount' => DB::raw('amount * -1')]); $count = AutoBudget::where('amount', '<', 0)->update(['amount' => DB::raw('amount * -1')]);
@@ -175,7 +234,7 @@ class CorrectsAmounts extends Command
{ {
try { try {
$check = bccomp((string) $item->trigger_value, '0'); $check = bccomp((string) $item->trigger_value, '0');
} catch (\ValueError $e) { } catch (\ValueError) {
$this->friendlyError(sprintf('Rule #%d contained invalid %s-trigger "%s". The trigger has been removed, and the rule is disabled.', $item->rule_id, $item->trigger_type, $item->trigger_value)); $this->friendlyError(sprintf('Rule #%d contained invalid %s-trigger "%s". The trigger has been removed, and the rule is disabled.', $item->rule_id, $item->trigger_type, $item->trigger_value));
$item->rule->active = false; $item->rule->active = false;
$item->rule->save(); $item->rule->save();
@@ -192,63 +251,4 @@ class CorrectsAmounts extends Command
return false; return false;
} }
private function correctTransfers(): void
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$type = TransactionType::where('type', TransactionTypeEnum::TRANSFER->value)->first();
$journals = TransactionJournal::where('transaction_type_id', $type->id)->get();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$repository->setUser($journal->user);
$native = Amount::getNativeCurrencyByUserGroup($journal->userGroup);
/** @var null|Transaction $source */
$source = $journal->transactions()->where('amount', '<', 0)->first();
/** @var null|Transaction $destination */
$destination = $journal->transactions()->where('amount', '>', 0)->first();
if (null === $source || null === $destination) {
continue;
}
if (null === $source->foreign_currency_id || null === $destination->foreign_currency_id) {
continue;
}
$sourceAccount = $source->account;
$destAccount = $destination->account;
if (null === $sourceAccount || null === $destAccount) {
continue;
}
$sourceCurrency = $repository->getAccountCurrency($sourceAccount) ?? $native;
$destCurrency = $repository->getAccountCurrency($destAccount) ?? $native;
if ($sourceCurrency->id === $destCurrency->id) {
Log::debug('Both accounts have the same currency. Removing foreign currency info.');
$source->foreign_currency_id = null;
$source->foreign_amount = null;
$source->save();
$destination->foreign_currency_id = null;
$destination->foreign_amount = null;
$destination->save();
continue;
}
// validate source
if ($destCurrency->id !== $source->foreign_currency_id) {
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $source->id, $source->foreignCurrency->code, $destCurrency->code));
$source->foreign_currency_id = $destCurrency->id;
$source->save();
}
// validate destination:
if ($sourceCurrency->id !== $destination->foreign_currency_id) {
Log::debug(sprintf('Journal #%d: Transaction #%d refers to "%s" but should refer to "%s".', $journal->id, $destination->id, $destination->foreignCurrency->code, $sourceCurrency->code));
$destination->foreign_currency_id = $sourceCurrency->id;
$destination->save();
}
}
}
} }

View File

@@ -115,9 +115,7 @@ class CorrectsCurrencies extends Command
$found = array_values( $found = array_values(
array_filter( array_filter(
$found, $found,
static function (int $currencyId) { static fn (int $currencyId) => 0 !== $currencyId
return 0 !== $currencyId;
}
) )
); );

View File

@@ -48,8 +48,8 @@ class CorrectsLongDescriptions extends Command
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
if (strlen($journal->description) > self::MAX_LENGTH) { if (strlen((string) $journal->description) > self::MAX_LENGTH) {
$journal->description = substr($journal->description, 0, self::MAX_LENGTH); $journal->description = substr((string) $journal->description, 0, self::MAX_LENGTH);
$journal->save(); $journal->save();
$this->friendlyWarning(sprintf('Truncated description of transaction journal #%d', $journal->id)); $this->friendlyWarning(sprintf('Truncated description of transaction journal #%d', $journal->id));
++$count; ++$count;
@@ -61,7 +61,7 @@ class CorrectsLongDescriptions extends Command
/** @var TransactionGroup $group */ /** @var TransactionGroup $group */
foreach ($groups as $group) { foreach ($groups as $group) {
if (strlen((string) $group->title) > self::MAX_LENGTH) { if (strlen((string) $group->title) > self::MAX_LENGTH) {
$group->title = substr($group->title, 0, self::MAX_LENGTH); $group->title = substr((string) $group->title, 0, self::MAX_LENGTH);
$group->save(); $group->save();
$this->friendlyWarning(sprintf('Truncated description of transaction group #%d', $group->id)); $this->friendlyWarning(sprintf('Truncated description of transaction group #%d', $group->id));
++$count; ++$count;

View File

@@ -38,8 +38,8 @@ use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Support\Facades\Preferences; use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\ExchangeRateConverter; use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use Illuminate\Console\Command; use Illuminate\Console\Command;
@@ -128,9 +128,7 @@ class CorrectsNativeAmounts extends Command
$repository->setUserGroup($userGroup); $repository->setUserGroup($userGroup);
$set = $repository->getPiggyBanks(); $set = $repository->getPiggyBanks();
$set = $set->filter( $set = $set->filter(
static function (PiggyBank $piggyBank) use ($currency) { static fn (PiggyBank $piggyBank) => $currency->id !== $piggyBank->transaction_currency_id
return $currency->id !== $piggyBank->transaction_currency_id;
}
); );
foreach ($set as $piggyBank) { foreach ($set as $piggyBank) {
$piggyBank->encrypted = false; $piggyBank->encrypted = false;

View File

@@ -100,7 +100,7 @@ class CorrectsRecurringTransactions extends Command
$destination = $transaction->destinationAccount; $destination = $transaction->destinationAccount;
$type = $recurrence->transactionType; $type = $recurrence->transactionType;
$link = config(sprintf('firefly.account_to_transaction.%s.%s', $source->accountType->type, $destination->accountType->type)); $link = config(sprintf('firefly.account_to_transaction.%s.%s', $source->accountType->type, $destination->accountType->type));
if (null !== $link && strtolower($type->type) !== strtolower($link)) { if (null !== $link && strtolower((string) $type->type) !== strtolower($link)) {
$this->friendlyWarning( $this->friendlyWarning(
sprintf('Recurring transaction #%d should be a "%s" but is a "%s" and will be corrected.', $recurrence->id, $link, $type->type) sprintf('Recurring transaction #%d should be a "%s" but is a "%s" and will be corrected.', $recurrence->id, $link, $type->type)
); );

View File

@@ -115,9 +115,7 @@ class CorrectsTransactionTypes extends Command
private function getSourceAccount(TransactionJournal $journal): Account private function getSourceAccount(TransactionJournal $journal): Account
{ {
$collection = $journal->transactions->filter( $collection = $journal->transactions->filter(
static function (Transaction $transaction) { static fn (Transaction $transaction) => $transaction->amount < 0
return $transaction->amount < 0;
}
); );
if (0 === $collection->count()) { if (0 === $collection->count()) {
throw new FireflyException(sprintf('300001: Journal #%d has no source transaction.', $journal->id)); throw new FireflyException(sprintf('300001: Journal #%d has no source transaction.', $journal->id));
@@ -144,9 +142,7 @@ class CorrectsTransactionTypes extends Command
private function getDestinationAccount(TransactionJournal $journal): Account private function getDestinationAccount(TransactionJournal $journal): Account
{ {
$collection = $journal->transactions->filter( $collection = $journal->transactions->filter(
static function (Transaction $transaction) { static fn (Transaction $transaction) => $transaction->amount > 0
return $transaction->amount > 0;
}
); );
if (0 === $collection->count()) { if (0 === $collection->count()) {
throw new FireflyException(sprintf('300004: Journal #%d has no destination transaction.', $journal->id)); throw new FireflyException(sprintf('300004: Journal #%d has no destination transaction.', $journal->id));

View File

@@ -25,9 +25,11 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction; namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum; use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Models\Transaction; use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Models\AccountBalanceCalculator; use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@@ -47,7 +49,12 @@ class CorrectsUnevenAmount extends Command
public function handle(): int public function handle(): int
{ {
$this->count = 0; $this->count = 0;
// convert transfers with foreign currency info where the amount is NOT uneven (it should be)
$this->convertOldStyleTransfers(); $this->convertOldStyleTransfers();
// convert old-style transactions between assets and liabilities.
$this->convertOldStyleTransactions();
$this->fixUnevenAmounts(); $this->fixUnevenAmounts();
$this->matchCurrencies(); $this->matchCurrencies();
if (true === config('firefly.feature_flags.running_balance_column')) { if (true === config('firefly.feature_flags.running_balance_column')) {
@@ -72,8 +79,6 @@ class CorrectsUnevenAmount extends Command
; ;
$count = 0; $count = 0;
Log::debug(sprintf('Found %d potential journal(s)', $transactions->count()));
/** @var Transaction $transaction */ /** @var Transaction $transaction */
foreach ($transactions as $transaction) { foreach ($transactions as $transaction) {
/** @var null|TransactionJournal $journal */ /** @var null|TransactionJournal $journal */
@@ -115,10 +120,15 @@ class CorrectsUnevenAmount extends Command
++$count; ++$count;
} }
} }
if (0 === $count) {
return;
}
$this->friendlyPositive(sprintf('Fixed %d transfer(s) with unbalanced amounts.', $count));
} }
private function fixUnevenAmounts(): void private function fixUnevenAmounts(): void
{ {
Log::debug('fixUnevenAmounts()');
$journals = DB::table('transactions') $journals = DB::table('transactions')
->groupBy('transaction_journal_id') ->groupBy('transaction_journal_id')
->whereNull('deleted_at') ->whereNull('deleted_at')
@@ -153,7 +163,7 @@ class CorrectsUnevenAmount extends Command
Log::error($e->getTraceAsString()); Log::error($e->getTraceAsString());
} }
if (0 !== $res) { if (0 !== $res) {
$this->fixJournal($entry->transaction_journal_id); $this->fixJournal((int) $entry->transaction_journal_id);
} }
} }
} }
@@ -184,7 +194,7 @@ class CorrectsUnevenAmount extends Command
return; return;
} }
$amount = bcmul('-1', $source->amount); $amount = bcmul('-1', (string) $source->amount);
// fix amount of destination: // fix amount of destination:
/** @var null|Transaction $destination */ /** @var null|Transaction $destination */
@@ -207,8 +217,8 @@ class CorrectsUnevenAmount extends Command
} }
// may still be able to salvage this journal if it is a transfer with foreign currency info // may still be able to salvage this journal if it is a transfer with foreign currency info
if ($this->isForeignCurrencyTransfer($journal)) { if ($this->isForeignCurrencyTransfer($journal) || $this->isBetweenAssetAndLiability($journal)) {
Log::debug(sprintf('Can skip foreign currency transfer #%d.', $journal->id)); Log::debug(sprintf('Can skip foreign currency transfer / asset+liability transaction #%d.', $journal->id));
return; return;
} }
@@ -249,9 +259,9 @@ class CorrectsUnevenAmount extends Command
// Log::debug(sprintf('[c] %s', var_export($source->transaction_currency_id === $destination->foreign_currency_id,true))); // Log::debug(sprintf('[c] %s', var_export($source->transaction_currency_id === $destination->foreign_currency_id,true)));
// Log::debug(sprintf('[d] %s', var_export((int) $destination->transaction_currency_id ===(int) $source->foreign_currency_id, true))); // Log::debug(sprintf('[d] %s', var_export((int) $destination->transaction_currency_id ===(int) $source->foreign_currency_id, true)));
if (0 === bccomp(app('steam')->positive($source->amount), app('steam')->positive($destination->foreign_amount)) if (0 === bccomp((string) app('steam')->positive($source->amount), (string) app('steam')->positive($destination->foreign_amount))
&& $source->transaction_currency_id === $destination->foreign_currency_id && $source->transaction_currency_id === $destination->foreign_currency_id
&& 0 === bccomp(app('steam')->positive($destination->amount), app('steam')->positive($source->foreign_amount)) && 0 === bccomp((string) app('steam')->positive($destination->amount), (string) app('steam')->positive($source->foreign_amount))
&& (int) $destination->transaction_currency_id === (int) $source->foreign_currency_id && (int) $destination->transaction_currency_id === (int) $source->foreign_currency_id
) { ) {
return true; return true;
@@ -271,13 +281,13 @@ class CorrectsUnevenAmount extends Command
/** @var TransactionJournal $journal */ /** @var TransactionJournal $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
if (!$this->isForeignCurrencyTransfer($journal)) { if (!$this->isForeignCurrencyTransfer($journal) && !$this->isBetweenAssetAndLiability($journal)) {
Transaction::where('transaction_journal_id', $journal->id)->update(['transaction_currency_id' => $journal->transaction_currency_id]); Transaction::where('transaction_journal_id', $journal->id)->update(['transaction_currency_id' => $journal->transaction_currency_id]);
++$count; ++$count;
continue; continue;
} }
Log::debug(sprintf('Can skip foreign currency transfer #%d.', $journal->id)); Log::debug(sprintf('Can skip foreign currency transfer or transaction between asset and liability #%d.', $journal->id));
} }
if (0 === $count) { if (0 === $count) {
return; return;
@@ -285,4 +295,155 @@ class CorrectsUnevenAmount extends Command
$this->friendlyPositive(sprintf('Fixed %d journal(s) with mismatched currencies.', $journals->count())); $this->friendlyPositive(sprintf('Fixed %d journal(s) with mismatched currencies.', $journals->count()));
} }
private function isBetweenAssetAndLiability(TransactionJournal $journal): bool
{
/** @var Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
/** @var Transaction $destinationTransaction */
$destinationTransaction = $journal->transactions()->where('amount', '>', 0)->first();
if (null === $sourceTransaction || null === $destinationTransaction) {
Log::warning('Either transaction is false, stop.');
return false;
}
if (null === $sourceTransaction->foreign_amount || null === $destinationTransaction->foreign_amount) {
Log::warning('Either foreign amount is false, stop.');
return false;
}
$source = $sourceTransaction->account;
$destination = $destinationTransaction->account;
if (null === $source || null === $destination) {
Log::warning('Either is false, stop.');
return false;
}
$sourceTypes = [AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value];
// source is liability, destination is asset
if (in_array($source->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $destination->accountType->type) {
Log::debug('Source is a liability account, destination is an asset account, return TRUE.');
return true;
}
// source is asset, destination is liability
if (in_array($destination->accountType->type, $sourceTypes, true) && AccountTypeEnum::ASSET->value === $source->accountType->type) {
Log::debug('Destination is a liability account, source is an asset account, return TRUE.');
return true;
}
return false;
}
private function convertOldStyleTransactions(): void
{
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
Log::debug('convertOldStyleTransactions()');
$count = 0;
$transactions = Transaction::distinct()
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id')
->leftJoin('accounts', 'accounts.id', 'transactions.account_id')
->leftJoin('account_types', 'account_types.id', 'accounts.account_type_id')
->whereNot('transaction_types.type', TransactionTypeEnum::TRANSFER->value)
->whereNotNull('foreign_currency_id')
->whereNotNull('foreign_amount')
->whereIn('account_types.type', [AccountTypeEnum::ASSET->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::LOAN->value])
->get(['transactions.transaction_journal_id'])
;
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
/** @var null|TransactionJournal $journal */
$journal = TransactionJournal::find($transaction->transaction_journal_id);
$repository->setUser($journal->user);
if (null === $journal) {
Log::debug('Found no journal, continue.');
continue;
}
if (!$this->isBetweenAssetAndLiability($journal)) {
Log::debug('Not between asset and liability, continue.');
continue;
}
$source = $journal->transactions()->where('amount', '<', 0)->first();
$destination = $journal->transactions()->where('amount', '>', 0)->first();
$sourceAccount = $source->account;
$destAccount = $destination->account;
$sourceCurrency = $repository->getAccountCurrency($sourceAccount);
$destCurrency = $repository->getAccountCurrency($destAccount);
if (null === $source || null === $destination) {
Log::debug('Either transaction is NULL, continue.');
continue;
}
if (0 === bccomp($source->amount, $source->foreign_amount) && 0 === bccomp($source->foreign_amount, $source->amount)) {
Log::debug('Already fixed, continue.');
continue;
}
// source transaction. Switch info when does not match.
if ((int) $source->transaction_currency_id !== (int) $sourceCurrency->id) {
Log::debug(sprintf('Ready to swap data in transaction #%d.', $source->id));
// swap amounts.
$amount = $source->amount;
$currency = $source->transaction_currency_id;
$source->amount = $source->foreign_amount;
$source->transaction_currency_id = $source->foreign_currency_id;
$source->foreign_amount = $amount;
$source->foreign_currency_id = $currency;
$source->saveQuietly();
$source->refresh();
// Log::debug(sprintf('source->amount = %s', $source->amount));
// Log::debug(sprintf('source->transaction_currency_id = %s', $source->transaction_currency_id));
// Log::debug(sprintf('source->foreign_amount = %s', $source->foreign_amount));
// Log::debug(sprintf('source->foreign_currency_id = %s', $source->foreign_currency_id));
++$count;
}
// same but for destination
if ((int) $destination->transaction_currency_id !== (int) $destCurrency->id) {
++$count;
Log::debug(sprintf('Ready to swap data in transaction #%d.', $destination->id));
// swap amounts.
$amount = $destination->amount;
$currency = $destination->transaction_currency_id;
$destination->amount = $destination->foreign_amount;
$destination->transaction_currency_id = $destination->foreign_currency_id;
$destination->foreign_amount = $amount;
$destination->foreign_currency_id = $currency;
$destination->balance_dirty = true;
$destination->saveQuietly();
$destination->refresh();
// Log::debug(sprintf('destination->amount = %s', $destination->amount));
// Log::debug(sprintf('destination->transaction_currency_id = %s', $destination->transaction_currency_id));
// Log::debug(sprintf('destination->foreign_amount = %s', $destination->foreign_amount));
// Log::debug(sprintf('destination->foreign_currency_id = %s', $destination->foreign_currency_id));
}
// // only fix the destination transaction
// $destination->foreign_currency_id = $source->transaction_currency_id;
// $destination->foreign_amount = app('steam')->positive($source->amount);
// $destination->transaction_currency_id = $source->foreign_currency_id;
// $destination->amount = app('steam')->positive($source->foreign_amount);
// $destination->balance_dirty = true;
// $source->balance_dirty = true;
// $destination->save();
// $source->save();
// $this->friendlyWarning(sprintf('Corrected foreign amounts of transaction #%d.', $journal->id));
}
if (0 === $count) {
return;
}
$this->friendlyPositive(sprintf('Fixed %d journal(s) with unbalanced amounts.', $count));
}
} }

View File

@@ -283,7 +283,7 @@ class ExportsData extends Command
$this->friendlyWarning(sprintf('File "%s" exists already but will be replaced.', $file)); $this->friendlyWarning(sprintf('File "%s" exists already but will be replaced.', $file));
} }
// continue to write to file. // continue to write to file.
file_put_contents($file, $content); \Safe\file_put_contents($file, $content);
$this->friendlyPositive(sprintf('Wrote %s-export to file "%s".', $key, $file)); $this->friendlyPositive(sprintf('Wrote %s-export to file "%s".', $key, $file));
} }
} }

View File

@@ -30,13 +30,6 @@ class ValidatesEnvironmentVariables extends Command
{ {
use ShowsFriendlyMessages; use ShowsFriendlyMessages;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'integrity:validates-environment-variables';
/** /**
* The console command description. * The console command description.
* *
@@ -44,6 +37,13 @@ class ValidatesEnvironmentVariables extends Command
*/ */
protected $description = 'Makes sure you use the correct variables.'; protected $description = 'Makes sure you use the correct variables.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'integrity:validates-environment-variables';
/** /**
* Execute the console command. * Execute the console command.
*/ */

View File

@@ -130,7 +130,7 @@ class ForcesDecimalSize extends Command
// if sqlite, add function? // 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) { DB::connection()->getPdo()->sqliteCreateFunction('REGEXP', static function ($pattern, $value) {
mb_regex_encoding('UTF-8'); \Safe\mb_regex_encoding('UTF-8');
$pattern = trim($pattern, '"'); $pattern = trim($pattern, '"');
return (false !== mb_ereg($pattern, (string) $value)) ? 1 : 0; return (false !== mb_ereg($pattern, (string) $value)) ? 1 : 0;
@@ -234,7 +234,7 @@ class ForcesDecimalSize extends Command
/** @var Builder $query */ /** @var Builder $query */
$query = Account::leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') $query = Account::leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id') ->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string) $currency->id)) ->where('account_meta.data', \Safe\json_encode((string) $currency->id))
; ;
$query->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { $query->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void {
foreach ($fields as $field) { foreach ($fields as $field) {
@@ -338,7 +338,7 @@ class ForcesDecimalSize extends Command
->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') ->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id') ->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string) $currency->id)) ->where('account_meta.data', \Safe\json_encode((string) $currency->id))
->where(static function (Builder $q) use ($fields, $currency, $cast, $operator, $regularExpression): void { ->where(static function (Builder $q) use ($fields, $currency, $cast, $operator, $regularExpression): void {
foreach ($fields as $field) { foreach ($fields as $field) {
$q->orWhere( $q->orWhere(
@@ -394,7 +394,7 @@ class ForcesDecimalSize extends Command
->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') ->leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id') ->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string) $currency->id)) ->where('account_meta.data', \Safe\json_encode((string) $currency->id))
->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void {
foreach ($fields as $field) { foreach ($fields as $field) {
$q->orWhere( $q->orWhere(
@@ -448,7 +448,7 @@ class ForcesDecimalSize extends Command
$query = PiggyBank::leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id') $query = PiggyBank::leftJoin('accounts', 'piggy_banks.account_id', '=', 'accounts.id')
->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id') ->leftJoin('account_meta', 'accounts.id', '=', 'account_meta.account_id')
->where('account_meta.name', 'currency_id') ->where('account_meta.name', 'currency_id')
->where('account_meta.data', json_encode((string) $currency->id)) ->where('account_meta.data', \Safe\json_encode((string) $currency->id))
->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void { ->where(static function (Builder $q) use ($fields, $currency, $operator, $cast, $regularExpression): void {
foreach ($fields as $field) { foreach ($fields as $field) {
$q->orWhere( $q->orWhere(

View File

@@ -147,10 +147,7 @@ class OutputsInstructions extends Command
*/ */
private function showLine(): void private function showLine(): void
{ {
$line = '+'; $this->line(sprintf('+%s+', str_repeat('-', 78)));
$line .= str_repeat('-', 78);
$line .= '+';
$this->line($line);
} }
/** /**
@@ -175,6 +172,13 @@ class OutputsInstructions extends Command
} }
} }
private function donationText(): void
{
$this->boxed('Did you know you can support the development of Firefly III?');
$this->boxed('You can donate in many ways, like GitHub Sponsors or Patreon.');
$this->boxed('For more information, please visit https://bit.ly/donate-to-Firefly-III');
}
/** /**
* Render instructions. * Render instructions.
*/ */
@@ -228,11 +232,4 @@ class OutputsInstructions extends Command
$this->boxed(''); $this->boxed('');
$this->showLine(); $this->showLine();
} }
private function donationText(): void
{
$this->boxed('Did you know you can support the development of Firefly III?');
$this->boxed('You can donate in many ways, like GitHub Sponsors or Patreon.');
$this->boxed('For more information, please visit https://bit.ly/donate-to-Firefly-III');
}
} }

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
/*
* RecalculatesRunningBalance.php
* Copyright (c) 2025 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
namespace FireflyIII\Console\Commands\System;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Support\Models\AccountBalanceCalculator;
use Illuminate\Console\Command;
class RecalculatesRunningBalance extends Command
{
use ShowsFriendlyMessages;
/**
* The console command description.
*
* @var string
*/
protected $description = 'Refreshes all running balances. May take a long time to run if forced.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:refresh-running-balance {--F|force : Force the execution of this command.}';
/**
* Execute the console command.
*/
public function handle()
{
if (true === config('firefly.feature_flags.running_balance_column')) {
$this->friendlyInfo('Will recalculate account balances. This may take a LONG time. Please be patient.');
$this->correctBalanceAmounts($this->option('force'));
$this->friendlyInfo('Done recalculating account balances.');
return 0;
}
$this->friendlyWarning('This command has been disabled.');
}
private function correctBalanceAmounts(bool $forced): void
{
AccountBalanceCalculator::recalculateAll($forced);
}
}

View File

@@ -63,15 +63,15 @@ class ScansAttachments extends Command
app('log')->error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage())); app('log')->error(sprintf('Could not decrypt data of attachment #%d: %s', $attachment->id, $e->getMessage()));
$decryptedContent = $encryptedContent; $decryptedContent = $encryptedContent;
} }
$tempFileName = tempnam(sys_get_temp_dir(), 'FireflyIII'); $tempFileName = \Safe\tempnam(sys_get_temp_dir(), 'FireflyIII');
if (false === $tempFileName) { if (false === $tempFileName) {
app('log')->error(sprintf('Could not create temporary file for attachment #%d', $attachment->id)); app('log')->error(sprintf('Could not create temporary file for attachment #%d', $attachment->id));
exit(1); exit(1);
} }
file_put_contents($tempFileName, $decryptedContent); \Safe\file_put_contents($tempFileName, $decryptedContent);
$attachment->md5 = (string) md5_file($tempFileName); $attachment->md5 = (string) \Safe\md5_file($tempFileName);
$attachment->mime = (string) mime_content_type($tempFileName); $attachment->mime = (string) \Safe\mime_content_type($tempFileName);
$attachment->save(); $attachment->save();
$this->friendlyInfo(sprintf('Fixed attachment #%d', $attachment->id)); $this->friendlyInfo(sprintf('Fixed attachment #%d', $attachment->id));
} }

View File

@@ -57,7 +57,7 @@ class VerifySecurityAlerts extends Command
return 0; return 0;
} }
$content = $disk->get('alerts.json'); $content = $disk->get('alerts.json');
$json = json_decode($content, true, 10); $json = \Safe\json_decode($content, true, 10);
/** @var array $array */ /** @var array $array */
foreach ($json as $array) { foreach ($json as $array) {

View File

@@ -150,6 +150,23 @@ class Cron extends Command
} }
} }
private function checkForUpdates(bool $force): void
{
$updateCheck = new UpdateCheckCronjob();
$updateCheck->setForce($force);
$updateCheck->fire();
if ($updateCheck->jobErrored) {
$this->friendlyError(sprintf('Error in "update check" cron: %s', $updateCheck->message));
}
if ($updateCheck->jobFired) {
$this->friendlyInfo(sprintf('"Update check" cron fired: %s', $updateCheck->message));
}
if ($updateCheck->jobSucceeded) {
$this->friendlyPositive(sprintf('"Update check" cron ran with success: %s', $updateCheck->message));
}
}
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
@@ -221,21 +238,4 @@ class Cron extends Command
$this->friendlyPositive(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message)); $this->friendlyPositive(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
} }
} }
private function checkForUpdates(bool $force): void
{
$updateCheck = new UpdateCheckCronjob();
$updateCheck->setForce($force);
$updateCheck->fire();
if ($updateCheck->jobErrored) {
$this->friendlyError(sprintf('Error in "update check" cron: %s', $updateCheck->message));
}
if ($updateCheck->jobFired) {
$this->friendlyInfo(sprintf('"Update check" cron fired: %s', $updateCheck->message));
}
if ($updateCheck->jobSucceeded) {
$this->friendlyPositive(sprintf('"Update check" cron ran with success: %s', $updateCheck->message));
}
}
} }

View File

@@ -167,7 +167,7 @@ class RemovesDatabaseDecryption extends Command
{ {
// try to json_decrypt the value. // try to json_decrypt the value.
try { try {
$newValue = json_decode($value, true, 512, JSON_THROW_ON_ERROR) ?? $value; $newValue = \Safe\json_decode($value, true, 512, JSON_THROW_ON_ERROR) ?? $value;
} catch (\JsonException $e) { } catch (\JsonException $e) {
$message = sprintf('Could not JSON decode preference row #%d: %s. This does not have to be a problem.', $id, $e->getMessage()); $message = sprintf('Could not JSON decode preference row #%d: %s. This does not have to be a problem.', $id, $e->getMessage());
$this->friendlyError($message); $this->friendlyError($message);

View File

@@ -24,7 +24,14 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Upgrade; namespace FireflyIII\Console\Commands\Upgrade;
set_time_limit(0); use Illuminate\Support\Facades\Log;
use Safe\Exceptions\InfoException;
try {
\Safe\set_time_limit(0);
} catch (InfoException) {
Log::warning('set_time_limit returned false. This could be an issue, unless you also run XDebug.');
}
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use Illuminate\Console\Command; use Illuminate\Console\Command;

View File

@@ -32,6 +32,7 @@ use Illuminate\Support\Facades\Artisan;
class UpgradesNativeAmounts extends Command class UpgradesNativeAmounts extends Command
{ {
use ShowsFriendlyMessages; use ShowsFriendlyMessages;
public const string CONFIG_NAME = '620_native_amounts'; public const string CONFIG_NAME = '620_native_amounts';
protected $description = 'Runs the native amounts calculations.'; protected $description = 'Runs the native amounts calculations.';
@@ -61,7 +62,7 @@ class UpgradesNativeAmounts extends Command
{ {
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false); $configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
if (null !== $configVar) { if (null !== $configVar) {
return (bool)$configVar->data; return (bool) $configVar->data;
} }
return false; return false;

View File

@@ -100,7 +100,7 @@ class UpgradesRecurrenceMetaData extends Command
if ('tags' === $meta->name) { if ('tags' === $meta->name) {
$array = explode(',', $meta->value); $array = explode(',', $meta->value);
$value = json_encode($array, JSON_THROW_ON_ERROR); $value = \Safe\json_encode($array, JSON_THROW_ON_ERROR);
} }
RecurrenceTransactionMeta::create( RecurrenceTransactionMeta::create(

View File

@@ -78,8 +78,8 @@ class UpgradesRuleActions extends Command
/** @var RuleAction $action */ /** @var RuleAction $action */
foreach ($actions as $action) { foreach ($actions as $action) {
if (str_starts_with($action->action_value, '=')) { if (str_starts_with((string) $action->action_value, '=')) {
$action->action_value = sprintf('%s%s', '\=', substr($action->action_value, 1)); $action->action_value = sprintf('%s%s', '\=', substr((string) $action->action_value, 1));
$action->save(); $action->save();
++$count; ++$count;
} }

View File

@@ -179,9 +179,7 @@ class UpgradesToGroups extends Command
private function getDestinationTransactions(TransactionJournal $journal): Collection private function getDestinationTransactions(TransactionJournal $journal): Collection
{ {
return $journal->transactions->filter( return $journal->transactions->filter(
static function (Transaction $transaction) { static fn (Transaction $transaction) => $transaction->amount > 0
return $transaction->amount > 0;
}
); );
} }
@@ -236,7 +234,7 @@ class UpgradesToGroups extends Command
$categoryId = $this->getTransactionCategory($transaction, $opposingTr) ?? $categoryId; $categoryId = $this->getTransactionCategory($transaction, $opposingTr) ?? $categoryId;
return [ return [
'type' => strtolower($journal->transactionType->type), 'type' => strtolower((string) $journal->transactionType->type),
'date' => $journal->date, 'date' => $journal->date,
'user' => $journal->user, 'user' => $journal->user,
'user_group' => $journal->user->userGroup, 'user_group' => $journal->user->userGroup,

View File

@@ -38,20 +38,20 @@ class UpgradesTransferCurrencies extends Command
{ {
use ShowsFriendlyMessages; use ShowsFriendlyMessages;
public const string CONFIG_NAME = '480_transfer_currencies'; public const string CONFIG_NAME = '480_transfer_currencies';
protected $description = 'Updates transfer currency information.'; protected $description = 'Updates transfer currency information.';
protected $signature = 'upgrade:480-transfer-currencies {--F|force : Force the execution of this command.}'; protected $signature = 'upgrade:480-transfer-currencies {--F|force : Force the execution of this command.}';
private array $accountCurrencies; private array $accountCurrencies;
private AccountRepositoryInterface $accountRepos; private AccountRepositoryInterface $accountRepos;
private JournalCLIRepositoryInterface $cliRepos; private JournalCLIRepositoryInterface $cliRepos;
private int $count; private int $count;
private ?Account $destinationAccount; private ?Account $destinationAccount = null;
private ?TransactionCurrency $destinationCurrency; private ?TransactionCurrency $destinationCurrency = null;
private ?Transaction $destinationTransaction; private ?Transaction $destinationTransaction = null;
private ?Account $sourceAccount; private ?Account $sourceAccount = null;
private ?TransactionCurrency $sourceCurrency; private ?TransactionCurrency $sourceCurrency = null;
private ?Transaction $sourceTransaction; private ?Transaction $sourceTransaction = null;
/** /**
* Execute the console command. * Execute the console command.

View File

@@ -35,6 +35,7 @@ class Kernel extends ConsoleKernel
/** /**
* Register the commands for the application. * Register the commands for the application.
*/ */
#[\Override]
protected function commands(): void protected function commands(): void
{ {
$this->load(__DIR__.'/Commands'); $this->load(__DIR__.'/Commands');
@@ -45,6 +46,7 @@ class Kernel extends ConsoleKernel
/** /**
* Define the application's command schedule. * Define the application's command schedule.
*/ */
#[\Override]
protected function schedule(Schedule $schedule): void protected function schedule(Schedule $schedule): void
{ {
$schedule->call( $schedule->call(

View File

@@ -36,15 +36,10 @@ class InvitationCreated extends Event
{ {
use SerializesModels; use SerializesModels;
public InvitedUser $invitee;
public TransactionGroup $transactionGroup; public TransactionGroup $transactionGroup;
/** /**
* Create a new event instance. * Create a new event instance.
*/ */
public function __construct(InvitedUser $invitee) public function __construct(public InvitedUser $invitee) {}
{
$this->invitee = $invitee;
}
} }

View File

@@ -34,14 +34,11 @@ class DestroyedTransactionGroup extends Event
{ {
use SerializesModels; use SerializesModels;
public TransactionGroup $transactionGroup;
/** /**
* Create a new event instance. * Create a new event instance.
*/ */
public function __construct(TransactionGroup $transactionGroup) public function __construct(public TransactionGroup $transactionGroup)
{ {
app('log')->debug(sprintf('Now in %s', __METHOD__)); app('log')->debug(sprintf('Now in %s', __METHOD__));
$this->transactionGroup = $transactionGroup;
} }
} }

View File

@@ -34,13 +34,10 @@ class DestroyedTransactionLink extends Event
{ {
use SerializesModels; use SerializesModels;
private TransactionJournalLink $link; // @phpstan-ignore-line // @phpstan-ignore-line
/** /**
* DestroyedTransactionLink constructor. * DestroyedTransactionLink constructor.
*/ */
public function __construct(TransactionJournalLink $link) public function __construct(private TransactionJournalLink $link) {}
{
$this->link = $link;
}
} }

View File

@@ -34,13 +34,8 @@ class DetectedNewIPAddress extends Event
{ {
use SerializesModels; use SerializesModels;
public User $user;
/** /**
* Create a new event instance. This event is triggered when a new user registers. * Create a new event instance. This event is triggered when a new user registers.
*/ */
public function __construct(User $user) public function __construct(public User $user) {}
{
$this->user = $user;
}
} }

View File

@@ -31,10 +31,5 @@ class Updated
{ {
use SerializesModels; use SerializesModels;
public Account $account; public function __construct(public Account $account) {}
public function __construct(Account $account)
{
$this->account = $account;
}
} }

View File

@@ -35,10 +35,5 @@ class Created extends Event
{ {
use SerializesModels; use SerializesModels;
public BudgetLimit $budgetLimit; public function __construct(public BudgetLimit $budgetLimit) {}
public function __construct(BudgetLimit $budgetLimit)
{
$this->budgetLimit = $budgetLimit;
}
} }

View File

@@ -35,10 +35,5 @@ class Deleted extends Event
{ {
use SerializesModels; use SerializesModels;
public BudgetLimit $budgetLimit; public function __construct(public BudgetLimit $budgetLimit) {}
public function __construct(BudgetLimit $budgetLimit)
{
$this->budgetLimit = $budgetLimit;
}
} }

View File

@@ -35,10 +35,5 @@ class Updated extends Event
{ {
use SerializesModels; use SerializesModels;
public BudgetLimit $budgetLimit; public function __construct(public BudgetLimit $budgetLimit) {}
public function __construct(BudgetLimit $budgetLimit)
{
$this->budgetLimit = $budgetLimit;
}
} }

View File

@@ -37,20 +37,16 @@ class ChangedAmount extends Event
{ {
use SerializesModels; use SerializesModels;
public string $amount; public string $amount;
public PiggyBank $piggyBank; public PiggyBank $piggyBank;
public ?TransactionGroup $transactionGroup;
public ?TransactionJournal $transactionJournal;
/** /**
* Create a new event instance. * Create a new event instance.
*/ */
public function __construct(PiggyBank $piggyBank, string $amount, ?TransactionJournal $transactionJournal, ?TransactionGroup $transactionGroup) public function __construct(PiggyBank $piggyBank, string $amount, public ?TransactionJournal $transactionJournal, public ?TransactionGroup $transactionGroup)
{ {
app('log')->debug(sprintf('Created piggy bank event for piggy bank #%d with amount %s', $piggyBank->id, $amount)); app('log')->debug(sprintf('Created piggy bank event for piggy bank #%d with amount %s', $piggyBank->id, $amount));
$this->piggyBank = $piggyBank; $this->piggyBank = $piggyBank;
$this->transactionJournal = $transactionJournal; $this->amount = $amount;
$this->transactionGroup = $transactionGroup;
$this->amount = $amount;
} }
} }

View File

@@ -34,15 +34,8 @@ class RuleActionFailedOnArray
{ {
use SerializesModels; use SerializesModels;
public string $error; public function __construct(public RuleAction $ruleAction, public array $journal, public string $error)
public array $journal;
public RuleAction $ruleAction;
public function __construct(RuleAction $ruleAction, array $journal, string $error)
{ {
app('log')->debug('Created new RuleActionFailedOnArray'); app('log')->debug('Created new RuleActionFailedOnArray');
$this->ruleAction = $ruleAction;
$this->journal = $journal;
$this->error = $error;
} }
} }

View File

@@ -35,15 +35,8 @@ class RuleActionFailedOnObject
{ {
use SerializesModels; use SerializesModels;
public string $error; public function __construct(public RuleAction $ruleAction, public TransactionJournal $journal, public string $error)
public TransactionJournal $journal;
public RuleAction $ruleAction;
public function __construct(RuleAction $ruleAction, TransactionJournal $journal, string $error)
{ {
app('log')->debug('Created new RuleActionFailedOnObject'); app('log')->debug('Created new RuleActionFailedOnObject');
$this->ruleAction = $ruleAction;
$this->journal = $journal;
$this->error = $error;
} }
} }

View File

@@ -34,14 +34,11 @@ class NewVersionAvailable extends Event
{ {
use SerializesModels; use SerializesModels;
public string $message;
/** /**
* Create a new event instance. This event is triggered when a new version is available. * Create a new event instance. This event is triggered when a new version is available.
*/ */
public function __construct(string $message) public function __construct(public string $message)
{ {
Log::debug(__METHOD__); Log::debug(__METHOD__);
$this->message = $message;
} }
} }

View File

@@ -33,11 +33,8 @@ class UserGroupChangedDefaultCurrency extends Event
{ {
use SerializesModels; use SerializesModels;
public UserGroup $userGroup; public function __construct(public UserGroup $userGroup)
public function __construct(UserGroup $userGroup)
{ {
Log::debug('User group changed default currency.'); Log::debug('User group changed default currency.');
$this->userGroup = $userGroup;
} }
} }

View File

@@ -35,15 +35,8 @@ class RegisteredUser extends Event
{ {
use SerializesModels; use SerializesModels;
public OwnerNotifiable $owner;
public User $user;
/** /**
* Create a new event instance. This event is triggered when a new user registers. * Create a new event instance. This event is triggered when a new user registers.
*/ */
public function __construct(OwnerNotifiable $owner, User $user) public function __construct(public OwnerNotifiable $owner, public User $user) {}
{
$this->user = $user;
$this->owner = $owner;
}
} }

Some files were not shown because too many files have changed in this diff Show More