diff --git a/.ci/php-cs-fixer/composer.lock b/.ci/php-cs-fixer/composer.lock
index 4e1d937036..4f9ef616a0 100644
--- a/.ci/php-cs-fixer/composer.lock
+++ b/.ci/php-cs-fixer/composer.lock
@@ -402,16 +402,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
- "version": "v3.88.2",
+ "version": "v3.89.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
- "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99"
+ "reference": "f34967da2866ace090a2b447de1f357356474573"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/a8d15584bafb0f0d9d938827840060fd4a3ebc99",
- "reference": "a8d15584bafb0f0d9d938827840060fd4a3ebc99",
+ "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/f34967da2866ace090a2b447de1f357356474573",
+ "reference": "f34967da2866ace090a2b447de1f357356474573",
"shasum": ""
},
"require": {
@@ -426,7 +426,6 @@
"php": "^7.4 || ^8.0",
"react/child-process": "^0.6.6",
"react/event-loop": "^1.5",
- "react/promise": "^3.3",
"react/socket": "^1.16",
"react/stream": "^1.4",
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
@@ -494,7 +493,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
- "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.88.2"
+ "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.89.1"
},
"funding": [
{
@@ -502,7 +501,7 @@
"type": "github"
}
],
- "time": "2025-09-27T00:24:15+00:00"
+ "time": "2025-10-24T12:05:10+00:00"
},
{
"name": "psr/container",
@@ -1252,16 +1251,16 @@
},
{
"name": "symfony/console",
- "version": "v7.3.4",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
+ "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
- "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
+ "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
+ "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"shasum": ""
},
"require": {
@@ -1326,7 +1325,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.4"
+ "source": "https://github.com/symfony/console/tree/v7.3.5"
},
"funding": [
{
@@ -1346,7 +1345,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-22T15:31:00+00:00"
+ "time": "2025-10-14T15:46:26+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -1647,16 +1646,16 @@
},
{
"name": "symfony/finder",
- "version": "v7.3.2",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f",
"shasum": ""
},
"require": {
@@ -1691,7 +1690,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.3.2"
+ "source": "https://github.com/symfony/finder/tree/v7.3.5"
},
"funding": [
{
@@ -1711,7 +1710,7 @@
"type": "tidelift"
}
],
- "time": "2025-07-15T13:41:35+00:00"
+ "time": "2025-10-15T18:45:57+00:00"
},
{
"name": "symfony/options-resolver",
diff --git a/THANKS.md b/THANKS.md
index 2839b6f7f6..4b590fc92b 100755
--- a/THANKS.md
+++ b/THANKS.md
@@ -4,6 +4,8 @@ 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.
## 2025
+- jreyesr
+- codearena-bot
- Nicky De Maeyer
- Denis Iskandarov
- Lompi
diff --git a/app/Api/V1/Controllers/Autocomplete/AccountController.php b/app/Api/V1/Controllers/Autocomplete/AccountController.php
index c3f7cd9618..dfb16b0eef 100644
--- a/app/Api/V1/Controllers/Autocomplete/AccountController.php
+++ b/app/Api/V1/Controllers/Autocomplete/AccountController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
@@ -79,20 +79,26 @@ class AccountController extends Controller
* @throws FireflyException
* @throws FireflyException
*/
- public function accounts(AutocompleteRequest $request): JsonResponse
+ public function accounts(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $types = $data['types'];
- $query = $data['query'];
- $date = $data['date'] ?? today(config('app.timezone'));
- $return = [];
- $timer = Timer::getInstance();
- $timer->start(sprintf('AC accounts "%s"', $query));
- $result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
+ [
+ 'types' => $types,
+ 'query' => $query,
+ 'date' => $date,
+ 'limit' => $limit,
+ ]
+ = $request->attributes->all();
+
+
+ $date ??= today(config('app.timezone'));
// set date to end-of-day for account balance. so it is at $date 23:59:59
$date->endOfDay();
+ $return = [];
+ $timer = Timer::getInstance();
+ $timer->start(sprintf('AC accounts "%s"', $query));
+ $result = $this->repository->searchAccount((string)$query, $types, $limit);
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
/** @var Account $account */
@@ -111,17 +117,17 @@ class AccountController extends Controller
}
$return[] = [
- 'id' => (string) $account->id,
+ 'id' => (string)$account->id,
'name' => $account->name,
'name_with_balance' => $nameWithBalance,
'active' => $account->active,
'type' => $account->accountType->type,
- 'currency_id' => (string) $useCurrency->id,
+ 'currency_id' => (string)$useCurrency->id,
'currency_name' => $useCurrency->name,
'currency_code' => $useCurrency->code,
'currency_symbol' => $useCurrency->symbol,
'currency_decimal_places' => $useCurrency->decimal_places,
- 'account_currency_id' => (string) $currency->id,
+ 'account_currency_id' => (string)$currency->id,
'account_currency_name' => $currency->name,
'account_currency_code' => $currency->code,
'account_currency_symbol' => $currency->symbol,
@@ -134,8 +140,8 @@ class AccountController extends Controller
$return,
static function (array $left, array $right) {
$order = [AccountTypeEnum::ASSET->value, AccountTypeEnum::REVENUE->value, AccountTypeEnum::EXPENSE->value];
- $posA = (int) array_search($left['type'], $order, true);
- $posB = (int) array_search($right['type'], $order, true);
+ $posA = (int)array_search($left['type'], $order, true);
+ $posB = (int)array_search($right['type'], $order, true);
return $posA - $posB;
}
diff --git a/app/Api/V1/Controllers/Autocomplete/BillController.php b/app/Api/V1/Controllers/Autocomplete/BillController.php
index 5fea014b5c..4c0da6fc4c 100644
--- a/app/Api/V1/Controllers/Autocomplete/BillController.php
+++ b/app/Api/V1/Controllers/Autocomplete/BillController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
@@ -61,10 +61,9 @@ class BillController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getBillsAC
*/
- public function bills(AutocompleteRequest $request): JsonResponse
+ public function bills(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $result = $this->repository->searchBill($data['query'], $this->parameters->get('limit'));
+ $result = $this->repository->searchBill($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(
static fn (Bill $item) => [
'id' => (string) $item->id,
diff --git a/app/Api/V1/Controllers/Autocomplete/BudgetController.php b/app/Api/V1/Controllers/Autocomplete/BudgetController.php
index c292adc5b1..4a096bff1e 100644
--- a/app/Api/V1/Controllers/Autocomplete/BudgetController.php
+++ b/app/Api/V1/Controllers/Autocomplete/BudgetController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
@@ -61,10 +61,9 @@ class BudgetController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getBudgetsAC
*/
- public function budgets(AutocompleteRequest $request): JsonResponse
+ public function budgets(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $result = $this->repository->searchBudget($data['query'], $this->parameters->get('limit'));
+ $result = $this->repository->searchBudget($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(
static fn (Budget $item) => [
'id' => (string) $item->id,
diff --git a/app/Api/V1/Controllers/Autocomplete/CategoryController.php b/app/Api/V1/Controllers/Autocomplete/CategoryController.php
index cf24f56776..34a963b5ea 100644
--- a/app/Api/V1/Controllers/Autocomplete/CategoryController.php
+++ b/app/Api/V1/Controllers/Autocomplete/CategoryController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
@@ -61,10 +61,9 @@ class CategoryController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCategoriesAC
*/
- public function categories(AutocompleteRequest $request): JsonResponse
+ public function categories(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit'));
+ $result = $this->repository->searchCategory($request->attributes->get('query'), $request->attributes->get('limit'));
$filtered = $result->map(
static fn (Category $item) => [
'id' => (string) $item->id,
diff --git a/app/Api/V1/Controllers/Autocomplete/CurrencyController.php b/app/Api/V1/Controllers/Autocomplete/CurrencyController.php
index 427e03d5b9..1528e17c18 100644
--- a/app/Api/V1/Controllers/Autocomplete/CurrencyController.php
+++ b/app/Api/V1/Controllers/Autocomplete/CurrencyController.php
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use Deprecated;
use FireflyIII\Api\V1\Controllers\Controller;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionCurrency;
@@ -62,10 +63,9 @@ class CurrencyController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getCurrenciesAC
*/
- public function currencies(AutocompleteRequest $request): JsonResponse
+ public function currencies(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $collection = $this->repository->searchCurrency($data['query'], $this->parameters->get('limit'));
+ $collection = $this->repository->searchCurrency($request->attributes->get('query'), $request->attributes->get('limit'));
$result = [];
/** @var TransactionCurrency $currency */
diff --git a/app/Api/V1/Controllers/Autocomplete/ObjectGroupController.php b/app/Api/V1/Controllers/Autocomplete/ObjectGroupController.php
index 0f4126f941..38a2ce56be 100644
--- a/app/Api/V1/Controllers/Autocomplete/ObjectGroupController.php
+++ b/app/Api/V1/Controllers/Autocomplete/ObjectGroupController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
@@ -61,11 +61,10 @@ class ObjectGroupController extends Controller
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getObjectGroupsAC
*/
- public function objectGroups(AutocompleteRequest $request): JsonResponse
+ public function objectGroups(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
$return = [];
- $result = $this->repository->search($data['query'], $this->parameters->get('limit'));
+ $result = $this->repository->search($request->attributes->get('query'), $request->attributes->get('limit'));
/** @var ObjectGroup $objectGroup */
foreach ($result as $objectGroup) {
diff --git a/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php b/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php
index 25fc1f145e..f31a990cf0 100644
--- a/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php
+++ b/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
@@ -64,10 +64,9 @@ class PiggyBankController extends Controller
);
}
- public function piggyBanks(AutocompleteRequest $request): JsonResponse
+ public function piggyBanks(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
+ $piggies = $this->piggyRepository->searchPiggyBank($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var PiggyBank $piggy */
@@ -90,10 +89,9 @@ class PiggyBankController extends Controller
return response()->api($response);
}
- public function piggyBanksWithBalance(AutocompleteRequest $request): JsonResponse
+ public function piggyBanksWithBalance(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
+ $piggies = $this->piggyRepository->searchPiggyBank($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var PiggyBank $piggy */
diff --git a/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php b/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php
index 202cf398f2..e757d098c1 100644
--- a/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php
+++ b/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
@@ -57,10 +57,9 @@ class RecurrenceController extends Controller
);
}
- public function recurring(AutocompleteRequest $request): JsonResponse
+ public function recurring(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $recurrences = $this->repository->searchRecurrence($data['query'], $this->parameters->get('limit'));
+ $recurrences = $this->repository->searchRecurrence($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var Recurrence $recurrence */
diff --git a/app/Api/V1/Controllers/Autocomplete/RuleController.php b/app/Api/V1/Controllers/Autocomplete/RuleController.php
index c2de7bb83b..1ff0271607 100644
--- a/app/Api/V1/Controllers/Autocomplete/RuleController.php
+++ b/app/Api/V1/Controllers/Autocomplete/RuleController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
@@ -57,10 +57,9 @@ class RuleController extends Controller
);
}
- public function rules(AutocompleteRequest $request): JsonResponse
+ public function rules(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $rules = $this->repository->searchRule($data['query'], $this->parameters->get('limit'));
+ $rules = $this->repository->searchRule($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var Rule $rule */
diff --git a/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php b/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php
index ff496d1e13..70c66be5ee 100644
--- a/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php
+++ b/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
@@ -57,10 +57,9 @@ class RuleGroupController extends Controller
);
}
- public function ruleGroups(AutocompleteRequest $request): JsonResponse
+ public function ruleGroups(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $groups = $this->repository->searchRuleGroup($data['query'], $this->parameters->get('limit'));
+ $groups = $this->repository->searchRuleGroup($request->attributes->get('query'), $request->attributes->get('limit'));
$response = [];
/** @var RuleGroup $group */
diff --git a/app/Api/V1/Controllers/Autocomplete/TagController.php b/app/Api/V1/Controllers/Autocomplete/TagController.php
index 5ad94ea7f5..d797931319 100644
--- a/app/Api/V1/Controllers/Autocomplete/TagController.php
+++ b/app/Api/V1/Controllers/Autocomplete/TagController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
@@ -57,10 +57,9 @@ class TagController extends Controller
);
}
- public function tags(AutocompleteRequest $request): JsonResponse
+ public function tags(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $result = $this->repository->searchTags($data['query'], $this->parameters->get('limit'));
+ $result = $this->repository->searchTags($request->attributes->get('query'), $request->attributes->get('limit'));
$array = [];
/** @var Tag $tag */
diff --git a/app/Api/V1/Controllers/Autocomplete/TransactionController.php b/app/Api/V1/Controllers/Autocomplete/TransactionController.php
index d088427937..2bc5c8314b 100644
--- a/app/Api/V1/Controllers/Autocomplete/TransactionController.php
+++ b/app/Api/V1/Controllers/Autocomplete/TransactionController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
@@ -64,10 +64,9 @@ class TransactionController extends Controller
);
}
- public function transactions(AutocompleteRequest $request): JsonResponse
+ public function transactions(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit'));
+ $result = $this->repository->searchJournalDescriptions($request->attributes->get('query'), $request->attributes->get('limit'));
// limit and unique
$filtered = $result->unique('description');
@@ -86,13 +85,12 @@ class TransactionController extends Controller
return response()->api($array);
}
- public function transactionsWithID(AutocompleteRequest $request): JsonResponse
+ public function transactionsWithID(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
$result = new Collection();
- if (is_numeric($data['query'])) {
+ if (is_numeric($request->attributes->get('query'))) {
// search for group, not journal.
- $firstResult = $this->groupRepository->find((int) $data['query']);
+ $firstResult = $this->groupRepository->find((int) $request->attributes->get('query'));
if ($firstResult instanceof TransactionGroup) {
// group may contain multiple journals, each a result:
foreach ($firstResult->transactionJournals as $journal) {
@@ -100,8 +98,8 @@ class TransactionController extends Controller
}
}
}
- if (!is_numeric($data['query'])) {
- $result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit'));
+ if (!is_numeric($request->attributes->get('query'))) {
+ $result = $this->repository->searchJournalDescriptions($request->attributes->get('query'), $request->attributes->get('limit'));
}
// limit and unique
diff --git a/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php b/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php
index 357efc37a1..bdfad0d9d9 100644
--- a/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php
+++ b/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Autocomplete;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteRequest;
+use FireflyIII\Api\V1\Requests\Autocomplete\AutocompleteApiRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
@@ -55,10 +55,9 @@ class TransactionTypeController extends Controller
);
}
- public function transactionTypes(AutocompleteRequest $request): JsonResponse
+ public function transactionTypes(AutocompleteApiRequest $request): JsonResponse
{
- $data = $request->getData();
- $types = $this->repository->searchTypes($data['query'], $this->parameters->get('limit'));
+ $types = $this->repository->searchTypes($request->attributes->get('query'), $request->attributes->get('limit'));
$array = [];
/** @var TransactionType $type */
diff --git a/app/Api/V1/Controllers/Chart/BudgetController.php b/app/Api/V1/Controllers/Chart/BudgetController.php
index 6f0425d6fb..090b90f65a 100644
--- a/app/Api/V1/Controllers/Chart/BudgetController.php
+++ b/app/Api/V1/Controllers/Chart/BudgetController.php
@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
+use FireflyIII\Api\V1\Requests\DateRangeRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
@@ -83,15 +83,13 @@ class BudgetController extends Controller
*
* @throws FireflyException
*/
- public function overview(SameDateRequest $request): JsonResponse
+ public function overview(DateRangeRequest $request): JsonResponse
{
- $params = $request->getAll();
-
/** @var Carbon $start */
- $start = $params['start'];
+ $start = $request->attributes->get('start');
/** @var Carbon $end */
- $end = $params['end'];
+ $end = $request->attributes->get('end');
// code from FrontpageChartGenerator, but not in separate class
$budgets = $this->repository->getActiveBudgets();
diff --git a/app/Api/V1/Controllers/Chart/CategoryController.php b/app/Api/V1/Controllers/Chart/CategoryController.php
index a81261e3ea..a85fc89fa3 100644
--- a/app/Api/V1/Controllers/Chart/CategoryController.php
+++ b/app/Api/V1/Controllers/Chart/CategoryController.php
@@ -26,7 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Data\SameDateRequest;
+use FireflyIII\Api\V1\Requests\DateRangeRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Enums\UserRoleEnum;
@@ -80,13 +80,13 @@ class CategoryController extends Controller
*
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
*/
- public function overview(SameDateRequest $request): JsonResponse
+ public function overview(DateRangeRequest $request): JsonResponse
{
/** @var Carbon $start */
- $start = $this->parameters->get('start');
+ $start = $request->attributes->get('start');
/** @var Carbon $end */
- $end = $this->parameters->get('end');
+ $end = $request->attributes->get('end');
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value]);
$currencies = [];
$return = [];
diff --git a/app/Api/V1/Controllers/Controller.php b/app/Api/V1/Controllers/Controller.php
index 298bc20cc7..c9169673b5 100644
--- a/app/Api/V1/Controllers/Controller.php
+++ b/app/Api/V1/Controllers/Controller.php
@@ -29,6 +29,7 @@ use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Exceptions\BadHttpHeaderException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Support\Facades\Amount;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\AbstractTransformer;
@@ -67,6 +68,8 @@ abstract class Controller extends BaseController
protected bool $convertToPrimary = false;
protected TransactionCurrency $primaryCurrency;
+
+ /** @deprecated use Request classes */
protected ParameterBag $parameters;
/**
@@ -98,7 +101,8 @@ abstract class Controller extends BaseController
}
/**
- * Method to grab all parameters from the URL.
+ * @deprecated use Request classes
+ * Method to grab all parameters from the URL
*/
private function getParameters(): ParameterBag
{
@@ -156,7 +160,7 @@ abstract class Controller extends BaseController
/** @var User $user */
$user = auth()->user();
- $pageSize = (int)app('preferences')->getForUser($user, 'listPageSize', 50)->data;
+ $pageSize = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
$bag->set($integer, $pageSize);
}
}
diff --git a/app/Api/V1/Controllers/Data/DestroyController.php b/app/Api/V1/Controllers/Data/DestroyController.php
index 87e791be7c..86180cf44c 100644
--- a/app/Api/V1/Controllers/Data/DestroyController.php
+++ b/app/Api/V1/Controllers/Data/DestroyController.php
@@ -46,6 +46,7 @@ use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Services\Internal\Destroy\AccountDestroyService;
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -102,7 +103,7 @@ class DestroyController extends Controller
default => throw new FireflyException(sprintf('200033: This endpoint can\'t handle object "%s"', $objects)),
};
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Account/DestroyController.php b/app/Api/V1/Controllers/Models/Account/DestroyController.php
index fc23429f76..d772b44557 100644
--- a/app/Api/V1/Controllers/Models/Account/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Account/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Account;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -60,7 +61,7 @@ class DestroyController extends Controller
public function destroy(Account $account): JsonResponse
{
$this->repository->destroy($account, null);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Account/ListController.php b/app/Api/V1/Controllers/Models/Account/ListController.php
index b230572b93..f830be0844 100644
--- a/app/Api/V1/Controllers/Models/Account/ListController.php
+++ b/app/Api/V1/Controllers/Models/Account/ListController.php
@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Account;
use FireflyIII\Api\V1\Controllers\Controller;
+use FireflyIII\Api\V1\Requests\PaginationRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -69,22 +70,25 @@ class ListController extends Controller
);
}
- public function attachments(Account $account): JsonResponse
+ public function attachments(PaginationRequest $request, Account $account): JsonResponse
{
$manager = $this->getManager();
- $pageSize = $this->parameters->get('limit');
+ [
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'page' => $page,
+ ] = $request->attributes->all();
$collection = $this->repository->getAttachments($account);
$count = $collection->count();
- $attachments = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
+ $attachments = $collection->slice($offset, $limit);
// make paginator:
- $paginator = new LengthAwarePaginator($attachments, $count, $pageSize, $this->parameters->get('page'));
+ $paginator = new LengthAwarePaginator($attachments, $count, $limit, $page);
$paginator->setPath(route('api.v1.accounts.attachments', [$account->id]).$this->buildParams());
/** @var AttachmentTransformer $transformer */
$transformer = app(AttachmentTransformer::class);
- $transformer->setParameters($this->parameters);
$resource = new FractalCollection($attachments, $transformer, 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
@@ -92,18 +96,21 @@ class ListController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
- public function piggyBanks(Account $account): JsonResponse
+ public function piggyBanks(PaginationRequest $request, Account $account): JsonResponse
{
// create some objects:
$manager = $this->getManager();
- // types to get, page size:
- $pageSize = $this->parameters->get('limit');
+ [
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'page' => $page,
+ ] = $request->attributes->all();
// get list of piggy banks. Count it and split it.
$collection = $this->repository->getPiggyBanks($account);
$count = $collection->count();
- $piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
+ $piggyBanks = $collection->slice(($page - 1) * $limit, $limit);
// enrich
/** @var User $admin */
@@ -113,12 +120,12 @@ class ListController extends Controller
$piggyBanks = $enrichment->enrich($piggyBanks);
// make paginator:
- $paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
+ $paginator = new LengthAwarePaginator($piggyBanks, $count, $limit, $page);
$paginator->setPath(route('api.v1.accounts.piggy-banks', [$account->id]).$this->buildParams());
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
- $transformer->setParameters($this->parameters);
+ // $transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
diff --git a/app/Api/V1/Controllers/Models/Account/ShowController.php b/app/Api/V1/Controllers/Models/Account/ShowController.php
index 587076d0db..5616869a8d 100644
--- a/app/Api/V1/Controllers/Models/Account/ShowController.php
+++ b/app/Api/V1/Controllers/Models/Account/ShowController.php
@@ -71,45 +71,45 @@ class ShowController extends Controller
public function index(ShowRequest $request): JsonResponse
{
$manager = $this->getManager();
- $params = $request->getParameters();
- $this->parameters->set('type', $params['type']);
-
- // types to get, page size:
- $types = $this->mapAccountTypes($params['type']);
+ [
+ 'types' => $types,
+ 'page' => $page,
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'sort' => $sort,
+ 'start' => $start,
+ 'end' => $end,
+ 'date' => $date,
+ ]
+ = $request->attributes->all();
// get list of accounts. Count it and split it.
$this->repository->resetAccountOrder();
- $collection = $this->repository->getAccountsByType($types, $params['sort']);
+ $collection = $this->repository->getAccountsByType($types, $sort);
$count = $collection->count();
// continue sort:
// TODO if the user sorts on DB dependent field there must be no slice before enrichment, only after.
// TODO still need to figure out how to do this easily.
- $accounts = $collection->slice(($this->parameters->get('page') - 1) * $params['limit'], $params['limit']);
-
- // #11007 go to the end of the previous day.
- $this->parameters->set('start', $this->parameters->get('start')?->subSecond());
- // #11018 also end of the day.
- $this->parameters->set('end', $this->parameters->get('end')?->endOfDay());
+ $accounts = $collection->slice($offset, $limit);
// enrich
/** @var User $admin */
$admin = auth()->user();
$enrichment = new AccountEnrichment();
- $enrichment->setSort($params['sort']);
- $enrichment->setDate($this->parameters->get('date'));
- $enrichment->setStart($this->parameters->get('start'));
- $enrichment->setEnd($this->parameters->get('end'));
+ $enrichment->setSort($sort);
+ $enrichment->setDate($date);
+ $enrichment->setStart($start);
+ $enrichment->setEnd($end);
$enrichment->setUser($admin);
$accounts = $enrichment->enrich($accounts);
// make paginator:
- $paginator = new LengthAwarePaginator($accounts, $count, $params['limit'], $this->parameters->get('page'));
+ $paginator = new LengthAwarePaginator($accounts, $count, $limit, $page);
$paginator->setPath(route('api.v1.accounts.index').$this->buildParams());
/** @var AccountTransformer $transformer */
$transformer = app(AccountTransformer::class);
- $transformer->setParameters($this->parameters);
$resource = new FractalCollection($accounts, $transformer, self::RESOURCE_KEY);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
@@ -128,28 +128,25 @@ class ShowController extends Controller
// get list of accounts. Count it and split it.
$this->repository->resetAccountOrder();
$account->refresh();
- $manager = $this->getManager();
-
- // #11007 go to the end of the previous day.
- $this->parameters->set('start', $this->parameters->get('start')?->subSecond());
- // #11018 also end of the day.
- $this->parameters->set('end', $this->parameters->get('end')?->endOfDay());
+ $manager = $this->getManager();
+ ['start' => $start,
+ 'end' => $end,
+ 'date' => $date,] = $request->attributes->all();
// enrich
/** @var User $admin */
- $admin = auth()->user();
- $enrichment = new AccountEnrichment();
- $enrichment->setDate($this->parameters->get('date'));
- $enrichment->setStart($this->parameters->get('start'));
- $enrichment->setEnd($this->parameters->get('end'));
+ $admin = auth()->user();
+ $enrichment = new AccountEnrichment();
+ $enrichment->setDate($date);
+ $enrichment->setStart($start);
+ $enrichment->setEnd($end);
$enrichment->setUser($admin);
- $account = $enrichment->enrichSingle($account);
+ $account = $enrichment->enrichSingle($account);
/** @var AccountTransformer $transformer */
- $transformer = app(AccountTransformer::class);
- $transformer->setParameters($this->parameters);
- $resource = new Item($account, $transformer, self::RESOURCE_KEY);
+ $transformer = app(AccountTransformer::class);
+ $resource = new Item($account, $transformer, self::RESOURCE_KEY);
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
diff --git a/app/Api/V1/Controllers/Models/Account/UpdateController.php b/app/Api/V1/Controllers/Models/Account/UpdateController.php
index 5118b1116d..5ae8f5b45d 100644
--- a/app/Api/V1/Controllers/Models/Account/UpdateController.php
+++ b/app/Api/V1/Controllers/Models/Account/UpdateController.php
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Account\UpdateRequest;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
@@ -74,7 +75,7 @@ class UpdateController extends Controller
$account = $this->repository->update($account, $data);
$manager = $this->getManager();
$account->refresh();
- app('preferences')->mark();
+ Preferences::mark();
// enrich
/** @var User $admin */
diff --git a/app/Api/V1/Controllers/Models/Attachment/DestroyController.php b/app/Api/V1/Controllers/Models/Attachment/DestroyController.php
index c7ee0d20e5..09cfbe1557 100644
--- a/app/Api/V1/Controllers/Models/Attachment/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Attachment/DestroyController.php
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Middleware\ApiDemoUser;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -74,7 +75,7 @@ class DestroyController extends Controller
}
$this->repository->destroy($attachment);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Bill/DestroyController.php b/app/Api/V1/Controllers/Models/Bill/DestroyController.php
index d62697d950..a709c73ec2 100644
--- a/app/Api/V1/Controllers/Models/Bill/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Bill/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Bill;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Bill $bill): JsonResponse
{
$this->repository->destroy($bill);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Budget/DestroyController.php b/app/Api/V1/Controllers/Models/Budget/DestroyController.php
index 93e2f738ec..05ee1da9e8 100644
--- a/app/Api/V1/Controllers/Models/Budget/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Budget/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Budget;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Budget $budget): JsonResponse
{
$this->repository->destroy($budget);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/BudgetLimit/DestroyController.php b/app/Api/V1/Controllers/Models/BudgetLimit/DestroyController.php
index 7c037dafd1..af96515cfb 100644
--- a/app/Api/V1/Controllers/Models/BudgetLimit/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/BudgetLimit/DestroyController.php
@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -71,7 +72,7 @@ class DestroyController extends Controller
throw new FireflyException('20028: The budget limit does not belong to the budget.');
}
$this->blRepository->destroyBudgetLimit($budgetLimit);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php b/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php
index 038c24a46c..501d680599 100644
--- a/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php
+++ b/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php
@@ -172,7 +172,6 @@ class ShowController extends Controller
/** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class);
- $transformer->setParameters($this->parameters);
$resource = new Item($budgetLimit, $transformer, 'budget_limits');
diff --git a/app/Api/V1/Controllers/Models/Category/DestroyController.php b/app/Api/V1/Controllers/Models/Category/DestroyController.php
index 29c58b2015..7d7295596f 100644
--- a/app/Api/V1/Controllers/Models/Category/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Category/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Category;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Category $category): JsonResponse
{
$this->repository->destroy($category);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php
index 733517a506..27ce2e6330 100644
--- a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/DestroyController.php
@@ -28,6 +28,7 @@ use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\DestroyRequest;
use FireflyIII\Enums\UserRoleEnum;
+use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\CurrencyExchangeRate;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
@@ -75,6 +76,9 @@ class DestroyController extends Controller
if ($exchangeRate instanceof CurrencyExchangeRate) {
$this->repository->deleteRate($exchangeRate);
}
+ if (!$exchangeRate instanceof CurrencyExchangeRate) {
+ throw new FireflyException('Bla');
+ }
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php
index 8326f44c52..19a34d1b5e 100644
--- a/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php
+++ b/app/Api/V1/Controllers/Models/CurrencyExchangeRate/UpdateController.php
@@ -82,7 +82,6 @@ class UpdateController extends Controller
$exchangeRate = $this->repository->updateExchangeRate($exchangeRate, $rate, $date);
$transformer = new ExchangeRateTransformer();
- $transformer->setParameters($this->parameters);
return response()
->api($this->jsonApiObject(self::RESOURCE_KEY, $exchangeRate, $transformer))
diff --git a/app/Api/V1/Controllers/Models/ObjectGroup/DestroyController.php b/app/Api/V1/Controllers/Models/ObjectGroup/DestroyController.php
index 02c229057a..097abb404b 100644
--- a/app/Api/V1/Controllers/Models/ObjectGroup/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/ObjectGroup/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\ObjectGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -64,7 +65,7 @@ class DestroyController extends Controller
public function destroy(ObjectGroup $objectGroup): JsonResponse
{
$this->repository->destroy($objectGroup);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/PiggyBank/DestroyController.php b/app/Api/V1/Controllers/Models/PiggyBank/DestroyController.php
index 5b5736e767..ce77892d37 100644
--- a/app/Api/V1/Controllers/Models/PiggyBank/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/PiggyBank/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\PiggyBank;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(PiggyBank $piggyBank): JsonResponse
{
$this->repository->destroy($piggyBank);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Recurrence/DestroyController.php b/app/Api/V1/Controllers/Models/Recurrence/DestroyController.php
index fa67c50147..8d596798d9 100644
--- a/app/Api/V1/Controllers/Models/Recurrence/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Recurrence/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
/**
@@ -61,7 +62,7 @@ class DestroyController extends Controller
public function destroy(Recurrence $recurrence): JsonResponse
{
$this->repository->destroy($recurrence);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Rule/DestroyController.php b/app/Api/V1/Controllers/Models/Rule/DestroyController.php
index 2144a5e34f..e8a9dbd124 100644
--- a/app/Api/V1/Controllers/Models/Rule/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Rule/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Rule;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -65,7 +66,7 @@ class DestroyController extends Controller
public function destroy(Rule $rule): JsonResponse
{
$this->ruleRepository->destroy($rule);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/RuleGroup/DestroyController.php b/app/Api/V1/Controllers/Models/RuleGroup/DestroyController.php
index e5ac3ccf71..9924ba1c75 100644
--- a/app/Api/V1/Controllers/Models/RuleGroup/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/RuleGroup/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\RuleGroup;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -65,7 +66,7 @@ class DestroyController extends Controller
public function destroy(RuleGroup $ruleGroup): JsonResponse
{
$this->ruleGroupRepository->destroy($ruleGroup, null);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Tag/DestroyController.php b/app/Api/V1/Controllers/Models/Tag/DestroyController.php
index 2f46224b32..fa6a31071a 100644
--- a/app/Api/V1/Controllers/Models/Tag/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Tag/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\Tag;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -65,7 +66,7 @@ class DestroyController extends Controller
public function destroy(Tag $tag): JsonResponse
{
$this->repository->destroy($tag);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Transaction/DestroyController.php b/app/Api/V1/Controllers/Models/Transaction/DestroyController.php
index f77339b188..ecf6a28432 100644
--- a/app/Api/V1/Controllers/Models/Transaction/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/Transaction/DestroyController.php
@@ -32,6 +32,7 @@ use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -92,7 +93,7 @@ class DestroyController extends Controller
$this->groupRepository->destroy($transactionGroup);
- app('preferences')->mark();
+ Preferences::mark();
/** @var Account $account */
foreach ($accounts as $account) {
@@ -112,7 +113,7 @@ class DestroyController extends Controller
public function destroyJournal(TransactionJournal $transactionJournal): JsonResponse
{
$this->repository->destroyJournal($transactionJournal);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/Transaction/StoreController.php b/app/Api/V1/Controllers/Models/Transaction/StoreController.php
index 37acce2eb6..6a7e603d5d 100644
--- a/app/Api/V1/Controllers/Models/Transaction/StoreController.php
+++ b/app/Api/V1/Controllers/Models/Transaction/StoreController.php
@@ -33,6 +33,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\Rules\IsDuplicateTransaction;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -107,7 +108,7 @@ class StoreController extends Controller
throw new ValidationException($validator);
}
- app('preferences')->mark();
+ Preferences::mark();
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
event(new StoredTransactionGroup($transactionGroup, $applyRules, $fireWebhooks));
diff --git a/app/Api/V1/Controllers/Models/Transaction/UpdateController.php b/app/Api/V1/Controllers/Models/Transaction/UpdateController.php
index 6db7503671..02fbb9b023 100644
--- a/app/Api/V1/Controllers/Models/Transaction/UpdateController.php
+++ b/app/Api/V1/Controllers/Models/Transaction/UpdateController.php
@@ -30,6 +30,7 @@ use FireflyIII\Events\UpdatedTransactionGroup;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
@@ -79,7 +80,7 @@ class UpdateController extends Controller
$newHash = $this->groupRepository->getCompareHash($transactionGroup);
$manager = $this->getManager();
- app('preferences')->mark();
+ Preferences::mark();
$applyRules = $data['apply_rules'] ?? true;
$fireWebhooks = $data['fire_webhooks'] ?? true;
$runRecalculations = $oldHash !== $newHash;
diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/DestroyController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/DestroyController.php
index b4aca8b763..a40d05dd2f 100644
--- a/app/Api/V1/Controllers/Models/TransactionCurrency/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/TransactionCurrency/DestroyController.php
@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Validator;
@@ -89,7 +90,7 @@ class DestroyController extends Controller
}
$this->repository->destroy($currency);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php
index 56b61b9c99..b225556b54 100644
--- a/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php
+++ b/app/Api/V1/Controllers/Models/TransactionCurrency/StoreController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionCurrency;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\StoreRequest;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer;
@@ -71,7 +72,7 @@ class StoreController extends Controller
$currency = $this->repository->store($request->getAll());
if (true === $request->boolean('default')) {
$this->repository->makePrimary($currency);
- app('preferences')->mark();
+ Preferences::mark();
}
$manager = $this->getManager();
diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php
index f76bfaf8a2..ca8b3f14da 100644
--- a/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php
+++ b/app/Api/V1/Controllers/Models/TransactionCurrency/UpdateController.php
@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\UpdateRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\CurrencyTransformer;
@@ -105,7 +106,7 @@ class UpdateController extends Controller
$this->repository->enable($currency);
$this->repository->makePrimary($currency);
- app('preferences')->mark();
+ Preferences::mark();
$manager = $this->getManager();
$currency->refreshForUser($user);
@@ -172,14 +173,13 @@ class UpdateController extends Controller
$currency = $this->repository->update($currency, $data);
- app('preferences')->mark();
+ Preferences::mark();
$manager = $this->getManager();
$currency->refreshForUser($user);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
- $transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
diff --git a/app/Api/V1/Controllers/Models/TransactionLink/DestroyController.php b/app/Api/V1/Controllers/Models/TransactionLink/DestroyController.php
index e5c0b5ff46..25c2b85008 100644
--- a/app/Api/V1/Controllers/Models/TransactionLink/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/TransactionLink/DestroyController.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\TransactionLink;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Models\TransactionJournalLink;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -66,7 +67,7 @@ class DestroyController extends Controller
public function destroy(TransactionJournalLink $link): JsonResponse
{
$this->repository->destroyLink($link);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/DestroyController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/DestroyController.php
index 7abbff55d7..df18a2ba62 100644
--- a/app/Api/V1/Controllers/Models/TransactionLinkType/DestroyController.php
+++ b/app/Api/V1/Controllers/Models/TransactionLinkType/DestroyController.php
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\LinkType;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@@ -73,7 +74,7 @@ class DestroyController extends Controller
throw new FireflyException('200020: Link type cannot be changed.');
}
$this->repository->destroy($linkType);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Controllers/Models/UserGroup/IndexController.php b/app/Api/V1/Controllers/Models/UserGroup/IndexController.php
index e689687467..5cdbb9023f 100644
--- a/app/Api/V1/Controllers/Models/UserGroup/IndexController.php
+++ b/app/Api/V1/Controllers/Models/UserGroup/IndexController.php
@@ -25,7 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\UserGroup;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Data\DateRequest;
+use FireflyIII\Api\V1\Requests\PaginationRequest;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
@@ -52,17 +52,19 @@ class IndexController extends Controller
);
}
- public function index(DateRequest $request): JsonResponse
+ public function index(PaginationRequest $request): JsonResponse
{
$administrations = $this->repository->get();
- $pageSize = $this->parameters->get('limit');
+ [
+ 'page' => $page,
+ 'limit' => $limit,
+ 'offset' => $offset,
+ ] = $request->attributes->all();
$count = $administrations->count();
- $administrations = $administrations->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
- $paginator = new LengthAwarePaginator($administrations, $count, $pageSize, $this->parameters->get('page'));
+ $administrations = $administrations->slice($offset, $limit);
+ $paginator = new LengthAwarePaginator($administrations, $count, $limit, $page);
$transformer = new UserGroupTransformer();
- $transformer->setParameters($this->parameters); // give params to transformer
-
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
diff --git a/app/Api/V1/Controllers/Models/UserGroup/UpdateController.php b/app/Api/V1/Controllers/Models/UserGroup/UpdateController.php
index e1a9e517e5..f118a5a960 100644
--- a/app/Api/V1/Controllers/Models/UserGroup/UpdateController.php
+++ b/app/Api/V1/Controllers/Models/UserGroup/UpdateController.php
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\UserGroup\UpdateRequest;
use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Transformers\UserGroupTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
@@ -59,7 +60,7 @@ class UpdateController extends Controller
$data = $request->getData();
$userGroup = $this->repository->update($userGroup, $data);
$userGroup->refresh();
- app('preferences')->mark();
+ Preferences::mark();
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters);
diff --git a/app/Api/V1/Controllers/Summary/BasicController.php b/app/Api/V1/Controllers/Summary/BasicController.php
index 6b2acc86eb..86b65b9e34 100644
--- a/app/Api/V1/Controllers/Summary/BasicController.php
+++ b/app/Api/V1/Controllers/Summary/BasicController.php
@@ -27,7 +27,7 @@ namespace FireflyIII\Api\V1\Controllers\Summary;
use Carbon\Carbon;
use Exception;
use FireflyIII\Api\V1\Controllers\Controller;
-use FireflyIII\Api\V1\Requests\Data\DateRequest;
+use FireflyIII\Api\V1\Requests\Summary\BasicRequest;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Enums\TransactionTypeEnum;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
@@ -88,34 +88,25 @@ class BasicController extends Controller
);
}
- /**
- * This endpoint is documented at:
- * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/summary/getBasicSummary
- *
- * @throws Exception
- */
- public function basic(DateRequest $request): JsonResponse
+ public function basic(BasicRequest $request): JsonResponse
{
// parameters for boxes:
- $dates = $request->getAll();
- $start = $dates['start'];
- $end = $dates['end'];
- $code = $request->get('currency_code');
+ ['start' => $start, 'end' => $end, 'code' => $code] = $request->attributes->all();
// balance information:
- $balanceData = $this->getBalanceInformation($start, $end);
- $billData = $this->getSubscriptionInformation($start, $end);
- $spentData = $this->getLeftToSpendInfo($start, $end);
- $netWorthData = $this->getNetWorthInfo($end);
+ $balanceData = $this->getBalanceInformation($start, $end);
+ $billData = $this->getSubscriptionInformation($start, $end);
+ $spentData = $this->getLeftToSpendInfo($start, $end);
+ $netWorthData = $this->getNetWorthInfo($end);
// $balanceData = [];
// $billData = [];
// $spentData = [];
// $netWorthData = [];
- $total = array_merge($balanceData, $billData, $spentData, $netWorthData);
+ $total = array_merge($balanceData, $billData, $spentData, $netWorthData);
// give new keys
- $return = [];
+ $return = [];
foreach ($total as $entry) {
- if (null === $code || ($code === $entry['currency_code'])) {
+ if ('' === $code || ($code === $entry['currency_code'])) {
$return[$entry['key']] = $entry;
}
}
@@ -589,8 +580,6 @@ class BasicController extends Controller
private function getNetWorthInfo(Carbon $end): array
{
- $end->endOfDay();
-
/** @var User $user */
$user = auth()->user();
Log::debug(sprintf('getNetWorthInfo up until "%s".', $end->format('Y-m-d H:i:s')));
diff --git a/app/Api/V1/Controllers/User/PreferencesController.php b/app/Api/V1/Controllers/User/PreferencesController.php
index e5a97f7628..9c0be7163e 100644
--- a/app/Api/V1/Controllers/User/PreferencesController.php
+++ b/app/Api/V1/Controllers/User/PreferencesController.php
@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\User\PreferenceStoreRequest;
use FireflyIII\Api\V1\Requests\User\PreferenceUpdateRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Preference;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Transformers\PreferenceTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -52,7 +53,7 @@ class PreferencesController extends Controller
*/
public function index(): JsonResponse
{
- $collection = app('preferences')->all();
+ $collection = Preferences::all();
$manager = $this->getManager();
$count = $collection->count();
$pageSize = $this->parameters->get('limit');
@@ -110,7 +111,7 @@ class PreferencesController extends Controller
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
- $pref = app('preferences')->set($data['name'], $data['data']);
+ $pref = Preferences::set($data['name'], $data['data']);
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
@@ -135,7 +136,7 @@ class PreferencesController extends Controller
$manager = $this->getManager();
$data = $request->getAll();
- $pref = app('preferences')->set($preference->name, $data['data']);
+ $pref = Preferences::set($preference->name, $data['data']);
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
diff --git a/app/Api/V1/Controllers/Webhook/DestroyController.php b/app/Api/V1/Controllers/Webhook/DestroyController.php
index 4899c7be20..98ee5f0586 100644
--- a/app/Api/V1/Controllers/Webhook/DestroyController.php
+++ b/app/Api/V1/Controllers/Webhook/DestroyController.php
@@ -30,6 +30,7 @@ use FireflyIII\Models\Webhook;
use FireflyIII\Models\WebhookAttempt;
use FireflyIII\Models\WebhookMessage;
use FireflyIII\Repositories\Webhook\WebhookRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -70,7 +71,7 @@ class DestroyController extends Controller
Log::channel('audit')->info(sprintf('User destroys webhook #%d.', $webhook->id));
$this->repository->destroy($webhook);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
@@ -101,7 +102,7 @@ class DestroyController extends Controller
Log::channel('audit')->info(sprintf('User destroys webhook #%d, message #%d, attempt #%d.', $webhook->id, $message->id, $attempt->id));
$this->repository->destroyAttempt($attempt);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
@@ -128,7 +129,7 @@ class DestroyController extends Controller
Log::channel('audit')->info(sprintf('User destroys webhook #%d, message #%d.', $webhook->id, $message->id));
$this->repository->destroyMessage($message);
- app('preferences')->mark();
+ Preferences::mark();
return response()->json([], 204);
}
diff --git a/app/Api/V1/Requests/AggregateFormRequest.php b/app/Api/V1/Requests/AggregateFormRequest.php
new file mode 100644
index 0000000000..001c902fda
--- /dev/null
+++ b/app/Api/V1/Requests/AggregateFormRequest.php
@@ -0,0 +1,97 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Api\V1\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Validation\Validator;
+use RuntimeException;
+
+abstract class AggregateFormRequest extends ApiRequest
+{
+ /**
+ * @var ApiRequest[]
+ */
+ protected array $requests = [];
+
+ /** @return class-string[] */
+ abstract protected function getRequests(): array;
+
+ public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): void
+ {
+ parent::initialize($query, $request, $attributes, $cookies, $files, $server, $content);
+
+ // instantiate all subrequests and share current requests' bags with them
+ Log::debug('Initializing AggregateFormRequest.');
+ foreach ($this->getRequests() as $config) {
+ $requestClass = is_array($config) ? array_shift($config) : $config;
+
+ if (!is_a($requestClass, Request::class, true)) {
+ throw new RuntimeException('getRequests() must return class-strings of subclasses of Request');
+ }
+ Log::debug(sprintf('Initializing subrequest %s', $requestClass));
+
+ $instance = $this->requests[] = new $requestClass();
+ $instance->request = $this->request;
+ $instance->query = $this->query;
+ $instance->attributes = $this->attributes;
+ $instance->cookies = $this->cookies;
+ $instance->files = $this->files;
+ $instance->server = $this->server;
+ $instance->headers = $this->headers;
+
+ if ($instance instanceof ApiRequest) {
+ $instance->handleConfig(is_array($config) ? $config : []);
+ }
+ }
+ Log::debug('Done initializing AggregateFormRequest.');
+ }
+
+ public function rules(): array
+ {
+ // check all subrequests for rules and combine them
+ return array_reduce(
+ $this->requests,
+ static fn (array $rules, FormRequest $request) => $rules
+ + (
+ method_exists($request, 'rules')
+ ? $request->rules()
+ : []
+ ),
+ [],
+ );
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ // register all subrequests' validators
+ foreach ($this->requests as $request) {
+ if (method_exists($request, 'withValidator')) {
+ Log::debug(sprintf('Process withValidator from class %s', get_class($request)));
+ $request->withValidator($validator);
+ }
+ }
+ }
+}
diff --git a/app/Api/V1/Requests/ApiRequest.php b/app/Api/V1/Requests/ApiRequest.php
new file mode 100644
index 0000000000..0d2a343f81
--- /dev/null
+++ b/app/Api/V1/Requests/ApiRequest.php
@@ -0,0 +1,43 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Api\V1\Requests;
+
+use FireflyIII\Support\Request\ChecksLogin;
+use FireflyIII\Support\Request\ConvertsDataTypes;
+use Illuminate\Foundation\Http\FormRequest;
+
+class ApiRequest extends FormRequest
+{
+ use ChecksLogin;
+ use ConvertsDataTypes;
+
+ protected string $required = '';
+
+ public function handleConfig(array $config): void
+ {
+ if (in_array('required', $config, true)) {
+ $this->required = 'required';
+ }
+ }
+}
diff --git a/app/Api/V1/Requests/Autocomplete/AutocompleteApiRequest.php b/app/Api/V1/Requests/Autocomplete/AutocompleteApiRequest.php
new file mode 100644
index 0000000000..751f9f580b
--- /dev/null
+++ b/app/Api/V1/Requests/Autocomplete/AutocompleteApiRequest.php
@@ -0,0 +1,46 @@
+.
+ */
+
+namespace FireflyIII\Api\V1\Requests\Autocomplete;
+
+use FireflyIII\Api\V1\Requests\AggregateFormRequest;
+use FireflyIII\Api\V1\Requests\DateRequest;
+use FireflyIII\Api\V1\Requests\Generic\QueryRequest;
+use FireflyIII\Api\V1\Requests\Models\Account\AccountTypesApiRequest;
+use FireflyIII\Api\V1\Requests\PaginationRequest;
+use FireflyIII\Models\Account;
+use Override;
+
+class AutocompleteApiRequest extends AggregateFormRequest
+{
+ #[Override]
+ protected function getRequests(): array
+ {
+ return [
+ DateRequest::class,
+ [PaginationRequest::class, 'sort_class' => Account::class],
+ AccountTypesApiRequest::class,
+ QueryRequest::class,
+ ];
+ }
+}
diff --git a/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php b/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php
index 566624b060..5dd6e8143e 100644
--- a/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php
+++ b/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php
@@ -31,6 +31,8 @@ use Illuminate\Foundation\Http\FormRequest;
/**
* Class AutocompleteRequest
+ *
+ * @deprecated
*/
class AutocompleteRequest extends FormRequest
{
@@ -48,10 +50,12 @@ class AutocompleteRequest extends FormRequest
// remove 'initial balance' from allowed types. its internal
$array = array_diff($array, [AccountTypeEnum::INITIAL_BALANCE->value, AccountTypeEnum::RECONCILIATION->value]);
+ $date = $this->getCarbonDate('date') ?? today(config('app.timezone'));
+
return [
'types' => $array,
'query' => $this->convertString('query'),
- 'date' => $this->getCarbonDate('date'),
+ 'date' => $date->endOfDay(),
];
}
diff --git a/app/Api/V1/Requests/Data/DateRequest.php b/app/Api/V1/Requests/Data/DateRequest.php
deleted file mode 100644
index 7155994862..0000000000
--- a/app/Api/V1/Requests/Data/DateRequest.php
+++ /dev/null
@@ -1,83 +0,0 @@
-.
- */
-
-declare(strict_types=1);
-
-namespace FireflyIII\Api\V1\Requests\Data;
-
-use FireflyIII\Exceptions\ValidationException;
-use FireflyIII\Support\Request\ChecksLogin;
-use FireflyIII\Support\Request\ConvertsDataTypes;
-use Illuminate\Foundation\Http\FormRequest;
-
-/**
- * Request class for end points that require date parameters.
- *
- * Class DateRequest
- */
-class DateRequest extends FormRequest
-{
- use ChecksLogin;
- use ConvertsDataTypes;
-
- /**
- * Get all data from the request.
- */
- public function getAll(): array
- {
- $start = $this->getCarbonDate('start');
- $end = $this->getCarbonDate('end');
- if (null === $start) {
- $start = now()->startOfMonth();
- }
- if (null === $end) {
- $end = now()->endOfMonth();
- }
- // sanity check on dates:
- [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
-
-
- $start->startOfDay();
- $end->endOfDay();
- if ($start->diffInYears($end, true) > 5) {
- throw new ValidationException('Date range out of range.');
- }
-
- return [
- 'start' => $start,
- 'end' => $end,
- 'date' => $this->getCarbonDate('date'),
- ];
- }
-
- /**
- * The rules that the incoming request must be matched against.
- */
- public function rules(): array
- {
- return [
- 'date' => 'date|after:1970-01-02|before:2038-01-17',
- 'start' => 'date|after:1970-01-02|before:2038-01-17|before:end|required_with:end',
- 'end' => 'date|after:1970-01-02|before:2038-01-17|after:start|required_with:start',
- ];
- }
-}
diff --git a/app/Api/V1/Requests/Data/SameDateRequest.php b/app/Api/V1/Requests/Data/SameDateRequest.php
index 9f419653f7..49709b1b4d 100644
--- a/app/Api/V1/Requests/Data/SameDateRequest.php
+++ b/app/Api/V1/Requests/Data/SameDateRequest.php
@@ -32,6 +32,8 @@ use Illuminate\Foundation\Http\FormRequest;
* Request class for end points that require date parameters.
*
* Class SameDateRequest
+ *
+ * @deprecated Replaced by DateRangeRequest
*/
class SameDateRequest extends FormRequest
{
diff --git a/app/Api/V1/Requests/DateRangeRequest.php b/app/Api/V1/Requests/DateRangeRequest.php
new file mode 100644
index 0000000000..bfefb467a6
--- /dev/null
+++ b/app/Api/V1/Requests/DateRangeRequest.php
@@ -0,0 +1,57 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Api\V1\Requests;
+
+use Illuminate\Validation\Validator;
+
+class DateRangeRequest extends ApiRequest
+{
+ public function rules(): array
+ {
+ return [
+ 'start' => sprintf('date|after:1970-01-02|before:2038-01-17|before:end|required_with:end|%s', $this->required),
+ 'end' => sprintf('date|after:1970-01-02|before:2038-01-17|after:start|required_with:start|%s', $this->required),
+ ];
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ $validator->after(
+ function (Validator $validator): void {
+ if ($validator->failed()) {
+ // set null values
+ $this->attributes->set('start', null);
+ $this->attributes->set('end', null);
+
+ return;
+ }
+ $start = $this->getCarbonDate('start')?->startOfDay();
+ $end = $this->getCarbonDate('end')?->endOfDay();
+
+ $this->attributes->set('start', $start);
+ $this->attributes->set('end', $end);
+ }
+ );
+ }
+}
diff --git a/app/Api/V1/Requests/DateRequest.php b/app/Api/V1/Requests/DateRequest.php
new file mode 100644
index 0000000000..b73970786d
--- /dev/null
+++ b/app/Api/V1/Requests/DateRequest.php
@@ -0,0 +1,58 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Api\V1\Requests;
+
+use Carbon\Carbon;
+use Illuminate\Validation\Validator;
+
+class DateRequest extends ApiRequest
+{
+ public function rules(): array
+ {
+ return [
+ 'date' => 'date|after:1970-01-02|before:2038-01-17|'.$this->required,
+ ];
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ $validator->after(
+ function (Validator $validator): void {
+ if ($validator->failed()) {
+ return;
+ }
+ $date = $this->getCarbonDate('date')?->endOfDay();
+
+ // if we also have a range, date must be in that range
+ $start = $this->attributes->get('start');
+ $end = $this->attributes->get('end');
+ if ($date instanceof Carbon && $start instanceof Carbon && $end instanceof Carbon && !$date->between($start, $end)) {
+ $validator->errors()->add('date', (string)trans('validation.between_date'));
+ }
+
+ $this->attributes->set('date', $date);
+ }
+ );
+ }
+}
diff --git a/app/Api/V1/Requests/Generic/QueryRequest.php b/app/Api/V1/Requests/Generic/QueryRequest.php
new file mode 100644
index 0000000000..6414cbbc64
--- /dev/null
+++ b/app/Api/V1/Requests/Generic/QueryRequest.php
@@ -0,0 +1,55 @@
+.
+ */
+
+namespace FireflyIII\Api\V1\Requests\Generic;
+
+use FireflyIII\Api\V1\Requests\ApiRequest;
+use FireflyIII\Support\Request\ChecksLogin;
+use FireflyIII\Support\Request\ConvertsDataTypes;
+use Illuminate\Validation\Validator;
+
+class QueryRequest extends ApiRequest
+{
+ use ChecksLogin;
+ use ConvertsDataTypes;
+
+ public function rules(): array
+ {
+ return [
+ 'query' => sprintf('min:1|max:50|%s', $this->required),
+ ];
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ $validator->after(
+ function (Validator $validator): void {
+ if ($validator->failed()) {
+ return;
+ }
+ $query = $this->convertString('query');
+ $this->attributes->set('query', $query);
+ }
+ );
+ }
+}
diff --git a/app/Api/V1/Requests/Generic/SingleDateRequest.php b/app/Api/V1/Requests/Generic/SingleDateRequest.php
index 14e3c5fc02..b7fe750a5f 100644
--- a/app/Api/V1/Requests/Generic/SingleDateRequest.php
+++ b/app/Api/V1/Requests/Generic/SingleDateRequest.php
@@ -33,6 +33,8 @@ use Illuminate\Foundation\Http\FormRequest;
* Request class for end points that require a date parameter.
*
* Class SingleDateRequest
+ *
+ * @deprecated
*/
class SingleDateRequest extends FormRequest
{
diff --git a/app/Api/V1/Requests/Models/Account/AccountTypeApiRequest.php b/app/Api/V1/Requests/Models/Account/AccountTypeApiRequest.php
new file mode 100644
index 0000000000..e1e6bc686f
--- /dev/null
+++ b/app/Api/V1/Requests/Models/Account/AccountTypeApiRequest.php
@@ -0,0 +1,57 @@
+.
+ */
+
+namespace FireflyIII\Api\V1\Requests\Models\Account;
+
+use FireflyIII\Api\V1\Requests\ApiRequest;
+use FireflyIII\Support\Http\Api\AccountFilter;
+use Illuminate\Validation\Validator;
+
+class AccountTypeApiRequest extends ApiRequest
+{
+ use AccountFilter;
+
+ public function rules(): array
+ {
+ return [
+ 'type' => sprintf('in:%s', implode(',', array_keys($this->types))),
+ ];
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ $validator->after(
+ function (Validator $validator): void {
+ if ($validator->failed()) {
+ return;
+ }
+
+ $type = $this->convertString('type', 'all');
+ $this->attributes->add([
+ 'type' => $type,
+ 'types' => $this->mapAccountTypes($type),
+ ]);
+ }
+ );
+ }
+}
diff --git a/app/Api/V1/Requests/Models/Account/AccountTypesApiRequest.php b/app/Api/V1/Requests/Models/Account/AccountTypesApiRequest.php
new file mode 100644
index 0000000000..e24a027974
--- /dev/null
+++ b/app/Api/V1/Requests/Models/Account/AccountTypesApiRequest.php
@@ -0,0 +1,58 @@
+.
+ */
+
+namespace FireflyIII\Api\V1\Requests\Models\Account;
+
+use FireflyIII\Api\V1\Requests\ApiRequest;
+use FireflyIII\Rules\Account\IsValidAccountTypeList;
+use FireflyIII\Support\Http\Api\AccountFilter;
+use Illuminate\Validation\Validator;
+
+class AccountTypesApiRequest extends ApiRequest
+{
+ use AccountFilter;
+
+ public function rules(): array
+ {
+ // sprintf('in:%s', implode(',', array_keys($this->types))),
+ return [
+ 'types' => new IsValidAccountTypeList(),
+ ];
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ $validator->after(
+ function (Validator $validator): void {
+ if ($validator->failed()) {
+ return;
+ }
+
+ $type = $this->convertString('types', 'all');
+ $this->attributes->add([
+ 'types' => $this->mapAccountTypes($type),
+ ]);
+ }
+ );
+ }
+}
diff --git a/app/Api/V1/Requests/Models/Account/ShowRequest.php b/app/Api/V1/Requests/Models/Account/ShowRequest.php
index f4f7d73332..ed0a7dafe1 100644
--- a/app/Api/V1/Requests/Models/Account/ShowRequest.php
+++ b/app/Api/V1/Requests/Models/Account/ShowRequest.php
@@ -23,77 +23,21 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Models\Account;
-use Carbon\Carbon;
+use FireflyIII\Api\V1\Requests\AggregateFormRequest;
+use FireflyIII\Api\V1\Requests\DateRangeRequest;
+use FireflyIII\Api\V1\Requests\DateRequest;
+use FireflyIII\Api\V1\Requests\PaginationRequest;
use FireflyIII\Models\Account;
-use FireflyIII\Rules\IsValidSortInstruction;
-use FireflyIII\Support\Facades\Preferences;
-use FireflyIII\Support\Http\Api\AccountFilter;
-use FireflyIII\Support\Request\ConvertsDataTypes;
-use FireflyIII\User;
-use Illuminate\Foundation\Http\FormRequest;
-use Illuminate\Validation\Validator;
-class ShowRequest extends FormRequest
+class ShowRequest extends AggregateFormRequest
{
- use AccountFilter;
- use ConvertsDataTypes;
-
- public function getParameters(): array
+ protected function getRequests(): array
{
- $limit = $this->convertInteger('limit');
- if (0 === $limit) {
- // get default for user:
- /** @var User $user */
- $user = auth()->user();
- $limit = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
- }
-
- $page = $this->convertInteger('page');
- $page = min(max(1, $page), 2 ** 16);
-
return [
- 'type' => $this->convertString('type', 'all'),
- 'limit' => $limit,
- 'sort' => $this->convertSortParameters('sort', Account::class),
- 'page' => $page,
+ [PaginationRequest::class, 'sort_class' => Account::class],
+ DateRangeRequest::class,
+ DateRequest::class,
+ AccountTypeApiRequest::class,
];
}
-
- public function rules(): array
- {
- $keys = implode(',', array_keys($this->types));
-
- return [
- 'date' => 'date',
- 'start' => 'date|present_with:end|before_or_equal:end|before:2038-01-17|after:1970-01-02',
- 'end' => 'date|present_with:start|after_or_equal:start|before:2038-01-17|after:1970-01-02',
- 'sort' => ['nullable', new IsValidSortInstruction(Account::class)],
- 'type' => sprintf('in:%s', $keys),
- 'limit' => 'numeric|min:1|max:131337',
- 'page' => 'numeric|min:1|max:131337',
- ];
- }
-
- public function withValidator(Validator $validator): void
- {
- $validator->after(
- function (Validator $validator): void {
- if (count($validator->failed()) > 0) {
- return;
- }
- $data = $validator->getData();
-
-
- if (array_key_exists('date', $data) && array_key_exists('start', $data) && array_key_exists('end', $data)) {
- // assume valid dates, before we got here.
- $start = Carbon::parse($data['start'], config('app.timezone'))->startOfDay();
- $end = Carbon::parse($data['end'], config('app.timezone'))->endOfDay();
- $date = Carbon::parse($data['date'], config('app.timezone'));
- if (!$date->between($start, $end)) {
- $validator->errors()->add('date', (string)trans('validation.between_date'));
- }
- }
- }
- );
- }
}
diff --git a/app/Api/V1/Requests/Models/TransactionCurrency/CurrencyCodeRequest.php b/app/Api/V1/Requests/Models/TransactionCurrency/CurrencyCodeRequest.php
new file mode 100644
index 0000000000..72a2c6bc59
--- /dev/null
+++ b/app/Api/V1/Requests/Models/TransactionCurrency/CurrencyCodeRequest.php
@@ -0,0 +1,50 @@
+.
+ */
+
+namespace FireflyIII\Api\V1\Requests\Models\TransactionCurrency;
+
+use FireflyIII\Api\V1\Requests\ApiRequest;
+use Illuminate\Validation\Validator;
+
+class CurrencyCodeRequest extends ApiRequest
+{
+ public function rules(): array
+ {
+ return [
+ 'code' => sprintf('exists:transaction_currencies,code|%s', $this->required),
+ ];
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ $validator->after(
+ function (Validator $validator): void {
+ if (!$validator->valid()) {
+ return;
+ }
+ $code = $this->convertString('code', '');
+ $this->attributes->set('code', $code);
+ }
+ );
+ }
+}
diff --git a/app/Api/V1/Requests/PaginationRequest.php b/app/Api/V1/Requests/PaginationRequest.php
new file mode 100644
index 0000000000..9b080007dc
--- /dev/null
+++ b/app/Api/V1/Requests/PaginationRequest.php
@@ -0,0 +1,84 @@
+.
+ */
+
+declare(strict_types=1);
+
+namespace FireflyIII\Api\V1\Requests;
+
+use FireflyIII\Rules\IsValidSortInstruction;
+use FireflyIII\Support\Facades\Preferences;
+use FireflyIII\User;
+use Illuminate\Validation\Validator;
+use RuntimeException;
+
+class PaginationRequest extends ApiRequest
+{
+ private ?string $sortClass = null;
+
+ public function handleConfig(array $config): void
+ {
+ parent::handleConfig($config);
+
+ $this->sortClass = $config['sort_class'] ?? null;
+
+ if (!$this->sortClass) {
+ throw new RuntimeException('PaginationRequest requires a sort_class config');
+ }
+ }
+
+ public function rules(): array
+ {
+ return [
+ 'sort' => ['nullable', new IsValidSortInstruction((string)$this->sortClass)],
+ 'limit' => 'numeric|min:1|max:131337',
+ 'page' => 'numeric|min:1|max:131337',
+ ];
+ }
+
+ public function withValidator(Validator $validator): void
+ {
+ $validator->after(
+ function (Validator $validator): void {
+ if ($validator->failed()) {
+ return;
+ }
+
+ $limit = $this->convertInteger('limit');
+ if (0 === $limit) {
+ // get default for user:
+ /** @var User $user */
+ $user = auth()->user();
+ $limit = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
+ }
+
+ $page = $this->convertInteger('page');
+ $page = min(max(1, $page), 2 ** 16);
+ $offset = ($page - 1) * $limit;
+ $sort = $this->sortClass ? $this->convertSortParameters('sort', $this->sortClass) : $this->get('sort');
+
+ $this->attributes->set('limit', $limit);
+ $this->attributes->set('sort', $sort);
+ $this->attributes->set('page', $page);
+ $this->attributes->set('offset', $offset);
+ }
+ );
+ }
+}
diff --git a/app/Api/V1/Requests/Summary/BasicRequest.php b/app/Api/V1/Requests/Summary/BasicRequest.php
new file mode 100644
index 0000000000..ce6ff670c0
--- /dev/null
+++ b/app/Api/V1/Requests/Summary/BasicRequest.php
@@ -0,0 +1,39 @@
+.
+ */
+
+namespace FireflyIII\Api\V1\Requests\Summary;
+
+use FireflyIII\Api\V1\Requests\AggregateFormRequest;
+use FireflyIII\Api\V1\Requests\DateRangeRequest;
+use FireflyIII\Api\V1\Requests\Models\TransactionCurrency\CurrencyCodeRequest;
+
+class BasicRequest extends AggregateFormRequest
+{
+ protected function getRequests(): array
+ {
+ return [
+ [DateRangeRequest::class, 'required'],
+ CurrencyCodeRequest::class,
+ ];
+ }
+}
diff --git a/app/Console/Commands/Correction/CorrectsFrontpageAccounts.php b/app/Console/Commands/Correction/CorrectsFrontpageAccounts.php
index 11a2926f6e..ab2b522115 100644
--- a/app/Console/Commands/Correction/CorrectsFrontpageAccounts.php
+++ b/app/Console/Commands/Correction/CorrectsFrontpageAccounts.php
@@ -28,6 +28,7 @@ use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Models\Preference;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -47,7 +48,7 @@ class CorrectsFrontpageAccounts extends Command
/** @var User $user */
foreach ($users as $user) {
- $preference = app('preferences')->getForUser($user, 'frontpageAccounts');
+ $preference = Preferences::getForUser($user, 'frontpageAccounts');
if (null !== $preference) {
$this->fixPreference($preference);
}
@@ -79,6 +80,6 @@ class CorrectsFrontpageAccounts extends Command
}
}
}
- app('preferences')->setForUser($preference->user, 'frontpageAccounts', $fixed);
+ Preferences::setForUser($preference->user, 'frontpageAccounts', $fixed);
}
}
diff --git a/app/Console/Commands/Correction/CreatesAccessTokens.php b/app/Console/Commands/Correction/CreatesAccessTokens.php
index 92603c83a6..ef478d8da2 100644
--- a/app/Console/Commands/Correction/CreatesAccessTokens.php
+++ b/app/Console/Commands/Correction/CreatesAccessTokens.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Console\Commands\Correction;
use Exception;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -54,10 +55,10 @@ class CreatesAccessTokens extends Command
/** @var User $user */
foreach ($users as $user) {
- $pref = app('preferences')->getForUser($user, 'access_token');
+ $pref = Preferences::getForUser($user, 'access_token');
if (null === $pref) {
$token = $user->generateAccessToken();
- app('preferences')->setForUser($user, 'access_token', $token);
+ Preferences::setForUser($user, 'access_token', $token);
$this->friendlyInfo(sprintf('Generated access token for user %s', $user->email));
++$count;
}
diff --git a/app/Console/Commands/System/SetsLatestVersion.php b/app/Console/Commands/System/SetsLatestVersion.php
index 3c6f6b5244..823f69fec6 100644
--- a/app/Console/Commands/System/SetsLatestVersion.php
+++ b/app/Console/Commands/System/SetsLatestVersion.php
@@ -46,7 +46,7 @@ class SetsLatestVersion extends Command
return 0;
}
- FireflyConfig::set('ff3_version', config('firefly.version'));
+ FireflyConfig::set('ff3_build_time', (int) config('firefly.build_time'));
$this->friendlyInfo('Updated version.');
return 0;
diff --git a/app/Console/Commands/Upgrade/UpgradesBillsToRules.php b/app/Console/Commands/Upgrade/UpgradesBillsToRules.php
index a244f74738..7575dc31e3 100644
--- a/app/Console/Commands/Upgrade/UpgradesBillsToRules.php
+++ b/app/Console/Commands/Upgrade/UpgradesBillsToRules.php
@@ -33,6 +33,7 @@ use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Console\Command;
@@ -114,7 +115,7 @@ class UpgradesBillsToRules extends Command
$this->ruleRepository->setUser($user);
/** @var Preference $lang */
- $lang = app('preferences')->getForUser($user, 'language', 'en_US');
+ $lang = Preferences::getForUser($user, 'language', 'en_US');
$language = null !== $lang->data && !is_array($lang->data) ? (string) $lang->data : 'en_US';
$groupTitle = (string) trans('firefly.rulegroup_for_bills_title', [], $language);
$ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle);
diff --git a/app/Console/Commands/Upgrade/UpgradesDatabase.php b/app/Console/Commands/Upgrade/UpgradesDatabase.php
index 32ff857c9e..877232ee58 100644
--- a/app/Console/Commands/Upgrade/UpgradesDatabase.php
+++ b/app/Console/Commands/Upgrade/UpgradesDatabase.php
@@ -87,7 +87,7 @@ class UpgradesDatabase extends Command
$this->call($command, $args);
}
// index will set FF3 version.
- FireflyConfig::set('ff3_version', (string) config('firefly.version'));
+ FireflyConfig::set('ff3_build_time', (int) config('firefly.build_time'));
return 0;
}
diff --git a/app/Console/Commands/VerifiesAccessToken.php b/app/Console/Commands/VerifiesAccessToken.php
index 906980df68..3726eb6a36 100644
--- a/app/Console/Commands/VerifiesAccessToken.php
+++ b/app/Console/Commands/VerifiesAccessToken.php
@@ -26,6 +26,7 @@ namespace FireflyIII\Console\Commands;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
@@ -79,7 +80,7 @@ trait VerifiesAccessToken
return false;
}
- $accessToken = app('preferences')->getForUser($user, 'access_token');
+ $accessToken = Preferences::getForUser($user, 'access_token');
if (null === $accessToken) {
Log::error(sprintf('User #%d has no access token, so cannot access command line options.', $userId));
diff --git a/app/Factory/AttachmentFactory.php b/app/Factory/AttachmentFactory.php
index 421af6dca2..74e8643886 100644
--- a/app/Factory/AttachmentFactory.php
+++ b/app/Factory/AttachmentFactory.php
@@ -84,8 +84,10 @@ class AttachmentFactory
return $attachment;
}
- public function setUser(User $user): void
+ public function setUser(User $user): static
{
$this->user = $user;
+
+ return $this;
}
}
diff --git a/app/Factory/PiggyBankEventFactory.php b/app/Factory/PiggyBankEventFactory.php
index 52643c55f7..e4635fb93c 100644
--- a/app/Factory/PiggyBankEventFactory.php
+++ b/app/Factory/PiggyBankEventFactory.php
@@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
+use Illuminate\Support\Facades\Log;
/**
* Create piggy bank events.
@@ -36,9 +37,9 @@ class PiggyBankEventFactory
{
public function create(TransactionJournal $journal, ?PiggyBank $piggyBank): void
{
- app('log')->debug(sprintf('Now in PiggyBankEventCreate for a %s', $journal->transactionType->type));
+ Log::debug(sprintf('Now in PiggyBankEventCreate for a %s', $journal->transactionType->type));
if (!$piggyBank instanceof PiggyBank) {
- app('log')->debug('Piggy bank is null');
+ Log::debug('Piggy bank is null');
return;
}
@@ -49,7 +50,7 @@ class PiggyBankEventFactory
$amount = $piggyRepos->getExactAmount($piggyBank, $journal);
if (0 === bccomp($amount, '0')) {
- app('log')->debug('Amount is zero, will not create event.');
+ Log::debug('Amount is zero, will not create event.');
return;
}
diff --git a/app/Factory/TransactionJournalFactory.php b/app/Factory/TransactionJournalFactory.php
index d11753a2bf..cd47828c9d 100644
--- a/app/Factory/TransactionJournalFactory.php
+++ b/app/Factory/TransactionJournalFactory.php
@@ -221,10 +221,26 @@ class TransactionJournalFactory
];
Log::debug('Source info:', $sourceInfo);
Log::debug('Destination info:', $destInfo);
- $sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
- $destinationAccount = $this->getAccount($type->type, 'destination', $destInfo, $sourceAccount);
+ $destinationAccount = null;
+ $sourceAccount = null;
+ if (TransactionTypeEnum::DEPOSIT->value === $type->type) {
+ Log::debug('Transaction type is deposit, start with destination first.');
+ $destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
+ $sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo, $destinationAccount);
+ }
+ if (TransactionTypeEnum::DEPOSIT->value !== $type->type) {
+ Log::debug('Transaction type is not deposit, start with source first.');
+ $sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
+ $destinationAccount = $this->getAccount($type->type, 'destination', $destInfo, $sourceAccount);
+ }
+
Log::debug('Done with getAccount(2x)');
+ // there is a safety catch here. If either account is NULL, they will be replaced with the cash account.
+ if (null === $destinationAccount) {
+ Log::warning('Destination account is NULL, will replace with cash account.');
+ $destinationAccount = $this->accountRepository->getCashAccount();
+ }
// this is the moment for a reconciliation sanity check (again).
if (TransactionTypeEnum::RECONCILIATION->value === $type->type) {
diff --git a/app/Generator/Report/Audit/MonthReportGenerator.php b/app/Generator/Report/Audit/MonthReportGenerator.php
index a0aea0c9df..b920ab172e 100644
--- a/app/Generator/Report/Audit/MonthReportGenerator.php
+++ b/app/Generator/Report/Audit/MonthReportGenerator.php
@@ -137,9 +137,12 @@ class MonthReportGenerator implements ReportGeneratorInterface
;
$journals = $collector->getExtractedJournals();
$journals = array_reverse($journals, true);
- // this call is correct.
- Log::debug(sprintf('getAuditReport: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
- $dayBeforeBalance = Steam::finalAccountBalance($account, $date);
+
+ Log::debug(sprintf('getAuditReport: Call accountsBalancesOptimized with date/time "%s"', $date->toIso8601String()));
+ // 2025-10-08 replace with accountsBalancesOptimized.
+ // $dayBeforeBalance = Steam::finalAccountBalance($account, $date);
+ $dayBeforeBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id];
+
$startBalance = $dayBeforeBalance['balance'];
$primaryCurrency = app('amount')->getPrimaryCurrencyByUserGroup($account->user->userGroup);
$currency = $accountRepository->getAccountCurrency($account) ?? $primaryCurrency;
@@ -176,12 +179,14 @@ class MonthReportGenerator implements ReportGeneratorInterface
// call is correct.
Log::debug(sprintf('getAuditReport end: Call finalAccountBalance with date/time "%s"', $this->end->toIso8601String()));
+ // 2025-10-08 replace with accountsBalancesOptimized:
return [
'journals' => $journals,
'currency' => $currency,
'exists' => 0 !== count($journals),
'end' => $this->end->isoFormat((string) trans('config.month_and_day_moment_js', [], $locale)),
- 'endBalance' => Steam::finalAccountBalance($account, $this->end)['balance'],
+ // 'endBalance' => Steam::finalAccountBalance($account, $this->end)['balance'],
+ 'endBalance' => Steam::accountsBalancesOptimized(new Collection()->push($account), $this->end)[$account->id]['balance'],
'dayBefore' => $date->isoFormat((string) trans('config.month_and_day_moment_js', [], $locale)),
'dayBeforeBalance' => $dayBeforeBalance,
];
diff --git a/app/Handlers/Events/AutomationHandler.php b/app/Handlers/Events/AutomationHandler.php
index 7a59a78a10..9d60e4dc5b 100644
--- a/app/Handlers/Events/AutomationHandler.php
+++ b/app/Handlers/Events/AutomationHandler.php
@@ -30,6 +30,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Notifications\User\TransactionCreation;
use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Transformers\TransactionGroupTransformer;
use Illuminate\Support\Facades\Notification;
@@ -52,7 +53,7 @@ class AutomationHandler
$user = $repository->find($event->userId);
/** @var bool $sendReport */
- $sendReport = app('preferences')->getForUser($user, 'notification_transaction_creation', false)->data;
+ $sendReport = Preferences::getForUser($user, 'notification_transaction_creation', false)->data;
if (false === $sendReport) {
app('log')->debug('Not sending report, because config says so.');
diff --git a/app/Handlers/Events/Model/RuleHandler.php b/app/Handlers/Events/Model/RuleHandler.php
index ea3bb107c8..9655368b52 100644
--- a/app/Handlers/Events/Model/RuleHandler.php
+++ b/app/Handlers/Events/Model/RuleHandler.php
@@ -27,6 +27,7 @@ namespace FireflyIII\Handlers\Events\Model;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnObject;
use FireflyIII\Notifications\User\RuleActionFailed;
+use FireflyIII\Support\Facades\Preferences;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
@@ -42,7 +43,7 @@ class RuleHandler
$rule = $ruleAction->rule;
/** @var bool $preference */
- $preference = app('preferences')->getForUser($rule->user, 'notification_rule_action_failures', true)->data;
+ $preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
if (false === $preference) {
return;
}
@@ -71,7 +72,7 @@ class RuleHandler
$rule = $ruleAction->rule;
/** @var bool $preference */
- $preference = app('preferences')->getForUser($rule->user, 'notification_rule_action_failures', true)->data;
+ $preference = Preferences::getForUser($rule->user, 'notification_rule_action_failures', true)->data;
if (false === $preference) {
return;
}
diff --git a/app/Handlers/Events/StoredGroupEventHandler.php b/app/Handlers/Events/StoredGroupEventHandler.php
index b960ff88df..fd33908b32 100644
--- a/app/Handlers/Events/StoredGroupEventHandler.php
+++ b/app/Handlers/Events/StoredGroupEventHandler.php
@@ -27,6 +27,7 @@ use FireflyIII\Enums\WebhookTrigger;
use FireflyIII\Events\RequestedSendWebhookMessages;
use FireflyIII\Events\StoredTransactionGroup;
use FireflyIII\Generator\Webhook\MessageGeneratorInterface;
+use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\PeriodStatistic\PeriodStatisticRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
@@ -105,10 +106,18 @@ class StoredGroupEventHandler
/** @var TransactionJournal $journal */
foreach ($event->transactionGroup->transactionJournals as $journal) {
+ /** @var null|Transaction $source */
$source = $journal->transactions()->where('amount', '<', '0')->first();
+
+ /** @var null|Transaction $dest */
$dest = $journal->transactions()->where('amount', '>', '0')->first();
- $repository->deleteStatisticsForModel($source->account, $journal->date);
- $repository->deleteStatisticsForModel($dest->account, $journal->date);
+
+ if (null !== $source) {
+ $repository->deleteStatisticsForModel($source->account, $journal->date);
+ }
+ if (null !== $dest) {
+ $repository->deleteStatisticsForModel($dest->account, $journal->date);
+ }
$categories = $journal->categories;
$tags = $journal->tags;
$budgets = $journal->budgets;
diff --git a/app/Handlers/Events/UserEventHandler.php b/app/Handlers/Events/UserEventHandler.php
index db1fdd4134..9e9f0d25cf 100644
--- a/app/Handlers/Events/UserEventHandler.php
+++ b/app/Handlers/Events/UserEventHandler.php
@@ -51,6 +51,7 @@ use FireflyIII\Notifications\User\UserLogin;
use FireflyIII\Notifications\User\UserNewPassword;
use FireflyIII\Notifications\User\UserRegistration as UserRegistrationNotification;
use FireflyIII\Repositories\User\UserRepositoryInterface;
+use FireflyIII\Support\Facades\Preferences;
use FireflyIII\User;
use Illuminate\Auth\Events\Login;
use Illuminate\Support\Facades\Log;
@@ -174,9 +175,10 @@ class UserEventHandler
$user = $event->user;
if ($repository->hasRole($user, 'demo')) {
// set user back to English.
- app('preferences')->setForUser($user, 'language', 'en_US');
- app('preferences')->setForUser($user, 'locale', 'equal');
- app('preferences')->mark();
+ Preferences::setForUser($user, 'language', 'en_US');
+ Preferences::setForUser($user, 'locale', 'equal');
+ Preferences::setForUser($user, 'anonymous', false);
+ Preferences::mark();
}
}
@@ -188,7 +190,7 @@ class UserEventHandler
return; // do not email demo user.
}
- $list = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
+ $list = Preferences::getForUser($user, 'login_ip_history', [])->data;
if (!is_array($list)) {
$list = [];
}
@@ -217,12 +219,12 @@ class UserEventHandler
$list[$index]['notified'] = true;
}
- app('preferences')->setForUser($user, 'login_ip_history', $list);
+ Preferences::setForUser($user, 'login_ip_history', $list);
}
public function sendAdminRegistrationNotification(RegisteredUser $event): void
{
- $sendMail = (bool) app('fireflyconfig')->get('notification_admin_new_reg', true)->data;
+ $sendMail = (bool)app('fireflyconfig')->get('notification_admin_new_reg', true)->data;
if ($sendMail) {
$owner = $event->owner;
@@ -257,7 +259,7 @@ class UserEventHandler
$newEmail = $event->newEmail;
$oldEmail = $event->oldEmail;
$user = $event->user;
- $token = app('preferences')->getForUser($user, 'email_change_confirm_token', 'invalid');
+ $token = Preferences::getForUser($user, 'email_change_confirm_token', 'invalid');
$url = route('profile.confirm-email-change', [$token->data]);
try {
@@ -281,8 +283,8 @@ class UserEventHandler
$newEmail = $event->newEmail;
$oldEmail = $event->oldEmail;
$user = $event->user;
- $token = app('preferences')->getForUser($user, 'email_change_undo_token', 'invalid');
- $hashed = hash('sha256', sprintf('%s%s', (string) config('app.key'), $oldEmail));
+ $token = Preferences::getForUser($user, 'email_change_undo_token', 'invalid');
+ $hashed = hash('sha256', sprintf('%s%s', (string)config('app.key'), $oldEmail));
$url = route('profile.undo-email-change', [$token->data, $hashed]);
try {
@@ -365,7 +367,7 @@ class UserEventHandler
*/
public function sendRegistrationMail(RegisteredUser $event): void
{
- $sendMail = (bool) app('fireflyconfig')->get('notification_user_new_reg', true)->data;
+ $sendMail = (bool)app('fireflyconfig')->get('notification_user_new_reg', true)->data;
if ($sendMail) {
try {
Notification::send($event->user, new UserRegistrationNotification());
@@ -455,7 +457,7 @@ class UserEventHandler
try {
/** @var array $preference */
- $preference = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
+ $preference = Preferences::getForUser($user, 'login_ip_history', [])->data;
} catch (FireflyException $e) {
// don't care.
app('log')->error($e->getMessage());
@@ -491,8 +493,8 @@ class UserEventHandler
$preference = array_values($preference);
/** @var bool $send */
- $send = app('preferences')->getForUser($user, 'notification_user_login', true)->data;
- app('preferences')->setForUser($user, 'login_ip_history', $preference);
+ $send = Preferences::getForUser($user, 'notification_user_login', true)->data;
+ Preferences::setForUser($user, 'login_ip_history', $preference);
if (false === $inArray && true === $send) {
event(new DetectedNewIPAddress($user));
diff --git a/app/Helpers/Collector/Extensions/AccountCollection.php b/app/Helpers/Collector/Extensions/AccountCollection.php
index d56ee1de4b..203cad80ab 100644
--- a/app/Helpers/Collector/Extensions/AccountCollection.php
+++ b/app/Helpers/Collector/Extensions/AccountCollection.php
@@ -62,12 +62,13 @@ trait AccountCollection
if (null === $account) {
continue;
}
+
+ // 2025-10-08 replace with accountsBalancesOptimized
// the balance must be found BEFORE the transaction date.
- // so sub one second. This is not perfect, but works well enough.
- $date = clone $transaction['date'];
- $date->subSecond();
- Log::debug(sprintf('accountBalanceIs: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
- $balance = Steam::finalAccountBalance($account, $date);
+ // so inclusive = false
+ Log::debug(sprintf('accountBalanceIs: Call accountsBalancesOptimized with date/time "%s"', $transaction['date']->toIso8601String()));
+ $balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $transaction['date'], convertToPrimary: null, inclusive: false)[$account->id];
+ // $balance = Steam::finalAccountBalance($account, $date);
$result = bccomp((string) $balance['balance'], $value);
Log::debug(sprintf('"%s" vs "%s" is %d', $balance['balance'], $value, $result));
diff --git a/app/Helpers/Fiscal/FiscalHelper.php b/app/Helpers/Fiscal/FiscalHelper.php
index 53aad1fef3..c9450d597e 100644
--- a/app/Helpers/Fiscal/FiscalHelper.php
+++ b/app/Helpers/Fiscal/FiscalHelper.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Fiscal;
use Carbon\Carbon;
+use FireflyIII\Support\Facades\Preferences;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -40,7 +41,7 @@ class FiscalHelper implements FiscalHelperInterface
*/
public function __construct()
{
- $this->useCustomFiscalYear = (bool) app('preferences')->get('customFiscalYear', false)->data;
+ $this->useCustomFiscalYear = (bool) Preferences::get('customFiscalYear', false)->data;
}
/**
@@ -74,7 +75,7 @@ class FiscalHelper implements FiscalHelperInterface
// get start mm-dd. Then create a start date in the year passed.
$startDate = clone $date;
if (true === $this->useCustomFiscalYear) {
- $prefStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data;
+ $prefStartStr = Preferences::get('fiscalYearStart', '01-01')->data;
if (is_array($prefStartStr)) {
$prefStartStr = '01-01';
}
diff --git a/app/Helpers/Report/NetWorth.php b/app/Helpers/Report/NetWorth.php
index 0ea1ce6cfe..b45659415c 100644
--- a/app/Helpers/Report/NetWorth.php
+++ b/app/Helpers/Report/NetWorth.php
@@ -25,8 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
-use Deprecated;
-use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\UserGroup;
@@ -130,55 +128,4 @@ class NetWorth implements NetWorthInterface
$this->accountRepository->setUserGroup($userGroup);
}
-
- #[Deprecated]
- public function sumNetWorthByCurrency(Carbon $date): array
- {
- /**
- * Collect accounts
- */
- $accounts = $this->getAccounts();
- $return = [];
- Log::debug(sprintf('SumNetWorth: accountsBalancesOptimized("%s")', $date->format('Y-m-d H:i:s')));
- $balances = Steam::accountsBalancesOptimized($accounts, $date);
- foreach ($accounts as $account) {
- $currency = $this->accountRepository->getAccountCurrency($account);
- $balance = $balances[$account->id]['balance'] ?? '0';
-
- // always subtract virtual balance.
- $virtualBalance = $account->virtual_balance;
- if ('' !== $virtualBalance) {
- $balance = bcsub($balance, (string) $virtualBalance);
- }
-
- $return[$currency->id] ??= [
- 'id' => (string) $currency->id,
- 'name' => $currency->name,
- 'symbol' => $currency->symbol,
- 'code' => $currency->code,
- 'decimal_places' => $currency->decimal_places,
- 'sum' => '0',
- ];
- $return[$currency->id]['sum'] = bcadd($return[$currency->id]['sum'], (string) $balance);
- }
-
- return $return;
- }
-
- private function getAccounts(): Collection
- {
- $accounts = $this->accountRepository->getAccountsByType(
- [AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]
- );
- $filtered = new Collection();
-
- /** @var Account $account */
- foreach ($accounts as $account) {
- if (1 === (int) $this->accountRepository->getMetaValue($account, 'include_net_worth')) {
- $filtered->push($account);
- }
- }
-
- return $filtered;
- }
}
diff --git a/app/Helpers/Report/NetWorthInterface.php b/app/Helpers/Report/NetWorthInterface.php
index 421caa9a74..3870359766 100644
--- a/app/Helpers/Report/NetWorthInterface.php
+++ b/app/Helpers/Report/NetWorthInterface.php
@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
-use Deprecated;
use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
@@ -49,12 +48,4 @@ interface NetWorthInterface
public function setUser(Authenticatable|User|null $user): void;
public function setUserGroup(UserGroup $userGroup): void;
-
- /**
- * TODO move to repository
- *
- * Same as above but cleaner function with less dependencies.
- */
- #[Deprecated]
- public function sumNetWorthByCurrency(Carbon $date): array;
}
diff --git a/app/Http/Controllers/Account/CreateController.php b/app/Http/Controllers/Account/CreateController.php
index bab54065d9..f246ec119a 100644
--- a/app/Http/Controllers/Account/CreateController.php
+++ b/app/Http/Controllers/Account/CreateController.php
@@ -96,11 +96,10 @@ class CreateController extends Controller
];
// interest calculation periods:
- $interestPeriods = [
- 'daily' => (string) trans('firefly.interest_calc_daily'),
- 'monthly' => (string) trans('firefly.interest_calc_monthly'),
- 'yearly' => (string) trans('firefly.interest_calc_yearly'),
- ];
+ $interestPeriods = [];
+ foreach (config('firefly.interest_periods') as $period) {
+ $interestPeriods[$period] = trans(sprintf('firefly.interest_calc_%s', $period));
+ }
// pre fill some data
$request->session()->flash(
diff --git a/app/Http/Controllers/Account/EditController.php b/app/Http/Controllers/Account/EditController.php
index 8c2d083b13..041b34a8f9 100644
--- a/app/Http/Controllers/Account/EditController.php
+++ b/app/Http/Controllers/Account/EditController.php
@@ -108,11 +108,10 @@ class EditController extends Controller
];
// interest calculation periods:
- $interestPeriods = [
- 'daily' => (string) trans('firefly.interest_calc_daily'),
- 'monthly' => (string) trans('firefly.interest_calc_monthly'),
- 'yearly' => (string) trans('firefly.interest_calc_yearly'),
- ];
+ $interestPeriods = [];
+ foreach (config('firefly.interest_periods') as $period) {
+ $interestPeriods[$period] = trans(sprintf('firefly.interest_calc_%s', $period));
+ }
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('accounts.edit.fromUpdate')) {
diff --git a/app/Http/Controllers/Account/IndexController.php b/app/Http/Controllers/Account/IndexController.php
index 4f34f0dd5f..41ee6981b3 100644
--- a/app/Http/Controllers/Account/IndexController.php
+++ b/app/Http/Controllers/Account/IndexController.php
@@ -74,32 +74,30 @@ class IndexController extends Controller
*/
public function inactive(Request $request, string $objectType)
{
- $inactivePage = true;
- $subTitle = (string) trans(sprintf('firefly.%s_accounts_inactive', $objectType));
- $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
- $types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
- $collection = $this->repository->getInactiveAccountsByType($types);
- $total = $collection->count();
- $page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
- $pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
- $accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
+ $inactivePage = true;
+ $subTitle = (string) trans(sprintf('firefly.%s_accounts_inactive', $objectType));
+ $subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
+ $types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
+ $collection = $this->repository->getInactiveAccountsByType($types);
+ $total = $collection->count();
+ $page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
+ $pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
+ $accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
unset($collection);
/** @var Carbon $start */
- $start = clone session('start', today(config('app.timezone'))->startOfMonth());
+ $start = clone session('start', today(config('app.timezone'))->startOfMonth());
/** @var Carbon $end */
- $end = clone session('end', today(config('app.timezone'))->endOfMonth());
+ $end = clone session('end', today(config('app.timezone'))->endOfMonth());
- // #10618 go to the end of the previous day.
- $start->subSecond();
-
- $ids = $accounts->pluck('id')->toArray();
- Log::debug(sprintf('inactive start: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
- Log::debug(sprintf('inactive end: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
- $startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
- $endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
- $activities = Steam::getLastActivities($ids);
+ $ids = $accounts->pluck('id')->toArray();
+ Log::debug(sprintf('inactive start: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
+ [
+ $startBalances,
+ $endBalances,
+ ] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
+ $activities = Steam::getLastActivities($ids);
$accounts->each(
@@ -119,7 +117,7 @@ class IndexController extends Controller
);
// make paginator:
- $accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
+ $accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
$accounts->setPath(route('accounts.inactive.index', [$objectType]));
return view('accounts.index', compact('objectType', 'inactivePage', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
@@ -169,14 +167,12 @@ class IndexController extends Controller
/** @var Carbon $end */
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
- // #10618 go to the end of the previous day.
- $start->subSecond();
-
$ids = $accounts->pluck('id')->toArray();
- Log::debug(sprintf('index start: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
- Log::debug(sprintf('index end: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
- $startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
- $endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
+ Log::debug(sprintf('index: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
+ [
+ $startBalances,
+ $endBalances,
+ ] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
$activities = Steam::getLastActivities($ids);
diff --git a/app/Http/Controllers/Account/ReconcileController.php b/app/Http/Controllers/Account/ReconcileController.php
index cee8c1c158..c78696f776 100644
--- a/app/Http/Controllers/Account/ReconcileController.php
+++ b/app/Http/Controllers/Account/ReconcileController.php
@@ -39,6 +39,7 @@ use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
@@ -113,13 +114,20 @@ class ReconcileController extends Controller
$start->startOfDay();
$end->endOfDay();
- $startDate = clone $start;
- $startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59
+ // $startDate = clone $start;
+ // $startDate->subDay()->endOfDay(); // this is correct, subday endofday ends at 23:59:59
// both are validated and are correct.
- Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
- Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
- $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
- $endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
+ // Log::debug(sprintf('reconcile: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
+ // Log::debug(sprintf('reconcile2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
+ // $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
+ // $endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
+
+ // 2025-10-08 replace with accountsBalancesOptimized
+ // no longer need to do subday->endofday on $start, set inclusive = false for the same effect.
+ $startBalance = Steam::bcround(Steam::accountsBalancesOptimized(new Collection()->push($account), $start, convertToPrimary: null, inclusive: false)[$account->id]['balance'], $currency->decimal_places);
+ $endBalance = Steam::bcround(Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id]['balance'], $currency->decimal_places);
+
+
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
diff --git a/app/Http/Controllers/Account/ShowController.php b/app/Http/Controllers/Account/ShowController.php
index 9b1a6922f6..bcb0ba6a0e 100644
--- a/app/Http/Controllers/Account/ShowController.php
+++ b/app/Http/Controllers/Account/ShowController.php
@@ -169,8 +169,9 @@ class ShowController extends Controller
$now = $end;
}
- Log::debug(sprintf('show: Call finalAccountBalance with date/time "%s"', $now->toIso8601String()));
- $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToPrimary, $accountCurrency);
+ // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
+ $balances = Steam::accountsBalancesOptimized(new Collection()->push($account), $now)[$account->id];
+ // $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $now), $account, $this->convertToPrimary, $accountCurrency);
return view(
'accounts.show',
@@ -237,8 +238,12 @@ class ShowController extends Controller
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
$showAll = true;
// correct
- Log::debug(sprintf('showAll: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
- $balances = Steam::filterAccountBalance(Steam::finalAccountBalance($account, $end), $account, $this->convertToPrimary, $accountCurrency);
+ Log::debug(sprintf('showAll: Call accountsBalancesOptimized with date/time "%s"', $end->toIso8601String()));
+
+ // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
+ // $balances = Steam::finalAccountBalance($account, $end);
+ // $balances = Steam::filterAccountBalance($balances, $account, $this->convertToPrimary, $accountCurrency);
+ $balances = Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id];
return view(
'accounts.show',
diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php
index 3df8e35845..ada7f9014e 100644
--- a/app/Http/Controllers/Chart/AccountController.php
+++ b/app/Http/Controllers/Chart/AccountController.php
@@ -116,10 +116,11 @@ class AccountController extends Controller
$accountNames = $this->extractNames($accounts);
// grab all balances
- Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
- Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
- $startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
- $endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
+ Log::debug(sprintf('expenseAccounts: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
+ [
+ $startBalances,
+ $endBalances,
+ ] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
Log::debug('Done collecting balances');
// loop the accounts, then check for balance and currency info.
foreach ($accounts as $account) {
@@ -521,9 +522,9 @@ class AccountController extends Controller
$range = Steam::filterAccountBalances($range, $account, $this->convertToPrimary, $accountCurrency);
Log::debug('Get and filter balance for entire range end');
// temp, get end balance.
- Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
- Steam::finalAccountBalance($account, $end);
- Log::debug('END temp get end balance done');
+ // Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
+ // Steam::finalAccountBalance($account, $end);
+ // Log::debug('END temp get end balance done');
$previous = array_values($range)[0];
$accountCurrency ??= $this->primaryCurrency; // do this AFTER getting the balances.
@@ -666,10 +667,11 @@ class AccountController extends Controller
$accountNames = $this->extractNames($accounts);
// grab all balances
- Log::debug(sprintf('revAccounts: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
- Log::debug(sprintf('revAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
- $startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
- $endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
+ Log::debug(sprintf('revAccounts: accountsBalancesInRange("%s", "%s")', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
+ [
+ $startBalances,
+ $endBalances,
+ ] = Steam::accountsBalancesInRange($accounts, $start, $end, $this->primaryCurrency, $this->convertToPrimary);
// loop the accounts, then check for balance and currency info.
diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php
index 534acf8488..3a148e0168 100644
--- a/app/Http/Controllers/Controller.php
+++ b/app/Http/Controllers/Controller.php
@@ -77,6 +77,7 @@ abstract class Controller extends BaseController
View::share('DEMO_USERNAME', config('firefly.demo_username'));
View::share('DEMO_PASSWORD', config('firefly.demo_password'));
View::share('FF_VERSION', config('firefly.version'));
+ View::share('FF_BUILD_TIME', config('firefly.build_time'));
// is webhooks enabled?
View::share('featuringWebhooks', true === config('firefly.feature_flags.webhooks') && true === config('firefly.allow_webhooks'));
@@ -131,6 +132,7 @@ abstract class Controller extends BaseController
$this->primaryCurrency = null;
// get shown-intro-preference:
if (auth()->check()) {
+ View::share('anonymous', Steam::anonymous());
$this->primaryCurrency = Amount::getPrimaryCurrency();
$language = Steam::getLanguage();
$locale = Steam::getLocale();
diff --git a/app/Http/Controllers/DebugController.php b/app/Http/Controllers/DebugController.php
index 1ed00b4710..0e6bddcd2d 100644
--- a/app/Http/Controllers/DebugController.php
+++ b/app/Http/Controllers/DebugController.php
@@ -81,11 +81,11 @@ class DebugController extends Controller
*/
public function displayError(): void
{
- app('log')->debug('This is a test message at the DEBUG level.');
- app('log')->info('This is a test message at the INFO level.');
+ Log::debug('This is a test message at the DEBUG level.');
+ Log::info('This is a test message at the INFO level.');
Log::notice('This is a test message at the NOTICE level.');
- app('log')->warning('This is a test message at the WARNING level.');
- app('log')->error('This is a test message at the ERROR level.');
+ Log::warning('This is a test message at the WARNING level.');
+ Log::error('This is a test message at the ERROR level.');
Log::critical('This is a test message at the CRITICAL level.');
Log::alert('This is a test message at the ALERT level.');
Log::emergency('This is a test message at the EMERGENCY level.');
@@ -187,6 +187,8 @@ class DebugController extends Controller
return [
'php_version' => PHP_VERSION,
'php_os' => PHP_OS,
+ 'build_time' => config('firefly.build_time'),
+ 'build_time_nice' => Carbon::parse(config('firefly.build_time'), 'Europe/Amsterdam')->setTimezone('Europe/Amsterdam')->format('Y-m-d H:i:s e'),
'uname' => php_uname('m'),
'interface' => PHP_SAPI,
'bits' => PHP_INT_SIZE * 8,
@@ -212,11 +214,11 @@ class DebugController extends Controller
try {
if (file_exists('/var/www/counter-main.txt')) {
$return['build'] = trim(file_get_contents('/var/www/counter-main.txt'));
- app('log')->debug(sprintf('build is now "%s"', $return['build']));
+ Log::debug(sprintf('build is now "%s"', $return['build']));
}
} catch (Exception $e) {
- app('log')->debug('Could not check build counter, but thats ok.');
- app('log')->warning($e->getMessage());
+ Log::debug('Could not check build counter, but thats ok.');
+ Log::warning($e->getMessage());
}
try {
@@ -224,8 +226,8 @@ class DebugController extends Controller
$return['build_date'] = trim(file_get_contents('/var/www/build-date-main.txt'));
}
} catch (Exception $e) {
- app('log')->debug('Could not check build date, but thats ok.');
- app('log')->warning($e->getMessage());
+ Log::debug('Could not check build date, but thats ok.');
+ Log::warning($e->getMessage());
}
if ('' !== (string) env('BASE_IMAGE_BUILD')) { // @phpstan-ignore-line
$return['base_build'] = env('BASE_IMAGE_BUILD'); // @phpstan-ignore-line
@@ -282,7 +284,7 @@ class DebugController extends Controller
$parts = Steam::getLocaleArray(Steam::getLocale());
foreach ($parts as $code) {
$code = trim($code);
- app('log')->debug(sprintf('Trying to set %s', $code));
+ Log::debug(sprintf('Trying to set %s', $code));
$result = setlocale(LC_ALL, $code);
$localeAttempts[$code] = $result === $code;
}
diff --git a/app/Http/Controllers/JavascriptController.php b/app/Http/Controllers/JavascriptController.php
index c5beecfeb4..059e005eb9 100644
--- a/app/Http/Controllers/JavascriptController.php
+++ b/app/Http/Controllers/JavascriptController.php
@@ -30,6 +30,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
+use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -114,6 +115,7 @@ class JavascriptController extends Controller
'currencyCode' => $currency->code,
'currencySymbol' => $currency->symbol,
'accountingLocaleInfo' => $accounting,
+ 'anonymous' => var_export(Steam::anonymous(), true),
'language' => $lang,
'dateRangeTitle' => $dateRange['title'],
'locale' => $locale,
diff --git a/app/Http/Controllers/Json/BoxController.php b/app/Http/Controllers/Json/BoxController.php
index d202a80af0..04d6a6b108 100644
--- a/app/Http/Controllers/Json/BoxController.php
+++ b/app/Http/Controllers/Json/BoxController.php
@@ -38,6 +38,7 @@ use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Http\JsonResponse;
+use Illuminate\Support\Facades\Log;
/**
* Class BoxController.
@@ -165,7 +166,7 @@ class BoxController extends Controller
$allAccounts = $accountRepository->getActiveAccountsByType(
[AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]
);
- app('log')->debug(sprintf('Found %d accounts.', $allAccounts->count()));
+ Log::debug(sprintf('Found %d accounts.', $allAccounts->count()));
// filter list on preference of being included.
$filtered = $allAccounts->filter(
@@ -173,7 +174,7 @@ class BoxController extends Controller
$includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth');
$result = null === $includeNetWorth || '1' === $includeNetWorth;
if (false === $result) {
- app('log')->debug(sprintf('Will not include "%s" in net worth charts.', $account->name));
+ Log::debug(sprintf('Will not include "%s" in net worth charts.', $account->name));
}
return $result;
diff --git a/app/Http/Controllers/Json/ReconcileController.php b/app/Http/Controllers/Json/ReconcileController.php
index 3d88bb0a88..ed85b21885 100644
--- a/app/Http/Controllers/Json/ReconcileController.php
+++ b/app/Http/Controllers/Json/ReconcileController.php
@@ -81,6 +81,12 @@ class ReconcileController extends Controller
if (!$start instanceof Carbon && !$end instanceof Carbon) {
throw new FireflyException('Invalid dates submitted.');
}
+ if (!is_numeric($startBalance)) {
+ $startBalance = '0';
+ }
+ if (!is_numeric($endBalance)) {
+ $endBalance = '0';
+ }
if ($end->lt($start)) {
[$start, $end] = [$end, $start];
}
@@ -197,10 +203,16 @@ class ReconcileController extends Controller
$currency = $this->accountRepos->getAccountCurrency($account) ?? $this->primaryCurrency;
// correct
- Log::debug(sprintf('transactions: Call finalAccountBalance with date/time "%s"', $startDate->toIso8601String()));
- Log::debug(sprintf('transactions2: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
- $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
- $endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
+ Log::debug(sprintf('transactions: Call accountsBalancesOptimized with date/time "%s"', $startDate->toIso8601String()));
+ Log::debug(sprintf('transactions2: Call accountsBalancesOptimized with date/time "%s"', $end->toIso8601String()));
+
+ // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized
+ // $startBalance = Steam::bcround(Steam::finalAccountBalance($account, $startDate)['balance'], $currency->decimal_places);
+ // $endBalance = Steam::bcround(Steam::finalAccountBalance($account, $end)['balance'], $currency->decimal_places);
+
+ $startBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $startDate)[$account->id];
+ $endBalance = Steam::accountsBalancesOptimized(new Collection()->push($account), $end)[$account->id];
+
// get the transactions
$selectionStart = clone $start;
diff --git a/app/Http/Controllers/Rule/CreateController.php b/app/Http/Controllers/Rule/CreateController.php
index 24c9c8bd64..5b95005a1b 100644
--- a/app/Http/Controllers/Rule/CreateController.php
+++ b/app/Http/Controllers/Rule/CreateController.php
@@ -268,7 +268,6 @@ class CreateController extends Controller
public function store(RuleFormRequest $request)
{
$data = $request->getRuleData();
-
$rule = $this->ruleRepos->store($data);
session()->flash('success_url', route('rules.select-transactions', [$rule->id]));
session()->flash('success', (string) trans('firefly.stored_new_rule', ['title' => $rule->title]));
@@ -283,6 +282,9 @@ class CreateController extends Controller
if ((int) $request->get('bill_id') > 0) {
return redirect($this->getPreviousUrl('bills.create.url'));
}
+ if (true === $data['run_after_form']) {
+ return redirect(route('rules.select-transactions', [$rule->id]));
+ }
$redirect = redirect($this->getPreviousUrl('rules.create.url'));
diff --git a/app/Http/Controllers/Rule/EditController.php b/app/Http/Controllers/Rule/EditController.php
index f1888c425d..b9295d5487 100644
--- a/app/Http/Controllers/Rule/EditController.php
+++ b/app/Http/Controllers/Rule/EditController.php
@@ -205,6 +205,11 @@ class EditController extends Controller
session()->flash('success', (string) trans('firefly.updated_rule', ['title' => $rule->title]));
app('preferences')->mark();
$redirect = redirect($this->getPreviousUrl('rules.edit.url'));
+
+ if (true === $data['run_after_form']) {
+ return redirect(route('rules.select-transactions', [$rule->id]));
+ }
+
if (1 === (int) $request->get('return_to_edit')) {
session()->put('rules.edit.fromUpdate', true);
diff --git a/app/Http/Controllers/Rule/SelectController.php b/app/Http/Controllers/Rule/SelectController.php
index 1084a9f2c8..458d866378 100644
--- a/app/Http/Controllers/Rule/SelectController.php
+++ b/app/Http/Controllers/Rule/SelectController.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Rule;
+use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SelectTransactionsRequest;
@@ -56,7 +57,7 @@ class SelectController extends Controller
$this->middleware(
static function ($request, $next) {
- app('view')->share('title', (string) trans('firefly.rules'));
+ app('view')->share('title', (string)trans('firefly.rules'));
app('view')->share('mainTitleIcon', 'fa-random');
return $next($request);
@@ -73,11 +74,20 @@ class SelectController extends Controller
/** @var User $user */
$user = auth()->user();
$accounts = implode(',', $request->get('accounts'));
-
// create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user);
+ // add date operators.
+ if (null !== $request->get('start')) {
+ $startDate = new Carbon($request->get('start'));
+ $newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]);
+ }
+ if (null !== $request->get('end')) {
+ $endDate = new Carbon($request->get('end'));
+ $newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]);
+ }
+
// add extra operators:
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);
@@ -102,7 +112,7 @@ class SelectController extends Controller
return redirect(route('rules.index'));
}
// does the user have shared accounts?
- $subTitle = (string) trans('firefly.apply_rule_selection', ['title' => $rule->title]);
+ $subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
return view('rules.rule.select-transactions', compact('rule', 'subTitle'));
}
@@ -127,7 +137,7 @@ class SelectController extends Controller
// warn if nothing.
if (0 === count($textTriggers)) {
- return response()->json(['html' => '', 'warning' => (string) trans('firefly.warning_no_valid_triggers')]);
+ return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]);
}
foreach ($textTriggers as $textTrigger) {
@@ -160,7 +170,7 @@ class SelectController extends Controller
// Warn the user if only a subset of transactions is returned
$warning = '';
if (0 === count($collection)) {
- $warning = (string) trans('firefly.warning_no_matching_transactions');
+ $warning = (string)trans('firefly.warning_no_matching_transactions');
}
// Return json response
@@ -190,7 +200,7 @@ class SelectController extends Controller
$triggers = $rule->ruleTriggers;
if (0 === count($triggers)) {
- return response()->json(['html' => '', 'warning' => (string) trans('firefly.warning_no_valid_triggers')]);
+ return response()->json(['html' => '', 'warning' => (string)trans('firefly.warning_no_valid_triggers')]);
}
// create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class);
@@ -202,7 +212,7 @@ class SelectController extends Controller
$warning = '';
if (0 === count($collection)) {
- $warning = (string) trans('firefly.warning_no_matching_transactions');
+ $warning = (string)trans('firefly.warning_no_matching_transactions');
}
// Return json response
diff --git a/app/Http/Controllers/RuleGroup/ExecutionController.php b/app/Http/Controllers/RuleGroup/ExecutionController.php
index a0191cba3f..14ee17209a 100644
--- a/app/Http/Controllers/RuleGroup/ExecutionController.php
+++ b/app/Http/Controllers/RuleGroup/ExecutionController.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\RuleGroup;
+use Carbon\Carbon;
use Exception;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SelectTransactionsRequest;
@@ -73,6 +74,16 @@ class ExecutionController extends Controller
$newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user);
+ // add date operators.
+ if (null !== $request->get('start')) {
+ $startDate = new Carbon($request->get('start'));
+ $newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]);
+ }
+ if (null !== $request->get('end')) {
+ $endDate = new Carbon($request->get('end'));
+ $newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]);
+ }
+
// add extra operators:
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);
diff --git a/app/Http/Controllers/System/InstallController.php b/app/Http/Controllers/System/InstallController.php
index 6e1e168d0a..f07f47758b 100644
--- a/app/Http/Controllers/System/InstallController.php
+++ b/app/Http/Controllers/System/InstallController.php
@@ -34,6 +34,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Laravel\Passport\Passport;
use phpseclib3\Crypt\RSA;
@@ -81,8 +82,10 @@ class InstallController extends Controller
public function index()
{
app('view')->share('FF_VERSION', config('firefly.version'));
+
// index will set FF3 version.
FireflyConfig::set('ff3_version', (string) config('firefly.version'));
+ FireflyConfig::set('ff3_build_time', (int) config('firefly.build_time'));
return view('install.index');
}
@@ -98,18 +101,18 @@ class InstallController extends Controller
'errorMessage' => null,
];
- app('log')->debug(sprintf('Will now run commands. Request index is %d', $requestIndex));
+ Log::debug(sprintf('Will now run commands. Request index is %d', $requestIndex));
$indexes = array_keys($this->upgradeCommands);
if (array_key_exists($requestIndex, $indexes)) {
$command = $indexes[$requestIndex];
$parameters = $this->upgradeCommands[$command];
- app('log')->debug(sprintf('Will now execute command "%s" with parameters', $command), $parameters);
+ Log::debug(sprintf('Will now execute command "%s" with parameters', $command), $parameters);
try {
$result = $this->executeCommand($command, $parameters);
} catch (FireflyException $e) {
- app('log')->error($e->getMessage());
- app('log')->error($e->getTraceAsString());
+ Log::error($e->getMessage());
+ Log::error($e->getTraceAsString());
if (str_contains($e->getMessage(), 'open_basedir restriction in effect')) {
$this->lastError = self::BASEDIR_ERROR;
}
@@ -134,7 +137,7 @@ class InstallController extends Controller
*/
private function executeCommand(string $command, array $args): bool
{
- app('log')->debug(sprintf('Will now call command %s with args.', $command), $args);
+ Log::debug(sprintf('Will now call command %s with args.', $command), $args);
try {
if ('generate-keys' === $command) {
@@ -142,7 +145,7 @@ class InstallController extends Controller
}
if ('generate-keys' !== $command) {
Artisan::call($command, $args);
- app('log')->debug(Artisan::output());
+ Log::debug(Artisan::output());
}
} catch (Exception $e) { // intentional generic exception
throw new FireflyException($e->getMessage(), 0, $e);
diff --git a/app/Http/Controllers/Transaction/ConvertController.php b/app/Http/Controllers/Transaction/ConvertController.php
index bb5aa6f7d6..5b26839211 100644
--- a/app/Http/Controllers/Transaction/ConvertController.php
+++ b/app/Http/Controllers/Transaction/ConvertController.php
@@ -37,6 +37,7 @@ use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Services\Internal\Update\JournalUpdateService;
+use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Controllers\ModelInformation;
use FireflyIII\Transformers\TransactionGroupTransformer;
@@ -45,6 +46,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
@@ -228,11 +230,13 @@ class ConvertController extends Controller
foreach ($accountList as $account) {
$date = today()->endOfDay();
Log::debug(sprintf('getLiabilities: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
- $balance = Steam::finalAccountBalance($account, $date)['balance'];
+ // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
+ // $balance = Steam::finalAccountBalance($account, $date)['balance'];
+ $balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]['balance'] ?? '0';
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->primaryCurrency;
- $role = 'l_'.$account->accountType->type;
- $key = (string) trans('firefly.opt_group_'.$role);
- $grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
+ $role = sprintf('l_%s', $account->accountType->type);
+ $key = (string) trans(sprintf('firefly.opt_group_%s', $role));
+ $grouped[$key][$account->id] = sprintf('%s (%s)', $account->name, Amount::formatAnything($currency, $balance, false));
}
return $grouped;
@@ -252,15 +256,18 @@ class ConvertController extends Controller
foreach ($accountList as $account) {
$date = today()->endOfDay();
Log::debug(sprintf('getAssetAccounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
- $balance = Steam::finalAccountBalance($account, $date)['balance'];
+ // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
+ // $balance = Steam::finalAccountBalance($account, $date)['balance'];
+ $balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]['balance'] ?? '0';
+
$currency = $this->accountRepository->getAccountCurrency($account) ?? $this->primaryCurrency;
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
if ('' === $role) {
$role = 'no_account_type';
}
- $key = (string) trans('firefly.opt_group_'.$role);
- $grouped[$key][$account->id] = $account->name.' ('.app('amount')->formatAnything($currency, $balance, false).')';
+ $key = (string) trans(sprintf('firefly.opt_group_%s', $role));
+ $grouped[$key][$account->id] = sprintf('%s (%s)', $account->name, Amount::formatAnything($currency, $balance, false));
}
return $grouped;
diff --git a/app/Http/Requests/RuleFormRequest.php b/app/Http/Requests/RuleFormRequest.php
index 8b7d9ca061..9cb1877ce9 100644
--- a/app/Http/Requests/RuleFormRequest.php
+++ b/app/Http/Requests/RuleFormRequest.php
@@ -54,6 +54,7 @@ class RuleFormRequest extends FormRequest
'description' => $this->stringWithNewlines('description'),
'stop_processing' => $this->boolean('stop_processing'),
'strict' => $this->boolean('strict'),
+ 'run_after_form' => $this->boolean('run_after_form'),
'triggers' => $this->getRuleTriggerData(),
'actions' => $this->getRuleActionData(),
];
@@ -140,16 +141,17 @@ class RuleFormRequest extends FormRequest
// initial set of rules:
$rules = [
- 'title' => 'required|min:1|max:255|uniqueObjectForUser:rules,title',
- 'description' => 'min:1|max:32768|nullable',
- 'stop_processing' => 'boolean',
- 'rule_group_id' => 'required|belongsToUser:rule_groups',
- 'trigger' => 'required|in:store-journal,update-journal,manual-activation',
- 'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
- 'triggers.*.value' => sprintf('required_if:triggers.*.type,%s|max:1024|min:1|ruleTriggerValue', $contextTriggers),
- 'actions.*.type' => 'required|in:'.implode(',', $validActions),
- 'actions.*.value' => [sprintf('required_if:actions.*.type,%s|min:0|max:1024', $contextActions), new IsValidActionExpression(), 'ruleActionValue'],
- 'strict' => 'in:0,1',
+ 'title' => 'required|min:1|max:255|uniqueObjectForUser:rules,title',
+ 'description' => 'min:1|max:32768|nullable',
+ 'stop_processing' => 'boolean',
+ 'rule_group_id' => 'required|belongsToUser:rule_groups',
+ 'trigger' => 'required|in:store-journal,update-journal,manual-activation',
+ 'triggers.*.type' => 'required|in:'.implode(',', $validTriggers),
+ 'triggers.*.value' => sprintf('required_if:triggers.*.type,%s|max:1024|min:1|ruleTriggerValue', $contextTriggers),
+ 'actions.*.type' => 'required|in:'.implode(',', $validActions),
+ 'actions.*.value' => [sprintf('required_if:actions.*.type,%s|min:0|max:1024', $contextActions), new IsValidActionExpression(), 'ruleActionValue'],
+ 'strict' => 'in:0,1',
+ 'run_after_form' => 'in:0,1',
];
/** @var null|Rule $rule */
diff --git a/app/Jobs/MailError.php b/app/Jobs/MailError.php
index ecc8c24b5d..6420ac67fd 100644
--- a/app/Jobs/MailError.php
+++ b/app/Jobs/MailError.php
@@ -31,6 +31,8 @@ use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
+use Safe\Exceptions\FilesystemException;
+use Safe\Exceptions\JsonException;
use Symfony\Component\Mailer\Exception\TransportException;
use function Safe\file_get_contents;
@@ -54,7 +56,7 @@ class MailError extends Job implements ShouldQueue
$debug = $this->exception;
unset($debug['stackTrace'], $debug['headers']);
- app('log')->error(sprintf('Exception is: %s', json_encode($debug)));
+ Log::error(sprintf('Exception is: %s', json_encode($debug)));
}
/**
@@ -90,17 +92,17 @@ class MailError extends Job implements ShouldQueue
} catch (Exception|TransportException $e) {
$message = $e->getMessage();
if (str_contains($message, 'Bcc')) {
- app('log')->warning('[Bcc] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
+ Log::warning('[Bcc] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
return;
}
if (str_contains($message, 'RFC 2822')) {
- app('log')->warning('[RFC] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
+ Log::warning('[RFC] Could not email or log the error. Please validate your email settings, use the .env.example file as a guide.');
return;
}
- app('log')->error($e->getMessage());
- app('log')->error($e->getTraceAsString());
+ Log::error($e->getMessage());
+ Log::error($e->getTraceAsString());
}
}
}
@@ -125,11 +127,25 @@ class MailError extends Job implements ShouldQueue
if (!file_exists($file)) {
Log::debug(sprintf('Wrote new file in "%s"', $file));
- file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
+
+ try {
+ file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
+ } catch (FilesystemException $e) {
+ Log::warning(sprintf('[a] Could not write file "%s": %s', $file, $e->getMessage()));
+ } catch (JsonException $e) {
+ Log::warning(sprintf('[b] Could not parse file "%s": %s', $file, $e->getMessage()));
+ }
}
if (file_exists($file)) {
Log::debug(sprintf('Read file in "%s"', $file));
- $limits = json_decode(file_get_contents($file), true);
+
+ try {
+ $limits = json_decode(file_get_contents($file), true);
+ } catch (FilesystemException $e) {
+ Log::warning(sprintf('[c] Could not read file "%s": %s', $file, $e->getMessage()));
+ } catch (JsonException $e) {
+ Log::warning(sprintf('[d] Could not parse file "%s": %s', $file, $e->getMessage()));
+ }
}
// limit reached?
foreach ($types as $type => $info) {
@@ -157,7 +173,14 @@ class MailError extends Job implements ShouldQueue
}
++$limits[$type]['sent'];
}
- file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
+
+ try {
+ file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
+ } catch (FilesystemException $e) {
+ Log::warning(sprintf('[c] Could not write file "%s": %s', $file, $e->getMessage()));
+ } catch (JsonException $e) {
+ Log::warning(sprintf('[c] Could not parse file "%s": %s', $file, $e->getMessage()));
+ }
Log::debug('No limits reached, return FALSE.');
return false;
diff --git a/app/Repositories/Account/AccountTasker.php b/app/Repositories/Account/AccountTasker.php
index 63260b6643..4278ac4183 100644
--- a/app/Repositories/Account/AccountTasker.php
+++ b/app/Repositories/Account/AccountTasker.php
@@ -50,10 +50,11 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
$yesterday = clone $start;
$yesterday->subDay()->endOfDay(); // exactly up until $start but NOT including.
$end->endOfDay(); // needs to be end of day to be correct.
- Log::debug(sprintf('getAccountReport: accountsBalancesOptimized("%s")', $yesterday->format('Y-m-d H:i:s')));
- Log::debug(sprintf('getAccountReport: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
- $startSet = Steam::accountsBalancesOptimized($accounts, $yesterday);
- $endSet = Steam::accountsBalancesOptimized($accounts, $end);
+ Log::debug(sprintf('getAccountReport: accountsBalancesInRange("%s", "%s")', $yesterday->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
+ [
+ $startSet,
+ $endSet,
+ ] = Steam::accountsBalancesInRange($accounts, $yesterday, $end);
Log::debug('Start of accountreport');
/** @var AccountRepositoryInterface $repository */
diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php
index 056825e7d8..022de3a98c 100644
--- a/app/Repositories/PiggyBank/PiggyBankRepository.php
+++ b/app/Repositories/PiggyBank/PiggyBankRepository.php
@@ -375,7 +375,9 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
{
Log::debug(sprintf('leftOnAccount("%s","%s","%s")', $piggyBank->name, $account->name, $date->format('Y-m-d H:i:s')));
Log::debug(sprintf('leftOnAccount: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
- $balance = Steam::finalAccountBalance($account, $date)['balance'];
+ // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
+ $balance = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id]['balance'];
+ // $balance = Steam::finalAccountBalance($account, $date)['balance'];
Log::debug(sprintf('Balance is: %s', $balance));
diff --git a/app/Repositories/RuleGroup/RuleGroupRepository.php b/app/Repositories/RuleGroup/RuleGroupRepository.php
index a3256ccf50..8ef670d2b2 100644
--- a/app/Repositories/RuleGroup/RuleGroupRepository.php
+++ b/app/Repositories/RuleGroup/RuleGroupRepository.php
@@ -139,7 +139,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
/** @var Rule $entry */
foreach ($set as $entry) {
if ($entry->order !== $count) {
- app('log')->debug(sprintf('Rule #%d was on spot %d but must be on spot %d', $entry->id, $entry->order, $count));
+ Log::debug(sprintf('Rule #%d was on spot %d but must be on spot %d', $entry->id, $entry->order, $count));
$entry->order = $count;
$entry->save();
}
@@ -167,7 +167,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
if ($action->order !== $index) {
$action->order = $index;
$action->save();
- app('log')->debug(sprintf('Rule action #%d was on spot %d but must be on spot %d', $action->id, $action->order, $index));
+ Log::debug(sprintf('Rule action #%d was on spot %d but must be on spot %d', $action->id, $action->order, $index));
}
++$index;
}
@@ -189,7 +189,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
if ($order !== $index) {
$trigger->order = $index;
$trigger->save();
- app('log')->debug(sprintf('Rule trigger #%d was on spot %d but must be on spot %d', $trigger->id, $order, $index));
+ Log::debug(sprintf('Rule trigger #%d was on spot %d but must be on spot %d', $trigger->id, $order, $index));
}
++$index;
}
@@ -235,6 +235,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
public function getActiveStoreRules(RuleGroup $group): Collection
{
return $group->rules()
+ ->orderBy('rules.order', 'ASC')
->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rule_triggers.trigger_type', 'user_action')
->where('rule_triggers.trigger_value', 'store-journal')
@@ -262,6 +263,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
[ // @phpstan-ignore-line
'rules' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC');
+ $query->where('rules.active', true);
},
'rules.ruleTriggers' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC');
@@ -275,23 +277,23 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
if (null === $filter) {
return $groups;
}
- app('log')->debug(sprintf('Will filter getRuleGroupsWithRules on "%s".', $filter));
+ Log::debug(sprintf('Will filter getRuleGroupsWithRules on "%s".', $filter));
return $groups->map(
static function (RuleGroup $group) use ($filter) { // @phpstan-ignore-line
- app('log')->debug(sprintf('Now filtering group #%d', $group->id));
+ Log::debug(sprintf('Now filtering group #%d', $group->id));
// filter the rules in the rule group:
$group->rules = $group->rules->filter(
static function (Rule $rule) use ($filter) {
- app('log')->debug(sprintf('Now filtering rule #%d', $rule->id));
+ Log::debug(sprintf('Now filtering rule #%d', $rule->id));
foreach ($rule->ruleTriggers as $trigger) {
if ('user_action' === $trigger->trigger_type && $filter === $trigger->trigger_value) {
- app('log')->debug(sprintf('Rule #%d triggers on %s, include it.', $rule->id, $filter));
+ Log::debug(sprintf('Rule #%d triggers on %s, include it.', $rule->id, $filter));
return true;
}
}
- app('log')->debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
+ Log::debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
return false;
}
@@ -318,6 +320,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
[ // @phpstan-ignore-line
'rules' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC');
+ $query->where('rules.active', true);
},
'rules.ruleTriggers' => static function (HasMany $query): void {
$query->orderBy('order', 'ASC');
@@ -331,23 +334,23 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
if (null === $filter) {
return $groups;
}
- app('log')->debug(sprintf('Will filter getRuleGroupsWithRules on "%s".', $filter));
+ Log::debug(sprintf('Will filter getRuleGroupsWithRules on "%s".', $filter));
return $groups->map(
static function (RuleGroup $group) use ($filter) { // @phpstan-ignore-line
- app('log')->debug(sprintf('Now filtering group #%d', $group->id));
+ Log::debug(sprintf('Now filtering group #%d', $group->id));
// filter the rules in the rule group:
$group->rules = $group->rules->filter(
static function (Rule $rule) use ($filter) {
- app('log')->debug(sprintf('Now filtering rule #%d', $rule->id));
+ Log::debug(sprintf('Now filtering rule #%d', $rule->id));
foreach ($rule->ruleTriggers as $trigger) {
if ('user_action' === $trigger->trigger_type && $filter === $trigger->trigger_value) {
- app('log')->debug(sprintf('Rule #%d triggers on %s, include it.', $rule->id, $filter));
+ Log::debug(sprintf('Rule #%d triggers on %s, include it.', $rule->id, $filter));
return true;
}
}
- app('log')->debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
+ Log::debug(sprintf('Rule #%d does not trigger on %s, do not include it.', $rule->id, $filter));
return false;
}
@@ -414,7 +417,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
->decrement('order')
;
$ruleGroup->order = $newOrder;
- app('log')->debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
+ Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save();
return;
@@ -425,7 +428,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
->increment('order')
;
$ruleGroup->order = $newOrder;
- app('log')->debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
+ Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save();
}
diff --git a/app/Rules/Account/IsValidAccountTypeList.php b/app/Rules/Account/IsValidAccountTypeList.php
new file mode 100644
index 0000000000..8f5b7422f2
--- /dev/null
+++ b/app/Rules/Account/IsValidAccountTypeList.php
@@ -0,0 +1,56 @@
+translate();
+ }
+ $keys = array_keys($this->types);
+ foreach ($values as $entry) {
+ $entry = (string) $entry;
+ if (!in_array($entry, $keys, true)) {
+ $fail('validation.invalid_account_list')->translate();
+ }
+ }
+ }
+}
diff --git a/app/Rules/IsValidSortInstruction.php b/app/Rules/IsValidSortInstruction.php
index 4d9e7b0cf7..66ed508fc3 100644
--- a/app/Rules/IsValidSortInstruction.php
+++ b/app/Rules/IsValidSortInstruction.php
@@ -38,6 +38,11 @@ class IsValidSortInstruction implements ValidationRule
return;
}
+ if ('' === $value) {
+ // don't validate.
+
+ return;
+ }
$validParameters = config(sprintf('firefly.allowed_sort_parameters.%s', $shortClass));
if (!is_array($validParameters)) {
$fail('validation.no_sort_instructions')->translate(['object' => $shortClass]);
diff --git a/app/Services/Internal/Support/JournalServiceTrait.php b/app/Services/Internal/Support/JournalServiceTrait.php
index a4ce044ebf..ec9a7dec3e 100644
--- a/app/Services/Internal/Support/JournalServiceTrait.php
+++ b/app/Services/Internal/Support/JournalServiceTrait.php
@@ -88,6 +88,7 @@ trait JournalServiceTrait
// the account that Firefly III creates must be "creatable", aka select the one we can create from the list just in case
$creatableType = $this->getCreatableType($expectedTypes[$transactionType]);
+ Log::debug(sprintf('Creatable type is "%s"', $creatableType), $expectedTypes[$transactionType]);
// if the result is NULL but the ID is set, an account could exist of the wrong type.
// that data can be used to create a new account of the right type.
@@ -227,9 +228,11 @@ trait JournalServiceTrait
}
// find by preferred type.
+ Log::debug('Find by preferred type.');
$result = $this->accountRepository->findByName($data['name'], [$types[0]]);
// or any expected type.
+ Log::debug('Find by any expected type.');
$result ??= $this->accountRepository->findByName($data['name'], $types);
if (null !== $result) {
diff --git a/app/Support/Amount.php b/app/Support/Amount.php
index 98e8aa284c..f4bf1de35c 100644
--- a/app/Support/Amount.php
+++ b/app/Support/Amount.php
@@ -163,6 +163,7 @@ class Amount
*/
public function formatFlat(string $symbol, int $decimalPlaces, string $amount, ?bool $coloured = null): string
{
+ $amount = Steam::anonymous() ? '0' : $amount;
$locale = Steam::getLocale();
$rounded = Steam::bcround($amount, $decimalPlaces);
$coloured ??= true;
diff --git a/app/Support/Authentication/RemoteUserGuard.php b/app/Support/Authentication/RemoteUserGuard.php
index 1c87806e00..f53ecaa4fc 100644
--- a/app/Support/Authentication/RemoteUserGuard.php
+++ b/app/Support/Authentication/RemoteUserGuard.php
@@ -49,14 +49,14 @@ class RemoteUserGuard implements Guard
{
/** @var null|Request $request */
$request = $app->get('request');
- Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
+ // Log::debug(sprintf('Created RemoteUserGuard for %s "%s"', $request?->getMethod(), $request?->getRequestUri()));
$this->application = $app;
$this->user = null;
}
public function authenticate(): void
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
if ($this->user instanceof User) {
Log::debug(sprintf('%s is found: #%d, "%s".', $this->user::class, $this->user->id, $this->user->email));
@@ -104,21 +104,21 @@ class RemoteUserGuard implements Guard
public function check(): bool
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
return $this->user() instanceof User;
}
public function guest(): bool
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
return !$this->check();
}
public function hasUser(): bool
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
throw new FireflyException('Did not implement RemoteUserGuard::hasUser()');
}
@@ -128,14 +128,14 @@ class RemoteUserGuard implements Guard
*/
public function id(): int|string|null
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
return $this->user?->id;
}
public function setUser(Authenticatable|User|null $user): void // @phpstan-ignore-line
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
if ($user instanceof User) {
$this->user = $user;
@@ -146,7 +146,7 @@ class RemoteUserGuard implements Guard
public function user(): ?User
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
$user = $this->user;
if (!$user instanceof User) {
Log::debug('User is NULL');
@@ -164,14 +164,14 @@ class RemoteUserGuard implements Guard
*/
public function validate(array $credentials = []): bool
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
throw new FireflyException('Did not implement RemoteUserGuard::validate()');
}
public function viaRemember(): bool
{
- Log::debug(sprintf('Now at %s', __METHOD__));
+ // Log::debug(sprintf('Now at %s', __METHOD__));
return false;
}
diff --git a/app/Support/Http/Controllers/PeriodOverview.php b/app/Support/Http/Controllers/PeriodOverview.php
index caa114007b..6fec7eadda 100644
--- a/app/Support/Http/Controllers/PeriodOverview.php
+++ b/app/Support/Http/Controllers/PeriodOverview.php
@@ -634,10 +634,10 @@ trait PeriodOverview
$currencySymbol = $journal['currency_symbol'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$foreignCurrencyId = $journal['foreign_currency_id'];
- $amount = $journal['amount'] ?? '0';
+ $amount = (string) ($journal['amount'] ?? '0');
if ($this->convertToPrimary && $currencyId !== $this->primaryCurrency->id && $foreignCurrencyId !== $this->primaryCurrency->id) {
- $amount = $journal['pc_amount'] ?? '0';
+ $amount = (string) ($journal['pc_amount'] ?? '0');
$currencyId = $this->primaryCurrency->id;
$currencyCode = $this->primaryCurrency->code;
$currencyName = $this->primaryCurrency->name;
@@ -650,7 +650,7 @@ trait PeriodOverview
$currencyName = $journal['foreign_currency_name'];
$currencySymbol = $journal['foreign_currency_symbol'];
$currencyDecimalPlaces = $journal['foreign_currency_decimal_places'];
- $amount = $journal['foreign_amount'] ?? '0';
+ $amount = (string) ($journal['foreign_amount'] ?? '0');
}
$return[$currencyId] ??= [
'amount' => '0',
diff --git a/app/Support/JsonApi/Enrichments/AccountEnrichment.php b/app/Support/JsonApi/Enrichments/AccountEnrichment.php
index 7aedeb6880..43179333d6 100644
--- a/app/Support/JsonApi/Enrichments/AccountEnrichment.php
+++ b/app/Support/JsonApi/Enrichments/AccountEnrichment.php
@@ -289,8 +289,10 @@ class AccountEnrichment implements EnrichmentInterface
{
$this->balances = Steam::accountsBalancesOptimized($this->collection, $this->getDate(), $this->primaryCurrency, $this->convertToPrimary);
if ($this->start instanceof Carbon && $this->end instanceof Carbon) {
- $this->startBalances = Steam::accountsBalancesOptimized($this->collection, $this->start, $this->primaryCurrency, $this->convertToPrimary);
- $this->endBalances = Steam::accountsBalancesOptimized($this->collection, $this->end, $this->primaryCurrency, $this->convertToPrimary);
+ [
+ $this->startBalances,
+ $this->endBalances,
+ ] = Steam::accountsBalancesInRange($this->collection, $this->start, $this->end, $this->primaryCurrency, $this->convertToPrimary);
}
}
diff --git a/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php b/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php
index e1a6be6a94..8306274b4d 100644
--- a/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php
+++ b/app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php
@@ -154,6 +154,9 @@ class BudgetLimitEnrichment implements EnrichmentInterface
$this->start = $this->collection->min('start_date') ?? Carbon::now()->startOfMonth();
$this->end = $this->collection->max('end_date') ?? Carbon::now()->endOfMonth();
+ // #11096 make sure that the max end date is also at the end of the day,
+ $this->end->endOfDay();
+
/** @var BudgetLimit $limit */
foreach ($this->collection as $limit) {
$id = (int)$limit->id;
diff --git a/app/Support/Navigation.php b/app/Support/Navigation.php
index dd5981e327..b80548d990 100644
--- a/app/Support/Navigation.php
+++ b/app/Support/Navigation.php
@@ -420,6 +420,7 @@ class Navigation
'week' => (string)trans('config.week_in_year_js'),
'weekly' => (string)trans('config.week_in_year_js'),
'1M' => (string)trans('config.month_js'),
+ 'MTD' => (string)trans('config.month_js'),
'month' => (string)trans('config.month_js'),
'monthly' => (string)trans('config.month_js'),
'1Y' => (string)trans('config.year_js'),
@@ -427,6 +428,11 @@ class Navigation
'year' => (string)trans('config.year_js'),
'yearly' => (string)trans('config.year_js'),
'6M' => (string)trans('config.half_year_js'),
+ 'last7' => (string)trans('config.specific_day_js'),
+ 'last30' => (string)trans('config.month_js'),
+ 'last90' => (string)trans('config.month_js'),
+ 'last365' => (string)trans('config.year_js'),
+ 'QTD' => (string)trans('config.month_js'),
];
if (array_key_exists($repeatFrequency, $formatMap)) {
diff --git a/app/Support/Repositories/UserGroup/UserGroupTrait.php b/app/Support/Repositories/UserGroup/UserGroupTrait.php
index 98781e5596..6a4a958917 100644
--- a/app/Support/Repositories/UserGroup/UserGroupTrait.php
+++ b/app/Support/Repositories/UserGroup/UserGroupTrait.php
@@ -88,7 +88,7 @@ trait UserGroupTrait
public function setUserGroup(UserGroup $userGroup): void
{
if (null === $this->user) {
- Log::warning(sprintf('User is not set in repository %s', static::class));
+ Log::warning(sprintf('User is not set in repository %s. This does not have to be a problem.', static::class));
}
$this->userGroup = $userGroup;
}
diff --git a/app/Support/Request/ConvertsDataTypes.php b/app/Support/Request/ConvertsDataTypes.php
index a57c45a320..f8cb76378f 100644
--- a/app/Support/Request/ConvertsDataTypes.php
+++ b/app/Support/Request/ConvertsDataTypes.php
@@ -402,21 +402,21 @@ trait ConvertsDataTypes
*/
protected function getCarbonDate(string $field): ?Carbon
{
- $result = null;
+ $data = (string)$this->get($field);
+ Log::debug(sprintf('Date string is "%s"', $data));
- Log::debug(sprintf('Date string is "%s"', (string)$this->get($field)));
+ if ('' === $data) {
+ return null;
+ }
try {
- $result = '' !== (string)$this->get($field) ? new Carbon((string)$this->get($field), config('app.timezone')) : null;
+ return new Carbon($data, config('app.timezone'));
} catch (InvalidFormatException) {
// @ignoreException
- Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
- }
- if (!$result instanceof Carbon) {
- Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
+ Log::debug(sprintf('Exception when parsing date "%s".', $data));
}
- return $result;
+ return null;
}
/**
diff --git a/app/Support/Search/QueryParser/QueryParser.php b/app/Support/Search/QueryParser/QueryParser.php
index bef27a0ec9..e9d5b7c914 100644
--- a/app/Support/Search/QueryParser/QueryParser.php
+++ b/app/Support/Search/QueryParser/QueryParser.php
@@ -52,13 +52,23 @@ class QueryParser implements QueryParserInterface
$inQuotes = false;
$fieldName = '';
$prohibited = false;
-
- while ($this->position < strlen($this->query)) {
- $char = $this->query[$this->position];
+ $chrArray = preg_split('//u', $this->query, -1, PREG_SPLIT_NO_EMPTY);
+ $count = count($chrArray);
+ while ($this->position < $count) {
+ $char = $chrArray[$this->position];
+ $nextChar = $chrArray[$this->position + 1] ?? '';
// Log::debug(sprintf('Char #%d: %s', $this->position, $char));
// If we're in a quoted string, we treat all characters except another quote as ordinary characters
if ($inQuotes) {
+ if ('\\' === $char && '"' === $nextChar) {
+ // Log::debug('BACKSLASH!');
+ // escaped quote, pretend it's a normal char and continue two places (skipping the actual character).
+ $tokenUnderConstruction .= '\\'.$nextChar;
+ $this->position += 2;
+
+ continue;
+ }
if ('"' !== $char) {
$tokenUnderConstruction .= $char;
++$this->position;
@@ -67,11 +77,9 @@ class QueryParser implements QueryParserInterface
}
// char is "
++$this->position;
+ Log::debug(sprintf('Constructed token: %s', $tokenUnderConstruction));
- return new NodeResult(
- $this->createNode($tokenUnderConstruction, $fieldName, $prohibited),
- false
- );
+ return new NodeResult($this->createNode($tokenUnderConstruction, $fieldName, $prohibited), false);
}
switch ($char) {
@@ -197,9 +205,13 @@ class QueryParser implements QueryParserInterface
private function createNode(string $token, string $fieldName, bool $prohibited): Node
{
if ('' !== $fieldName) {
- Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true)));
+ // OK dus hoe trim je \" correct?
$token = ltrim($token, ':"');
- $token = rtrim($token, '"');
+ if (!str_ends_with($token, '\"')) {
+ $token = rtrim($token, '"');
+ }
+ $token = str_replace('\"', '"', $token);
+ Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true)));
return new FieldNode(trim($fieldName), trim($token), $prohibited);
}
diff --git a/app/Support/Steam.php b/app/Support/Steam.php
index 10a8061153..e290941e87 100644
--- a/app/Support/Steam.php
+++ b/app/Support/Steam.php
@@ -49,9 +49,9 @@ use function Safe\preg_replace;
*/
class Steam
{
- public function accountsBalancesOptimized(Collection $accounts, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
+ public function accountsBalancesOptimized(Collection $accounts, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null, bool $inclusive = true): array
{
- Log::debug(sprintf('accountsBalancesOptimized: Called for %d account(s) with date/time "%s"', $accounts->count(), $date->toIso8601String()));
+ Log::debug(sprintf('accountsBalancesOptimized: Called for %d account(s) with date/time "%s" (inclusive: %s)', $accounts->count(), $date->toIso8601String(), var_export($inclusive, true)));
$result = [];
$convertToPrimary ??= Amount::convertToPrimary();
$primary ??= Amount::getPrimaryCurrency();
@@ -61,14 +61,15 @@ class Steam
$arrayOfSums = Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
- ->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
+ ->where('transaction_journals.date', $inclusive ? '<=' : '<', $date->format('Y-m-d H:i:s'))
->groupBy(['transactions.account_id', 'transaction_currencies.code'])
->get(['transactions.account_id', 'transaction_currencies.code', DB::raw('SUM(transactions.amount) as sum_of_amount')])->toArray()
;
+ Log::debug('Array of sums: ', $arrayOfSums);
+
/** @var Account $account */
foreach ($accounts as $account) {
- // this array is PER account, so we wait a bit before we change code here.
$return = [
'pc_balance' => '0',
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
@@ -76,19 +77,19 @@ class Steam
$currency = $currencies[$account->id];
// second array
- $accountSum = array_filter($arrayOfSums, fn ($entry) => $entry['account_id'] === $account->id);
- if (0 === count($accountSum)) {
+ $accountSums = array_filter($arrayOfSums, fn ($entry) => $entry['account_id'] === $account->id);
+ if (0 === count($accountSums)) {
$result[$account->id] = $return;
continue;
}
- $accountSum = array_values($accountSum)[0];
- $sumOfAmount = (string)$accountSum['sum_of_amount'];
- $sumOfAmount = $this->floatalize('' === $sumOfAmount ? '0' : $sumOfAmount);
- $sumsByCode = [
- $accountSum['code'] => $sumOfAmount,
- ];
-
+ $sumsByCode = [];
+ foreach ($accountSums as $accountSum) {
+ // $accountSum = array_values($accountSum)[0];
+ $sumOfAmount = (string)$accountSum['sum_of_amount'];
+ $sumOfAmount = $this->floatalize('' === $sumOfAmount ? '0' : $sumOfAmount);
+ $sumsByCode[$accountSum['code']] = $sumOfAmount;
+ }
// Log::debug('All balances are (joined)', $others);
// if there is no request to convert, take this as "balance" and "pc_balance".
$return['balance'] = $sumsByCode[$currency->code] ?? '0';
@@ -96,6 +97,7 @@ class Steam
unset($return['pc_balance']);
// Log::debug(sprintf('Set balance to %s, unset pc_balance', $return['balance']));
}
+
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
if ($convertToPrimary) {
$return['pc_balance'] = $this->convertAllBalances($sumsByCode, $primary, $date);
@@ -119,12 +121,23 @@ class Steam
}
$final = array_merge($return, $sumsByCode);
$result[$account->id] = $final;
- // Log::debug('Final balance is', $final);
+ Log::debug(sprintf('Final balance for account #%d is', $account->id), $final);
}
return $result;
}
+ /**
+ * Calls accountsBalancesOptimized for the given accounts and makes sure that inclusive is set to false, so it properly gets the balance of a range.
+ */
+ public function accountsBalancesInRange(Collection $accounts, Carbon $start, Carbon $end, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
+ {
+ return [
+ $this->accountsBalancesOptimized($accounts, $start, $primary, $convertToPrimary, inclusive: false),
+ $this->accountsBalancesOptimized($accounts, $end, $primary, $convertToPrimary),
+ ];
+ }
+
/**
* https://stackoverflow.com/questions/1642614/how-to-ceil-floor-and-round-bcmath-numbers
*/
@@ -276,7 +289,9 @@ class Steam
}
/**
- * Returns smaller than or equal to, so be careful with END OF DAY.
+ * @deprecated
+ * By default this method returns "smaller than or equal to", so be careful with END OF DAY.
+ * If you need end of day balance, use "inclusive = false".
*
* Returns the balance of an account at exact moment given. Array with at least one value.
* Always returns:
@@ -288,18 +303,17 @@ class Steam
* --> "pc_balance": balance in the user's primary currency, with all amounts converted to the primary currency.
* "EUR": balance in EUR (or whatever currencies the account has balance in)
*/
- public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
+ public function finalAccountBalance(Account $account, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null, bool $inclusive = true): array
{
$cache = new CacheProperties();
$cache->addProperty($account->id);
$cache->addProperty($date);
if ($cache->has()) {
- Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
-
+ Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s, inclusive:%s)', $account->id, $date->format('Y-m-d H:i:s'), var_export($inclusive, true)));
// return $cache->get();
}
- // Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
+ Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
if (null === $convertToPrimary) {
$convertToPrimary = Amount::convertToPrimary($account->user);
}
@@ -312,7 +326,6 @@ class Steam
$accountCurrency = $account->meta['currency'];
}
if (!$currencyPresent) {
-
$accountCurrency = $this->getAccountCurrency($account);
}
$hasCurrency = null !== $accountCurrency;
@@ -325,11 +338,11 @@ class Steam
$array = $account->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
- ->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
+ ->where('transaction_journals.date', $inclusive ? '<=' : '<', $date->format('Y-m-d H:i:s'))
->get(['transaction_currencies.code', 'transactions.amount'])->toArray()
;
$others = $this->groupAndSumTransactions($array, 'code', 'amount');
- // Log::debug('All balances are (joined)', $others);
+ Log::debug('All balances are (joined)', $others);
// if there is no request to convert, take this as "balance" and "pc_balance".
$return['balance'] = $others[$currency->code] ?? '0';
if (!$convertToPrimary) {
@@ -338,7 +351,7 @@ class Steam
}
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
if ($convertToPrimary) {
- $return['pc_balance'] = $this->convertAllBalances($others, $primary, $date); // todo sum all and convert.
+ $return['pc_balance'] = $this->convertAllBalances($others, $primary, $date);
// Log::debug(sprintf('Set pc_balance to %s', $return['pc_balance']));
}
@@ -358,18 +371,21 @@ class Steam
// Log::debug(sprintf('Virtual balance makes the (primary currency) total %s', $return['balance']));
}
$final = array_merge($return, $others);
- // Log::debug('Final balance is', $final);
+ Log::debug('Final balance is', $final);
$cache->store($final);
return $final;
}
+ /**
+ * Returns the balance for the given account in the range, with daily precision.
+ */
public function finalAccountBalanceInRange(Account $account, Carbon $start, Carbon $end, bool $convertToPrimary): array
{
// expand period.
$start->startOfDay();
$end->endOfDay();
- Log::debug(sprintf('finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
+ Log::debug(sprintf('called finalAccountBalanceInRange(#%d, %s, %s)', $account->id, $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
// set up cache
$cache = new CacheProperties();
@@ -379,28 +395,21 @@ class Steam
$cache->addProperty($convertToPrimary);
$cache->addProperty($end);
if ($cache->has()) {
- return $cache->get();
+ Log::debug('Return cached finalAccountBalanceInRange');
+ // return $cache->get();
}
$balances = [];
$formatted = $start->format('Y-m-d');
- /*
- * To make sure the start balance is correct, we need to get the balance at the exact end of the previous day.
- * Since we just did "startOfDay" we can do subDay()->endOfDay() to get the correct moment.
- * THAT will be the start balance.
- */
- $request = clone $start;
- $request->subDay()->endOfDay();
Log::debug('Get first balance to start.');
- Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
- $startBalance = $this->finalAccountBalance($account, $request);
+ // 2025-10-08 replaced finalAccountBalance with accountsBalancesOptimized:
$primaryCurrency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup);
+ $startBalance = $this->accountsBalancesOptimized(new Collection()->push($account), $start, $primaryCurrency, $convertToPrimary, false)[$account->id];
$accountCurrency = $this->getAccountCurrency($account);
$hasCurrency = $accountCurrency instanceof TransactionCurrency;
$currency = $accountCurrency ?? $primaryCurrency;
Log::debug(sprintf('Currency is %s', $currency->code));
-
// set start balances:
$startBalance[$currency->code] ??= '0';
if ($hasCurrency) {
@@ -542,7 +551,7 @@ class Steam
try {
$hostName = gethostbyaddr($ipAddress);
} catch (Exception $e) {
- app('log')->error($e->getMessage());
+ Log::error($e->getMessage());
$hostName = $ipAddress;
}
@@ -618,6 +627,19 @@ class Steam
return $locale;
}
+ public function anonymous(): bool // get preference
+ {
+ $singleton = PreferencesSingleton::getInstance();
+ $cached = $singleton->getPreference('anonymous');
+ if (null !== $cached) {
+ return $cached;
+ }
+ $anonymous = app('preferences')->get('anonymous', config('firefly.default_preferences.anonymous', false))->data;
+ $singleton->setPreference('anonymous', $anonymous);
+
+ return $anonymous;
+ }
+
public function getLocaleArray(string $locale): array
{
return [
@@ -757,7 +779,7 @@ class Steam
$current = $converter->convert($currency, $primary, $date, $amount);
Log::debug(sprintf('Convert %s %s to %s %s', $currency->code, $amount, $primary->code, $current));
}
- $total = bcadd((string) $current, $total);
+ $total = bcadd((string)$current, $total);
}
return $total;
diff --git a/app/Support/System/IsOldVersion.php b/app/Support/System/IsOldVersion.php
index 2499debbe8..345463abfe 100644
--- a/app/Support/System/IsOldVersion.php
+++ b/app/Support/System/IsOldVersion.php
@@ -67,32 +67,16 @@ trait IsOldVersion
protected function isOldVersionInstalled(): bool
{
// version compare thing.
- $configVersion = (string)config('firefly.version');
- $dbVersion = (string)FireflyConfig::getFresh('ff3_version', '1.0')->data;
- $compare = 0;
- // compare develop to develop
- if (str_starts_with($configVersion, 'develop') && str_starts_with($dbVersion, 'develop')) {
- $compare = $this->compareDevelopVersions($configVersion, $dbVersion);
- }
- // user has develop installed, goes to normal version.
- if (!str_starts_with($configVersion, 'develop') && str_starts_with($dbVersion, 'develop')) {
- return true;
- }
-
- // user has normal, goes to develop version.
- if (str_starts_with($configVersion, 'develop') && !str_starts_with($dbVersion, 'develop')) {
- return true;
- }
-
- // compare normal with normal.
- if (!str_starts_with($configVersion, 'develop') && !str_starts_with($dbVersion, 'develop')) {
- $compare = version_compare($configVersion, $dbVersion);
- }
- if (-1 === $compare) {
- Log::warning(sprintf('The current configured Firefly III version (%s) is older than the required version (%s). Redirect to migrate routine.', $dbVersion, $configVersion));
+ $configBuildTime = (int)config('firefly.build_time');
+ $dbBuildTime = (int)FireflyConfig::getFresh('ff3_build_time', 123)->data;
+ $configTime = Carbon::createFromTimestamp($configBuildTime, config('app.timezone'));
+ $dbTime = Carbon::createFromTimestamp($dbBuildTime, config('app.timezone'));
+ if ($dbBuildTime < $configBuildTime) {
+ Log::warning(sprintf('Your database was last managed by an older version of Firefly III (I see %s, I expect %s). Redirect to migrate routine.', $dbTime->format('Y-m-d H:i:s'), $configTime->format('Y-m-d H:i:s')));
return true;
}
+ Log::debug(sprintf('Your database is up to date (I see %s, I expect %s).', $dbTime->format('Y-m-d H:i:s'), $configTime->format('Y-m-d H:i:s')));
return false;
}
diff --git a/app/Support/System/OAuthKeys.php b/app/Support/System/OAuthKeys.php
index afb028180a..0f66372a69 100644
--- a/app/Support/System/OAuthKeys.php
+++ b/app/Support/System/OAuthKeys.php
@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Support\System;
use FireflyIII\Exceptions\FireflyException;
+use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Crypt;
@@ -63,10 +64,10 @@ class OAuthKeys
$privateKey = '';
$publicKey = '';
// better check if keys are in the database:
- if (app('fireflyconfig')->has(self::PRIVATE_KEY) && app('fireflyconfig')->has(self::PUBLIC_KEY)) {
+ if (FireflyConfig::has(self::PRIVATE_KEY) && FireflyConfig::has(self::PUBLIC_KEY)) {
try {
- $privateKey = (string)app('fireflyconfig')->get(self::PRIVATE_KEY)?->data;
- $publicKey = (string)app('fireflyconfig')->get(self::PUBLIC_KEY)?->data;
+ $privateKey = (string)FireflyConfig::get(self::PRIVATE_KEY)?->data;
+ $publicKey = (string)FireflyConfig::get(self::PUBLIC_KEY)?->data;
} catch (ContainerExceptionInterface|FireflyException|NotFoundExceptionInterface $e) {
app('log')->error(sprintf('Could not validate keysInDatabase(): %s', $e->getMessage()));
app('log')->error($e->getTraceAsString());
@@ -87,8 +88,8 @@ class OAuthKeys
*/
public static function restoreKeysFromDB(): bool
{
- $privateKey = (string)app('fireflyconfig')->get(self::PRIVATE_KEY)?->data;
- $publicKey = (string)app('fireflyconfig')->get(self::PUBLIC_KEY)?->data;
+ $privateKey = (string)FireflyConfig::get(self::PRIVATE_KEY)?->data;
+ $publicKey = (string)FireflyConfig::get(self::PUBLIC_KEY)?->data;
try {
$privateContent = Crypt::decrypt($privateKey);
@@ -98,8 +99,8 @@ class OAuthKeys
app('log')->error($e->getMessage());
// delete config vars from DB:
- app('fireflyconfig')->delete(self::PRIVATE_KEY);
- app('fireflyconfig')->delete(self::PUBLIC_KEY);
+ FireflyConfig::delete(self::PRIVATE_KEY);
+ FireflyConfig::delete(self::PUBLIC_KEY);
return false;
}
@@ -115,8 +116,8 @@ class OAuthKeys
{
$private = storage_path('oauth-private.key');
$public = storage_path('oauth-public.key');
- app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private)));
- app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public)));
+ FireflyConfig::set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private)));
+ FireflyConfig::set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public)));
}
public static function verifyKeysRoutine(): void
diff --git a/app/Support/Twig/General.php b/app/Support/Twig/General.php
index 485dfe1bd9..80d72a9f75 100644
--- a/app/Support/Twig/General.php
+++ b/app/Support/Twig/General.php
@@ -30,6 +30,7 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Search\OperatorQuerySearch;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use League\CommonMark\GithubFlavoredMarkdownConverter;
@@ -155,9 +156,12 @@ class General extends AbstractExtension
}
/** @var Carbon $date */
- $date = session('end', today(config('app.timezone'))->endOfMonth());
+ $date = now();
Log::debug(sprintf('twig balance: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
- $info = Steam::finalAccountBalance($account, $date);
+
+ // 2025-10-08 replace finalAccountBalance with accountsBalancesOptimized.
+ $info = Steam::accountsBalancesOptimized(new Collection()->push($account), $date)[$account->id];
+ // $info = Steam::finalAccountBalance($account, $date);
$currency = Steam::getAccountCurrency($account);
$primary = Amount::getPrimaryCurrency();
$convertToPrimary = Amount::convertToPrimary();
diff --git a/app/TransactionRules/Actions/UpdatePiggyBank.php b/app/TransactionRules/Actions/UpdatePiggyBank.php
index 9e21497d97..7a0bd2daaf 100644
--- a/app/TransactionRules/Actions/UpdatePiggyBank.php
+++ b/app/TransactionRules/Actions/UpdatePiggyBank.php
@@ -59,9 +59,7 @@ class UpdatePiggyBank implements ActionInterface
$piggyBank = $this->findPiggyBank($user, $actionValue);
if (!$piggyBank instanceof PiggyBank) {
- Log::info(
- sprintf('No piggy bank named "%s", cant execute action #%d of rule #%d', $actionValue, $this->action->id, $this->action->rule_id)
- );
+ Log::info(sprintf('No piggy bank named "%s", cant execute action #%d of rule #%d', $actionValue, $this->action->id, $this->action->rule_id));
event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.cannot_find_piggy', ['name' => $actionValue])));
return false;
diff --git a/app/TransactionRules/Engine/SearchRuleEngine.php b/app/TransactionRules/Engine/SearchRuleEngine.php
index 7843d1ffca..72f7228f20 100644
--- a/app/TransactionRules/Engine/SearchRuleEngine.php
+++ b/app/TransactionRules/Engine/SearchRuleEngine.php
@@ -506,9 +506,23 @@ class SearchRuleEngine implements RuleEngineInterface
*/
private function fireGroup(RuleGroup $group): void
{
- Log::debug(sprintf('Going to fire group #%d with %d rule(s)', $group->id, $group->rules->count()));
-
- $rules = $group->rules()->orderBy('order', 'ASC')->get();
+ $rules = [];
+ if ($group->relationLoaded('rules')) {
+ Log::debug('Group rules have been pre-loaded, do not reload them.');
+ $rules = $group->rules;
+ }
+ if (!$group->relationLoaded('rules')) {
+ Log::debug('Group rules have NOT been pre-loaded, load them NOW.');
+ $rules = $group->rules()
+ ->orderBy('rules.order', 'ASC')
+// ->leftJoin('rule_triggers', 'rules.id', '=', 'rule_triggers.rule_id')
+// ->where('rule_triggers.trigger_type', 'user_action')
+// ->where('rule_triggers.trigger_value', 'store-journal')
+ ->where('rules.active', true)
+ ->get(['rules.*'])
+ ;
+ }
+ Log::debug(sprintf('Going to fire group #%d with %d rule(s)', $group->id, $rules->count()));
/** @var Rule $rule */
foreach ($rules as $rule) {
diff --git a/app/Transformers/AbstractTransformer.php b/app/Transformers/AbstractTransformer.php
index 054173dd0f..d741ba0cf7 100644
--- a/app/Transformers/AbstractTransformer.php
+++ b/app/Transformers/AbstractTransformer.php
@@ -34,11 +34,17 @@ abstract class AbstractTransformer extends TransformerAbstract
{
protected ParameterBag $parameters;
+ /**
+ * @deprecated
+ */
final public function getParameters(): ParameterBag
{
return $this->parameters;
}
+ /**
+ * @deprecated
+ */
final public function setParameters(ParameterBag $parameters): void
{
$this->parameters = $parameters;
diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php
index c9e5d3aeee..5538e745e7 100644
--- a/app/Transformers/AccountTransformer.php
+++ b/app/Transformers/AccountTransformer.php
@@ -30,7 +30,6 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
-use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Class AccountTransformer
@@ -46,7 +45,6 @@ class AccountTransformer extends AbstractTransformer
*/
public function __construct()
{
- $this->parameters = new ParameterBag();
$this->repository = app(AccountRepositoryInterface::class);
$this->convertToPrimary = Amount::convertToPrimary();
$this->primary = Amount::getPrimaryCurrency();
diff --git a/changelog.md b/changelog.md
index e04c8b79a9..19fdba3fa6 100644
--- a/changelog.md
+++ b/changelog.md
@@ -3,6 +3,42 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
+## 6.4.3 - 2025-11-01
+
+### Added
+
+- [PR 10993](https://github.com/firefly-iii/firefly-iii/pull/10993) (use correct translation key for category report income table) reported by @ctrl-f5
+- [PR 11028](https://github.com/firefly-iii/firefly-iii/pull/11028) (Adding Latin American Currency Support) reported by @codearena-bot
+- [PR 11039](https://github.com/firefly-iii/firefly-iii/pull/11039) (proposal for improved request handling) reported by @ctrl-f5
+- [PR 11041](https://github.com/firefly-iii/firefly-iii/pull/11041) (Add XML mimetypes to the allowedMimes list) reported by @jreyesr
+- [Issue 11102](https://github.com/firefly-iii/firefly-iii/issues/11102) (Allow to redact account totals in web ui) reported by @edvgui
+- [Issue 11132](https://github.com/firefly-iii/firefly-iii/issues/11132) (Add a 6 month interest period) reported by @CiramorDev
+
+### Fixed
+
+- [Issue 11109](https://github.com/firefly-iii/firefly-iii/issues/11109) (Could not find a transaction currency with code "Korean Won"/"Russian ruble") reported by @mattephi
+- [PR 11019](https://github.com/firefly-iii/firefly-iii/pull/11019) (fix issue 11015 set end date time to end of day) reported by @ctrl-f5
+- [PR 11024](https://github.com/firefly-iii/firefly-iii/pull/11024) (improved balance range date handling) reported by @ctrl-f5
+- [Issue 11031](https://github.com/firefly-iii/firefly-iii/issues/11031) (Rule with trigger "When a transaction is created" being triggered on transaction updates) reported by @pvieira84
+- [Issue 11038](https://github.com/firefly-iii/firefly-iii/issues/11038) (Missing date formats when using "MTD" on the frontpage) reported by @cristiangrossano
+- [Issue 11042](https://github.com/firefly-iii/firefly-iii/issues/11042) (Option to apply rules on a specific date range has disappeared from the UI) reported by @angelbarrera92
+- [PR 11052](https://github.com/firefly-iii/firefly-iii/pull/11052) (correct validator function to check for errors + `Account\ShowControllerTest`) reported by @ctrl-f5
+- [Issue 11054](https://github.com/firefly-iii/firefly-iii/issues/11054) (Autocreation of revenue account when depositing to liability) reported by @Mr-Kanister
+- [Issue 11063](https://github.com/firefly-iii/firefly-iii/issues/11063) ("bcadd: argument must be of type string, int given" when viewing categories or tags) reported by @df911
+- [Discussion 11104](https://github.com/orgs/firefly-iii/discussions/11104) (Personal Access Token failing on 6.4.2 for data-importer) started by @marcoblancas
+- [Discussion 11122](https://github.com/orgs/firefly-iii/discussions/11122) (Convenient Rules Creation) started by @viewmatic2025
+- [Issue 11134](https://github.com/firefly-iii/firefly-iii/issues/11134) (Rules are not applied if description in quotes) reported by @beatbesmer
+
+### Security
+
+- Debug route is now behind 2FA
+
+### API
+
+- [Issue 11050](https://github.com/firefly-iii/firefly-iii/issues/11050) (Dev Version: `/api/v1/accounts/get/$id` requires (optional) `start` parameter, throws error otherwise) reported by @dreautall
+- [PR 11056](https://github.com/firefly-iii/firefly-iii/pull/11056) (account/attachments endpoint use request object for pagination, add test) reported by @ctrl-f5
+- [Issue 11096](https://github.com/firefly-iii/firefly-iii/issues/11096) (Budget Limit API ignores transactions on the last day of the month) reported by @edbingo
+
## 6.4.2 - 2055-10-07
diff --git a/composer.lock b/composer.lock
index 2cdbc5e87e..35d94930a5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1878,16 +1878,16 @@
},
{
"name": "laravel/framework",
- "version": "v12.32.5",
+ "version": "v12.36.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
- "reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a"
+ "reference": "cad110d7685fbab990a6bb8184d0cfd847d7c4d8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/framework/zipball/77b2740391cd2a825ba59d6fada45e9b8b9bcc5a",
- "reference": "77b2740391cd2a825ba59d6fada45e9b8b9bcc5a",
+ "url": "https://api.github.com/repos/laravel/framework/zipball/cad110d7685fbab990a6bb8184d0cfd847d7c4d8",
+ "reference": "cad110d7685fbab990a6bb8184d0cfd847d7c4d8",
"shasum": ""
},
"require": {
@@ -1999,7 +1999,7 @@
"league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10",
"opis/json-schema": "^2.4.1",
- "orchestra/testbench-core": "^10.6.5",
+ "orchestra/testbench-core": "^10.7.0",
"pda/pheanstalk": "^5.0.6|^7.0.0",
"php-http/discovery": "^1.15",
"phpstan/phpstan": "^2.0",
@@ -2093,7 +2093,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-09-30T17:39:22+00:00"
+ "time": "2025-10-29T14:20:57+00:00"
},
{
"name": "laravel/passport",
@@ -2296,16 +2296,16 @@
},
{
"name": "laravel/serializable-closure",
- "version": "v2.0.5",
+ "version": "v2.0.6",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
- "reference": "3832547db6e0e2f8bb03d4093857b378c66eceed"
+ "reference": "038ce42edee619599a1debb7e81d7b3759492819"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3832547db6e0e2f8bb03d4093857b378c66eceed",
- "reference": "3832547db6e0e2f8bb03d4093857b378c66eceed",
+ "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/038ce42edee619599a1debb7e81d7b3759492819",
+ "reference": "038ce42edee619599a1debb7e81d7b3759492819",
"shasum": ""
},
"require": {
@@ -2353,7 +2353,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
- "time": "2025-09-22T17:29:40+00:00"
+ "time": "2025-10-09T13:42:30+00:00"
},
{
"name": "laravel/slack-notification-channel",
@@ -2485,34 +2485,34 @@
},
{
"name": "lcobucci/clock",
- "version": "3.3.1",
+ "version": "3.5.0",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/clock.git",
- "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b"
+ "reference": "a3139d9e97d47826f27e6a17bb63f13621f86058"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/lcobucci/clock/zipball/db3713a61addfffd615b79bf0bc22f0ccc61b86b",
- "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b",
+ "url": "https://api.github.com/repos/lcobucci/clock/zipball/a3139d9e97d47826f27e6a17bb63f13621f86058",
+ "reference": "a3139d9e97d47826f27e6a17bb63f13621f86058",
"shasum": ""
},
"require": {
- "php": "~8.2.0 || ~8.3.0 || ~8.4.0",
+ "php": "~8.3.0 || ~8.4.0 || ~8.5.0",
"psr/clock": "^1.0"
},
"provide": {
"psr/clock-implementation": "1.0"
},
"require-dev": {
- "infection/infection": "^0.29",
- "lcobucci/coding-standard": "^11.1.0",
+ "infection/infection": "^0.31",
+ "lcobucci/coding-standard": "^11.2.0",
"phpstan/extension-installer": "^1.3.1",
- "phpstan/phpstan": "^1.10.25",
- "phpstan/phpstan-deprecation-rules": "^1.1.3",
- "phpstan/phpstan-phpunit": "^1.3.13",
- "phpstan/phpstan-strict-rules": "^1.5.1",
- "phpunit/phpunit": "^11.3.6"
+ "phpstan/phpstan": "^2.0.0",
+ "phpstan/phpstan-deprecation-rules": "^2.0.0",
+ "phpstan/phpstan-phpunit": "^2.0.0",
+ "phpstan/phpstan-strict-rules": "^2.0.0",
+ "phpunit/phpunit": "^12.0.0"
},
"type": "library",
"autoload": {
@@ -2533,7 +2533,7 @@
"description": "Yet another clock abstraction",
"support": {
"issues": "https://github.com/lcobucci/clock/issues",
- "source": "https://github.com/lcobucci/clock/tree/3.3.1"
+ "source": "https://github.com/lcobucci/clock/tree/3.5.0"
},
"funding": [
{
@@ -2545,26 +2545,26 @@
"type": "patreon"
}
],
- "time": "2024-09-24T20:45:14+00:00"
+ "time": "2025-10-27T09:03:17+00:00"
},
{
"name": "lcobucci/jwt",
- "version": "5.5.0",
+ "version": "5.6.0",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/jwt.git",
- "reference": "a835af59b030d3f2967725697cf88300f579088e"
+ "reference": "bb3e9f21e4196e8afc41def81ef649c164bca25e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e",
- "reference": "a835af59b030d3f2967725697cf88300f579088e",
+ "url": "https://api.github.com/repos/lcobucci/jwt/zipball/bb3e9f21e4196e8afc41def81ef649c164bca25e",
+ "reference": "bb3e9f21e4196e8afc41def81ef649c164bca25e",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"ext-sodium": "*",
- "php": "~8.2.0 || ~8.3.0 || ~8.4.0",
+ "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"psr/clock": "^1.0"
},
"require-dev": {
@@ -2606,7 +2606,7 @@
],
"support": {
"issues": "https://github.com/lcobucci/jwt/issues",
- "source": "https://github.com/lcobucci/jwt/tree/5.5.0"
+ "source": "https://github.com/lcobucci/jwt/tree/5.6.0"
},
"funding": [
{
@@ -2618,7 +2618,7 @@
"type": "patreon"
}
],
- "time": "2025-01-26T21:29:45+00:00"
+ "time": "2025-10-17T11:30:53+00:00"
},
{
"name": "league/commonmark",
@@ -2811,16 +2811,16 @@
},
{
"name": "league/csv",
- "version": "9.26.0",
+ "version": "9.27.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/csv.git",
- "reference": "7fce732754d043f3938899e5183e2d0f3d31b571"
+ "reference": "26de738b8fccf785397d05ee2fc07b6cd8749797"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/csv/zipball/7fce732754d043f3938899e5183e2d0f3d31b571",
- "reference": "7fce732754d043f3938899e5183e2d0f3d31b571",
+ "url": "https://api.github.com/repos/thephpleague/csv/zipball/26de738b8fccf785397d05ee2fc07b6cd8749797",
+ "reference": "26de738b8fccf785397d05ee2fc07b6cd8749797",
"shasum": ""
},
"require": {
@@ -2898,7 +2898,7 @@
"type": "github"
}
],
- "time": "2025-10-01T11:24:54+00:00"
+ "time": "2025-10-25T08:35:20+00:00"
},
{
"name": "league/event",
@@ -2956,16 +2956,16 @@
},
{
"name": "league/flysystem",
- "version": "3.30.0",
+ "version": "3.30.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
- "reference": "2203e3151755d874bb2943649dae1eb8533ac93e"
+ "reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e",
- "reference": "2203e3151755d874bb2943649dae1eb8533ac93e",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c139fd65c1f796b926f4aec0df37f6caa959a8da",
+ "reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da",
"shasum": ""
},
"require": {
@@ -3033,9 +3033,9 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
- "source": "https://github.com/thephpleague/flysystem/tree/3.30.0"
+ "source": "https://github.com/thephpleague/flysystem/tree/3.30.1"
},
- "time": "2025-06-25T13:29:59+00:00"
+ "time": "2025-10-20T15:35:26+00:00"
},
{
"name": "league/flysystem-local",
@@ -3476,22 +3476,22 @@
},
{
"name": "mailersend/laravel-driver",
- "version": "v2.11.0",
+ "version": "v2.12.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-laravel-driver.git",
- "reference": "63acebb5064745076df27b1a80423986b6d7b69e"
+ "reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/63acebb5064745076df27b1a80423986b6d7b69e",
- "reference": "63acebb5064745076df27b1a80423986b6d7b69e",
+ "url": "https://api.github.com/repos/mailersend/mailersend-laravel-driver/zipball/15e1ec41e29e65d3ca226929c65804190aaa93eb",
+ "reference": "15e1ec41e29e65d3ca226929c65804190aaa93eb",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/support": "^9.0 || ^10.0 || ^11.0 || ^12.0",
- "mailersend/mailersend": "^0.34.0",
+ "mailersend/mailersend": "^0.35.0",
"nyholm/psr7": "^1.5",
"php": ">=8.0",
"php-http/guzzle7-adapter": "^1.0",
@@ -3539,22 +3539,22 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-laravel-driver/issues",
- "source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.11.0"
+ "source": "https://github.com/mailersend/mailersend-laravel-driver/tree/v2.12.0"
},
- "time": "2025-06-04T08:47:41+00:00"
+ "time": "2025-10-28T14:59:16+00:00"
},
{
"name": "mailersend/mailersend",
- "version": "v0.34.0",
+ "version": "v0.35.0",
"source": {
"type": "git",
"url": "https://github.com/mailersend/mailersend-php.git",
- "reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab"
+ "reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
- "reference": "1cb8c42e5569e7455b1e0e794dcbf68e3b7898ab",
+ "url": "https://api.github.com/repos/mailersend/mailersend-php/zipball/f1696cf9e727e9503fbc5882d2a111bd966ad276",
+ "reference": "f1696cf9e727e9503fbc5882d2a111bd966ad276",
"shasum": ""
},
"require": {
@@ -3605,9 +3605,9 @@
],
"support": {
"issues": "https://github.com/mailersend/mailersend-php/issues",
- "source": "https://github.com/mailersend/mailersend-php/tree/v0.34.0"
+ "source": "https://github.com/mailersend/mailersend-php/tree/v0.35.0"
},
- "time": "2025-06-04T07:53:52+00:00"
+ "time": "2025-10-28T13:11:43+00:00"
},
{
"name": "monolog/monolog",
@@ -3819,25 +3819,25 @@
},
{
"name": "nette/schema",
- "version": "v1.3.2",
+ "version": "v1.3.3",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
- "reference": "da801d52f0354f70a638673c4a0f04e16529431d"
+ "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d",
- "reference": "da801d52f0354f70a638673c4a0f04e16529431d",
+ "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004",
+ "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004",
"shasum": ""
},
"require": {
"nette/utils": "^4.0",
- "php": "8.1 - 8.4"
+ "php": "8.1 - 8.5"
},
"require-dev": {
"nette/tester": "^2.5.2",
- "phpstan/phpstan-nette": "^1.0",
+ "phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.8"
},
"type": "library",
@@ -3847,6 +3847,9 @@
}
},
"autoload": {
+ "psr-4": {
+ "Nette\\": "src"
+ },
"classmap": [
"src/"
]
@@ -3875,9 +3878,9 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
- "source": "https://github.com/nette/schema/tree/v1.3.2"
+ "source": "https://github.com/nette/schema/tree/v1.3.3"
},
- "time": "2024-10-06T23:10:23+00:00"
+ "time": "2025-10-30T22:57:59+00:00"
},
{
"name": "nette/utils",
@@ -4069,31 +4072,31 @@
},
{
"name": "nunomaduro/termwind",
- "version": "v2.3.1",
+ "version": "v2.3.2",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/termwind.git",
- "reference": "dfa08f390e509967a15c22493dc0bac5733d9123"
+ "reference": "eb61920a53057a7debd718a5b89c2178032b52c0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123",
- "reference": "dfa08f390e509967a15c22493dc0bac5733d9123",
+ "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/eb61920a53057a7debd718a5b89c2178032b52c0",
+ "reference": "eb61920a53057a7debd718a5b89c2178032b52c0",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^8.2",
- "symfony/console": "^7.2.6"
+ "symfony/console": "^7.3.4"
},
"require-dev": {
- "illuminate/console": "^11.44.7",
- "laravel/pint": "^1.22.0",
+ "illuminate/console": "^11.46.1",
+ "laravel/pint": "^1.25.1",
"mockery/mockery": "^1.6.12",
- "pestphp/pest": "^2.36.0 || ^3.8.2",
- "phpstan/phpstan": "^1.12.25",
+ "pestphp/pest": "^2.36.0 || ^3.8.4",
+ "phpstan/phpstan": "^1.12.32",
"phpstan/phpstan-strict-rules": "^1.6.2",
- "symfony/var-dumper": "^7.2.6",
+ "symfony/var-dumper": "^7.3.4",
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
},
"type": "library",
@@ -4136,7 +4139,7 @@
],
"support": {
"issues": "https://github.com/nunomaduro/termwind/issues",
- "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1"
+ "source": "https://github.com/nunomaduro/termwind/tree/v2.3.2"
},
"funding": [
{
@@ -4152,7 +4155,7 @@
"type": "github"
}
],
- "time": "2025-05-08T08:14:37+00:00"
+ "time": "2025-10-18T11:10:27+00:00"
},
{
"name": "nyholm/psr7",
@@ -6416,16 +6419,16 @@
},
{
"name": "symfony/cache",
- "version": "v7.3.4",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
- "reference": "bf8afc8ffd4bfd3d9c373e417f041d9f1e5b863f"
+ "reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/cache/zipball/bf8afc8ffd4bfd3d9c373e417f041d9f1e5b863f",
- "reference": "bf8afc8ffd4bfd3d9c373e417f041d9f1e5b863f",
+ "url": "https://api.github.com/repos/symfony/cache/zipball/4a55feb59664f49042a0824c0f955e2f4c1412ad",
+ "reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad",
"shasum": ""
},
"require": {
@@ -6494,7 +6497,7 @@
"psr6"
],
"support": {
- "source": "https://github.com/symfony/cache/tree/v7.3.4"
+ "source": "https://github.com/symfony/cache/tree/v7.3.5"
},
"funding": [
{
@@ -6514,7 +6517,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T10:12:26+00:00"
+ "time": "2025-10-16T13:55:38+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -6668,16 +6671,16 @@
},
{
"name": "symfony/console",
- "version": "v7.3.4",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
+ "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
- "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
+ "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
+ "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"shasum": ""
},
"require": {
@@ -6742,7 +6745,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.4"
+ "source": "https://github.com/symfony/console/tree/v7.3.5"
},
"funding": [
{
@@ -6762,7 +6765,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-22T15:31:00+00:00"
+ "time": "2025-10-14T15:46:26+00:00"
},
{
"name": "symfony/css-selector",
@@ -7207,16 +7210,16 @@
},
{
"name": "symfony/finder",
- "version": "v7.3.2",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f",
"shasum": ""
},
"require": {
@@ -7251,7 +7254,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.3.2"
+ "source": "https://github.com/symfony/finder/tree/v7.3.5"
},
"funding": [
{
@@ -7271,7 +7274,7 @@
"type": "tidelift"
}
],
- "time": "2025-07-15T13:41:35+00:00"
+ "time": "2025-10-15T18:45:57+00:00"
},
{
"name": "symfony/http-client",
@@ -7453,16 +7456,16 @@
},
{
"name": "symfony/http-foundation",
- "version": "v7.3.4",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "c061c7c18918b1b64268771aad04b40be41dd2e6"
+ "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c061c7c18918b1b64268771aad04b40be41dd2e6",
- "reference": "c061c7c18918b1b64268771aad04b40be41dd2e6",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897",
+ "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897",
"shasum": ""
},
"require": {
@@ -7512,7 +7515,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v7.3.4"
+ "source": "https://github.com/symfony/http-foundation/tree/v7.3.5"
},
"funding": [
{
@@ -7532,20 +7535,20 @@
"type": "tidelift"
}
],
- "time": "2025-09-16T08:38:17+00:00"
+ "time": "2025-10-24T21:42:11+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v7.3.4",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "b796dffea7821f035047235e076b60ca2446e3cf"
+ "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b796dffea7821f035047235e076b60ca2446e3cf",
- "reference": "b796dffea7821f035047235e076b60ca2446e3cf",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab",
+ "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab",
"shasum": ""
},
"require": {
@@ -7630,7 +7633,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-kernel/tree/v7.3.4"
+ "source": "https://github.com/symfony/http-kernel/tree/v7.3.5"
},
"funding": [
{
@@ -7650,20 +7653,20 @@
"type": "tidelift"
}
],
- "time": "2025-09-27T12:32:17+00:00"
+ "time": "2025-10-28T10:19:01+00:00"
},
{
"name": "symfony/mailer",
- "version": "v7.3.4",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
- "reference": "ab97ef2f7acf0216955f5845484235113047a31d"
+ "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mailer/zipball/ab97ef2f7acf0216955f5845484235113047a31d",
- "reference": "ab97ef2f7acf0216955f5845484235113047a31d",
+ "url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba",
+ "reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba",
"shasum": ""
},
"require": {
@@ -7714,7 +7717,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/mailer/tree/v7.3.4"
+ "source": "https://github.com/symfony/mailer/tree/v7.3.5"
},
"funding": [
{
@@ -7734,7 +7737,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-17T05:51:54+00:00"
+ "time": "2025-10-24T14:27:20+00:00"
},
{
"name": "symfony/mailgun-mailer",
@@ -9453,16 +9456,16 @@
},
{
"name": "symfony/var-dumper",
- "version": "v7.3.4",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb"
+ "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
- "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
+ "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
"shasum": ""
},
"require": {
@@ -9516,7 +9519,7 @@
"dump"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v7.3.4"
+ "source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
},
"funding": [
{
@@ -9536,7 +9539,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T10:12:26+00:00"
+ "time": "2025-09-27T09:00:46+00:00"
},
{
"name": "symfony/var-exporter",
@@ -9815,16 +9818,16 @@
},
{
"name": "twig/twig",
- "version": "v3.21.1",
+ "version": "v3.22.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d"
+ "reference": "4509984193026de413baf4ba80f68590a7f2c51d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d",
- "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/4509984193026de413baf4ba80f68590a7f2c51d",
+ "reference": "4509984193026de413baf4ba80f68590a7f2c51d",
"shasum": ""
},
"require": {
@@ -9878,7 +9881,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v3.21.1"
+ "source": "https://github.com/twigphp/Twig/tree/v3.22.0"
},
"funding": [
{
@@ -9890,7 +9893,7 @@
"type": "tidelift"
}
],
- "time": "2025-05-03T07:21:55+00:00"
+ "time": "2025-10-29T15:56:47+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -10052,28 +10055,28 @@
},
{
"name": "webmozart/assert",
- "version": "1.11.0",
+ "version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
+ "reference": "9be6926d8b485f55b9229203f962b51ed377ba68"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
+ "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68",
+ "reference": "9be6926d8b485f55b9229203f962b51ed377ba68",
"shasum": ""
},
"require": {
"ext-ctype": "*",
+ "ext-date": "*",
+ "ext-filter": "*",
"php": "^7.2 || ^8.0"
},
- "conflict": {
- "phpstan/phpstan": "<0.12.20",
- "vimeo/psalm": "<4.6.1 || 4.6.2"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.5.13"
+ "suggest": {
+ "ext-intl": "",
+ "ext-simplexml": "",
+ "ext-spl": ""
},
"type": "library",
"extra": {
@@ -10104,9 +10107,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
- "source": "https://github.com/webmozarts/assert/tree/1.11.0"
+ "source": "https://github.com/webmozarts/assert/tree/1.12.1"
},
- "time": "2022-06-03T18:03:27+00:00"
+ "time": "2025-10-29T15:56:20+00:00"
}
],
"packages-dev": [
@@ -10549,16 +10552,16 @@
},
{
"name": "driftingly/rector-laravel",
- "version": "2.0.7",
+ "version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/driftingly/rector-laravel.git",
- "reference": "625dc02cee08d47ecf0ac86de2f02a55026cf34e"
+ "reference": "abc336cbf06f53d90ab74cecfd319379fc55d408"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/driftingly/rector-laravel/zipball/625dc02cee08d47ecf0ac86de2f02a55026cf34e",
- "reference": "625dc02cee08d47ecf0ac86de2f02a55026cf34e",
+ "url": "https://api.github.com/repos/driftingly/rector-laravel/zipball/abc336cbf06f53d90ab74cecfd319379fc55d408",
+ "reference": "abc336cbf06f53d90ab74cecfd319379fc55d408",
"shasum": ""
},
"require": {
@@ -10578,9 +10581,9 @@
"description": "Rector upgrades rules for Laravel Framework",
"support": {
"issues": "https://github.com/driftingly/rector-laravel/issues",
- "source": "https://github.com/driftingly/rector-laravel/tree/2.0.7"
+ "source": "https://github.com/driftingly/rector-laravel/tree/2.1.1"
},
- "time": "2025-08-19T20:49:47+00:00"
+ "time": "2025-10-23T13:53:44+00:00"
},
{
"name": "fakerphp/faker",
@@ -11036,16 +11039,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v5.6.1",
+ "version": "v5.6.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb",
"shasum": ""
},
"require": {
@@ -11088,9 +11091,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
},
- "time": "2025-08-13T20:13:15+00:00"
+ "time": "2025-10-21T19:32:17+00:00"
},
{
"name": "phar-io/manifest",
@@ -11333,11 +11336,11 @@
},
{
"name": "phpstan/phpstan",
- "version": "2.1.30",
+ "version": "2.1.31",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a4a7f159927983dd4f7c8020ed227d80b7f39d7d",
- "reference": "a4a7f159927983dd4f7c8020ed227d80b7f39d7d",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96",
+ "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96",
"shasum": ""
},
"require": {
@@ -11382,7 +11385,7 @@
"type": "github"
}
],
- "time": "2025-10-02T16:07:52+00:00"
+ "time": "2025-10-10T14:14:11+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -11815,16 +11818,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "12.4.0",
+ "version": "12.4.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9"
+ "reference": "a94ea4d26d865875803b23aaf78c3c2c670ea2ea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9",
- "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a94ea4d26d865875803b23aaf78c3c2c670ea2ea",
+ "reference": "a94ea4d26d865875803b23aaf78c3c2c670ea2ea",
"shasum": ""
},
"require": {
@@ -11892,7 +11895,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.2"
},
"funding": [
{
@@ -11916,20 +11919,20 @@
"type": "tidelift"
}
],
- "time": "2025-10-03T04:28:03+00:00"
+ "time": "2025-10-30T08:41:39+00:00"
},
{
"name": "rector/rector",
- "version": "2.2.1",
+ "version": "2.2.7",
"source": {
"type": "git",
"url": "https://github.com/rectorphp/rector.git",
- "reference": "e1aaf3061e9ae9342ed0824865e3a3360defddeb"
+ "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/rectorphp/rector/zipball/e1aaf3061e9ae9342ed0824865e3a3360defddeb",
- "reference": "e1aaf3061e9ae9342ed0824865e3a3360defddeb",
+ "url": "https://api.github.com/repos/rectorphp/rector/zipball/022038537838bc8a4e526af86c2d6e38eaeff7ef",
+ "reference": "022038537838bc8a4e526af86c2d6e38eaeff7ef",
"shasum": ""
},
"require": {
@@ -11968,7 +11971,7 @@
],
"support": {
"issues": "https://github.com/rectorphp/rector/issues",
- "source": "https://github.com/rectorphp/rector/tree/2.2.1"
+ "source": "https://github.com/rectorphp/rector/tree/2.2.7"
},
"funding": [
{
@@ -11976,7 +11979,7 @@
"type": "github"
}
],
- "time": "2025-10-06T21:25:14+00:00"
+ "time": "2025-10-29T15:46:12+00:00"
},
{
"name": "sebastian/cli-parser",
diff --git a/config/firefly.php b/config/firefly.php
index 8bdd78ce6e..ff61d3b3f8 100644
--- a/config/firefly.php
+++ b/config/firefly.php
@@ -78,8 +78,8 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag.
],
- 'version' => '6.4.2',
- 'build_time' => 1759824590,
+ 'version' => '6.4.3',
+ 'build_time' => 1761889776,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.
@@ -182,6 +182,7 @@ return [
'darkMode' => 'browser',
'list_length' => 10, // to be removed if v1 is cancelled.
'default_preferences' => [
+ 'anonymous' => false,
'frontpageAccounts' => [],
'listPageSize' => 50,
'currencyPreference' => 'EUR',
@@ -225,6 +226,8 @@ return [
// plain files
'text/plain',
'text/html',
+ 'text/xml',
+ 'application/xml',
// images
'image/jpeg',
@@ -306,7 +309,7 @@ return [
// "period must be in this list" values
'bill_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
- 'interest_periods' => ['weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
+ 'interest_periods' => ['daily', 'weekly', 'monthly', 'quarterly', 'half-year', 'yearly'],
// settings to translate X to Y
'range_to_repeat_freq' => [
diff --git a/database/factories/AccountFactory.php b/database/factories/AccountFactory.php
new file mode 100644
index 0000000000..dd2eb4ac04
--- /dev/null
+++ b/database/factories/AccountFactory.php
@@ -0,0 +1,24 @@
+ $this->faker->name(),
+ 'active' => true,
+ ];
+ }
+
+ public function withType(AccountTypeEnum $type): static
+ {
+ return $this->for(AccountType::where('type', $type->value)->first());
+ }
+}
diff --git a/database/migrations/2025_09_25_175248_create_period_statistics.php b/database/migrations/2025_09_25_175248_create_period_statistics.php
index 0cda62b0ef..1e118fc58d 100644
--- a/database/migrations/2025_09_25_175248_create_period_statistics.php
+++ b/database/migrations/2025_09_25_175248_create_period_statistics.php
@@ -11,34 +11,36 @@ return new class extends Migration
*/
public function up(): void
{
- Schema::create('period_statistics', function (Blueprint $table) {
- $table->id();
- $table->timestamps();
+ if (!Schema::hasTable('period_statistics')) {
+ Schema::create('period_statistics', function (Blueprint $table) {
+ $table->id();
+ $table->timestamps();
- // reference to user group id.
- $table->bigInteger('user_group_id', false, true);
+ // reference to user group id.
+ $table->bigInteger('user_group_id', false, true);
- $table->integer('primary_statable_id', false, true)->nullable();
- $table->string('primary_statable_type', 255)->nullable();
+ $table->integer('primary_statable_id', false, true)->nullable();
+ $table->string('primary_statable_type', 255)->nullable();
- $table->integer('secondary_statable_id', false, true)->nullable();
- $table->string('secondary_statable_type', 255)->nullable();
+ $table->integer('secondary_statable_id', false, true)->nullable();
+ $table->string('secondary_statable_type', 255)->nullable();
- $table->integer('tertiary_statable_id', false, true)->nullable();
- $table->string('tertiary_statable_type', 255)->nullable();
+ $table->integer('tertiary_statable_id', false, true)->nullable();
+ $table->string('tertiary_statable_type', 255)->nullable();
- $table->integer('transaction_currency_id', false, true);
- $table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade');
+ $table->integer('transaction_currency_id', false, true);
+ $table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('cascade');
- $table->dateTime('start')->nullable();
- $table->string('start_tz', 50)->nullable();
- $table->dateTime('end')->nullable();
- $table->string('end_tz', 50)->nullable();
- $table->string('type',255);
- $table->integer('count', false, true)->default(0);
- $table->decimal('amount', 32, 12);
- $table->foreign('user_group_id')->references('id')->on('user_groups')->onDelete('cascade');
- });
+ $table->dateTime('start')->nullable();
+ $table->string('start_tz', 50)->nullable();
+ $table->dateTime('end')->nullable();
+ $table->string('end_tz', 50)->nullable();
+ $table->string('type', 255);
+ $table->integer('count', false, true)->default(0);
+ $table->decimal('amount', 32, 12);
+ $table->foreign('user_group_id')->references('id')->on('user_groups')->onDelete('cascade');
+ });
+ }
}
/**
diff --git a/database/seeders/TransactionCurrencySeeder.php b/database/seeders/TransactionCurrencySeeder.php
index ce75ec253d..5673362389 100644
--- a/database/seeders/TransactionCurrencySeeder.php
+++ b/database/seeders/TransactionCurrencySeeder.php
@@ -53,6 +53,10 @@ class TransactionCurrencySeeder extends Seeder
$currencies[] = ['code' => 'BRL', 'name' => 'Brazilian real', 'symbol' => 'R$', 'decimal_places' => 2];
$currencies[] = ['code' => 'CAD', 'name' => 'Canadian dollar', 'symbol' => 'C$', 'decimal_places' => 2];
$currencies[] = ['code' => 'MXN', 'name' => 'Mexican peso', 'symbol' => 'MX$', 'decimal_places' => 2];
+ $currencies[] = ['code' => 'PEN', 'name' => 'Peruvian Sol', 'symbol' => 'S/', 'decimal_places' => 2];
+ $currencies[] = ['code' => 'ARS', 'name' => 'Argentinian Peso', 'symbol' => '$', 'decimal_places' => 2];
+ $currencies[] = ['code' => 'COP', 'name' => 'Colombian Peso', 'symbol' => '$', 'decimal_places' => 2];
+ $currencies[] = ['code' => 'CLP', 'name' => 'Chilean Peso', 'symbol' => '$', 'decimal_places' => 2];
// oceanian currencies
$currencies[] = ['code' => 'IDR', 'name' => 'Indonesian rupiah', 'symbol' => 'Rp', 'decimal_places' => 2];
diff --git a/package-lock.json b/package-lock.json
index a9ba1b32a1..6f0fc7e4e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,9 +29,9 @@
}
},
"node_modules/@babel/compat-data": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
- "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
+ "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -39,21 +39,21 @@
}
},
"node_modules/@babel/core": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
- "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
+ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.3",
+ "@babel/generator": "^7.28.5",
"@babel/helper-compilation-targets": "^7.27.2",
"@babel/helper-module-transforms": "^7.28.3",
"@babel/helpers": "^7.28.4",
- "@babel/parser": "^7.28.4",
+ "@babel/parser": "^7.28.5",
"@babel/template": "^7.27.2",
- "@babel/traverse": "^7.28.4",
- "@babel/types": "^7.28.4",
+ "@babel/traverse": "^7.28.5",
+ "@babel/types": "^7.28.5",
"@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
@@ -80,14 +80,14 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
- "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
+ "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.28.3",
- "@babel/types": "^7.28.2",
+ "@babel/parser": "^7.28.5",
+ "@babel/types": "^7.28.5",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
@@ -137,18 +137,18 @@
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz",
- "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz",
+ "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.3",
- "@babel/helper-member-expression-to-functions": "^7.27.1",
+ "@babel/helper-member-expression-to-functions": "^7.28.5",
"@babel/helper-optimise-call-expression": "^7.27.1",
"@babel/helper-replace-supers": "^7.27.1",
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
- "@babel/traverse": "^7.28.3",
+ "@babel/traverse": "^7.28.5",
"semver": "^6.3.1"
},
"engines": {
@@ -169,14 +169,14 @@
}
},
"node_modules/@babel/helper-create-regexp-features-plugin": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz",
- "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz",
+ "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-annotate-as-pure": "^7.27.1",
- "regexpu-core": "^6.2.0",
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "regexpu-core": "^6.3.1",
"semver": "^6.3.1"
},
"engines": {
@@ -224,14 +224,14 @@
}
},
"node_modules/@babel/helper-member-expression-to-functions": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz",
- "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz",
+ "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/traverse": "^7.27.1",
- "@babel/types": "^7.27.1"
+ "@babel/traverse": "^7.28.5",
+ "@babel/types": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -353,9 +353,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
- "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -402,13 +402,13 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
- "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
+ "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.28.4"
+ "@babel/types": "^7.28.5"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -418,14 +418,14 @@
}
},
"node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz",
- "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz",
+ "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
- "@babel/traverse": "^7.27.1"
+ "@babel/traverse": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -679,9 +679,9 @@
}
},
"node_modules/@babel/plugin-transform-block-scoping": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz",
- "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz",
+ "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -767,14 +767,14 @@
}
},
"node_modules/@babel/plugin-transform-destructuring": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz",
- "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz",
+ "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
- "@babel/traverse": "^7.28.0"
+ "@babel/traverse": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -867,9 +867,9 @@
}
},
"node_modules/@babel/plugin-transform-exponentiation-operator": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz",
- "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz",
+ "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -966,9 +966,9 @@
}
},
"node_modules/@babel/plugin-transform-logical-assignment-operators": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz",
- "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz",
+ "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1032,16 +1032,16 @@
}
},
"node_modules/@babel/plugin-transform-modules-systemjs": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz",
- "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz",
+ "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-module-transforms": "^7.27.1",
+ "@babel/helper-module-transforms": "^7.28.3",
"@babel/helper-plugin-utils": "^7.27.1",
- "@babel/helper-validator-identifier": "^7.27.1",
- "@babel/traverse": "^7.27.1"
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -1186,9 +1186,9 @@
}
},
"node_modules/@babel/plugin-transform-optional-chaining": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz",
- "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz",
+ "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1319,9 +1319,9 @@
}
},
"node_modules/@babel/plugin-transform-runtime": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.3.tgz",
- "integrity": "sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.5.tgz",
+ "integrity": "sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1498,17 +1498,17 @@
}
},
"node_modules/@babel/preset-env": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz",
- "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz",
+ "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/compat-data": "^7.28.0",
+ "@babel/compat-data": "^7.28.5",
"@babel/helper-compilation-targets": "^7.27.2",
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-validator-option": "^7.27.1",
- "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1",
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5",
"@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1",
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1",
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1",
@@ -1521,42 +1521,42 @@
"@babel/plugin-transform-async-generator-functions": "^7.28.0",
"@babel/plugin-transform-async-to-generator": "^7.27.1",
"@babel/plugin-transform-block-scoped-functions": "^7.27.1",
- "@babel/plugin-transform-block-scoping": "^7.28.0",
+ "@babel/plugin-transform-block-scoping": "^7.28.5",
"@babel/plugin-transform-class-properties": "^7.27.1",
"@babel/plugin-transform-class-static-block": "^7.28.3",
- "@babel/plugin-transform-classes": "^7.28.3",
+ "@babel/plugin-transform-classes": "^7.28.4",
"@babel/plugin-transform-computed-properties": "^7.27.1",
- "@babel/plugin-transform-destructuring": "^7.28.0",
+ "@babel/plugin-transform-destructuring": "^7.28.5",
"@babel/plugin-transform-dotall-regex": "^7.27.1",
"@babel/plugin-transform-duplicate-keys": "^7.27.1",
"@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1",
"@babel/plugin-transform-dynamic-import": "^7.27.1",
"@babel/plugin-transform-explicit-resource-management": "^7.28.0",
- "@babel/plugin-transform-exponentiation-operator": "^7.27.1",
+ "@babel/plugin-transform-exponentiation-operator": "^7.28.5",
"@babel/plugin-transform-export-namespace-from": "^7.27.1",
"@babel/plugin-transform-for-of": "^7.27.1",
"@babel/plugin-transform-function-name": "^7.27.1",
"@babel/plugin-transform-json-strings": "^7.27.1",
"@babel/plugin-transform-literals": "^7.27.1",
- "@babel/plugin-transform-logical-assignment-operators": "^7.27.1",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.28.5",
"@babel/plugin-transform-member-expression-literals": "^7.27.1",
"@babel/plugin-transform-modules-amd": "^7.27.1",
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
- "@babel/plugin-transform-modules-systemjs": "^7.27.1",
+ "@babel/plugin-transform-modules-systemjs": "^7.28.5",
"@babel/plugin-transform-modules-umd": "^7.27.1",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1",
"@babel/plugin-transform-new-target": "^7.27.1",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1",
"@babel/plugin-transform-numeric-separator": "^7.27.1",
- "@babel/plugin-transform-object-rest-spread": "^7.28.0",
+ "@babel/plugin-transform-object-rest-spread": "^7.28.4",
"@babel/plugin-transform-object-super": "^7.27.1",
"@babel/plugin-transform-optional-catch-binding": "^7.27.1",
- "@babel/plugin-transform-optional-chaining": "^7.27.1",
+ "@babel/plugin-transform-optional-chaining": "^7.28.5",
"@babel/plugin-transform-parameters": "^7.27.7",
"@babel/plugin-transform-private-methods": "^7.27.1",
"@babel/plugin-transform-private-property-in-object": "^7.27.1",
"@babel/plugin-transform-property-literals": "^7.27.1",
- "@babel/plugin-transform-regenerator": "^7.28.3",
+ "@babel/plugin-transform-regenerator": "^7.28.4",
"@babel/plugin-transform-regexp-modifiers": "^7.27.1",
"@babel/plugin-transform-reserved-words": "^7.27.1",
"@babel/plugin-transform-shorthand-properties": "^7.27.1",
@@ -1632,18 +1632,18 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
- "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
+ "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.3",
+ "@babel/generator": "^7.28.5",
"@babel/helper-globals": "^7.28.0",
- "@babel/parser": "^7.28.4",
+ "@babel/parser": "^7.28.5",
"@babel/template": "^7.27.2",
- "@babel/types": "^7.28.4",
+ "@babel/types": "^7.28.5",
"debug": "^4.3.1"
},
"engines": {
@@ -1651,14 +1651,14 @@
}
},
"node_modules/@babel/types": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
- "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
+ "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
- "@babel/helper-validator-identifier": "^7.27.1"
+ "@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
@@ -1693,9 +1693,9 @@
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
- "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz",
+ "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==",
"cpu": [
"ppc64"
],
@@ -1710,9 +1710,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
- "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz",
+ "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==",
"cpu": [
"arm"
],
@@ -1727,9 +1727,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
- "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz",
+ "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==",
"cpu": [
"arm64"
],
@@ -1744,9 +1744,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
- "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz",
+ "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==",
"cpu": [
"x64"
],
@@ -1761,9 +1761,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
- "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz",
+ "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==",
"cpu": [
"arm64"
],
@@ -1778,9 +1778,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
- "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz",
+ "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==",
"cpu": [
"x64"
],
@@ -1795,9 +1795,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
- "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz",
+ "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==",
"cpu": [
"arm64"
],
@@ -1812,9 +1812,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
- "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz",
+ "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==",
"cpu": [
"x64"
],
@@ -1829,9 +1829,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
- "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz",
+ "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==",
"cpu": [
"arm"
],
@@ -1846,9 +1846,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
- "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz",
+ "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==",
"cpu": [
"arm64"
],
@@ -1863,9 +1863,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
- "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz",
+ "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==",
"cpu": [
"ia32"
],
@@ -1880,9 +1880,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
- "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz",
+ "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==",
"cpu": [
"loong64"
],
@@ -1897,9 +1897,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
- "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz",
+ "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==",
"cpu": [
"mips64el"
],
@@ -1914,9 +1914,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
- "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz",
+ "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==",
"cpu": [
"ppc64"
],
@@ -1931,9 +1931,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
- "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz",
+ "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==",
"cpu": [
"riscv64"
],
@@ -1948,9 +1948,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
- "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz",
+ "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==",
"cpu": [
"s390x"
],
@@ -1965,9 +1965,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
- "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz",
+ "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==",
"cpu": [
"x64"
],
@@ -1982,9 +1982,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
- "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz",
+ "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==",
"cpu": [
"arm64"
],
@@ -1999,9 +1999,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
- "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz",
+ "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==",
"cpu": [
"x64"
],
@@ -2016,9 +2016,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
- "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz",
+ "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==",
"cpu": [
"arm64"
],
@@ -2033,9 +2033,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
- "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz",
+ "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==",
"cpu": [
"x64"
],
@@ -2050,9 +2050,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
- "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz",
+ "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==",
"cpu": [
"arm64"
],
@@ -2067,9 +2067,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
- "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz",
+ "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==",
"cpu": [
"x64"
],
@@ -2084,9 +2084,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
- "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz",
+ "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==",
"cpu": [
"arm64"
],
@@ -2101,9 +2101,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
- "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz",
+ "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==",
"cpu": [
"ia32"
],
@@ -2118,9 +2118,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
- "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz",
+ "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==",
"cpu": [
"x64"
],
@@ -2589,9 +2589,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz",
- "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
+ "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==",
"cpu": [
"arm"
],
@@ -2603,9 +2603,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz",
- "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz",
+ "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==",
"cpu": [
"arm64"
],
@@ -2617,9 +2617,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz",
- "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz",
+ "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==",
"cpu": [
"arm64"
],
@@ -2631,9 +2631,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz",
- "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz",
+ "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==",
"cpu": [
"x64"
],
@@ -2645,9 +2645,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz",
- "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz",
+ "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==",
"cpu": [
"arm64"
],
@@ -2659,9 +2659,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz",
- "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz",
+ "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==",
"cpu": [
"x64"
],
@@ -2673,9 +2673,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz",
- "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz",
+ "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==",
"cpu": [
"arm"
],
@@ -2687,9 +2687,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz",
- "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz",
+ "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==",
"cpu": [
"arm"
],
@@ -2701,9 +2701,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz",
- "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz",
+ "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==",
"cpu": [
"arm64"
],
@@ -2715,9 +2715,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz",
- "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz",
+ "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==",
"cpu": [
"arm64"
],
@@ -2729,9 +2729,9 @@
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz",
- "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz",
+ "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==",
"cpu": [
"loong64"
],
@@ -2743,9 +2743,9 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz",
- "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz",
+ "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==",
"cpu": [
"ppc64"
],
@@ -2757,9 +2757,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz",
- "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz",
+ "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==",
"cpu": [
"riscv64"
],
@@ -2771,9 +2771,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz",
- "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz",
+ "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==",
"cpu": [
"riscv64"
],
@@ -2785,9 +2785,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz",
- "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz",
+ "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==",
"cpu": [
"s390x"
],
@@ -2799,9 +2799,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz",
- "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz",
+ "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==",
"cpu": [
"x64"
],
@@ -2813,9 +2813,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz",
- "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz",
+ "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==",
"cpu": [
"x64"
],
@@ -2827,9 +2827,9 @@
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz",
- "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz",
+ "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==",
"cpu": [
"arm64"
],
@@ -2841,9 +2841,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz",
- "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz",
+ "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==",
"cpu": [
"arm64"
],
@@ -2855,9 +2855,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz",
- "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz",
+ "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==",
"cpu": [
"ia32"
],
@@ -2869,9 +2869,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz",
- "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz",
+ "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==",
"cpu": [
"x64"
],
@@ -2883,9 +2883,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz",
- "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz",
+ "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==",
"cpu": [
"x64"
],
@@ -3034,16 +3034,16 @@
"license": "MIT"
},
"node_modules/@types/express": {
- "version": "4.17.23",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz",
- "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
+ "version": "4.17.25",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz",
+ "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.33",
"@types/qs": "*",
- "@types/serve-static": "*"
+ "@types/serve-static": "^1"
}
},
"node_modules/@types/express-serve-static-core": {
@@ -3091,9 +3091,9 @@
"license": "MIT"
},
"node_modules/@types/http-proxy": {
- "version": "1.17.16",
- "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz",
- "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==",
+ "version": "1.17.17",
+ "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz",
+ "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3173,13 +3173,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "24.7.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz",
- "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==",
+ "version": "24.9.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz",
+ "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~7.14.0"
+ "undici-types": "~7.16.0"
}
},
"node_modules/@types/node-forge": {
@@ -3221,9 +3221,9 @@
"license": "MIT"
},
"node_modules/@types/send": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz",
- "integrity": "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3241,9 +3241,9 @@
}
},
"node_modules/@types/serve-static": {
- "version": "1.15.9",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.9.tgz",
- "integrity": "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==",
+ "version": "1.15.10",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz",
+ "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3253,9 +3253,9 @@
}
},
"node_modules/@types/serve-static/node_modules/@types/send": {
- "version": "0.17.5",
- "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
- "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
+ "version": "0.17.6",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz",
+ "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3776,9 +3776,9 @@
}
},
"node_modules/alpinejs": {
- "version": "3.15.0",
- "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.0.tgz",
- "integrity": "sha512-lpokA5okCF1BKh10LG8YjqhfpxyHBk4gE7boIgVHltJzYoM7O9nK3M7VlntLEJGsVmu7U/RzUWajmHREGT38Eg==",
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.1.tgz",
+ "integrity": "sha512-HLO1TtiE92VajFHtLLPK8BWaK1YepV/uj31UrfoGnQ00lyFOJZ+oVY3F0DghPAwvg8sLU79pmjGQSytERa2gEg==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "~3.1.1"
@@ -3963,9 +3963,9 @@
}
},
"node_modules/axios": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
- "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz",
+ "integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4075,9 +4075,9 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
- "version": "2.8.12",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.12.tgz",
- "integrity": "sha512-vAPMQdnyKCBtkmQA6FMCBvU9qFIppS3nzyXnEM+Lo2IAhG4Mpjv9cCxMudhgV3YdNNJv6TNqXy97dfRVL2LmaQ==",
+ "version": "2.8.21",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.21.tgz",
+ "integrity": "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -4360,9 +4360,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.26.3",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz",
- "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==",
+ "version": "4.27.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz",
+ "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==",
"dev": true,
"funding": [
{
@@ -4380,11 +4380,11 @@
],
"license": "MIT",
"dependencies": {
- "baseline-browser-mapping": "^2.8.9",
- "caniuse-lite": "^1.0.30001746",
- "electron-to-chromium": "^1.5.227",
- "node-releases": "^2.0.21",
- "update-browserslist-db": "^1.1.3"
+ "baseline-browser-mapping": "^2.8.19",
+ "caniuse-lite": "^1.0.30001751",
+ "electron-to-chromium": "^1.5.238",
+ "node-releases": "^2.0.26",
+ "update-browserslist-db": "^1.1.4"
},
"bin": {
"browserslist": "cli.js"
@@ -4521,9 +4521,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001748",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz",
- "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==",
+ "version": "1.0.30001752",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001752.tgz",
+ "integrity": "sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g==",
"dev": true,
"funding": [
{
@@ -4569,9 +4569,9 @@
}
},
"node_modules/chart.js": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz",
- "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==",
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
+ "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
"license": "MIT",
"dependencies": {
"@kurkle/color": "^0.3.0"
@@ -4966,13 +4966,13 @@
"license": "MIT"
},
"node_modules/core-js-compat": {
- "version": "3.45.1",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz",
- "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==",
+ "version": "3.46.0",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz",
+ "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==",
"dev": true,
"license": "MIT",
"dependencies": {
- "browserslist": "^4.25.3"
+ "browserslist": "^4.26.3"
},
"funding": {
"type": "opencollective",
@@ -5736,9 +5736,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.232",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.232.tgz",
- "integrity": "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg==",
+ "version": "1.5.244",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.244.tgz",
+ "integrity": "sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==",
"dev": true,
"license": "ISC"
},
@@ -5820,9 +5820,9 @@
}
},
"node_modules/envinfo": {
- "version": "7.17.0",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.17.0.tgz",
- "integrity": "sha512-GpfViocsFM7viwClFgxK26OtjMlKN67GCR5v6ASFkotxtpBWd9d+vNy+AH7F2E1TUkMDZ8P/dDPZX71/NG8xnQ==",
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.19.0.tgz",
+ "integrity": "sha512-DoSM9VyG6O3vqBf+p3Gjgr/Q52HYBBtO3v+4koAxt1MnWr+zEnxE+nke/yXS4lt2P4SYCHQ4V3f1i88LQVOpAw==",
"dev": true,
"license": "MIT",
"bin": {
@@ -5899,9 +5899,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.25.10",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
- "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
+ "version": "0.25.11",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz",
+ "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -5912,32 +5912,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.10",
- "@esbuild/android-arm": "0.25.10",
- "@esbuild/android-arm64": "0.25.10",
- "@esbuild/android-x64": "0.25.10",
- "@esbuild/darwin-arm64": "0.25.10",
- "@esbuild/darwin-x64": "0.25.10",
- "@esbuild/freebsd-arm64": "0.25.10",
- "@esbuild/freebsd-x64": "0.25.10",
- "@esbuild/linux-arm": "0.25.10",
- "@esbuild/linux-arm64": "0.25.10",
- "@esbuild/linux-ia32": "0.25.10",
- "@esbuild/linux-loong64": "0.25.10",
- "@esbuild/linux-mips64el": "0.25.10",
- "@esbuild/linux-ppc64": "0.25.10",
- "@esbuild/linux-riscv64": "0.25.10",
- "@esbuild/linux-s390x": "0.25.10",
- "@esbuild/linux-x64": "0.25.10",
- "@esbuild/netbsd-arm64": "0.25.10",
- "@esbuild/netbsd-x64": "0.25.10",
- "@esbuild/openbsd-arm64": "0.25.10",
- "@esbuild/openbsd-x64": "0.25.10",
- "@esbuild/openharmony-arm64": "0.25.10",
- "@esbuild/sunos-x64": "0.25.10",
- "@esbuild/win32-arm64": "0.25.10",
- "@esbuild/win32-ia32": "0.25.10",
- "@esbuild/win32-x64": "0.25.10"
+ "@esbuild/aix-ppc64": "0.25.11",
+ "@esbuild/android-arm": "0.25.11",
+ "@esbuild/android-arm64": "0.25.11",
+ "@esbuild/android-x64": "0.25.11",
+ "@esbuild/darwin-arm64": "0.25.11",
+ "@esbuild/darwin-x64": "0.25.11",
+ "@esbuild/freebsd-arm64": "0.25.11",
+ "@esbuild/freebsd-x64": "0.25.11",
+ "@esbuild/linux-arm": "0.25.11",
+ "@esbuild/linux-arm64": "0.25.11",
+ "@esbuild/linux-ia32": "0.25.11",
+ "@esbuild/linux-loong64": "0.25.11",
+ "@esbuild/linux-mips64el": "0.25.11",
+ "@esbuild/linux-ppc64": "0.25.11",
+ "@esbuild/linux-riscv64": "0.25.11",
+ "@esbuild/linux-s390x": "0.25.11",
+ "@esbuild/linux-x64": "0.25.11",
+ "@esbuild/netbsd-arm64": "0.25.11",
+ "@esbuild/netbsd-x64": "0.25.11",
+ "@esbuild/openbsd-arm64": "0.25.11",
+ "@esbuild/openbsd-x64": "0.25.11",
+ "@esbuild/openharmony-arm64": "0.25.11",
+ "@esbuild/sunos-x64": "0.25.11",
+ "@esbuild/win32-arm64": "0.25.11",
+ "@esbuild/win32-ia32": "0.25.11",
+ "@esbuild/win32-x64": "0.25.11"
}
},
"node_modules/escalade": {
@@ -7088,9 +7088,9 @@
}
},
"node_modules/i18next": {
- "version": "25.5.3",
- "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.3.tgz",
- "integrity": "sha512-joFqorDeQ6YpIXni944upwnuHBf5IoPMuqAchGVeQLdWC2JOjxgM9V8UGLhNIIH/Q8QleRxIi0BSRQehSrDLcg==",
+ "version": "25.6.0",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.6.0.tgz",
+ "integrity": "sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw==",
"funding": [
{
"type": "individual",
@@ -7266,9 +7266,9 @@
}
},
"node_modules/immutable": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
- "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
+ "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
"dev": true,
"license": "MIT"
},
@@ -7874,9 +7874,9 @@
}
},
"node_modules/launch-editor": {
- "version": "2.11.1",
- "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz",
- "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==",
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz",
+ "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7908,13 +7908,17 @@
"license": "MIT"
},
"node_modules/loader-runner": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
- "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
+ "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.11.5"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
}
},
"node_modules/loader-utils": {
@@ -7994,9 +7998,9 @@
}
},
"node_modules/magic-string": {
- "version": "0.30.19",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
- "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8464,9 +8468,9 @@
}
},
"node_modules/node-releases": {
- "version": "2.0.23",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz",
- "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==",
+ "version": "2.0.27",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
"dev": true,
"license": "MIT"
},
@@ -9984,13 +9988,13 @@
"license": "MIT"
},
"node_modules/resolve": {
- "version": "1.22.10",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
- "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "version": "1.22.11",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
+ "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "is-core-module": "^2.16.0",
+ "is-core-module": "^2.16.1",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
@@ -10106,9 +10110,9 @@
}
},
"node_modules/rollup": {
- "version": "4.52.4",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz",
- "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==",
+ "version": "4.52.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
+ "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -10122,28 +10126,28 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.52.4",
- "@rollup/rollup-android-arm64": "4.52.4",
- "@rollup/rollup-darwin-arm64": "4.52.4",
- "@rollup/rollup-darwin-x64": "4.52.4",
- "@rollup/rollup-freebsd-arm64": "4.52.4",
- "@rollup/rollup-freebsd-x64": "4.52.4",
- "@rollup/rollup-linux-arm-gnueabihf": "4.52.4",
- "@rollup/rollup-linux-arm-musleabihf": "4.52.4",
- "@rollup/rollup-linux-arm64-gnu": "4.52.4",
- "@rollup/rollup-linux-arm64-musl": "4.52.4",
- "@rollup/rollup-linux-loong64-gnu": "4.52.4",
- "@rollup/rollup-linux-ppc64-gnu": "4.52.4",
- "@rollup/rollup-linux-riscv64-gnu": "4.52.4",
- "@rollup/rollup-linux-riscv64-musl": "4.52.4",
- "@rollup/rollup-linux-s390x-gnu": "4.52.4",
- "@rollup/rollup-linux-x64-gnu": "4.52.4",
- "@rollup/rollup-linux-x64-musl": "4.52.4",
- "@rollup/rollup-openharmony-arm64": "4.52.4",
- "@rollup/rollup-win32-arm64-msvc": "4.52.4",
- "@rollup/rollup-win32-ia32-msvc": "4.52.4",
- "@rollup/rollup-win32-x64-gnu": "4.52.4",
- "@rollup/rollup-win32-x64-msvc": "4.52.4",
+ "@rollup/rollup-android-arm-eabi": "4.52.5",
+ "@rollup/rollup-android-arm64": "4.52.5",
+ "@rollup/rollup-darwin-arm64": "4.52.5",
+ "@rollup/rollup-darwin-x64": "4.52.5",
+ "@rollup/rollup-freebsd-arm64": "4.52.5",
+ "@rollup/rollup-freebsd-x64": "4.52.5",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.52.5",
+ "@rollup/rollup-linux-arm-musleabihf": "4.52.5",
+ "@rollup/rollup-linux-arm64-gnu": "4.52.5",
+ "@rollup/rollup-linux-arm64-musl": "4.52.5",
+ "@rollup/rollup-linux-loong64-gnu": "4.52.5",
+ "@rollup/rollup-linux-ppc64-gnu": "4.52.5",
+ "@rollup/rollup-linux-riscv64-gnu": "4.52.5",
+ "@rollup/rollup-linux-riscv64-musl": "4.52.5",
+ "@rollup/rollup-linux-s390x-gnu": "4.52.5",
+ "@rollup/rollup-linux-x64-gnu": "4.52.5",
+ "@rollup/rollup-linux-x64-musl": "4.52.5",
+ "@rollup/rollup-openharmony-arm64": "4.52.5",
+ "@rollup/rollup-win32-arm64-msvc": "4.52.5",
+ "@rollup/rollup-win32-ia32-msvc": "4.52.5",
+ "@rollup/rollup-win32-x64-gnu": "4.52.5",
+ "@rollup/rollup-win32-x64-msvc": "4.52.5",
"fsevents": "~2.3.2"
}
},
@@ -10290,9 +10294,9 @@
}
},
"node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"dev": true,
"license": "ISC",
"bin": {
@@ -10784,9 +10788,9 @@
}
},
"node_modules/std-env": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
- "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
"dev": true,
"license": "MIT"
},
@@ -11316,9 +11320,9 @@
}
},
"node_modules/undici-types": {
- "version": "7.14.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
- "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
@@ -11387,9 +11391,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
- "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz",
+ "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==",
"dev": true,
"funding": [
{
@@ -11513,9 +11517,9 @@
}
},
"node_modules/vite": {
- "version": "7.1.11",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz",
- "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==",
+ "version": "7.1.12",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz",
+ "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11836,9 +11840,9 @@
"license": "BSD-2-Clause"
},
"node_modules/webpack": {
- "version": "5.102.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.0.tgz",
- "integrity": "sha512-hUtqAR3ZLVEYDEABdBioQCIqSoguHbFn1K7WlPPWSuXmx0031BD73PSE35jKyftdSh4YLDoQNgK4pqBt5Q82MA==",
+ "version": "5.102.1",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz",
+ "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -11850,7 +11854,7 @@
"@webassemblyjs/wasm-parser": "^1.14.1",
"acorn": "^8.15.0",
"acorn-import-phases": "^1.0.3",
- "browserslist": "^4.24.5",
+ "browserslist": "^4.26.3",
"chrome-trace-event": "^1.0.2",
"enhanced-resolve": "^5.17.3",
"es-module-lexer": "^1.2.1",
@@ -11862,8 +11866,8 @@
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
"neo-async": "^2.6.2",
- "schema-utils": "^4.3.2",
- "tapable": "^2.2.3",
+ "schema-utils": "^4.3.3",
+ "tapable": "^2.3.0",
"terser-webpack-plugin": "^5.3.11",
"watchpack": "^2.4.4",
"webpack-sources": "^3.3.3"
diff --git a/public/v1/js/ff/charts.defaults.js b/public/v1/js/ff/charts.defaults.js
index 4bb308ee26..4bd57b5445 100644
--- a/public/v1/js/ff/charts.defaults.js
+++ b/public/v1/js/ff/charts.defaults.js
@@ -42,13 +42,11 @@ function formatLabel(str, maxwidth) {
if (concat.length > maxwidth) {
sections.push(temp);
temp = "";
- }
- else {
+ } else {
if (index === (words.length - 1)) {
sections.push(concat);
return;
- }
- else {
+ } else {
temp = concat;
return;
}
@@ -62,8 +60,7 @@ function formatLabel(str, maxwidth) {
if (item.length < maxwidth) {
temp = item;
- }
- else {
+ } else {
sections.push(item);
}
@@ -98,9 +95,11 @@ var defaultChartOptions = {
ticks: {
callback: function (tickValue) {
"use strict";
+ if (anonymous) {
+ return accounting.formatMoney(0);
+ }
// use first symbol or null:
return accounting.formatMoney(tickValue);
-
},
beginAtZero: true
}
@@ -112,8 +111,11 @@ var defaultChartOptions = {
callbacks: {
label: function (tooltipItem, data) {
"use strict";
- return data.datasets[tooltipItem.datasetIndex].label + ': ' +
- accounting.formatMoney(tooltipItem.yLabel, data.datasets[tooltipItem.datasetIndex].currency_symbol);
+ var string = accounting.formatMoney(tooltipItem.yLabel, data.datasets[tooltipItem.datasetIndex].currency_symbol);
+ if (anonymous) {
+ string = accounting.formatMoney(0);
+ }
+ return data.datasets[tooltipItem.datasetIndex].label + ': ' + string;
}
}
}
@@ -125,7 +127,11 @@ var pieOptionsWithCurrency = {
label: function (tooltipItem, data) {
"use strict";
var value = data.datasets[0].data[tooltipItem.index];
- return data.labels[tooltipItem.index] + ': ' + accounting.formatMoney(value, data.datasets[tooltipItem.datasetIndex].currency_symbol[tooltipItem.index]);
+ var string = accounting.formatMoney(value, data.datasets[tooltipItem.datasetIndex].currency_symbol[tooltipItem.index]);
+ if (anonymous) {
+ string = accounting.formatMoney(0);
+ }
+ return data.labels[tooltipItem.index] + ': ' + string;
}
}
},
@@ -139,7 +145,11 @@ var defaultPieOptions = {
label: function (tooltipItem, data) {
"use strict";
var value = data.datasets[0].data[tooltipItem.index];
- return data.labels[tooltipItem.index] + ': ' + accounting.formatMoney(value);
+ var string = accounting.formatMoney(value);
+ if (anonymous) {
+ string = accounting.formatMoney(0);
+ }
+ return data.labels[tooltipItem.index] + ': ' + string;
}
}
},
@@ -153,7 +163,11 @@ var neutralDefaultPieOptions = {
label: function (tooltipItem, data) {
"use strict";
var value = data.datasets[0].data[tooltipItem.index];
- return data.labels[tooltipItem.index] + ': ' + accounting.formatMoney(value, '¤');
+ var string = accounting.formatMoney(value, '¤');
+ if(anonymous) {
+ string = accounting.formatMoney(0);
+ }
+ return data.labels[tooltipItem.index] + ': ' + string;
}
}
},
diff --git a/public/v1/js/ff/firefly.js b/public/v1/js/ff/firefly.js
index 442fd820d1..846971fb5b 100644
--- a/public/v1/js/ff/firefly.js
+++ b/public/v1/js/ff/firefly.js
@@ -47,7 +47,6 @@ function parseToLocalDates() {
$(function () {
"use strict";
-
configAccounting(currencySymbol);
// on submit of logout button:
diff --git a/public/v1/js/ff/help.js b/public/v1/js/ff/help.js
index 36998bbfea..30c0f76c0f 100644
--- a/public/v1/js/ff/help.js
+++ b/public/v1/js/ff/help.js
@@ -17,13 +17,42 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see