diff --git a/.ci/php-cs-fixer/composer.lock b/.ci/php-cs-fixer/composer.lock index e51f03d8a6..b783d43031 100644 --- a/.ci/php-cs-fixer/composer.lock +++ b/.ci/php-cs-fixer/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "composer/pcre", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", "shasum": "" }, "require": { @@ -59,7 +59,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.0" + "source": "https://github.com/composer/pcre/tree/3.1.1" }, "funding": [ { @@ -75,7 +75,7 @@ "type": "tidelift" } ], - "time": "2022-11-17T09:50:14+00:00" + "time": "2023-10-11T07:11:09+00:00" }, { "name": "composer/semver", @@ -226,16 +226,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.28.0", + "version": "v3.35.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "113e09fea3d2306319ffaa2423fe3de768b28cff" + "reference": "ec1ccc264994b6764882669973ca435cf05bab08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/113e09fea3d2306319ffaa2423fe3de768b28cff", - "reference": "113e09fea3d2306319ffaa2423fe3de768b28cff", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ec1ccc264994b6764882669973ca435cf05bab08", + "reference": "ec1ccc264994b6764882669973ca435cf05bab08", "shasum": "" }, "require": { @@ -268,8 +268,6 @@ "phpspec/prophecy": "^1.16", "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.5", - "phpunitgoodpractices/polyfill": "^1.6", - "phpunitgoodpractices/traits": "^1.9.2", "symfony/phpunit-bridge": "^6.2.3", "symfony/yaml": "^5.4 || ^6.0" }, @@ -309,7 +307,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.28.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.35.1" }, "funding": [ { @@ -317,7 +315,7 @@ "type": "github" } ], - "time": "2023-09-22T20:43:40+00:00" + "time": "2023-10-12T13:47:26+00:00" }, { "name": "psr/container", @@ -917,16 +915,16 @@ }, { "name": "symfony/finder", - "version": "v6.3.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e" + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e", + "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4", + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4", "shasum": "" }, "require": { @@ -961,7 +959,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.3.3" + "source": "https://github.com/symfony/finder/tree/v6.3.5" }, "funding": [ { @@ -977,7 +975,7 @@ "type": "tidelift" } ], - "time": "2023-07-31T08:31:44+00:00" + "time": "2023-09-26T12:56:25+00:00" }, { "name": "symfony/options-resolver", @@ -1745,16 +1743,16 @@ }, { "name": "symfony/string", - "version": "v6.3.2", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "53d1a83225002635bca3482fcbf963001313fb68" + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", - "reference": "53d1a83225002635bca3482fcbf963001313fb68", + "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339", + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339", "shasum": "" }, "require": { @@ -1811,7 +1809,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.3.2" + "source": "https://github.com/symfony/string/tree/v6.3.5" }, "funding": [ { @@ -1827,7 +1825,7 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2023-09-18T10:38:32+00:00" } ], "packages-dev": [], diff --git a/app/Api/V1/Controllers/Autocomplete/AccountController.php b/app/Api/V1/Controllers/Autocomplete/AccountController.php index 25cee01da6..ecbfba6e61 100644 --- a/app/Api/V1/Controllers/Autocomplete/AccountController.php +++ b/app/Api/V1/Controllers/Autocomplete/AccountController.php @@ -82,7 +82,8 @@ class AccountController extends Controller $date = $data['date'] ?? today(config('app.timezone')); $return = []; - $result = $this->repository->searchAccount((string)$query, $types, $data['limit']); + + $result = $this->repository->searchAccount((string)$query, $types, $this->parameters->get('limit')); // TODO this code is duplicated in the V2 Autocomplete controller, which means this code is due to be deprecated. $defaultCurrency = app('amount')->getDefaultCurrency(); diff --git a/app/Api/V1/Controllers/Autocomplete/BillController.php b/app/Api/V1/Controllers/Autocomplete/BillController.php index 88656746d8..542fd4a25f 100644 --- a/app/Api/V1/Controllers/Autocomplete/BillController.php +++ b/app/Api/V1/Controllers/Autocomplete/BillController.php @@ -58,7 +58,6 @@ 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 - * TODO expand API to add active field. * * @param AutocompleteRequest $request * @@ -67,7 +66,7 @@ class BillController extends Controller public function bills(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $result = $this->repository->searchBill($data['query'], $data['limit']); + $result = $this->repository->searchBill($data['query'], $this->parameters->get('limit')); $filtered = $result->map( static function (Bill $item) { return [ diff --git a/app/Api/V1/Controllers/Autocomplete/BudgetController.php b/app/Api/V1/Controllers/Autocomplete/BudgetController.php index 61bb6a82b9..f3334df101 100644 --- a/app/Api/V1/Controllers/Autocomplete/BudgetController.php +++ b/app/Api/V1/Controllers/Autocomplete/BudgetController.php @@ -66,7 +66,7 @@ class BudgetController extends Controller public function budgets(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $result = $this->repository->searchBudget($data['query'], $data['limit']); + $result = $this->repository->searchBudget($data['query'], $this->parameters->get('limit')); $filtered = $result->map( static function (Budget $item) { return [ diff --git a/app/Api/V1/Controllers/Autocomplete/CategoryController.php b/app/Api/V1/Controllers/Autocomplete/CategoryController.php index 1abd086dac..a35b7e11a6 100644 --- a/app/Api/V1/Controllers/Autocomplete/CategoryController.php +++ b/app/Api/V1/Controllers/Autocomplete/CategoryController.php @@ -66,7 +66,7 @@ class CategoryController extends Controller public function categories(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $result = $this->repository->searchCategory($data['query'], $data['limit']); + $result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit')); $filtered = $result->map( static function (Category $item) { return [ diff --git a/app/Api/V1/Controllers/Autocomplete/CurrencyController.php b/app/Api/V1/Controllers/Autocomplete/CurrencyController.php index e46a477034..2250b32f33 100644 --- a/app/Api/V1/Controllers/Autocomplete/CurrencyController.php +++ b/app/Api/V1/Controllers/Autocomplete/CurrencyController.php @@ -66,7 +66,7 @@ class CurrencyController extends Controller public function currencies(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $collection = $this->repository->searchCurrency($data['query'], $data['limit']); + $collection = $this->repository->searchCurrency($data['query'], $this->parameters->get('limit')); $result = []; /** @var TransactionCurrency $currency */ @@ -95,7 +95,7 @@ class CurrencyController extends Controller public function currenciesWithCode(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $collection = $this->repository->searchCurrency($data['query'], $data['limit']); + $collection = $this->repository->searchCurrency($data['query'], $this->parameters->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 6ad068c28d..67cd318e38 100644 --- a/app/Api/V1/Controllers/Autocomplete/ObjectGroupController.php +++ b/app/Api/V1/Controllers/Autocomplete/ObjectGroupController.php @@ -67,7 +67,7 @@ class ObjectGroupController extends Controller { $data = $request->getData(); $return = []; - $result = $this->repository->search($data['query'], $data['limit']); + $result = $this->repository->search($data['query'], $this->parameters->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 8bcbc216c8..74ac1c0498 100644 --- a/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php +++ b/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php @@ -70,7 +70,7 @@ class PiggyBankController extends Controller public function piggyBanks(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $data['limit']); + $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit')); $defaultCurrency = app('amount')->getDefaultCurrency(); $response = []; @@ -105,7 +105,7 @@ class PiggyBankController extends Controller public function piggyBanksWithBalance(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $data['limit']); + $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit')); $defaultCurrency = app('amount')->getDefaultCurrency(); $response = []; /** @var PiggyBank $piggy */ diff --git a/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php b/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php index a209d6934c..74c1262ae4 100644 --- a/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php +++ b/app/Api/V1/Controllers/Autocomplete/RecurrenceController.php @@ -64,7 +64,7 @@ class RecurrenceController extends Controller public function recurring(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $recurrences = $this->repository->searchRecurrence($data['query'], $data['limit']); + $recurrences = $this->repository->searchRecurrence($data['query'], $this->parameters->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 2cc3acd57b..0f45c8fd44 100644 --- a/app/Api/V1/Controllers/Autocomplete/RuleController.php +++ b/app/Api/V1/Controllers/Autocomplete/RuleController.php @@ -63,7 +63,7 @@ class RuleController extends Controller public function rules(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $rules = $this->repository->searchRule($data['query'], $data['limit']); + $rules = $this->repository->searchRule($data['query'], $this->parameters->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 f5e69f793a..c3c1af2503 100644 --- a/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php +++ b/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php @@ -63,7 +63,7 @@ class RuleGroupController extends Controller public function ruleGroups(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $groups = $this->repository->searchRuleGroup($data['query'], $data['limit']); + $groups = $this->repository->searchRuleGroup($data['query'], $this->parameters->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 8b2a442de8..c0bf758e75 100644 --- a/app/Api/V1/Controllers/Autocomplete/TagController.php +++ b/app/Api/V1/Controllers/Autocomplete/TagController.php @@ -67,7 +67,7 @@ class TagController extends Controller { $data = $request->getData(); - $result = $this->repository->searchTags($data['query'], $data['limit']); + $result = $this->repository->searchTags($data['query'], $this->parameters->get('limit')); $array = []; /** @var Tag $tag */ foreach ($result as $tag) { diff --git a/app/Api/V1/Controllers/Autocomplete/TransactionController.php b/app/Api/V1/Controllers/Autocomplete/TransactionController.php index 5d5cb94daf..a8033ed624 100644 --- a/app/Api/V1/Controllers/Autocomplete/TransactionController.php +++ b/app/Api/V1/Controllers/Autocomplete/TransactionController.php @@ -71,7 +71,7 @@ class TransactionController extends Controller public function transactions(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']); + $result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit')); // limit and unique $filtered = $result->unique('description'); @@ -113,7 +113,7 @@ class TransactionController extends Controller } } if (!is_numeric($data['query'])) { - $result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']); + $result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit')); } // limit and unique diff --git a/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php b/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php index 88d636c905..66f1f23a8f 100644 --- a/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php +++ b/app/Api/V1/Controllers/Autocomplete/TransactionTypeController.php @@ -62,7 +62,7 @@ class TransactionTypeController extends Controller public function transactionTypes(AutocompleteRequest $request): JsonResponse { $data = $request->getData(); - $types = $this->repository->searchTypes($data['query'], $data['limit']); + $types = $this->repository->searchTypes($data['query'], $this->parameters->get('limit')); $array = []; /** @var TransactionType $type */ diff --git a/app/Api/V1/Controllers/Controller.php b/app/Api/V1/Controllers/Controller.php index 8740fb7c08..1e2b2b45d7 100644 --- a/app/Api/V1/Controllers/Controller.php +++ b/app/Api/V1/Controllers/Controller.php @@ -61,9 +61,9 @@ abstract class Controller extends BaseController { // get global parameters $this->allowedSort = config('firefly.allowed_sort_parameters'); - $this->parameters = $this->getParameters(); $this->middleware( function ($request, $next) { + $this->parameters = $this->getParameters(); if (auth()->check()) { $language = app('steam')->getLanguage(); app()->setLocale($language); @@ -137,6 +137,11 @@ abstract class Controller extends BaseController if (null !== $value) { $bag->set($integer, (int)$value); } + if (null === $value && 'limit' === $integer && auth()->check()) { + // set default for user: + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $bag->set($integer, $pageSize); + } } // sort fields: diff --git a/app/Api/V1/Controllers/Models/Account/ListController.php b/app/Api/V1/Controllers/Models/Account/ListController.php index 562b9c8d95..6e3660121c 100644 --- a/app/Api/V1/Controllers/Models/Account/ListController.php +++ b/app/Api/V1/Controllers/Models/Account/ListController.php @@ -81,7 +81,7 @@ class ListController extends Controller public function attachments(Account $account): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAttachments($account); $count = $collection->count(); @@ -116,7 +116,7 @@ class ListController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->repository->getPiggyBanks($account); @@ -152,15 +152,9 @@ class ListController extends Controller */ public function transactions(Request $request, Account $account): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); - - // user can overrule page size with limit parameter. - $limit = $this->parameters->get('limit'); - if (null !== $limit && $limit > 0) { - $pageSize = $limit; - } $types = $this->mapTransactionTypes($this->parameters->get('type')); $manager = $this->getManager(); /** @var User $admin */ @@ -172,8 +166,11 @@ class ListController extends Controller $collector->setUser($admin)->setAccounts(new Collection([$account])) ->withAPIInformation()->setLimit($pageSize)->setPage($this->parameters->get('page'))->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } $paginator = $collector->getPaginatedGroups(); diff --git a/app/Api/V1/Controllers/Models/Account/ShowController.php b/app/Api/V1/Controllers/Models/Account/ShowController.php index b3e7d75942..8decc0a0dd 100644 --- a/app/Api/V1/Controllers/Models/Account/ShowController.php +++ b/app/Api/V1/Controllers/Models/Account/ShowController.php @@ -84,7 +84,7 @@ class ShowController extends Controller // types to get, page size: $types = $this->mapAccountTypes($this->parameters->get('type')); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of accounts. Count it and split it. $this->repository->resetAccountOrder(); diff --git a/app/Api/V1/Controllers/Models/Attachment/ShowController.php b/app/Api/V1/Controllers/Models/Attachment/ShowController.php index 31dc2bfd93..12e53d298c 100644 --- a/app/Api/V1/Controllers/Models/Attachment/ShowController.php +++ b/app/Api/V1/Controllers/Models/Attachment/ShowController.php @@ -123,7 +123,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of attachments. Count it and split it. $collection = $this->repository->get(); diff --git a/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php b/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php index d122321e71..268fa4a317 100644 --- a/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php +++ b/app/Api/V1/Controllers/Models/AvailableBudget/ShowController.php @@ -76,7 +76,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $start = $this->parameters->get('start'); $end = $this->parameters->get('end'); diff --git a/app/Api/V1/Controllers/Models/Bill/ListController.php b/app/Api/V1/Controllers/Models/Bill/ListController.php index 1000ec433e..df2535bb49 100644 --- a/app/Api/V1/Controllers/Models/Bill/ListController.php +++ b/app/Api/V1/Controllers/Models/Bill/ListController.php @@ -80,7 +80,7 @@ class ListController extends Controller public function attachments(Bill $bill): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAttachments($bill); $count = $collection->count(); @@ -116,7 +116,7 @@ class ListController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->repository->getRulesForBill($bill); @@ -151,7 +151,7 @@ class ListController extends Controller */ public function transactions(Request $request, Bill $bill): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -177,9 +177,11 @@ class ListController extends Controller // set types of transactions to return. ->setTypes($types); - // do parameter stuff on new group collector. - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } // get paginator. diff --git a/app/Api/V1/Controllers/Models/Bill/ShowController.php b/app/Api/V1/Controllers/Models/Bill/ShowController.php index a5bc503eed..7848ce9cc9 100644 --- a/app/Api/V1/Controllers/Models/Bill/ShowController.php +++ b/app/Api/V1/Controllers/Models/Bill/ShowController.php @@ -73,7 +73,7 @@ class ShowController extends Controller $this->repository->correctOrder(); $bills = $this->repository->getBills(); $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $count = $bills->count(); $bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page')); diff --git a/app/Api/V1/Controllers/Models/Budget/ListController.php b/app/Api/V1/Controllers/Models/Budget/ListController.php index 6f5ba252a8..88bf49569c 100644 --- a/app/Api/V1/Controllers/Models/Budget/ListController.php +++ b/app/Api/V1/Controllers/Models/Budget/ListController.php @@ -82,7 +82,7 @@ class ListController extends Controller public function attachments(Budget $budget): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAttachments($budget); $count = $collection->count(); @@ -116,7 +116,7 @@ class ListController extends Controller public function budgetLimits(Budget $budget): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $this->parameters->set('budget_id', $budget->id); $collection = $this->blRepository->getBudgetLimits($budget, $this->parameters->get('start'), $this->parameters->get('end')); $count = $collection->count(); @@ -148,13 +148,7 @@ class ListController extends Controller */ public function transactions(Request $request, Budget $budget): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; - - // user can overrule page size with limit parameter. - $limit = $this->parameters->get('limit'); - if (null !== $limit && $limit > 0) { - $pageSize = $limit; - } + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -181,8 +175,11 @@ class ListController extends Controller // set types of transactions to return. ->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } $paginator = $collector->getPaginatedGroups(); @@ -211,13 +208,7 @@ class ListController extends Controller */ public function withoutBudget(Request $request): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; - - // user can overrule page size with limit parameter. - $limit = $this->parameters->get('limit'); - if (null !== $limit && $limit > 0) { - $pageSize = $limit; - } + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -244,8 +235,11 @@ class ListController extends Controller // set types of transactions to return. ->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } $paginator = $collector->getPaginatedGroups(); diff --git a/app/Api/V1/Controllers/Models/Budget/ShowController.php b/app/Api/V1/Controllers/Models/Budget/ShowController.php index 02252caf35..8f36f0fbfb 100644 --- a/app/Api/V1/Controllers/Models/Budget/ShowController.php +++ b/app/Api/V1/Controllers/Models/Budget/ShowController.php @@ -77,7 +77,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->repository->getBudgets(); diff --git a/app/Api/V1/Controllers/Models/BudgetLimit/ListController.php b/app/Api/V1/Controllers/Models/BudgetLimit/ListController.php index e006c95d7b..adc69dc9a0 100644 --- a/app/Api/V1/Controllers/Models/BudgetLimit/ListController.php +++ b/app/Api/V1/Controllers/Models/BudgetLimit/ListController.php @@ -80,7 +80,7 @@ class ListController extends Controller */ public function transactions(Request $request, Budget $budget, BudgetLimit $budgetLimit): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); diff --git a/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php b/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php index 365bc19dcd..1a4c4e6302 100644 --- a/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php +++ b/app/Api/V1/Controllers/Models/BudgetLimit/ShowController.php @@ -85,7 +85,7 @@ class ShowController extends Controller { $manager = $this->getManager(); $manager->parseIncludes('budget'); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->blRepository->getBudgetLimits($budget, $this->parameters->get('start'), $this->parameters->get('end')); $count = $collection->count(); $budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); @@ -117,7 +117,7 @@ class ShowController extends Controller { $manager = $this->getManager(); $manager->parseIncludes('budget'); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->blRepository->getAllBudgetLimits($this->parameters->get('start'), $this->parameters->get('end')); $count = $collection->count(); $budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); diff --git a/app/Api/V1/Controllers/Models/Category/ListController.php b/app/Api/V1/Controllers/Models/Category/ListController.php index 16c2bfd4d2..ffc37839e1 100644 --- a/app/Api/V1/Controllers/Models/Category/ListController.php +++ b/app/Api/V1/Controllers/Models/Category/ListController.php @@ -77,7 +77,7 @@ class ListController extends Controller public function attachments(Category $category): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAttachments($category); $count = $collection->count(); @@ -112,7 +112,7 @@ class ListController extends Controller */ public function transactions(Request $request, Category $category): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -138,8 +138,11 @@ class ListController extends Controller // set types of transactions to return. ->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } $paginator = $collector->getPaginatedGroups(); diff --git a/app/Api/V1/Controllers/Models/Category/ShowController.php b/app/Api/V1/Controllers/Models/Category/ShowController.php index 01f328eff1..5a772647a1 100644 --- a/app/Api/V1/Controllers/Models/Category/ShowController.php +++ b/app/Api/V1/Controllers/Models/Category/ShowController.php @@ -73,7 +73,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->repository->getCategories(); diff --git a/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php b/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php index 10b96a4e93..33dc0d4e5b 100644 --- a/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php +++ b/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php @@ -77,7 +77,7 @@ class ListController extends Controller { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of piggy banks. Count it and split it. $collection = $this->repository->getBills($objectGroup); $count = $collection->count(); @@ -114,7 +114,7 @@ class ListController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of piggy banks. Count it and split it. $collection = $this->repository->getPiggyBanks($objectGroup); diff --git a/app/Api/V1/Controllers/Models/ObjectGroup/ShowController.php b/app/Api/V1/Controllers/Models/ObjectGroup/ShowController.php index 911f803b08..ae8e202aa3 100644 --- a/app/Api/V1/Controllers/Models/ObjectGroup/ShowController.php +++ b/app/Api/V1/Controllers/Models/ObjectGroup/ShowController.php @@ -79,7 +79,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $this->repository->resetOrder(); $collection = $this->repository->get(); diff --git a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php index 8943791638..96a62a4940 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php @@ -71,7 +71,7 @@ class ListController extends Controller public function attachments(PiggyBank $piggyBank): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAttachments($piggyBank); $count = $collection->count(); @@ -105,7 +105,7 @@ class ListController extends Controller public function piggyBankEvents(PiggyBank $piggyBank): JsonResponse { // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $manager = $this->getManager(); $collection = $this->repository->getEvents($piggyBank); diff --git a/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php b/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php index 0c8e01e968..22bb4f3624 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php @@ -72,7 +72,7 @@ class ShowController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->repository->getPiggyBanks(); diff --git a/app/Api/V1/Controllers/Models/Recurrence/ListController.php b/app/Api/V1/Controllers/Models/Recurrence/ListController.php index 9e017818db..9d81586362 100644 --- a/app/Api/V1/Controllers/Models/Recurrence/ListController.php +++ b/app/Api/V1/Controllers/Models/Recurrence/ListController.php @@ -77,7 +77,7 @@ class ListController extends Controller */ public function transactions(Request $request, Recurrence $recurrence): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -105,9 +105,13 @@ class ListController extends Controller // set types of transactions to return. ->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); + } + $paginator = $collector->getPaginatedGroups(); $paginator->setPath(route('api.v1.transactions.index') . $this->buildParams()); $transactions = $paginator->getCollection(); diff --git a/app/Api/V1/Controllers/Models/Recurrence/ShowController.php b/app/Api/V1/Controllers/Models/Recurrence/ShowController.php index 99ed67b074..54d1f86c30 100644 --- a/app/Api/V1/Controllers/Models/Recurrence/ShowController.php +++ b/app/Api/V1/Controllers/Models/Recurrence/ShowController.php @@ -73,7 +73,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->repository->get(); diff --git a/app/Api/V1/Controllers/Models/Rule/ShowController.php b/app/Api/V1/Controllers/Models/Rule/ShowController.php index ff8ed98044..b4b93c7767 100644 --- a/app/Api/V1/Controllers/Models/Rule/ShowController.php +++ b/app/Api/V1/Controllers/Models/Rule/ShowController.php @@ -77,7 +77,7 @@ class ShowController extends Controller $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->ruleRepository->getAll(); diff --git a/app/Api/V1/Controllers/Models/RuleGroup/ListController.php b/app/Api/V1/Controllers/Models/RuleGroup/ListController.php index 0e3f7cbab4..5c197da60d 100644 --- a/app/Api/V1/Controllers/Models/RuleGroup/ListController.php +++ b/app/Api/V1/Controllers/Models/RuleGroup/ListController.php @@ -75,7 +75,7 @@ class ListController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->ruleGroupRepository->getRules($group); diff --git a/app/Api/V1/Controllers/Models/RuleGroup/ShowController.php b/app/Api/V1/Controllers/Models/RuleGroup/ShowController.php index 465ac40a5d..cfe41894c4 100644 --- a/app/Api/V1/Controllers/Models/RuleGroup/ShowController.php +++ b/app/Api/V1/Controllers/Models/RuleGroup/ShowController.php @@ -75,7 +75,7 @@ class ShowController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of rule groups. Count it and split it. $collection = $this->ruleGroupRepository->get(); diff --git a/app/Api/V1/Controllers/Models/Tag/ListController.php b/app/Api/V1/Controllers/Models/Tag/ListController.php index 89bc31dee8..864c01385c 100644 --- a/app/Api/V1/Controllers/Models/Tag/ListController.php +++ b/app/Api/V1/Controllers/Models/Tag/ListController.php @@ -80,7 +80,7 @@ class ListController extends Controller public function attachments(Tag $tag): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAttachments($tag); $count = $collection->count(); @@ -114,7 +114,7 @@ class ListController extends Controller */ public function transactions(Request $request, Tag $tag): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -139,8 +139,11 @@ class ListController extends Controller // set types of transactions to return. ->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } $paginator = $collector->getPaginatedGroups(); $paginator->setPath(route('api.v1.tags.transactions', [$tag->id]) . $this->buildParams()); diff --git a/app/Api/V1/Controllers/Models/Tag/ShowController.php b/app/Api/V1/Controllers/Models/Tag/ShowController.php index 068c266f95..9c50ddf6c1 100644 --- a/app/Api/V1/Controllers/Models/Tag/ShowController.php +++ b/app/Api/V1/Controllers/Models/Tag/ShowController.php @@ -76,7 +76,7 @@ class ShowController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. $collection = $this->repository->get(); diff --git a/app/Api/V1/Controllers/Models/Transaction/ListController.php b/app/Api/V1/Controllers/Models/Transaction/ListController.php index 2a0266b798..25d9d098d0 100644 --- a/app/Api/V1/Controllers/Models/Transaction/ListController.php +++ b/app/Api/V1/Controllers/Models/Transaction/ListController.php @@ -78,7 +78,7 @@ class ListController extends Controller public function attachments(TransactionGroup $transactionGroup): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = new Collection(); foreach ($transactionGroup->transactionJournals as $transactionJournal) { $collection = $this->journalAPIRepository->getAttachments($transactionJournal)->merge($collection); @@ -114,7 +114,7 @@ class ListController extends Controller { $manager = $this->getManager(); $collection = new Collection(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); foreach ($transactionGroup->transactionJournals as $transactionJournal) { $collection = $this->journalAPIRepository->getPiggyBankEvents($transactionJournal)->merge($collection); } @@ -152,7 +152,7 @@ class ListController extends Controller { $manager = $this->getManager(); $collection = $this->journalAPIRepository->getJournalLinks($transactionJournal); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $count = $collection->count(); $journalLinks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); diff --git a/app/Api/V1/Controllers/Models/Transaction/ShowController.php b/app/Api/V1/Controllers/Models/Transaction/ShowController.php index b7c63b9520..2819c50fb2 100644 --- a/app/Api/V1/Controllers/Models/Transaction/ShowController.php +++ b/app/Api/V1/Controllers/Models/Transaction/ShowController.php @@ -58,7 +58,7 @@ class ShowController extends Controller */ public function index(Request $request): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php index 2404b9b54e..cd52b0060b 100644 --- a/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php +++ b/app/Api/V1/Controllers/Models/TransactionCurrency/ListController.php @@ -106,7 +106,7 @@ class ListController extends Controller // types to get, page size: $types = $this->mapAccountTypes($this->parameters->get('type')); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of accounts. Count it and split it. /** @var AccountRepositoryInterface $accountRepository */ @@ -153,7 +153,7 @@ class ListController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of available budgets. Count it and split it. /** @var AvailableBudgetRepositoryInterface $abRepository */ @@ -193,7 +193,7 @@ class ListController extends Controller /** @var BillRepositoryInterface $billRepos */ $billRepos = app(BillRepositoryInterface::class); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $unfiltered = $billRepos->getBills(); // filter and paginate list: @@ -236,7 +236,7 @@ class ListController extends Controller $blRepository = app(BudgetLimitRepositoryInterface::class); $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $blRepository->getAllBudgetLimitsByCurrency($currency, $this->parameters->get('start'), $this->parameters->get('end')); $count = $collection->count(); $budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); @@ -268,7 +268,7 @@ class ListController extends Controller { $manager = $this->getManager(); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. /** @var RecurringRepositoryInterface $recurringRepos */ @@ -319,7 +319,7 @@ class ListController extends Controller public function rules(TransactionCurrency $currency): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of budgets. Count it and split it. /** @var RuleRepositoryInterface $ruleRepos */ @@ -371,7 +371,7 @@ class ListController extends Controller */ public function transactions(Request $request, TransactionCurrency $currency): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -396,8 +396,11 @@ class ListController extends Controller ->setPage($this->parameters->get('page')) // set types of transactions to return. ->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } $paginator = $collector->getPaginatedGroups(); $paginator->setPath(route('api.v1.currencies.transactions', [$currency->code]) . $this->buildParams()); diff --git a/app/Api/V1/Controllers/Models/TransactionCurrency/ShowController.php b/app/Api/V1/Controllers/Models/TransactionCurrency/ShowController.php index e9e21d722a..3c5b7c65c0 100644 --- a/app/Api/V1/Controllers/Models/TransactionCurrency/ShowController.php +++ b/app/Api/V1/Controllers/Models/TransactionCurrency/ShowController.php @@ -78,7 +78,7 @@ class ShowController extends Controller */ public function index(): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAll(); $count = $collection->count(); // slice them: diff --git a/app/Api/V1/Controllers/Models/TransactionLink/ShowController.php b/app/Api/V1/Controllers/Models/TransactionLink/ShowController.php index bdf7af1407..485cbd51b2 100644 --- a/app/Api/V1/Controllers/Models/TransactionLink/ShowController.php +++ b/app/Api/V1/Controllers/Models/TransactionLink/ShowController.php @@ -85,7 +85,7 @@ class ShowController extends Controller $name = $request->get('name'); // types to get, page size: - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $linkType = $this->repository->findByName($name); // get list of transaction links. Count it and split it. diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php index b34e702b77..3e18860ccb 100644 --- a/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php +++ b/app/Api/V1/Controllers/Models/TransactionLinkType/ListController.php @@ -78,7 +78,7 @@ class ListController extends Controller */ public function transactions(Request $request, LinkType $linkType): JsonResponse { - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $type = $request->get('type') ?? 'default'; $this->parameters->set('type', $type); @@ -106,8 +106,11 @@ class ListController extends Controller ->setPage($this->parameters->get('page')) // set types of transactions to return. ->setTypes($types); - if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) { - $collector->setRange($this->parameters->get('start'), $this->parameters->get('end')); + if (null !== $this->parameters->get('start')) { + $collector->setStart($this->parameters->get('start')); + } + if (null !== $this->parameters->get('end')) { + $collector->setEnd($this->parameters->get('end')); } $paginator = $collector->getPaginatedGroups(); $paginator->setPath(route('api.v1.transactions.index') . $this->buildParams()); diff --git a/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php b/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php index 49f19afd4e..cc63966521 100644 --- a/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php +++ b/app/Api/V1/Controllers/Models/TransactionLinkType/ShowController.php @@ -78,7 +78,7 @@ class ShowController extends Controller { // create some objects: $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); // get list of accounts. Count it and split it. $collection = $this->repository->get(); diff --git a/app/Api/V1/Controllers/Search/TransactionController.php b/app/Api/V1/Controllers/Search/TransactionController.php index 7fc503d201..2588d0520a 100644 --- a/app/Api/V1/Controllers/Search/TransactionController.php +++ b/app/Api/V1/Controllers/Search/TransactionController.php @@ -53,8 +53,7 @@ class TransactionController extends Controller $manager = $this->getManager(); $fullQuery = (string)$request->get('query'); $page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page'); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; - $pageSize = 0 === (int)$request->get('limit') ? $pageSize : (int)$request->get('limit'); + $pageSize = $this->parameters->get('limit'); $searcher->parseQuery($fullQuery); $searcher->setPage($page); $searcher->setLimit($pageSize); diff --git a/app/Api/V1/Controllers/Summary/BasicController.php b/app/Api/V1/Controllers/Summary/BasicController.php index 7e4e5bdb8c..28ec3b227a 100644 --- a/app/Api/V1/Controllers/Summary/BasicController.php +++ b/app/Api/V1/Controllers/Summary/BasicController.php @@ -236,6 +236,7 @@ class BasicController extends Controller */ private function getBillInformation(Carbon $start, Carbon $end): array { + app('log')->debug(sprintf('Now in getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-'))); /* * Since both this method and the chart use the exact same data, we can suffice * with calling the one method in the bill repository that will get this amount. @@ -281,7 +282,7 @@ class BasicController extends Controller 'sub_title' => '', ]; } - + app('log')->debug(sprintf('Done with getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-'))); return $return; } diff --git a/app/Api/V1/Controllers/System/UserController.php b/app/Api/V1/Controllers/System/UserController.php index 413bf3a037..b0c6e519bc 100644 --- a/app/Api/V1/Controllers/System/UserController.php +++ b/app/Api/V1/Controllers/System/UserController.php @@ -101,7 +101,7 @@ class UserController extends Controller public function index(): JsonResponse { // user preferences - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $manager = $this->getManager(); // build collection diff --git a/app/Api/V1/Controllers/User/PreferencesController.php b/app/Api/V1/Controllers/User/PreferencesController.php index 6d618fc86c..325e567814 100644 --- a/app/Api/V1/Controllers/User/PreferencesController.php +++ b/app/Api/V1/Controllers/User/PreferencesController.php @@ -58,7 +58,7 @@ class PreferencesController extends Controller $collection = app('preferences')->all(); $manager = $this->getManager(); $count = $collection->count(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $preferences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); // make paginator: diff --git a/app/Api/V1/Controllers/Webhook/AttemptController.php b/app/Api/V1/Controllers/Webhook/AttemptController.php index a64066da1f..901e22519e 100644 --- a/app/Api/V1/Controllers/Webhook/AttemptController.php +++ b/app/Api/V1/Controllers/Webhook/AttemptController.php @@ -76,7 +76,7 @@ class AttemptController extends Controller } $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getAttempts($message); $count = $collection->count(); $attempts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); diff --git a/app/Api/V1/Controllers/Webhook/MessageController.php b/app/Api/V1/Controllers/Webhook/MessageController.php index cdcefd9885..53b427af0e 100644 --- a/app/Api/V1/Controllers/Webhook/MessageController.php +++ b/app/Api/V1/Controllers/Webhook/MessageController.php @@ -70,7 +70,7 @@ class MessageController extends Controller public function index(Webhook $webhook): JsonResponse { $manager = $this->getManager(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $collection = $this->repository->getMessages($webhook); $count = $collection->count(); diff --git a/app/Api/V1/Controllers/Webhook/ShowController.php b/app/Api/V1/Controllers/Webhook/ShowController.php index e675e62b27..4ad46fdacc 100644 --- a/app/Api/V1/Controllers/Webhook/ShowController.php +++ b/app/Api/V1/Controllers/Webhook/ShowController.php @@ -74,7 +74,7 @@ class ShowController extends Controller { $manager = $this->getManager(); $collection = $this->repository->all(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $count = $collection->count(); $webhooks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); diff --git a/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php b/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php index 5d071fe7b6..875d1f7335 100644 --- a/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php +++ b/app/Api/V1/Requests/Autocomplete/AutocompleteRequest.php @@ -46,8 +46,6 @@ class AutocompleteRequest extends FormRequest if ('' !== $types) { $array = explode(',', $types); } - $limit = $this->convertInteger('limit'); - $limit = 0 === $limit ? 10 : $limit; // remove 'initial balance' from allowed types. its internal $array = array_diff($array, [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION]); @@ -56,7 +54,6 @@ class AutocompleteRequest extends FormRequest 'types' => $array, 'query' => $this->convertString('query'), 'date' => $this->getCarbonDate('date'), - 'limit' => $limit, ]; } @@ -66,7 +63,6 @@ class AutocompleteRequest extends FormRequest public function rules(): array { return [ - 'limit' => 'min:0|max:1337', ]; } } diff --git a/app/Api/V2/Controllers/Autocomplete/AccountController.php b/app/Api/V2/Controllers/Autocomplete/AccountController.php index 5e777b6893..5da7fc8381 100644 --- a/app/Api/V2/Controllers/Autocomplete/AccountController.php +++ b/app/Api/V2/Controllers/Autocomplete/AccountController.php @@ -32,7 +32,7 @@ use FireflyIII\Models\AccountType; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface; use FireflyIII\Support\Http\Api\AccountFilter; -use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; +use http\Env\Response; use Illuminate\Http\JsonResponse; /** @@ -41,7 +41,6 @@ use Illuminate\Http\JsonResponse; class AccountController extends Controller { use AccountFilter; - use ValidatesUserGroupTrait; private AdminAccountRepositoryInterface $adminRepository; private array $balanceTypes; @@ -86,15 +85,14 @@ class AccountController extends Controller */ public function accounts(AutocompleteRequest $request): JsonResponse { - $data = $request->getData(); - $types = $data['types']; - $query = $data['query']; - $date = $this->parameters->get('date') ?? today(config('app.timezone')); - - $return = []; + $data = $request->getData(); + $types = $data['types']; + $query = $data['query']; + $date = $this->parameters->get('date') ?? today(config('app.timezone')); $result = $this->adminRepository->searchAccount((string)$query, $types, $data['limit']); $defaultCurrency = app('amount')->getDefaultCurrency(); + $allItems = []; /** @var Account $account */ foreach ($result as $account) { $nameWithBalance = $account->name; @@ -104,11 +102,17 @@ class AccountController extends Controller $balance = app('steam')->balance($account, $date); $nameWithBalance = sprintf('%s (%s)', $account->name, app('amount')->formatAnything($currency, $balance, false)); } - - $return[] = [ + $type = (string)trans(sprintf('firefly.%s', $account->accountType->type)); + $groupedResult[$type] = $groupedResult[$type] ?? [ + 'group ' => $type, + 'items' => [], + ]; + $allItems[] = [ 'id' => (string)$account->id, + 'value' => (string)$account->id, 'name' => $account->name, 'name_with_balance' => $nameWithBalance, + 'label' => $nameWithBalance, 'type' => $account->accountType->type, 'currency_id' => (string)$currency->id, 'currency_name' => $currency->name, @@ -118,10 +122,9 @@ class AccountController extends Controller ]; } - // custom order. usort( - $return, - function ($a, $b) { + $allItems, + function (array $a, array $b): int { $order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE]; $pos_a = array_search($a['type'], $order, true); $pos_b = array_search($b['type'], $order, true); @@ -129,7 +132,6 @@ class AccountController extends Controller return $pos_a - $pos_b; } ); - - return response()->json($return); + return response()->json($allItems); } } diff --git a/app/Api/V2/Controllers/Autocomplete/TransactionController.php b/app/Api/V2/Controllers/Autocomplete/TransactionController.php new file mode 100644 index 0000000000..175e787969 --- /dev/null +++ b/app/Api/V2/Controllers/Autocomplete/TransactionController.php @@ -0,0 +1,94 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V2\Controllers\Autocomplete; + +use FireflyIII\Api\V2\Controllers\Controller; +use FireflyIII\Api\V2\Request\Autocomplete\AutocompleteRequest; +use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\UserGroups\Journal\JournalRepositoryInterface; +use Illuminate\Http\JsonResponse; + +/** + * Class TransactionController + */ +class TransactionController extends Controller +{ + private JournalRepositoryInterface $repository; + + /** + * AccountController constructor. + */ + public function __construct() + { + parent::__construct(); + $this->middleware( + function ($request, $next) { + $this->repository = app(JournalRepositoryInterface::class); + + $userGroup = $this->validateUserGroup($request); + if (null !== $userGroup) { + $this->repository->setUserGroup($userGroup); + } + + return $next($request); + } + ); + } + + /** + * Documentation for this endpoint: + * TODO list of checks + * 1. use dates from ParameterBag + * 2. Request validates dates + * 3. Request includes user_group_id + * 4. Endpoint is documented. + * 5. Collector uses user_group_id + * + * + * @return JsonResponse + */ + public function transactionDescriptions(AutocompleteRequest $request): JsonResponse + { + $data = $request->getData(); + $result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']); + + // limit and unique + $filtered = $result->unique('description'); + $array = []; + + /** @var TransactionJournal $journal */ + foreach ($filtered as $journal) { + $array[] = [ + 'id' => (string)$journal->id, + 'transaction_group_id' => (string)$journal->transaction_group_id, + 'name' => $journal->description, + 'description' => $journal->description, + ]; + } + + return response()->json($array); + + } + +} diff --git a/app/Api/V2/Controllers/Controller.php b/app/Api/V2/Controllers/Controller.php index 2dfd00b8aa..6783b2e812 100644 --- a/app/Api/V2/Controllers/Controller.php +++ b/app/Api/V2/Controllers/Controller.php @@ -27,6 +27,7 @@ namespace FireflyIII\Api\V2\Controllers; use Carbon\Carbon; use Carbon\Exceptions\InvalidDateException; use Carbon\Exceptions\InvalidFormatException; +use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; use FireflyIII\Transformers\V2\AbstractTransformer; use Illuminate\Database\Eloquent\Model; use Illuminate\Pagination\LengthAwarePaginator; @@ -48,8 +49,9 @@ use Symfony\Component\HttpFoundation\ParameterBag; */ class Controller extends BaseController { + use ValidatesUserGroupTrait; + protected const CONTENT_TYPE = 'application/vnd.api+json'; - protected int $pageSize; protected ParameterBag $parameters; /** @@ -57,11 +59,14 @@ class Controller extends BaseController */ public function __construct() { - $this->parameters = $this->getParameters(); - $this->pageSize = 50; - if (auth()->check()) { - $this->pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; - } + $this->middleware( + function ($request, $next) { + $this->parameters = $this->getParameters(); + + return $next($request); + } + ); + } /** @@ -73,6 +78,7 @@ class Controller extends BaseController private function getParameters(): ParameterBag { $bag = new ParameterBag(); + $bag->set('limit', 50); try { $page = (int)request()->get('page'); } catch (ContainerExceptionInterface | NotFoundExceptionInterface $e) { @@ -129,6 +135,11 @@ class Controller extends BaseController if (null !== $value) { $bag->set($integer, (int)$value); } + if (null === $value && 'limit' === $integer && auth()->check()) { + // set default for user: + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $bag->set($integer, $pageSize); + } } // sort fields: diff --git a/app/Api/V2/Controllers/Model/Bill/ShowController.php b/app/Api/V2/Controllers/Model/Bill/ShowController.php index 33fece0c92..6c2793fa1c 100644 --- a/app/Api/V2/Controllers/Model/Bill/ShowController.php +++ b/app/Api/V2/Controllers/Model/Bill/ShowController.php @@ -74,7 +74,7 @@ class ShowController extends Controller { $this->repository->correctOrder(); $bills = $this->repository->getBills(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $count = $bills->count(); $bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page')); diff --git a/app/Api/V2/Controllers/Model/Budget/ListController.php b/app/Api/V2/Controllers/Model/Budget/ListController.php index 3a3cca394d..b7bbaff1c7 100644 --- a/app/Api/V2/Controllers/Model/Budget/ListController.php +++ b/app/Api/V2/Controllers/Model/Budget/ListController.php @@ -64,9 +64,9 @@ class ListController extends Controller exit; $collection = $this->repository->getActiveBudgets(); $total = $collection->count(); - $collection->slice($this->pageSize * $this->parameters->get('page'), $this->pageSize); + $collection->slice($this->pageXSize * $this->parameters->get('page'), $this->pXageSize); - $paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page')); + $paginator = new LengthAwarePaginator($collection, $total, $this->pagXeSize, $this->parameters->get('page')); $transformer = new BudgetTransformer(); return response() diff --git a/app/Api/V2/Controllers/Model/BudgetLimit/ListController.php b/app/Api/V2/Controllers/Model/BudgetLimit/ListController.php index 701f064b6d..cf7ef4f9d7 100644 --- a/app/Api/V2/Controllers/Model/BudgetLimit/ListController.php +++ b/app/Api/V2/Controllers/Model/BudgetLimit/ListController.php @@ -57,12 +57,13 @@ class ListController extends Controller */ public function index(DateRequest $request, Budget $budget): JsonResponse { + $pageSize = $this->parameters->get('limit'); $dates = $request->getAll(); $collection = $this->repository->getBudgetLimits($budget, $dates['start'], $dates['end']); $total = $collection->count(); - $collection->slice($this->pageSize * $this->parameters->get('page'), $this->pageSize); + $collection->slice($pageSize * $this->parameters->get('page'), $pageSize); - $paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page')); + $paginator = new LengthAwarePaginator($collection, $total, $pageSize, $this->parameters->get('page')); $transformer = new BudgetLimitTransformer(); return response() diff --git a/app/Api/V2/Controllers/Model/PiggyBank/ShowController.php b/app/Api/V2/Controllers/Model/PiggyBank/ShowController.php index 57eac1739a..e75e8b8866 100644 --- a/app/Api/V2/Controllers/Model/PiggyBank/ShowController.php +++ b/app/Api/V2/Controllers/Model/PiggyBank/ShowController.php @@ -70,7 +70,7 @@ class ShowController extends Controller public function index(Request $request): JsonResponse { $piggies = $this->repository->getPiggyBanks(); - $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + $pageSize = $this->parameters->get('limit'); $count = $piggies->count(); $piggies = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $paginator = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page')); diff --git a/app/Api/V2/Controllers/Transaction/List/AccountController.php b/app/Api/V2/Controllers/Transaction/List/AccountController.php index 057b330f11..ceb6f7802d 100644 --- a/app/Api/V2/Controllers/Transaction/List/AccountController.php +++ b/app/Api/V2/Controllers/Transaction/List/AccountController.php @@ -52,30 +52,28 @@ class AccountController extends Controller public function list(ListRequest $request, Account $account): JsonResponse { // collect transactions: - $limit = $request->getLimit(); - $page = $request->getPage(); - $page = max($page, 1); - - if ($limit > 0 && $limit <= $this->pageSize) { - $this->pageSize = $limit; - } + $page = $request->getPage(); + $page = max($page, 1); + $pageSize = $this->parameters->get('limit'); /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setAccounts(new Collection([$account])) ->withAPIInformation() - ->setLimit($this->pageSize) + ->setLimit($pageSize) ->setPage($page) ->setTypes($request->getTransactionTypes()); $start = $request->getStartDate(); $end = $request->getEndDate(); if (null !== $start) { + app('log')->debug(sprintf('Set start date to %s', $start->toIso8601String())); $collector->setStart($start); } if (null !== $end) { - $collector->setEnd($start); + app('log')->debug(sprintf('Set end date to %s', $start->toIso8601String())); + $collector->setEnd($end); } $paginator = $collector->getPaginatedGroups(); @@ -83,7 +81,7 @@ class AccountController extends Controller sprintf( '%s?%s', route('api.v2.accounts.transactions', [$account->id]), - $request->buildParams() + $request->buildParams($pageSize) ) ); diff --git a/app/Api/V2/Controllers/Transaction/List/TransactionController.php b/app/Api/V2/Controllers/Transaction/List/TransactionController.php index 9bcfcbf3de..9bcc831a16 100644 --- a/app/Api/V2/Controllers/Transaction/List/TransactionController.php +++ b/app/Api/V2/Controllers/Transaction/List/TransactionController.php @@ -42,20 +42,16 @@ class TransactionController extends Controller public function list(ListRequest $request): JsonResponse { // collect transactions: - $limit = $request->getLimit(); - $page = $request->getPage(); - $page = max($page, 1); - - if ($limit > 0 && $limit <= $this->pageSize) { - $this->pageSize = $limit; - } + $pageSize = $this->parameters->get('limit'); + $page = $request->getPage(); + $page = max($page, 1); /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setUserGroup(auth()->user()->userGroup) ->withAPIInformation() - ->setLimit($this->pageSize) + ->setLimit($pageSize) ->setPage($page) ->setTypes($request->getTransactionTypes()); @@ -72,11 +68,12 @@ class TransactionController extends Controller // exit; $paginator = $collector->getPaginatedGroups(); + $params = $request->buildParams($pageSize); $paginator->setPath( sprintf( '%s?%s', route('api.v2.transactions.list'), - $request->buildParams() + $params ) ); diff --git a/app/Api/V2/Controllers/UserGroup/ShowController.php b/app/Api/V2/Controllers/UserGroup/ShowController.php index afd87d4706..fbc441427e 100644 --- a/app/Api/V2/Controllers/UserGroup/ShowController.php +++ b/app/Api/V2/Controllers/UserGroup/ShowController.php @@ -64,6 +64,7 @@ class ShowController extends Controller public function index(Request $request): JsonResponse { $collection = new Collection(); + $pageSize = $this->parameters->get('limit'); // if the user has the system owner role, get all. Otherwise, get only the users' groups. if (!auth()->user()->hasRole('owner')) { $collection = $this->repository->get(); @@ -72,9 +73,9 @@ class ShowController extends Controller $collection = $this->repository->getAll(); } $count = $collection->count(); - $userGroups = $collection->slice(($this->parameters->get('page') - 1) * $this->pageSize, $this->pageSize); + $userGroups = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); - $paginator = new LengthAwarePaginator($userGroups, $count, $this->pageSize, $this->parameters->get('page')); + $paginator = new LengthAwarePaginator($userGroups, $count, $pageSize, $this->parameters->get('page')); $transformer = new UserGroupTransformer(); $transformer->setParameters($this->parameters); // give params to transformer diff --git a/app/Api/V2/Request/Autocomplete/AutocompleteRequest.php b/app/Api/V2/Request/Autocomplete/AutocompleteRequest.php index 3b7426e6a7..9da06a81be 100644 --- a/app/Api/V2/Request/Autocomplete/AutocompleteRequest.php +++ b/app/Api/V2/Request/Autocomplete/AutocompleteRequest.php @@ -28,6 +28,7 @@ use FireflyIII\Models\AccountType; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\User; +use FireflyIII\Validation\Administration\ValidatesAdministrationAccess; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Validator; @@ -38,6 +39,7 @@ class AutocompleteRequest extends FormRequest { use ConvertsDataTypes; use ChecksLogin; + protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS]; /** @@ -75,21 +77,4 @@ class AutocompleteRequest extends FormRequest 'limit' => 'min:0|max:1337', ]; } - - /** - * Configure the validator instance with special rules for after the basic validation rules. - * - * @param Validator $validator - * - * @return void - */ - public function withValidator(Validator $validator): void - { - $validator->after( - function (Validator $validator) { - // validate if the account can access this administration - $this->validateAdministration($validator, [UserRoleEnum::MANAGE_TRANSACTIONS]); - } - ); - } } diff --git a/app/Api/V2/Request/Model/Transaction/ListRequest.php b/app/Api/V2/Request/Model/Transaction/ListRequest.php index 4a0dbc2a61..8913feea10 100644 --- a/app/Api/V2/Request/Model/Transaction/ListRequest.php +++ b/app/Api/V2/Request/Model/Transaction/ListRequest.php @@ -43,10 +43,11 @@ class ListRequest extends FormRequest /** * @return string */ - public function buildParams(): string + public function buildParams(int $pageSize): string { $array = [ - 'page' => $this->getPage(), + 'page' => $this->getPage(), + 'limit' => $pageSize, ]; $start = $this->getStartDate(); @@ -55,9 +56,6 @@ class ListRequest extends FormRequest $array['start'] = $start->format('Y-m-d'); $array['end'] = $end->format('Y-m-d'); } - if (0 !== $this->getLimit()) { - $array['limit'] = $this->getLimit(); - } return http_build_query($array); } @@ -86,14 +84,6 @@ class ListRequest extends FormRequest return $this->getCarbonDate('end'); } - /** - * @return int - */ - public function getLimit(): int - { - return $this->convertInteger('limit'); - } - /** * @return array */ diff --git a/app/Console/Commands/Correction/FixAccountTypes.php b/app/Console/Commands/Correction/FixAccountTypes.php index 019cb655ee..a9d74e3d11 100644 --- a/app/Console/Commands/Correction/FixAccountTypes.php +++ b/app/Console/Commands/Correction/FixAccountTypes.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Console\Commands\Correction; use FireflyIII\Console\Commands\ShowsFriendlyMessages; +use FireflyIII\Enums\AccountTypeEnum; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Factory\AccountFactory; use FireflyIII\Models\AccountType; @@ -31,7 +32,8 @@ use FireflyIII\Models\Transaction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionType; use Illuminate\Console\Command; -use Illuminate\Support\Facades\Log; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Query\JoinClause; use JsonException; /** @@ -51,22 +53,78 @@ class FixAccountTypes extends Command * Execute the console command. * * @return int - * @throws FireflyException + * @throws FireflyException|JsonException */ public function handle(): int { $this->stupidLaravel(); $this->factory = app(AccountFactory::class); $this->expected = config('firefly.source_dests'); - $journals = TransactionJournal::with(['TransactionType', 'transactions', 'transactions.account', 'transactions.account.accounttype'])->get(); - foreach ($journals as $journal) { - $this->inspectJournal($journal); + $expected = config('firefly.source_dests'); + + $query = TransactionJournal::leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id') + ->leftJoin( + 'transactions as source', + static function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'source.transaction_journal_id')->where('source.amount', '<', 0); + } + ) + ->leftJoin( + 'transactions as destination', + static function (JoinClause $join) { + $join->on('transaction_journals.id', '=', 'destination.transaction_journal_id')->where('destination.amount', '>', 0); + } + ) + ->leftJoin('accounts as source_account', 'source.account_id', '=', 'source_account.id') + ->leftJoin('accounts as destination_account', 'destination.account_id', '=', 'destination_account.id') + ->leftJoin('account_types as source_account_type', 'source_account.account_type_id', '=', 'source_account_type.id') + ->leftJoin('account_types as destination_account_type', 'destination_account.account_type_id', '=', 'destination_account_type.id'); + + // list all valid combinations, those are allowed. So we select those which are broken. + $query->where(function (Builder $q) use ($expected) { + foreach ($expected as $transactionType => $info) { + foreach ($info as $source => $destinations) { + foreach ($destinations as $destination) { + $q->whereNot(function (Builder $q1) use ($transactionType, $source, $destination) { + $q1->where('transaction_types.type', $transactionType); + $q1->where('source_account_type.type', $source); + $q1->where('destination_account_type.type', $destination); + }); + } + } + } + }); + + $resultSet = $query->get( + [ + 'transaction_journals.id', + //'transaction_type_id as type_id', + 'transaction_types.type as journal_type', + //'source.id as source_transaction_id', + //'source_account.id as source_account_id', + //'source_account_type.id as source_account_type_id', + 'source_account_type.type as source_account_type', + //'destination.id as destination_transaction_id', + //'destination_account.id as destination_account_id', + //'destination_account_type.id as destination_account_type_id', + 'destination_account_type.type as destination_account_type', + ] + ); + if ($resultSet->count() > 0) { + $this->friendlyLine(sprintf('Found %d journals that need to be fixed.', $resultSet->count())); + foreach ($resultSet as $entry) { + app('log')->debug(sprintf('Now fixing journal #%d', $entry->id)); + $journal = TransactionJournal::find((int)$entry->id); + if (null !== $journal) { + $this->inspectJournal($journal); + } + } } if (0 === $this->count) { $this->friendlyPositive('All account types are OK'); } if (0 !== $this->count) { - Log::debug(sprintf('%d journals had to be fixed.', $this->count)); + app('log')->debug(sprintf('%d journals had to be fixed.', $this->count)); $this->friendlyInfo(sprintf('Acted on %d transaction(s)', $this->count)); } @@ -74,11 +132,7 @@ class FixAccountTypes extends Command } /** - * Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is - * executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should - * be called from the handle method instead of using the constructor to initialize the command. - * - + * @return void */ private function stupidLaravel(): void { @@ -93,9 +147,10 @@ class FixAccountTypes extends Command */ private function inspectJournal(TransactionJournal $journal): void { + app('log')->debug(sprintf('Now inspecting journal #%d', $journal->id)); $transactions = $journal->transactions()->count(); if (2 !== $transactions) { - Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions)); + app('log')->debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions)); $this->friendlyError(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions)); return; @@ -109,20 +164,20 @@ class FixAccountTypes extends Command $destAccountType = $destAccount->accountType->type; if (!array_key_exists($type, $this->expected)) { - Log::info(sprintf('No source/destination info for transaction type %s.', $type)); + app('log')->info(sprintf('No source/destination info for transaction type %s.', $type)); $this->friendlyError(sprintf('No source/destination info for transaction type %s.', $type)); return; } if (!array_key_exists($sourceAccountType, $this->expected[$type])) { - Log::debug(sprintf('Going to fix journal #%d', $journal->id)); + app('log')->debug(sprintf('[a] Going to fix journal #%d', $journal->id)); $this->fixJournal($journal, $type, $sourceTransaction, $destTransaction); return; } $expectedTypes = $this->expected[$type][$sourceAccountType]; if (!in_array($destAccountType, $expectedTypes, true)) { - Log::debug(sprintf('Going to fix journal #%d', $journal->id)); + app('log')->debug(sprintf('[b] Going to fix journal #%d', $journal->id)); $this->fixJournal($journal, $type, $sourceTransaction, $destTransaction); } } @@ -158,10 +213,11 @@ class FixAccountTypes extends Command */ private function fixJournal(TransactionJournal $journal, string $type, Transaction $source, Transaction $dest): void { + app('log')->debug(sprintf('Going to fix journal #%d', $journal->id)); $this->count++; // variables: $combination = sprintf('%s%s%s', $type, $source->account->accountType->type, $dest->account->accountType->type); - + app('log')->debug(sprintf('Combination is "%s"', $combination)); switch ($combination) { case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::ASSET, AccountType::LOAN): case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::ASSET, AccountType::DEBT): @@ -172,10 +228,10 @@ class FixAccountTypes extends Command $journal->save(); $message = sprintf('Converted transaction #%d from a transfer to a withdrawal.', $journal->id); $this->friendlyInfo($message); - Log::debug($message); + app('log')->debug($message); // check it again: $this->inspectJournal($journal); - break; + return; case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::LOAN, AccountType::ASSET): case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::DEBT, AccountType::ASSET): case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::MORTGAGE, AccountType::ASSET): @@ -185,11 +241,11 @@ class FixAccountTypes extends Command $journal->save(); $message = sprintf('Converted transaction #%d from a transfer to a deposit.', $journal->id); $this->friendlyInfo($message); - Log::debug($message); + app('log')->debug($message); // check it again: $this->inspectJournal($journal); - break; + return; case sprintf('%s%s%s', TransactionType::WITHDRAWAL, AccountType::ASSET, AccountType::REVENUE): // withdrawals with a revenue account as destination instead of an expense account. $this->factory->setUser($journal->user); @@ -206,9 +262,9 @@ class FixAccountTypes extends Command $result->name ); $this->friendlyWarning($message); - Log::debug($message); + app('log')->debug($message); $this->inspectJournal($journal); - break; + return; case sprintf('%s%s%s', TransactionType::DEPOSIT, AccountType::EXPENSE, AccountType::ASSET): // deposits with an expense account as source instead of a revenue account. // find revenue account. @@ -226,19 +282,61 @@ class FixAccountTypes extends Command $result->name ); $this->friendlyWarning($message); - Log::debug($message); + app('log')->debug($message); $this->inspectJournal($journal); - break; - default: - $message = sprintf('The source account of %s #%d cannot be of type "%s".', $type, $journal->id, $source->account->accountType->type); - $this->friendlyError($message); - Log::debug($message); + return; + } + app('log')->debug(sprintf('Fallback to fix transaction journal #%d of type "%s".', $journal->id, $type)); - $message = sprintf('The destination account of %s #%d cannot be of type "%s".', $type, $journal->id, $dest->account->accountType->type); - $this->friendlyError($message); - Log::debug($message); + // transaction has no valid source. + $validSources = array_keys($this->expected[$type]); + if (!in_array($source->account->accountType->type, $validSources, true)) { + app('log')->debug('Journal has no valid source.'); + // perhaps we can create the account of type we need: - break; + if (in_array(AccountTypeEnum::REVENUE->value, $validSources, true)) { + app('log')->debug(sprintf('An account of type "%s" could be a valid source.', AccountTypeEnum::REVENUE->value)); + $this->factory->setUser($journal->user); + $newSource = $this->factory->findOrCreate($source->account->name, AccountTypeEnum::REVENUE->value); + $source->account()->associate($newSource); + $source->save(); + $this->friendlyPositive(sprintf('Firefly III gave transaction #%d a new source %s: #%d ("%s").', $journal->transaction_group_id, AccountTypeEnum::REVENUE->value, $newSource->id, $newSource->name)); + app('log')->debug(sprintf('Associated account #%d with transaction #%d', $newSource->id, $source->id)); + $this->inspectJournal($journal); + return; + } + if (!in_array(AccountTypeEnum::REVENUE->value, $validSources, true)) { + app('log')->debug('This transaction type has no source we can create. Just give error.'); + $message = sprintf('The source account of %s #%d cannot be of type "%s". Firefly III cannot fix this. You may have to remove the transaction yourself.', $type, $journal->id, $source->account->accountType->type); + $this->friendlyError($message); + app('log')->debug($message); + } + } + + // transaction has no valid destination: + $sourceType = $source->account->accountType->type; + $validDestinations = $this->expected[$type][$sourceType] ?? []; + if (!in_array($dest->account->accountType->type, $validDestinations, true)) { + app('log')->debug('Journal has no valid destination (perhaps because the source is also broken).'); + // perhaps we can create the account of type we need: + if (in_array(AccountTypeEnum::EXPENSE->value, $validDestinations, true)) { + app('log')->debug(sprintf('An account of type "%s" could be a valid destination.', AccountTypeEnum::EXPENSE->value)); + $this->factory->setUser($journal->user); + $newDestination = $this->factory->findOrCreate($dest->account->name, AccountTypeEnum::EXPENSE->value); + $dest->account()->associate($newDestination); + $dest->save(); + $this->friendlyPositive(sprintf('Firefly III gave transaction #%d a new destination %s: #%d ("%s").', $journal->transaction_group_id, AccountTypeEnum::EXPENSE->value, $newDestination->id, $newDestination->name)); + app('log')->debug(sprintf('Associated account #%d with transaction #%d', $newDestination->id, $source->id)); + $this->inspectJournal($journal); + return; + } + if (!in_array(AccountTypeEnum::EXPENSE->value, $validSources, true)) { + app('log')->debug('This transaction type has no destination we can create. Just give error.'); + $message = sprintf('The destination account of %s #%d cannot be of type "%s". Firefly III cannot fix this. You may have to remove the transaction yourself.', $type, $journal->id, $dest->account->accountType->type); + $this->friendlyError($message); + app('log')->debug($message); + return; + } } } } diff --git a/app/Console/Commands/Correction/TriggerCreditCalculation.php b/app/Console/Commands/Correction/TriggerCreditCalculation.php index 2d799e8719..21be5aa4fe 100644 --- a/app/Console/Commands/Correction/TriggerCreditCalculation.php +++ b/app/Console/Commands/Correction/TriggerCreditCalculation.php @@ -31,7 +31,6 @@ use Illuminate\Console\Command; /** * Class CorrectionSkeleton - * TODO DONT FORGET TO ADD THIS TO THE DOCKER BUILD */ class TriggerCreditCalculation extends Command { diff --git a/app/Http/Controllers/Bill/ShowController.php b/app/Http/Controllers/Bill/ShowController.php index 3813448d31..327c84c5f9 100644 --- a/app/Http/Controllers/Bill/ShowController.php +++ b/app/Http/Controllers/Bill/ShowController.php @@ -159,6 +159,7 @@ class ShowController extends Controller $object = $manager->createData($resource)->toArray(); $object['data']['currency'] = $bill->transactionCurrency; + /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setBill($bill)->setLimit($pageSize)->setPage($page)->withBudgetInformation() diff --git a/app/Http/Controllers/Budget/ShowController.php b/app/Http/Controllers/Budget/ShowController.php index 1d9e53e90b..c07af019e7 100644 --- a/app/Http/Controllers/Budget/ShowController.php +++ b/app/Http/Controllers/Budget/ShowController.php @@ -213,7 +213,7 @@ class ShowController extends Controller $collector->setRange($budgetLimit->start_date, $budgetLimit->end_date)->withAccountInformation() ->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation()->withCategoryInformation(); $groups = $collector->getPaginatedGroups(); - $groups->setPath(route('budgets.show', [$budget->id, $budgetLimit->id])); + $groups->setPath(route('budgets.show.limit', [$budget->id, $budgetLimit->id])); /** @var Carbon $start */ $start = session('first', today(config('app.timezone'))->startOfYear()); $end = today(config('app.timezone')); diff --git a/app/Http/Controllers/Chart/AccountController.php b/app/Http/Controllers/Chart/AccountController.php index b57bee22d8..00c6a5c661 100644 --- a/app/Http/Controllers/Chart/AccountController.php +++ b/app/Http/Controllers/Chart/AccountController.php @@ -472,6 +472,7 @@ class AccountController extends Controller */ private function periodByCurrency(Carbon $start, Carbon $end, Account $account, TransactionCurrency $currency): array { + app('log')->debug(sprintf('Now in periodByCurrency("%s", "%s", %s, "%s")', $start->format('Y-m-d'), $end->format('Y-m-d'), $account->id, $currency->code)); $locale = app('steam')->getLocale(); $step = $this->calculateStep($start, $end); $result = [ @@ -481,6 +482,13 @@ class AccountController extends Controller ]; $entries = []; $current = clone $start; + app('log')->debug(sprintf('Step is %s', $step)); + + // fix for issue https://github.com/firefly-iii/firefly-iii/issues/8041 + // have to make sure this chart is always based on the balance at the END of the period. + // This period depends on the size of the chart + $current = app('navigation')->endOfX($current, $step, null); + app('log')->debug(sprintf('$current date is %s', $current->format('Y-m-d'))); if ('1D' === $step) { // per day the entire period, balance for every day. $format = (string)trans('config.month_and_day_js', [], $locale); @@ -497,10 +505,13 @@ class AccountController extends Controller } if ('1W' === $step || '1M' === $step || '1Y' === $step) { while ($end >= $current) { + app('log')->debug(sprintf('Current is: %s', $current->format('Y-m-d'))); $balance = (float)app('steam')->balance($account, $current, $currency); $label = app('navigation')->periodShow($current, $step); $entries[$label] = $balance; $current = app('navigation')->addPeriod($current, $step, 0); + // here too, to fix #8041, the data is corrected to the end of the period. + $current = app('navigation')->endOfX($current, $step, null); } } $result['entries'] = $entries; diff --git a/app/Http/Controllers/DebugController.php b/app/Http/Controllers/DebugController.php index 5414311f8e..c4fc690fe1 100644 --- a/app/Http/Controllers/DebugController.php +++ b/app/Http/Controllers/DebugController.php @@ -23,9 +23,9 @@ declare(strict_types=1); namespace FireflyIII\Http\Controllers; +use Carbon\Carbon; use DB; use Exception; -use FireflyConfig; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Http\Middleware\IsDemoUser; use FireflyIII\Models\AccountType; @@ -229,8 +229,17 @@ class DebugController extends Controller { $userGuard = config('auth.defaults.guard'); + $config = app('fireflyconfig')->get('last_rt_job', 0); + $lastTime = (int)$config->data; + $lastCronjob = 'never'; + $lastCronjobAgo = 'never'; + if ($lastTime > 0) { + $carbon = Carbon::createFromTimestamp($lastTime); + $lastCronjob = $carbon->format('Y-m-d H:i:s'); + $lastCronjobAgo = $carbon->locale('en')->diffForHumans(); + } + return [ - 'tz' => env('TZ'), 'debug' => var_export(config('app.debug'), true), 'audit_log_channel' => envNonEmpty('AUDIT_LOG_CHANNEL', '(empty)'), 'default_language' => (string)config('firefly.default_language'), @@ -238,6 +247,13 @@ class DebugController extends Controller 'remote_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_header') : 'N/A', 'remote_mail_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_email') : 'N/A', 'stateful_domains' => join(', ', config('sanctum.stateful')), + + // the dates for the cron job are based on the recurring cron job's times. + // any of the cron jobs will do, they always run at the same time. + // but this job is the oldest, so the biggest chance it ran once + + 'last_cronjob' => $lastCronjob, + 'last_cronjob_ago' => $lastCronjobAgo, ]; } @@ -288,40 +304,40 @@ class DebugController extends Controller // has liabilities if ($user->accounts()->accountTypeIn([AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->count() > 0) { - $flags[] = ':credit_card:'; + $flags[] = ':credit_card:'; } // has piggies if ($user->piggyBanks()->count() > 0) { - $flags[] = ':pig:'; + $flags[] = ':pig:'; } // has stored reconciliations $type = TransactionType::whereType(TransactionType::RECONCILIATION)->first(); if ($user->transactionJournals()->where('transaction_type_id', $type->id)->count()) { - $flags[] = ':ledger:'; + $flags[] = ':ledger:'; } // has used importer? // has rules if ($user->rules()->count() > 0) { - $flags[] = ':wrench:'; + $flags[] = ':wrench:'; } // has recurring transactions if ($user->recurrences()->count() > 0) { - $flags[] = ':clock130:'; + $flags[] = ':clock130:'; } // has groups if ($user->objectGroups()->count() > 0) { - $flags[] = ':bookmark_tabs:'; + $flags[] = ':bookmark_tabs:'; } // uses bills if ($user->bills()->count() > 0) { - $flags[] = ':email:'; + $flags[] = ':email:'; } return join(' ', $flags); } diff --git a/app/Http/Controllers/Rule/CreateController.php b/app/Http/Controllers/Rule/CreateController.php index ec7b69e3a8..eb42aa0b03 100644 --- a/app/Http/Controllers/Rule/CreateController.php +++ b/app/Http/Controllers/Rule/CreateController.php @@ -98,7 +98,9 @@ class CreateController extends Controller $operators = $search->getOperators()->toArray(); if ('' !== $words) { session()->flash('warning', trans('firefly.rule_from_search_words', ['string' => $words])); - $operators[] = ['type' => 'description_contains', 'value' => $words]; + $operators[] = [ + 'type' => 'description_contains', + 'value' => $words]; } $oldTriggers = $this->parseFromOperators($operators); } diff --git a/app/Models/CurrencyExchangeRate.php b/app/Models/CurrencyExchangeRate.php index 7f752412d4..31a95e8348 100644 --- a/app/Models/CurrencyExchangeRate.php +++ b/app/Models/CurrencyExchangeRate.php @@ -63,6 +63,9 @@ use Illuminate\Support\Carbon; * @method static Builder|CurrencyExchangeRate whereUserRate($value) * @property int|null $user_group_id * @method static Builder|CurrencyExchangeRate whereUserGroupId($value) + * @method static Builder|CurrencyExchangeRate onlyTrashed() + * @method static Builder|CurrencyExchangeRate withTrashed() + * @method static Builder|CurrencyExchangeRate withoutTrashed() * @mixin Eloquent */ class CurrencyExchangeRate extends Model diff --git a/app/Models/TransactionJournal.php b/app/Models/TransactionJournal.php index 9581764f8e..166cb72b53 100644 --- a/app/Models/TransactionJournal.php +++ b/app/Models/TransactionJournal.php @@ -117,6 +117,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * @property int $the_count * @property int|null $user_group_id * @method static EloquentBuilder|TransactionJournal whereUserGroupId($value) + * @property-read Collection $auditLogEntries + * @property-read int|null $audit_log_entries_count * @mixin Eloquent */ class TransactionJournal extends Model diff --git a/app/Models/UserGroup.php b/app/Models/UserGroup.php index 21941ef0d9..5be2e89e81 100644 --- a/app/Models/UserGroup.php +++ b/app/Models/UserGroup.php @@ -65,6 +65,26 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; * @property-read int|null $piggy_banks_count * @property-read Collection $transactionJournals * @property-read int|null $transaction_journals_count + * @property-read Collection $attachments + * @property-read int|null $attachments_count + * @property-read Collection $categories + * @property-read int|null $categories_count + * @property-read Collection $currencyExchangeRates + * @property-read int|null $currency_exchange_rates_count + * @property-read Collection $objectGroups + * @property-read int|null $object_groups_count + * @property-read Collection $recurrences + * @property-read int|null $recurrences_count + * @property-read Collection $ruleGroups + * @property-read int|null $rule_groups_count + * @property-read Collection $rules + * @property-read int|null $rules_count + * @property-read Collection $tags + * @property-read int|null $tags_count + * @property-read Collection $transactionGroups + * @property-read int|null $transaction_groups_count + * @property-read Collection $webhooks + * @property-read int|null $webhooks_count * @mixin Eloquent */ class UserGroup extends Model diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index ed7df41697..0d93ba7b23 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -227,7 +227,6 @@ class EventServiceProvider extends ServiceProvider */ private function registerObservers(): void { - app('log')->debug('Register observers'); Attachment::observe(new AttachmentObserver()); PiggyBank::observe(new PiggyBankObserver()); Account::observe(new AccountObserver()); diff --git a/app/Providers/JournalServiceProvider.php b/app/Providers/JournalServiceProvider.php index 8a2ae5ae89..fa8dd0c960 100644 --- a/app/Providers/JournalServiceProvider.php +++ b/app/Providers/JournalServiceProvider.php @@ -31,6 +31,8 @@ use FireflyIII\Repositories\Journal\JournalCLIRepository; use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepository; use FireflyIII\Repositories\Journal\JournalRepositoryInterface; +use FireflyIII\Repositories\UserGroups\Journal\JournalRepository as GroupJournalRepository; +use FireflyIII\Repositories\UserGroups\Journal\JournalRepositoryInterface as GroupJournalRepositoryInterface; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository; use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface; use Illuminate\Foundation\Application; @@ -76,6 +78,19 @@ class JournalServiceProvider extends ServiceProvider } ); + $this->app->bind( + GroupJournalRepositoryInterface::class, + static function (Application $app) { + /** @var GroupJournalRepositoryInterface $repository */ + $repository = app(GroupJournalRepository::class); + if ($app->auth->check()) { // @phpstan-ignore-line (phpstan does not understand the reference to auth) + $repository->setUser(auth()->user()); + } + + return $repository; + } + ); + // also bind new API repository $this->app->bind( JournalAPIRepositoryInterface::class, diff --git a/app/Repositories/Bill/BillRepository.php b/app/Repositories/Bill/BillRepository.php index e1ebd24fe4..cc3f91b14c 100644 --- a/app/Repositories/Bill/BillRepository.php +++ b/app/Repositories/Bill/BillRepository.php @@ -665,13 +665,17 @@ class BillRepository implements BillRepositoryInterface */ public function sumUnpaidInRange(Carbon $start, Carbon $end): array { + app('log')->debug(sprintf('Now in sumUnpaidInRange("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d'))); $bills = $this->getActiveBills(); $return = []; /** @var Bill $bill */ foreach ($bills as $bill) { + app('log')->debug(sprintf('Processing bill #%d ("%s")', $bill->id, $bill->name)); $dates = $this->getPayDatesInRange($bill, $start, $end); $count = $bill->transactionJournals()->after($start)->before($end)->count(); $total = $dates->count() - $count; + app('log')->debug(sprintf('Pay dates: %d, count: %d, left: %d', $dates->count(), $count, $total)); + app('log')->debug('dates', $dates->toArray()); if ($total > 0) { $currency = $bill->transactionCurrency; diff --git a/app/Repositories/Journal/JournalRepository.php b/app/Repositories/Journal/JournalRepository.php index 7b2a2b5f88..859c8f953e 100644 --- a/app/Repositories/Journal/JournalRepository.php +++ b/app/Repositories/Journal/JournalRepository.php @@ -245,7 +245,7 @@ class JournalRepository implements JournalRepositoryInterface { $query = $this->user->transactionJournals() ->orderBy('date', 'DESC'); - if ('' !== $query) { + if ('' !== $search) { $query->where('description', 'LIKE', sprintf('%%%s%%', $search)); } diff --git a/app/Repositories/UserGroups/Journal/JournalRepository.php b/app/Repositories/UserGroups/Journal/JournalRepository.php new file mode 100644 index 0000000000..387438df74 --- /dev/null +++ b/app/Repositories/UserGroups/Journal/JournalRepository.php @@ -0,0 +1,49 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Repositories\UserGroups\Journal; + +use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; +use Illuminate\Support\Collection; + +/** + * Class JournalRepository + */ +class JournalRepository implements JournalRepositoryInterface +{ + use UserGroupTrait; + + /** + * @inheritDoc + */ + public function searchJournalDescriptions(string $search, int $limit): Collection + { + $query = $this->userGroup->transactionJournals() + ->orderBy('date', 'DESC'); + if ('' !== $search) { + $query->where('description', 'LIKE', sprintf('%%%s%%', $search)); + } + + return $query->take($limit)->get(); + } +} diff --git a/app/Repositories/UserGroups/Journal/JournalRepositoryInterface.php b/app/Repositories/UserGroups/Journal/JournalRepositoryInterface.php new file mode 100644 index 0000000000..5a2cd1b938 --- /dev/null +++ b/app/Repositories/UserGroups/Journal/JournalRepositoryInterface.php @@ -0,0 +1,42 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Repositories\UserGroups\Journal; + +use Illuminate\Support\Collection; + +/** + * Interface JournalRepositoryInterface + */ +interface JournalRepositoryInterface +{ + /** + * Search in journal descriptions. + * + * @param string $search + * @param int $limit + * + * @return Collection + */ + public function searchJournalDescriptions(string $search, int $limit): Collection; +} diff --git a/app/Services/Internal/Destroy/AccountDestroyService.php b/app/Services/Internal/Destroy/AccountDestroyService.php index 5decf97a8c..af4fd4cace 100644 --- a/app/Services/Internal/Destroy/AccountDestroyService.php +++ b/app/Services/Internal/Destroy/AccountDestroyService.php @@ -100,9 +100,11 @@ class AccountDestroyService $ibAccount->delete(); } $journal = TransactionJournal::find($journalId); - /** @var JournalDestroyService $service */ - $service = app(JournalDestroyService::class); - $service->destroy($journal); + if (null !== $journal) { + /** @var JournalDestroyService $service */ + $service = app(JournalDestroyService::class); + $service->destroy($journal); + } } } diff --git a/app/Services/Internal/Support/CreditRecalculateService.php b/app/Services/Internal/Support/CreditRecalculateService.php index 0535f3ec99..c221ab4131 100644 --- a/app/Services/Internal/Support/CreditRecalculateService.php +++ b/app/Services/Internal/Support/CreditRecalculateService.php @@ -185,10 +185,20 @@ class CreditRecalculateService app('log')->debug(sprintf('Now processing account #%d ("%s")', $account->id, $account->name)); // get opening balance (if present) $this->repository->setUser($account->user); + $direction = (string)$this->repository->getMetaValue($account, 'liability_direction'); + $openingBalance = $this->repository->getOpeningBalance($account); + if (null !== $openingBalance) { + app('log')->debug(sprintf('Found opening balance transaction journal #%d', $openingBalance->id)); + // if account direction is "debit" ("I owe this amount") the opening balance must always be AWAY from the account: + if ('debit' === $direction) { + $this->validateOpeningBalance($account, $openingBalance); + } + } $startOfDebt = $this->repository->getOpeningBalanceAmount($account) ?? '0'; $leftOfDebt = app('steam')->positive($startOfDebt); - - app('log')->debug(sprintf('Start of debt is "%s", so initial left of debt is "%s"', $startOfDebt, $leftOfDebt)); + $currency = $this->repository->getAccountCurrency($account); + $decimals = (int)($currency?->decimal_places ?? 2); + app('log')->debug(sprintf('Start of debt is "%s", so initial left of debt is "%s"', app('steam')->bcround($startOfDebt, $decimals), app('steam')->bcround($leftOfDebt, $decimals))); /** @var AccountMetaFactory $factory */ $factory = app(AccountMetaFactory::class); @@ -196,9 +206,6 @@ class CreditRecalculateService // amount is positive or negative, doesn't matter. $factory->crud($account, 'start_of_debt', $startOfDebt); - // get direction of liability: - $direction = (string)$this->repository->getMetaValue($account, 'liability_direction'); - app('log')->debug(sprintf('Debt direction is "%s"', $direction)); // now loop all transactions (except opening balance and credit thing) @@ -217,6 +224,42 @@ class CreditRecalculateService app('log')->debug(sprintf('Done processing account #%d ("%s")', $account->id, $account->name)); } + /** + * If account direction is "debit" ("I owe this amount") the opening balance must always be AWAY from the account: + * + * @param Account $account + * @param TransactionJournal $openingBalance + * + * @return void + */ + private function validateOpeningBalance(Account $account, TransactionJournal $openingBalance) + { + /** @var Transaction $source */ + $source = $openingBalance->transactions()->where('amount', '<', 0)->first(); + /** @var Transaction $dest */ + $dest = $openingBalance->transactions()->where('amount', '>', 0)->first(); + if ((int)$source->account_id !== $account->id) { + app('log')->info(sprintf('Liability #%d has a reversed opening balance. Will fix this now.', $account->id)); + app('log')->debug(sprintf('Source amount "%s" is now "%s"', $source->amount, app('steam')->positive($source->amount))); + app('log')->debug(sprintf('Destination amount "%s" is now "%s"', $dest->amount, app('steam')->negative($dest->amount))); + $source->amount = app('steam')->positive($source->amount); + $dest->amount = app('steam')->negative($source->amount); + var_dump($source->foreign_amount); + if (null !== $source->foreign_amount && '' !== $source->foreign_amount) { + $source->foreign_amount = app('steam')->positive($source->foreign_amount); + app('log')->debug(sprintf('Source foreign amount "%s" is now "%s"', $source->foreign_amount, app('steam')->positive($source->foreign_amount))); + } + if (null !== $dest->foreign_amount && '' !== $dest->foreign_amount) { + $dest->foreign_amount = app('steam')->negative($dest->foreign_amount); + app('log')->debug(sprintf('Destination amount "%s" is now "%s"', $dest->foreign_amount, app('steam')->negative($dest->foreign_amount))); + } + $source->save(); + $dest->save(); + return; + } + app('log')->debug('Opening balance is valid'); + } + /** * @param Account $account * @param string $direction @@ -227,17 +270,20 @@ class CreditRecalculateService */ private function processTransaction(Account $account, string $direction, Transaction $transaction, string $leftOfDebt): string { - app('log')->debug(sprintf('Left of debt is: %s', $leftOfDebt)); $journal = $transaction->transactionJournal; $foreignCurrency = $transaction->foreignCurrency; $accountCurrency = $this->repository->getAccountCurrency($account); $groupId = $journal->transaction_group_id; + $decimals = (int)$accountCurrency->decimal_places; $type = $journal->transactionType->type; /** @var Transaction $destTransaction */ $destTransaction = $journal->transactions()->where('amount', '>', '0')->first(); /** @var Transaction $sourceTransaction */ $sourceTransaction = $journal->transactions()->where('amount', '<', '0')->first(); + + app('log')->debug(sprintf('Left of debt is: %s', app('steam')->bcround($leftOfDebt, $decimals))); + if ('' === $direction) { app('log')->warning('Direction is empty, so do nothing.'); return $leftOfDebt; @@ -249,10 +295,10 @@ class CreditRecalculateService // amount to use depends on the currency: $usedAmount = $transaction->amount; - app('log')->debug(sprintf('Amount of transaction is %s', $usedAmount)); + app('log')->debug(sprintf('Amount of transaction is %s', app('steam')->bcround($usedAmount, $decimals))); if (null !== $foreignCurrency && $foreignCurrency->id === $accountCurrency->id) { $usedAmount = $transaction->foreign_amount; - app('log')->debug(sprintf('Overruled by foreign amount. Amount of transaction is now %s', $usedAmount)); + app('log')->debug(sprintf('Overruled by foreign amount. Amount of transaction is now %s', app('steam')->bcround($usedAmount, $decimals))); } // Case 1 @@ -267,7 +313,7 @@ class CreditRecalculateService ) { $usedAmount = app('steam')->positive($usedAmount); $result = bcadd($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case 1 (withdrawal into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case 1 (withdrawal into credit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } @@ -283,7 +329,7 @@ class CreditRecalculateService ) { $usedAmount = app('steam')->positive($usedAmount); $result = bcsub($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case 2 (withdrawal away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case 2 (withdrawal away from liability): %s - %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } @@ -299,7 +345,7 @@ class CreditRecalculateService ) { $usedAmount = app('steam')->positive($usedAmount); $result = bcsub($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case 3 (deposit away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case 3 (deposit away from liability): %s - %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } @@ -315,7 +361,7 @@ class CreditRecalculateService ) { $usedAmount = app('steam')->positive($usedAmount); $result = bcadd($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case 4 (deposit into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case 4 (deposit into credit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } // case 5: transfer into loan (from other loan). @@ -329,7 +375,7 @@ class CreditRecalculateService ) { $usedAmount = app('steam')->positive($usedAmount); $result = bcadd($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case 5 (transfer into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case 5 (transfer into credit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } // Case 6 @@ -344,7 +390,7 @@ class CreditRecalculateService ) { $usedAmount = app('steam')->positive($usedAmount); $result = bcsub($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case 6 (withdrawal into debit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case 6 (withdrawal into debit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } // case 7 @@ -359,19 +405,35 @@ class CreditRecalculateService ) { $usedAmount = app('steam')->positive($usedAmount); $result = bcadd($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case 7 (deposit away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case 7 (deposit away from liability): %s - %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } + // case 8 + // it's a withdrawal from this liability (to expense account). + // if it's a debit ("I owe this amount") this increase the amount due. + // because we are paying interest. + if ( + $type === TransactionType::WITHDRAWAL + && (int)$account->id === (int)$transaction->account_id + && -1 === bccomp($usedAmount, '0') + && 'debit' === $direction + ) { + $usedAmount = app('steam')->positive($usedAmount); + $result = bcadd($leftOfDebt, $usedAmount); + app('log')->debug(sprintf('Case 8 (withdrawal away from liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); + return $result; + } + // in any other case, remove amount from left of debt. if (in_array($type, [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER], true)) { $usedAmount = app('steam')->negative($usedAmount); $result = bcadd($leftOfDebt, $usedAmount); - app('log')->debug(sprintf('Case X (all other cases): %s + %s = %s', $leftOfDebt, $usedAmount, $result)); + app('log')->debug(sprintf('Case X (all other cases): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals))); return $result; } - Log::warning(sprintf('[6] Catch-all, should not happen. Left of debt = %s', $leftOfDebt)); + Log::warning(sprintf('[-1] Catch-all, should not happen. Left of debt = %s', app('steam')->bcround($leftOfDebt, $decimals))); return $leftOfDebt; } diff --git a/app/Support/Http/Api/ValidatesUserGroupTrait.php b/app/Support/Http/Api/ValidatesUserGroupTrait.php index a7f1f16bc7..abc8666155 100644 --- a/app/Support/Http/Api/ValidatesUserGroupTrait.php +++ b/app/Support/Http/Api/ValidatesUserGroupTrait.php @@ -29,6 +29,9 @@ use FireflyIII\Models\UserGroup; use FireflyIII\User; use Illuminate\Http\Request; +/** + * Trait ValidatesUserGroupTrait + */ trait ValidatesUserGroupTrait { /** diff --git a/app/Support/Http/Controllers/RuleManagement.php b/app/Support/Http/Controllers/RuleManagement.php index a80b8e48a8..874829cc6d 100644 --- a/app/Support/Http/Controllers/RuleManagement.php +++ b/app/Support/Http/Controllers/RuleManagement.php @@ -143,11 +143,12 @@ trait RuleManagement $renderedEntries[] = view( 'rules.partials.trigger', [ - 'oldTrigger' => OperatorQuerySearch::getRootOperator($operator['type']), - 'oldValue' => $operator['value'], - 'oldChecked' => false, - 'count' => $index + 1, - 'triggers' => $triggers, + 'oldTrigger' => OperatorQuerySearch::getRootOperator($operator['type']), + 'oldValue' => $operator['value'], + 'oldChecked' => false, + 'oldProhibited' => $operator['prohibited'] ?? false, + 'count' => $index + 1, + 'triggers' => $triggers, ] )->render(); } catch (Throwable $e) { diff --git a/app/Support/Navigation.php b/app/Support/Navigation.php index 7f0aafea32..0cd95afc07 100644 --- a/app/Support/Navigation.php +++ b/app/Support/Navigation.php @@ -55,7 +55,6 @@ class Navigation * @param int $skip * * @return Carbon - * @deprecated This method will be substituted by nextDateByInterval() */ public function addPeriod(Carbon $theDate, string $repeatFreq, int $skip = 0): Carbon { @@ -342,6 +341,35 @@ class Navigation return $currentEnd; } + /** + * @param string $period + * @param Carbon $beginning + * @param Carbon $end + * + * @return int + */ + public function diffInPeriods(string $period, Carbon $beginning, Carbon $end): int + { + $map = [ + 'daily' => 'diffInDays', + 'weekly' => 'diffInWeeks', + 'monthly' => 'diffInMonths', + 'quarterly' => 'diffInQuarters', + 'half-year' => 'diffInQuarters', + 'yearly' => 'diffInYears', + ]; + if (!array_key_exists($period, $map)) { + app('log')->warning(sprintf('No diffInPeriods for period "%s"', $period)); + return 1; + } + $func = $map[$period]; + $diff = $beginning->$func($end); + if ('half-year' === $period) { + $diff = ceil($diff / 2); + } + return (int)$diff; + } + /** * @param Carbon $theCurrentEnd * @param string $repeatFreq diff --git a/app/Support/Steam.php b/app/Support/Steam.php index e824840c24..335f246abf 100644 --- a/app/Support/Steam.php +++ b/app/Support/Steam.php @@ -782,7 +782,7 @@ class Steam if (!is_string($preference)) { throw new FireflyException(sprintf('Preference "language" must be a string, but is unexpectedly a "%s".', gettype($preference))); } - return $preference; + return str_replace('-', '_', $preference); } /** diff --git a/app/Transformers/BillTransformer.php b/app/Transformers/BillTransformer.php index 9588a4aef6..22a7e8c16d 100644 --- a/app/Transformers/BillTransformer.php +++ b/app/Transformers/BillTransformer.php @@ -30,7 +30,6 @@ use FireflyIII\Models\ObjectGroup; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Bill\BillRepositoryInterface; use Illuminate\Support\Collection; -use Log; /** * Class BillTransformer @@ -150,9 +149,9 @@ class BillTransformer extends AbstractTransformer */ protected function paidData(Bill $bill): array { - Log::debug(sprintf('Now in paidData for bill #%d', $bill->id)); + app('log')->debug(sprintf('Now in paidData for bill #%d', $bill->id)); if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) { - Log::debug('parameters are NULL, return empty array'); + app('log')->debug('parameters are NULL, return empty array'); return [ 'paid_dates' => [], @@ -163,44 +162,49 @@ class BillTransformer extends AbstractTransformer // 2023-07-18 this particular date is used to search for the last paid date. // 2023-07-18 the cloned $searchDate is used to grab the correct transactions. /** @var Carbon $start */ - $start = clone $this->parameters->get('start'); + $start = clone $this->parameters->get('start'); + $searchStart = clone $start; $start->subDay(); - $searchStart = clone $start; - //Log::debug(sprintf('Parameters are start:%s end:%s', $start->format('Y-m-d'), $this->parameters->get('end')->format('Y-m-d'))); + app('log')->debug(sprintf('Parameters are start: %s end: %s', $start->format('Y-m-d'), $this->parameters->get('end')->format('Y-m-d'))); + app('log')->debug(sprintf('Search parameters are: start: %s', $searchStart->format('Y-m-d'))); /* * Get from database when bill was paid. */ $set = $this->repository->getPaidDatesInRange($bill, $searchStart, $this->parameters->get('end')); - //Log::debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count())); + app('log')->debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count())); /* * Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date. */ - //Log::debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d'))); + app('log')->debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d'))); $lastPaidDate = $this->lastPaidDate($set, $start); - //Log::debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d'))); + app('log')->debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d'))); /* * The next expected match (nextMatch) is, initially, the bill's date. */ $nextMatch = clone $bill->date; - //Log::debug(sprintf('Next match is %s (bill->date)', $nextMatch->format('Y-m-d'))); - while ($nextMatch < $lastPaidDate) { + /* + * Diff in months (or other period) between bill start and last paid date or $start. + */ + $steps = app('navigation')->diffInPeriods($bill->repeat_freq, $start, $nextMatch); + $nextMatch = app('navigation')->addPeriod($nextMatch, $bill->repeat_freq, $steps); + + if ($nextMatch->lt($lastPaidDate)) { /* - * As long as this date is smaller than the last time the bill was paid, keep jumping ahead. - * For example: 1 jan, 1 feb, etc. + * Add another period because it's before the last paid date */ - //Log::debug(sprintf('next match %s < last paid date %s, so add one period.', $nextMatch->format('Y-m-d'), $lastPaidDate->format('Y-m-d'))); + app('log')->debug('Because the last paid date was before our next expected match, add another period.'); $nextMatch = app('navigation')->addPeriod($nextMatch, $bill->repeat_freq, $bill->skip); - //Log::debug(sprintf('Next match is now %s.', $nextMatch->format('Y-m-d'))); } + if ($nextMatch->isSameDay($lastPaidDate)) { /* * Add another period because it's the same day as the last paid date. */ - //Log::debug('Because the last paid date was on the same day as our next expected match, add another day.'); + app('log')->debug('Because the last paid date was on the same day as our next expected match, add another day.'); $nextMatch = app('navigation')->addPeriod($nextMatch, $bill->repeat_freq, $bill->skip); } /* @@ -215,7 +219,7 @@ class BillTransformer extends AbstractTransformer ]; } - //Log::debug('Result', $result); + app('log')->debug(sprintf('Next match: %s', $nextMatch->toIso8601String())); return [ 'paid_dates' => $result, @@ -254,23 +258,28 @@ class BillTransformer extends AbstractTransformer */ protected function payDates(Bill $bill): array { - //Log::debug(sprintf('Now in payDates() for bill #%d', $bill->id)); + app('log')->debug(sprintf('Now in payDates() for bill #%d', $bill->id)); if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) { - //Log::debug('No start or end date, give empty array.'); + app('log')->debug('No start or end date, give empty array.'); return []; } + app('log')->debug(sprintf('Start: %s, end: %s', $this->parameters->get('start')->toIso8601String(), $this->parameters->get('end')->toIso8601String())); $set = new Collection(); $currentStart = clone $this->parameters->get('start'); // 2023-06-23 subDay to fix 7655 $currentStart->subDay(); $loop = 0; while ($currentStart <= $this->parameters->get('end')) { + app('log')->debug(sprintf('Current start is %s', $currentStart->toIso8601String())); $nextExpectedMatch = $this->nextDateMatch($bill, $currentStart); + // If nextExpectedMatch is after end, we continue: if ($nextExpectedMatch > $this->parameters->get('end')) { + app('log')->debug('Next expected match is after END, so stop looking'); break; } + app('log')->debug(sprintf('Next expected match is %s', $nextExpectedMatch->toIso8601String())); // add to set $set->push(clone $nextExpectedMatch); $nextExpectedMatch->addDay(); @@ -285,13 +294,14 @@ class BillTransformer extends AbstractTransformer return $date->format('Y-m-d'); } ); + app('log')->debug(sprintf('Found %d pay dates', $set->count()), $simple->toArray()); return $simple->toArray(); } /** * Given a bill and a date, this method will tell you at which moment this bill expects its next - * transaction. Whether or not it is there already, is not relevant. + * transaction. Whether it is there already, is not relevant. * * @param Bill $bill * @param Carbon $date @@ -300,15 +310,13 @@ class BillTransformer extends AbstractTransformer */ protected function nextDateMatch(Bill $bill, Carbon $date): Carbon { - //Log::debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d'))); + app('log')->debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d'))); $start = clone $bill->date; - //Log::debug(sprintf('Bill start date is %s', $start->format('Y-m-d'))); - while ($start < $date) { - $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); - } + app('log')->debug(sprintf('Bill start date is %s', $start->format('Y-m-d'))); - //Log::debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d'))); - - return $start; + $steps = app('navigation')->diffInPeriods($bill->repeat_freq, $start, $date); + $result = app('navigation')->addPeriod($start, $bill->repeat_freq, $steps); + app('log')->debug(sprintf('Number of steps is %d, result is %s', $steps, $start->format('Y-m-d'))); + return $result; } } diff --git a/app/Transformers/RecurrenceTransformer.php b/app/Transformers/RecurrenceTransformer.php index f63dd9d65a..ddc95d7ef4 100644 --- a/app/Transformers/RecurrenceTransformer.php +++ b/app/Transformers/RecurrenceTransformer.php @@ -72,17 +72,17 @@ class RecurrenceTransformer extends AbstractTransformer */ public function transform(Recurrence $recurrence): array { - Log::debug('Now in Recurrence::transform()'); + app('log')->debug('Now in Recurrence::transform()'); $this->repository->setUser($recurrence->user); $this->piggyRepos->setUser($recurrence->user); $this->factory->setUser($recurrence->user); $this->budgetRepos->setUser($recurrence->user); - Log::debug('Set user.'); + app('log')->debug('Set user.'); $shortType = (string)config(sprintf('firefly.transactionTypesToShort.%s', $recurrence->transactionType->type)); $notes = $this->repository->getNoteText($recurrence); $reps = 0 === (int)$recurrence->repetitions ? null : (int)$recurrence->repetitions; - Log::debug('Get basic data.'); + app('log')->debug('Get basic data.'); // basic data. return [ @@ -118,7 +118,7 @@ class RecurrenceTransformer extends AbstractTransformer */ private function getRepetitions(Recurrence $recurrence): array { - Log::debug('Now in getRepetitions().'); + app('log')->debug('Now in getRepetitions().'); $fromDate = $recurrence->latest_date ?? $recurrence->first_date; $return = []; @@ -157,7 +157,7 @@ class RecurrenceTransformer extends AbstractTransformer */ private function getTransactions(Recurrence $recurrence): array { - Log::debug(sprintf('Now in %s', __METHOD__)); + app('log')->debug(sprintf('Now in %s', __METHOD__)); $return = []; // get all transactions: /** @var RecurrenceTransaction $transaction */ @@ -246,7 +246,7 @@ class RecurrenceTransformer extends AbstractTransformer */ private function getTransactionMeta(RecurrenceTransaction $transaction, array $array): array { - Log::debug(sprintf('Now in %s', __METHOD__)); + app('log')->debug(sprintf('Now in %s', __METHOD__)); $array['tags'] = []; $array['category_id'] = null; $array['category_name'] = null; diff --git a/app/Transformers/TransactionGroupTransformer.php b/app/Transformers/TransactionGroupTransformer.php index f8983940e3..cb12faa4de 100644 --- a/app/Transformers/TransactionGroupTransformer.php +++ b/app/Transformers/TransactionGroupTransformer.php @@ -344,8 +344,8 @@ class TransactionGroupTransformer extends AbstractTransformer ], ]; } catch (FireflyException $e) { - Log::error($e->getMessage()); - Log::error($e->getTraceAsString()); + app('log')->error($e->getMessage()); + app('log')->error($e->getTraceAsString()); throw new FireflyException(sprintf('Transaction group #%d is broken. Please check out your log files.', $group->id), 0, $e); } diff --git a/app/Transformers/V2/BillTransformer.php b/app/Transformers/V2/BillTransformer.php index e77318487b..4dae4997c5 100644 --- a/app/Transformers/V2/BillTransformer.php +++ b/app/Transformers/V2/BillTransformer.php @@ -320,9 +320,9 @@ class BillTransformer extends AbstractTransformer */ protected function payDates(Bill $bill): array { - //Log::debug(sprintf('Now in payDates() for bill #%d', $bill->id)); + //app('log')->debug(sprintf('Now in payDates() for bill #%d', $bill->id)); if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) { - //Log::debug('No start or end date, give empty array.'); + //app('log')->debug('No start or end date, give empty array.'); return []; } @@ -366,14 +366,14 @@ class BillTransformer extends AbstractTransformer */ protected function nextDateMatch(Bill $bill, Carbon $date): Carbon { - //Log::debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d'))); + //app('log')->debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d'))); $start = clone $bill->date; - //Log::debug(sprintf('Bill start date is %s', $start->format('Y-m-d'))); + //app('log')->debug(sprintf('Bill start date is %s', $start->format('Y-m-d'))); while ($start < $date) { $start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip); } - //Log::debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d'))); + //app('log')->debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d'))); return $start; } diff --git a/app/Transformers/V2/TransactionGroupTransformer.php b/app/Transformers/V2/TransactionGroupTransformer.php index b6668b9433..e67db9c145 100644 --- a/app/Transformers/V2/TransactionGroupTransformer.php +++ b/app/Transformers/V2/TransactionGroupTransformer.php @@ -270,7 +270,7 @@ class TransactionGroupTransformer extends AbstractTransformer */ private function stringFromArray(NullArrayObject $array, string $key, ?string $default): ?string { - //Log::debug(sprintf('%s: %s', $key, var_export($array[$key], true))); + //app('log')->debug(sprintf('%s: %s', $key, var_export($array[$key], true))); if (null === $array[$key] && null === $default) { return null; } @@ -301,7 +301,7 @@ class TransactionGroupTransformer extends AbstractTransformer if (null === $string) { return null; } - // Log::debug(sprintf('Now in date("%s")', $string)); + // app('log')->debug(sprintf('Now in date("%s")', $string)); if (10 === strlen($string)) { return Carbon::createFromFormat('Y-m-d', $string, config('app.timezone')); } diff --git a/app/Transformers/WebhookMessageTransformer.php b/app/Transformers/WebhookMessageTransformer.php index 452aec5a06..02a290a069 100644 --- a/app/Transformers/WebhookMessageTransformer.php +++ b/app/Transformers/WebhookMessageTransformer.php @@ -45,7 +45,7 @@ class WebhookMessageTransformer extends AbstractTransformer try { $json = json_encode($message->message, JSON_THROW_ON_ERROR); } catch (JsonException $e) { - Log::error(sprintf('Could not encode webhook message #%d: %s', $message->id, $e->getMessage())); + app('log')->error(sprintf('Could not encode webhook message #%d: %s', $message->id, $e->getMessage())); } return [ diff --git a/changelog.md b/changelog.md index 0d35cf275d..c28367f30d 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,31 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## v6.0.27 - 2023-10-16 + +### Added + +- [Issue 8004](https://github.com/firefly-iii/firefly-iii/issues/8004) Warning in entrypoint script for missing variables. + +### Changed + +- Experimental database validation command. +- Add some values to the debug form. +- Better debug logs at various places + +### Fixed + +- [Issue 8020](https://github.com/firefly-iii/firefly-iii/issues/8020), [issue 8028](https://github.com/firefly-iii/firefly-iii/issues/8028) Liability calculation edge case found by @tieu1991 +- [Issue 7655](https://github.com/firefly-iii/firefly-iii/issues/7655), [issue 8026](https://github.com/firefly-iii/firefly-iii/issues/8026) Bill date calculation edge case found by @devfaz +- [Issue 8051](https://github.com/firefly-iii/firefly-iii/issues/8051) Null pointer when deleting account +- [Issue 8041](https://github.com/firefly-iii/firefly-iii/issues/8041) Confusing chart is no longer confusing +- [Issue 8050](https://github.com/firefly-iii/firefly-iii/issues/8050) Path is normal for page 2. +- [Issue 8057](https://github.com/firefly-iii/firefly-iii/issues/8057) negative query parameters are handled correctly. + +### API (v2.0.10) + +- All endpoints (v1 and v2) should now respect the `?limit=` param. + ## 6.0.26 - 2023-09-24 ### Fixed diff --git a/composer.lock b/composer.lock index 2eecc063c8..214c235c1e 100644 --- a/composer.lock +++ b/composer.lock @@ -473,16 +473,16 @@ }, { "name": "doctrine/dbal", - "version": "3.6.7", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "8e0e268052b4a8974cb00215bb2892787021614f" + "reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/8e0e268052b4a8974cb00215bb2892787021614f", - "reference": "8e0e268052b4a8974cb00215bb2892787021614f", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/5b7bd66c9ff58c04c5474ab85edce442f8081cb2", + "reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2", "shasum": "" }, "require": { @@ -498,9 +498,9 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.34", + "phpstan/phpstan": "1.10.35", "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "9.6.12", + "phpunit/phpunit": "9.6.13", "psalm/plugin-phpunit": "0.18.4", "slevomat/coding-standard": "8.13.1", "squizlabs/php_codesniffer": "3.7.2", @@ -566,7 +566,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.6.7" + "source": "https://github.com/doctrine/dbal/tree/3.7.1" }, "funding": [ { @@ -582,20 +582,20 @@ "type": "tidelift" } ], - "time": "2023-09-19T20:15:41+00:00" + "time": "2023-10-06T05:06:20+00:00" }, { "name": "doctrine/deprecations", - "version": "v1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "shasum": "" }, "require": { @@ -627,9 +627,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" + "source": "https://github.com/doctrine/deprecations/tree/1.1.2" }, - "time": "2023-06-03T09:27:29+00:00" + "time": "2023-09-27T20:04:15+00:00" }, { "name": "doctrine/event-manager", @@ -953,16 +953,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.1", + "version": "4.0.2", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff" + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/3a85486b709bc384dae8eb78fb2eec649bdb64ff", - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", "shasum": "" }, "require": { @@ -971,8 +971,8 @@ "symfony/polyfill-intl-idn": "^1.26" }, "require-dev": { - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^4.30" + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -1008,7 +1008,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.1" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" }, "funding": [ { @@ -1016,7 +1016,7 @@ "type": "github" } ], - "time": "2023-01-14T14:17:03+00:00" + "time": "2023-10-06T06:47:41+00:00" }, { "name": "facade/ignition-contracts", @@ -1144,16 +1144,16 @@ }, { "name": "firebase/php-jwt", - "version": "v6.8.1", + "version": "v6.9.0", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "5dbc8959427416b8ee09a100d7a8588c00fb2e26" + "reference": "f03270e63eaccf3019ef0f32849c497385774e11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/5dbc8959427416b8ee09a100d7a8588c00fb2e26", - "reference": "5dbc8959427416b8ee09a100d7a8588c00fb2e26", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/f03270e63eaccf3019ef0f32849c497385774e11", + "reference": "f03270e63eaccf3019ef0f32849c497385774e11", "shasum": "" }, "require": { @@ -1201,27 +1201,27 @@ ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", - "source": "https://github.com/firebase/php-jwt/tree/v6.8.1" + "source": "https://github.com/firebase/php-jwt/tree/v6.9.0" }, - "time": "2023-07-14T18:33:00+00:00" + "time": "2023-10-05T00:24:42+00:00" }, { "name": "fruitcake/php-cors", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/fruitcake/php-cors.git", - "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e" + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/58571acbaa5f9f462c9c77e911700ac66f446d4e", - "reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", "shasum": "" }, "require": { "php": "^7.4|^8.0", - "symfony/http-foundation": "^4.4|^5.4|^6" + "symfony/http-foundation": "^4.4|^5.4|^6|^7" }, "require-dev": { "phpstan/phpstan": "^1.4", @@ -1231,7 +1231,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.1-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -1262,7 +1262,7 @@ ], "support": { "issues": "https://github.com/fruitcake/php-cors/issues", - "source": "https://github.com/fruitcake/php-cors/tree/v1.2.0" + "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" }, "funding": [ { @@ -1274,7 +1274,7 @@ "type": "github" } ], - "time": "2022-02-20T15:07:15+00:00" + "time": "2023-10-12T05:21:21+00:00" }, { "name": "gdbots/query-parser", @@ -1939,16 +1939,16 @@ }, { "name": "laravel/framework", - "version": "v10.24.0", + "version": "v10.28.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726" + "reference": "09137f50f715c1efc649788a26092dcb1ec4ab6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/bcebd0a4c015d5c38aeec299d355a42451dd3726", - "reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726", + "url": "https://api.github.com/repos/laravel/framework/zipball/09137f50f715c1efc649788a26092dcb1ec4ab6e", + "reference": "09137f50f715c1efc649788a26092dcb1ec4ab6e", "shasum": "" }, "require": { @@ -1966,7 +1966,7 @@ "ext-tokenizer": "*", "fruitcake/php-cors": "^1.2", "guzzlehttp/uri-template": "^1.0", - "laravel/prompts": "^0.1", + "laravel/prompts": "^0.1.9", "laravel/serializable-closure": "^1.3", "league/commonmark": "^2.2.1", "league/flysystem": "^3.8.0", @@ -2048,7 +2048,7 @@ "league/flysystem-read-only": "^3.3", "league/flysystem-sftp-v3": "^3.0", "mockery/mockery": "^1.5.1", - "orchestra/testbench-core": "^8.10", + "orchestra/testbench-core": "^8.12", "pda/pheanstalk": "^4.0", "phpstan/phpstan": "^1.4.7", "phpunit/phpunit": "^10.0.7", @@ -2135,7 +2135,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-09-19T15:25:04+00:00" + "time": "2023-10-10T13:01:37+00:00" }, { "name": "laravel/passport", @@ -2217,16 +2217,16 @@ }, { "name": "laravel/prompts", - "version": "v0.1.8", + "version": "v0.1.11", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c" + "reference": "cce65a90e64712909ea1adc033e1d88de8455ffd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/68dcc65babf92e1fb43cba0b3f78fc3d8002709c", - "reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c", + "url": "https://api.github.com/repos/laravel/prompts/zipball/cce65a90e64712909ea1adc033e1d88de8455ffd", + "reference": "cce65a90e64712909ea1adc033e1d88de8455ffd", "shasum": "" }, "require": { @@ -2235,6 +2235,10 @@ "php": "^8.1", "symfony/console": "^6.2" }, + "conflict": { + "illuminate/console": ">=10.17.0 <10.25.0", + "laravel/framework": ">=10.17.0 <10.25.0" + }, "require-dev": { "mockery/mockery": "^1.5", "pestphp/pest": "^2.3", @@ -2245,6 +2249,11 @@ "ext-pcntl": "Required for the spinner to be animated." }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.1.x-dev" + } + }, "autoload": { "files": [ "src/helpers.php" @@ -2259,9 +2268,9 @@ ], "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.8" + "source": "https://github.com/laravel/prompts/tree/v0.1.11" }, - "time": "2023-09-19T15:33:56+00:00" + "time": "2023-10-03T01:07:35+00:00" }, { "name": "laravel/sanctum", @@ -2987,16 +2996,16 @@ }, { "name": "league/flysystem", - "version": "3.16.0", + "version": "3.17.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729" + "reference": "bd4c9b26849d82364119c68429541f1631fba94b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729", - "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/bd4c9b26849d82364119c68429541f1631fba94b", + "reference": "bd4c9b26849d82364119c68429541f1631fba94b", "shasum": "" }, "require": { @@ -3014,8 +3023,8 @@ "symfony/http-client": "<5.2" }, "require-dev": { - "async-aws/s3": "^1.5", - "async-aws/simple-s3": "^1.1", + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", "aws/aws-sdk-php": "^3.220.0", "composer/semver": "^3.0", "ext-fileinfo": "*", @@ -3061,7 +3070,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.16.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.17.0" }, "funding": [ { @@ -3073,7 +3082,7 @@ "type": "github" } ], - "time": "2023-09-07T19:22:17+00:00" + "time": "2023-10-05T20:15:05+00:00" }, { "name": "league/flysystem-local", @@ -3680,16 +3689,16 @@ }, { "name": "nesbot/carbon", - "version": "2.70.0", + "version": "2.71.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d" + "reference": "98276233188583f2ff845a0f992a235472d9466a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d3298b38ea8612e5f77d38d1a99438e42f70341d", - "reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/98276233188583f2ff845a0f992a235472d9466a", + "reference": "98276233188583f2ff845a0f992a235472d9466a", "shasum": "" }, "require": { @@ -3782,20 +3791,20 @@ "type": "tidelift" } ], - "time": "2023-09-07T16:43:50+00:00" + "time": "2023-09-25T11:31:05+00:00" }, { "name": "nette/schema", - "version": "v1.2.4", + "version": "v1.2.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab" + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/c9ff517a53903b3d4e29ec547fb20feecb05b8ab", - "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab", + "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a", + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a", "shasum": "" }, "require": { @@ -3842,9 +3851,9 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.2.4" + "source": "https://github.com/nette/schema/tree/v1.2.5" }, - "time": "2023-08-05T18:56:25+00:00" + "time": "2023-10-05T20:37:59+00:00" }, { "name": "nette/utils", @@ -3934,16 +3943,16 @@ }, { "name": "nunomaduro/collision", - "version": "v7.9.0", + "version": "v7.10.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "296d0cf9fe462837ac0da8a568b56fc026b132da" + "reference": "49ec67fa7b002712da8526678abd651c09f375b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/296d0cf9fe462837ac0da8a568b56fc026b132da", - "reference": "296d0cf9fe462837ac0da8a568b56fc026b132da", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/49ec67fa7b002712da8526678abd651c09f375b2", + "reference": "49ec67fa7b002712da8526678abd651c09f375b2", "shasum": "" }, "require": { @@ -3952,19 +3961,22 @@ "php": "^8.1.0", "symfony/console": "^6.3.4" }, + "conflict": { + "laravel/framework": ">=11.0.0" + }, "require-dev": { - "brianium/paratest": "^7.2.7", - "laravel/framework": "^10.23.1", - "laravel/pint": "^1.13.1", + "brianium/paratest": "^7.3.0", + "laravel/framework": "^10.28.0", + "laravel/pint": "^1.13.3", "laravel/sail": "^1.25.0", "laravel/sanctum": "^3.3.1", "laravel/tinker": "^2.8.2", "nunomaduro/larastan": "^2.6.4", - "orchestra/testbench-core": "^8.11.0", - "pestphp/pest": "^2.19.1", - "phpunit/phpunit": "^10.3.5", + "orchestra/testbench-core": "^8.13.0", + "pestphp/pest": "^2.23.2", + "phpunit/phpunit": "^10.4.1", "sebastian/environment": "^6.0.1", - "spatie/laravel-ignition": "^2.3.0" + "spatie/laravel-ignition": "^2.3.1" }, "type": "library", "extra": { @@ -4023,7 +4035,7 @@ "type": "patreon" } ], - "time": "2023-09-19T10:45:09+00:00" + "time": "2023-10-11T15:45:01+00:00" }, { "name": "nunomaduro/termwind", @@ -5790,16 +5802,16 @@ }, { "name": "spatie/laravel-ignition", - "version": "2.3.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/spatie/laravel-ignition.git", - "reference": "4ed813d16edb5a1ab0d7f4b1d116c37ee8cdf3c0" + "reference": "bf21cd15aa47fa4ec5d73bbc932005c70261efc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/4ed813d16edb5a1ab0d7f4b1d116c37ee8cdf3c0", - "reference": "4ed813d16edb5a1ab0d7f4b1d116c37ee8cdf3c0", + "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/bf21cd15aa47fa4ec5d73bbc932005c70261efc8", + "reference": "bf21cd15aa47fa4ec5d73bbc932005c70261efc8", "shasum": "" }, "require": { @@ -5878,7 +5890,7 @@ "type": "github" } ], - "time": "2023-08-23T06:24:34+00:00" + "time": "2023-10-09T12:55:26+00:00" }, { "name": "spatie/period", @@ -6158,16 +6170,16 @@ }, { "name": "symfony/error-handler", - "version": "v6.3.2", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "85fd65ed295c4078367c784e8a5a6cee30348b7a" + "reference": "1f69476b64fb47105c06beef757766c376b548c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/85fd65ed295c4078367c784e8a5a6cee30348b7a", - "reference": "85fd65ed295c4078367c784e8a5a6cee30348b7a", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/1f69476b64fb47105c06beef757766c376b548c4", + "reference": "1f69476b64fb47105c06beef757766c376b548c4", "shasum": "" }, "require": { @@ -6212,7 +6224,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.3.2" + "source": "https://github.com/symfony/error-handler/tree/v6.3.5" }, "funding": [ { @@ -6228,7 +6240,7 @@ "type": "tidelift" } ], - "time": "2023-07-16T17:05:46+00:00" + "time": "2023-09-12T06:57:20+00:00" }, { "name": "symfony/event-dispatcher", @@ -6388,16 +6400,16 @@ }, { "name": "symfony/finder", - "version": "v6.3.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e" + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e", + "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4", + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4", "shasum": "" }, "require": { @@ -6432,7 +6444,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.3.3" + "source": "https://github.com/symfony/finder/tree/v6.3.5" }, "funding": [ { @@ -6448,20 +6460,20 @@ "type": "tidelift" } ], - "time": "2023-07-31T08:31:44+00:00" + "time": "2023-09-26T12:56:25+00:00" }, { "name": "symfony/http-client", - "version": "v6.3.2", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00" + "reference": "213e564da4cbf61acc9728d97e666bcdb868c10d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00", - "reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00", + "url": "https://api.github.com/repos/symfony/http-client/zipball/213e564da4cbf61acc9728d97e666bcdb868c10d", + "reference": "213e564da4cbf61acc9728d97e666bcdb868c10d", "shasum": "" }, "require": { @@ -6524,7 +6536,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.3.2" + "source": "https://github.com/symfony/http-client/tree/v6.3.5" }, "funding": [ { @@ -6540,7 +6552,7 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2023-09-29T15:57:12+00:00" }, { "name": "symfony/http-client-contracts", @@ -6622,16 +6634,16 @@ }, { "name": "symfony/http-foundation", - "version": "v6.3.4", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "cac1556fdfdf6719668181974104e6fcfa60e844" + "reference": "b50f5e281d722cb0f4c296f908bacc3e2b721957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/cac1556fdfdf6719668181974104e6fcfa60e844", - "reference": "cac1556fdfdf6719668181974104e6fcfa60e844", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b50f5e281d722cb0f4c296f908bacc3e2b721957", + "reference": "b50f5e281d722cb0f4c296f908bacc3e2b721957", "shasum": "" }, "require": { @@ -6679,7 +6691,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.3.4" + "source": "https://github.com/symfony/http-foundation/tree/v6.3.5" }, "funding": [ { @@ -6695,20 +6707,20 @@ "type": "tidelift" } ], - "time": "2023-08-22T08:20:46+00:00" + "time": "2023-09-04T21:33:54+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.3.4", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "36abb425b4af863ae1fe54d8a8b8b4c76a2bccdb" + "reference": "9f991a964368bee8d883e8d57ced4fe9fff04dfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/36abb425b4af863ae1fe54d8a8b8b4c76a2bccdb", - "reference": "36abb425b4af863ae1fe54d8a8b8b4c76a2bccdb", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f991a964368bee8d883e8d57ced4fe9fff04dfc", + "reference": "9f991a964368bee8d883e8d57ced4fe9fff04dfc", "shasum": "" }, "require": { @@ -6792,7 +6804,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/v6.3.4" + "source": "https://github.com/symfony/http-kernel/tree/v6.3.5" }, "funding": [ { @@ -6808,20 +6820,20 @@ "type": "tidelift" } ], - "time": "2023-08-26T13:54:49+00:00" + "time": "2023-09-30T06:37:04+00:00" }, { "name": "symfony/mailer", - "version": "v6.3.0", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435" + "reference": "d89611a7830d51b5e118bca38e390dea92f9ea06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/7b03d9be1dea29bfec0a6c7b603f5072a4c97435", - "reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435", + "url": "https://api.github.com/repos/symfony/mailer/zipball/d89611a7830d51b5e118bca38e390dea92f9ea06", + "reference": "d89611a7830d51b5e118bca38e390dea92f9ea06", "shasum": "" }, "require": { @@ -6872,7 +6884,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.3.0" + "source": "https://github.com/symfony/mailer/tree/v6.3.5" }, "funding": [ { @@ -6888,20 +6900,20 @@ "type": "tidelift" } ], - "time": "2023-05-29T12:49:39+00:00" + "time": "2023-09-06T09:47:15+00:00" }, { "name": "symfony/mailgun-mailer", - "version": "v6.3.2", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/mailgun-mailer.git", - "reference": "df371e42a4c2a78a28c8de910f96949040e308fd" + "reference": "b467aba49c8240a71f7027c213d9d140ba1abce7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/df371e42a4c2a78a28c8de910f96949040e308fd", - "reference": "df371e42a4c2a78a28c8de910f96949040e308fd", + "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/b467aba49c8240a71f7027c213d9d140ba1abce7", + "reference": "b467aba49c8240a71f7027c213d9d140ba1abce7", "shasum": "" }, "require": { @@ -6941,7 +6953,7 @@ "description": "Symfony Mailgun Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailgun-mailer/tree/v6.3.2" + "source": "https://github.com/symfony/mailgun-mailer/tree/v6.3.5" }, "funding": [ { @@ -6957,20 +6969,20 @@ "type": "tidelift" } ], - "time": "2023-07-20T10:26:17+00:00" + "time": "2023-09-29T17:30:10+00:00" }, { "name": "symfony/mime", - "version": "v6.3.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98" + "reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/9a0cbd52baa5ba5a5b1f0cacc59466f194730f98", - "reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98", + "url": "https://api.github.com/repos/symfony/mime/zipball/d5179eedf1cb2946dbd760475ebf05c251ef6a6e", + "reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e", "shasum": "" }, "require": { @@ -7025,7 +7037,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.3.3" + "source": "https://github.com/symfony/mime/tree/v6.3.5" }, "funding": [ { @@ -7041,7 +7053,7 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2023-09-29T06:59:36+00:00" }, { "name": "symfony/polyfill-ctype", @@ -7933,16 +7945,16 @@ }, { "name": "symfony/routing", - "version": "v6.3.3", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e7243039ab663822ff134fbc46099b5fdfa16f6a" + "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e7243039ab663822ff134fbc46099b5fdfa16f6a", - "reference": "e7243039ab663822ff134fbc46099b5fdfa16f6a", + "url": "https://api.github.com/repos/symfony/routing/zipball/82616e59acd3e3d9c916bba798326cb7796d7d31", + "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31", "shasum": "" }, "require": { @@ -7996,7 +8008,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.3.3" + "source": "https://github.com/symfony/routing/tree/v6.3.5" }, "funding": [ { @@ -8012,7 +8024,7 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2023-09-20T16:05:51+00:00" }, { "name": "symfony/service-contracts", @@ -8098,16 +8110,16 @@ }, { "name": "symfony/string", - "version": "v6.3.2", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "53d1a83225002635bca3482fcbf963001313fb68" + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", - "reference": "53d1a83225002635bca3482fcbf963001313fb68", + "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339", + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339", "shasum": "" }, "require": { @@ -8164,7 +8176,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.3.2" + "source": "https://github.com/symfony/string/tree/v6.3.5" }, "funding": [ { @@ -8180,7 +8192,7 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2023-09-18T10:38:32+00:00" }, { "name": "symfony/translation", @@ -8431,16 +8443,16 @@ }, { "name": "symfony/var-dumper", - "version": "v6.3.4", + "version": "v6.3.5", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "2027be14f8ae8eae999ceadebcda5b4909b81d45" + "reference": "3d9999376be5fea8de47752837a3e1d1c5f69ef5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2027be14f8ae8eae999ceadebcda5b4909b81d45", - "reference": "2027be14f8ae8eae999ceadebcda5b4909b81d45", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3d9999376be5fea8de47752837a3e1d1c5f69ef5", + "reference": "3d9999376be5fea8de47752837a3e1d1c5f69ef5", "shasum": "" }, "require": { @@ -8495,7 +8507,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.3.4" + "source": "https://github.com/symfony/var-dumper/tree/v6.3.5" }, "funding": [ { @@ -8511,7 +8523,7 @@ "type": "tidelift" } ], - "time": "2023-08-24T14:51:05+00:00" + "time": "2023-09-12T10:11:35+00:00" }, { "name": "therobfonz/laravel-mandrill-driver", @@ -9138,16 +9150,16 @@ }, { "name": "composer/pcre", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", "shasum": "" }, "require": { @@ -9189,7 +9201,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.0" + "source": "https://github.com/composer/pcre/tree/3.1.1" }, "funding": [ { @@ -9205,7 +9217,7 @@ "type": "tidelift" } ], - "time": "2022-11-17T09:50:14+00:00" + "time": "2023-10-11T07:11:09+00:00" }, { "name": "ergebnis/phpstan-rules", @@ -10005,16 +10017,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.24.1", + "version": "1.24.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01" + "reference": "bcad8d995980440892759db0c32acae7c8e79442" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", - "reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442", + "reference": "bcad8d995980440892759db0c32acae7c8e79442", "shasum": "" }, "require": { @@ -10046,22 +10058,22 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2" }, - "time": "2023-09-18T12:18:02+00:00" + "time": "2023-09-26T12:28:12+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.35", + "version": "1.10.38", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3" + "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e730e5facb75ffe09dfb229795e8c01a459f26c3", - "reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691", + "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691", "shasum": "" }, "require": { @@ -10110,7 +10122,7 @@ "type": "tidelift" } ], - "time": "2023-09-19T15:27:56+00:00" + "time": "2023-10-06T14:19:14+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -10211,16 +10223,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "10.1.6", + "version": "10.1.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "56f33548fe522c8d82da7ff3824b42829d324364" + "reference": "355324ca4980b8916c18b9db29f3ef484078f26e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/56f33548fe522c8d82da7ff3824b42829d324364", - "reference": "56f33548fe522c8d82da7ff3824b42829d324364", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e", + "reference": "355324ca4980b8916c18b9db29f3ef484078f26e", "shasum": "" }, "require": { @@ -10277,7 +10289,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7" }, "funding": [ { @@ -10285,7 +10297,7 @@ "type": "github" } ], - "time": "2023-09-19T04:59:03+00:00" + "time": "2023-10-04T15:34:17+00:00" }, { "name": "phpunit/php-file-iterator", @@ -10532,16 +10544,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.3.5", + "version": "10.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503" + "reference": "62bd7af13d282deeb95650077d28ba3600ca321c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503", - "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/62bd7af13d282deeb95650077d28ba3600ca321c", + "reference": "62bd7af13d282deeb95650077d28ba3600ca321c", "shasum": "" }, "require": { @@ -10581,7 +10593,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.3-dev" + "dev-main": "10.4-dev" } }, "autoload": { @@ -10613,7 +10625,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.1" }, "funding": [ { @@ -10629,7 +10641,7 @@ "type": "tidelift" } ], - "time": "2023-09-19T05:42:37+00:00" + "time": "2023-10-08T05:01:11+00:00" }, { "name": "sebastian/cli-parser", @@ -10877,16 +10889,16 @@ }, { "name": "sebastian/complexity", - "version": "3.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "c70b73893e10757af9c6a48929fa6a333b56a97a" + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c70b73893e10757af9c6a48929fa6a333b56a97a", - "reference": "c70b73893e10757af9c6a48929fa6a333b56a97a", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957", + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957", "shasum": "" }, "require": { @@ -10899,7 +10911,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" } }, "autoload": { @@ -10923,7 +10935,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0" }, "funding": [ { @@ -10931,7 +10943,7 @@ "type": "github" } ], - "time": "2023-08-31T09:55:53+00:00" + "time": "2023-09-28T11:50:59+00:00" }, { "name": "sebastian/diff", @@ -11066,16 +11078,16 @@ }, { "name": "sebastian/exporter", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344" + "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c3fa8483f9539b190f7cd4bfc4a07631dd1df344", - "reference": "c3fa8483f9539b190f7cd4bfc4a07631dd1df344", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc", + "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc", "shasum": "" }, "require": { @@ -11089,7 +11101,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -11132,7 +11144,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1" }, "funding": [ { @@ -11140,7 +11152,7 @@ "type": "github" } ], - "time": "2023-09-18T07:15:37+00:00" + "time": "2023-09-24T13:22:09+00:00" }, { "name": "sebastian/global-state", diff --git a/config/database.php b/config/database.php index af30a9f4f4..cb181adbd7 100644 --- a/config/database.php +++ b/config/database.php @@ -105,6 +105,7 @@ return [ 'charset' => 'utf8', 'prefix' => '', 'search_path' => envNonEmpty('PGSQL_SCHEMA', 'public'), + 'schema' => envNonEmpty('PGSQL_SCHEMA', 'public'), 'sslmode' => envNonEmpty('PGSQL_SSL_MODE', 'prefer'), 'sslcert' => envNonEmpty('PGSQL_SSL_CERT'), 'sslkey' => envNonEmpty('PGSQL_SSL_KEY'), diff --git a/config/firefly.php b/config/firefly.php index 259d093e55..66fdf0205e 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -112,8 +112,8 @@ return [ 'handle_debts' => true, // see cer.php for exchange rates feature flag. ], - 'version' => '6.0.26', - 'api_version' => '2.0.9', + 'version' => '6.0.27', + 'api_version' => '2.0.10', 'db_version' => 20, // generic settings diff --git a/package-lock.json b/package-lock.json index ed72fca070..e1b180dcab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "dependencies": { "@fortawesome/fontawesome-free": "^6.4.0", "@popperjs/core": "^2.11.8", - "alpinejs": "^3.13.0", + "alpinejs": "^3.13.1", "bootstrap": "^5.3.0", "bootstrap5-autocomplete": "^1.1.22", "chart.js": "^4.4.0", @@ -18,17 +18,17 @@ "store": "^2.0.12" }, "devDependencies": { - "axios": "^1.5.0", - "laravel-vite-plugin": "^0.8.0", - "sass": "^1.66.1", - "vite": "^4.0.0", + "axios": "^1.5.1", + "laravel-vite-plugin": "^0.8.1", + "sass": "^1.69.0", + "vite": "^4.4.11", "vite-plugin-manifest-sri": "^0.1.0" } }, "node_modules/@babel/runtime": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", - "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -425,9 +425,9 @@ "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==" }, "node_modules/alpinejs": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.0.tgz", - "integrity": "sha512-7FYR1Yz3evIjlJD1mZ3SYWSw+jlOmQGeQ1QiSufSQ6J84XMQFkzxm6OobiZ928SfqhGdoIp2SsABNsS4rXMMJw==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.1.tgz", + "integrity": "sha512-/LZ7mumW02V7AV5xTTftJFHS0I3KOXLl7tHm4xpxXAV+HJ/zjTT0n8MU7RZ6UoGPhmO/i+KEhQojaH/0RsH5tg==", "dependencies": { "@vue/reactivity": "~3.1.1" } @@ -452,9 +452,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", - "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", "dev": true, "dependencies": { "follow-redirects": "^1.15.0", @@ -773,9 +773,9 @@ } }, "node_modules/laravel-vite-plugin": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.0.tgz", - "integrity": "sha512-6VjLI+azBpeK6rWBiKcb/En5GnTdYpL0U4zS8gXYvb2/VSq4mlau5H3NWpSktUDBMM1b97LLgICx5zevi8IY0w==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.1.tgz", + "integrity": "sha512-fxzUDjOA37kOsYq8dP+3oPIlw8/kJVXwu0hOXLun82R1LpV02shGeWGYKx2lbpKffL5I0sfPPjfqbYxuqBluAA==", "dev": true, "dependencies": { "picocolors": "^1.0.0", @@ -916,9 +916,9 @@ "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/rollup": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.2.tgz", - "integrity": "sha512-CJouHoZ27v6siztc21eEQGo0kIcE5D1gVPA571ez0mMYb25LGYGKnVNXpEj5MGlepmDWGXNjDB5q7uNiPHC11A==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -932,9 +932,9 @@ } }, "node_modules/sass": { - "version": "1.68.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz", - "integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==", + "version": "1.69.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.3.tgz", + "integrity": "sha512-X99+a2iGdXkdWn1akFPs0ZmelUzyAQfvqYc2P/MPTrJRuIRoTffGzT9W9nFqG00S+c8hXzVmgxhUuHFdrwxkhQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -978,9 +978,9 @@ } }, "node_modules/vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/package.json b/package.json index c170c8dfae..f58614c426 100644 --- a/package.json +++ b/package.json @@ -6,16 +6,16 @@ "build": "vite build" }, "devDependencies": { - "axios": "^1.5.0", - "laravel-vite-plugin": "^0.8.0", - "sass": "^1.66.1", - "vite": "^4.0.0", + "axios": "^1.5.1", + "laravel-vite-plugin": "^0.8.1", + "sass": "^1.69.0", + "vite": "^4.4.11", "vite-plugin-manifest-sri": "^0.1.0" }, "dependencies": { "@fortawesome/fontawesome-free": "^6.4.0", "@popperjs/core": "^2.11.8", - "alpinejs": "^3.13.0", + "alpinejs": "^3.13.1", "bootstrap": "^5.3.0", "bootstrap5-autocomplete": "^1.1.22", "chart.js": "^4.4.0", diff --git a/public/build/assets/create-baf83427.js b/public/build/assets/create-baf83427.js new file mode 100644 index 0000000000..b1cd642430 --- /dev/null +++ b/public/build/assets/create-baf83427.js @@ -0,0 +1 @@ +var N=Object.defineProperty;var q=(n,e,t)=>e in n?N(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var C=(n,e,t)=>(q(n,typeof e!="symbol"?e+"":e,t),t);import{x as H,w as P,J as j,z as R,I as z,A as $,y as V}from"./load-translations-9a154502.js";function A(){return{id:"",name:""}}function B(){let e=H(new Date,"yyyy-MM-dd HH:mm");return{description:"",amount:"",source_account:A(),destination_account:A(),date:e}}function W(n,e){let t=[];for(let s in n)if(n.hasOwnProperty(s)){const i=n[s];let o={};o.description=i.description,o.source_name=i.source_account.name,o.destination_name=i.destination_account.name,o.amount=i.amount,o.date=i.date,i.source_account.id.toString()!==""&&(o.source_id=i.source_account.id),i.destination_account.id.toString()!==""&&(o.destination_id=i.destination_account.id),o.type=e,t.push(o)}return t}const T={showAllSuggestions:!1,suggestionsThreshold:1,maximumItems:0,autoselectFirst:!0,ignoreEnter:!1,updateOnSelect:!1,highlightTyped:!1,highlightClass:"",fullWidth:!1,fixed:!1,fuzzy:!1,startsWith:!1,preventBrowserAutocomplete:!1,itemClass:"",activeClasses:["bg-primary","text-white"],labelField:"label",valueField:"value",searchFields:["label"],queryParam:"query",items:[],source:null,hiddenInput:!1,hiddenValue:"",clearControl:"",datalist:"",server:"",serverMethod:"GET",serverParams:{},serverDataKey:"data",fetchOptions:{},liveServer:!1,noCache:!0,debounceTime:300,notFoundMessage:"",onRenderItem:(n,e,t)=>e,onSelectItem:(n,e)=>{},onServerResponse:(n,e)=>n.json(),onChange:(n,e)=>{}},x="is-loading",L="is-active",f="show",_="next",v="prev",g=new WeakMap;let k=0,b=0;function U(n,e=300){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>{n.apply(this,s)},e)}}function G(n){return n.normalize("NFD").replace(/[\u0300-\u036f]/g,"")}function y(n){return n?G(n.toString()).toLowerCase():""}function K(n,e){if(n.indexOf(e)>=0)return!0;let t=0;for(let s=0;se+"‍").join("")}class I{constructor(e,t={}){C(this,"handleEvent",e=>{["scroll","resize"].includes(e.type)?(this._timer&&window.cancelAnimationFrame(this._timer),this._timer=window.requestAnimationFrame(()=>{this[`on${e.type}`](e)})):this[`on${e.type}`](e)});if(!(e instanceof HTMLElement)){console.error("Invalid element",e);return}g.set(e,this),k++,b++,this._searchInput=e,this._configure(t),this._preventInput=!1,this._keyboardNavigation=!1,this._searchFunc=U(()=>{this._loadFromServer(!0)},this._config.debounceTime),this._configureSearchInput(),this._configureDropElement(),this._config.fixed&&(document.addEventListener("scroll",this,!0),window.addEventListener("resize",this));const s=this._getClearControl();s&&s.addEventListener("click",this),["focus","change","blur","input","keydown"].forEach(i=>{this._searchInput.addEventListener(i,this)}),["mousemove","mouseleave"].forEach(i=>{this._dropElement.addEventListener(i,this)}),this._fetchData()}static init(e="input.autocomplete",t={}){document.querySelectorAll(e).forEach(i=>{this.getOrCreateInstance(i,t)})}static getInstance(e){return g.has(e)?g.get(e):null}static getOrCreateInstance(e,t={}){return this.getInstance(e)||new this(e,t)}dispose(){b--,["focus","change","blur","input","keydown"].forEach(t=>{this._searchInput.removeEventListener(t,this)}),["mousemove","mouseleave"].forEach(t=>{this._dropElement.removeEventListener(t,this)});const e=this._getClearControl();e&&e.removeEventListener("click",this),this._config.fixed&&b<=0&&(document.removeEventListener("scroll",this,!0),window.removeEventListener("resize",this)),this._dropElement.parentElement.removeChild(this._dropElement),g.delete(this._searchInput)}_getClearControl(){if(this._config.clearControl)return document.querySelector(this._config.clearControl)}_configure(e={}){this._config=Object.assign({},T);const t={...e,...this._searchInput.dataset},s=i=>["true","false","1","0",!0,!1].includes(i)&&!!JSON.parse(i);for(const[i,o]of Object.entries(T)){if(t[i]===void 0)continue;const a=t[i];switch(typeof o){case"number":this._config[i]=parseInt(a);break;case"boolean":this._config[i]=s(a);break;case"string":this._config[i]=a.toString();break;case"object":if(Array.isArray(o))if(typeof a=="string"){const r=a.includes("|")?"|":",";this._config[i]=a.split(r)}else this._config[i]=a;else this._config[i]=typeof a=="string"?JSON.parse(a):a;break;case"function":this._config[i]=typeof a=="string"?window[a]:a;break;default:this._config[i]=a;break}}}_configureSearchInput(){if(this._searchInput.autocomplete="off",this._searchInput.spellcheck=!1,w(this._searchInput,{"aria-autocomplete":"list","aria-haspopup":"menu","aria-expanded":"false",role:"combobox"}),this._searchInput.id&&this._config.preventBrowserAutocomplete){const e=document.querySelector(`[for="${this._searchInput.id}"]`);e&&X(e)}this._hiddenInput=null,this._config.hiddenInput&&(this._hiddenInput=document.createElement("input"),this._hiddenInput.type="hidden",this._hiddenInput.value=this._config.hiddenValue,this._hiddenInput.name=this._searchInput.name,this._searchInput.name="_"+this._searchInput.name,D(this._searchInput,this._hiddenInput))}_configureDropElement(){this._dropElement=document.createElement("ul"),this._dropElement.id="ac-menu-"+k,this._dropElement.classList.add("dropdown-menu","autocomplete-menu","p-0"),this._dropElement.style.maxHeight="280px",this._config.fullWidth||(this._dropElement.style.maxWidth="360px"),this._config.fixed&&(this._dropElement.style.position="fixed"),this._dropElement.style.overflowY="auto",this._dropElement.style.overscrollBehavior="contain",this._dropElement.style.textAlign="unset",D(this._searchInput,this._dropElement),this._searchInput.setAttribute("aria-controls",this._dropElement.id)}onclick(e){e.target.matches(this._config.clearControl)&&this.clear()}oninput(e){this._preventInput||(this._hiddenInput&&(this._hiddenInput.value=null),this.showOrSearch())}onchange(e){const t=this._searchInput.value,s=Object.values(this._items).find(i=>i.label===t);this._config.onChange(s,this)}onblur(e){this.hideSuggestions()}onfocus(e){this.showOrSearch()}onkeydown(e){switch(e.keyCode||e.key){case 13:case"Enter":if(this.isDropdownVisible()){const s=this.getSelection();s&&s.click(),(s||!this._config.ignoreEnter)&&e.preventDefault()}break;case 38:case"ArrowUp":e.preventDefault(),this._keyboardNavigation=!0,this._moveSelection(v);break;case 40:case"ArrowDown":e.preventDefault(),this._keyboardNavigation=!0,this.isDropdownVisible()?this._moveSelection(_):this.showOrSearch(!1);break;case 27:case"Escape":this.isDropdownVisible()&&(this._searchInput.focus(),this.hideSuggestions());break}}onmousemove(e){this._keyboardNavigation=!1}onmouseleave(e){this.removeSelection()}onscroll(e){this._positionMenu()}onresize(e){this._positionMenu()}getConfig(e=null){return e!==null?this._config[e]:this._config}setConfig(e,t){this._config[e]=t}setData(e){this._items={},this._addItems(e)}enable(){this._searchInput.setAttribute("disabled","")}disable(){this._searchInput.removeAttribute("disabled")}isDisabled(){return this._searchInput.hasAttribute("disabled")||this._searchInput.disabled||this._searchInput.hasAttribute("readonly")}isDropdownVisible(){return this._dropElement.classList.contains(f)}clear(){this._searchInput.value="",this._hiddenInput&&(this._hiddenInput.value="")}getSelection(){return this._dropElement.querySelector("a."+L)}removeSelection(){const e=this.getSelection();e&&e.classList.remove(...this._activeClasses())}_activeClasses(){return[...this._config.activeClasses,L]}_isItemEnabled(e){if(e.style.display==="none")return!1;const t=e.firstElementChild;return t.tagName==="A"&&!t.classList.contains("disabled")}_moveSelection(e=_,t=null){const s=this.getSelection();if(s){const i=e===_?"nextSibling":"previousSibling";t=s.parentNode;do t=t[i];while(t&&!this._isItemEnabled(t));t?(s.classList.remove(...this._activeClasses()),e===v?t.parentNode.scrollTop=t.offsetTop-t.parentNode.offsetTop:t.offsetTop>t.parentNode.offsetHeight-t.offsetHeight&&(t.parentNode.scrollTop+=t.offsetHeight)):s&&(t=s.parentElement)}else{if(e===v)return t;if(!t)for(t=this._dropElement.firstChild;t&&!this._isItemEnabled(t);)t=t.nextSibling}if(t){const i=t.querySelector("a");i.classList.add(...this._activeClasses()),this._searchInput.setAttribute("aria-activedescendant",i.id),this._config.updateOnSelect&&(this._searchInput.value=i.dataset.label)}else this._searchInput.setAttribute("aria-activedescendant","");return t}_shouldShow(){return this.isDisabled()?!1:this._searchInput.value.length>=this._config.suggestionsThreshold}showOrSearch(e=!0){if(e&&!this._shouldShow()){this.hideSuggestions();return}this._config.liveServer?this._searchFunc():this._config.source?this._config.source(this._searchInput.value,t=>{this.setData(t),this._showSuggestions()}):this._showSuggestions()}_createGroup(e){const t=this._createLi(),s=document.createElement("span");return t.append(s),s.classList.add("dropdown-header","text-truncate"),s.innerHTML=e,t}_createItem(e,t){let s=t.label;if(this._config.highlightTyped){const a=y(s).indexOf(e);s=s.substring(0,a)+`${s.substring(a,a+e.length)}`+s.substring(a+e.length,s.length)}s=this._config.onRenderItem(t,s,this);const i=this._createLi(),o=document.createElement("a");if(i.append(o),o.id=this._dropElement.id+"-"+this._dropElement.children.length,o.classList.add("dropdown-item","text-truncate"),this._config.itemClass&&o.classList.add(...this._config.itemClass.split(" ")),o.setAttribute("data-value",t.value),o.setAttribute("data-label",t.label),o.setAttribute("tabindex","-1"),o.setAttribute("role","menuitem"),o.setAttribute("href","#"),o.innerHTML=s,t.data)for(const[a,r]of Object.entries(t.data))o.dataset[a]=r;return o.addEventListener("mouseenter",a=>{this._keyboardNavigation||(this.removeSelection(),i.querySelector("a").classList.add(...this._activeClasses()))}),o.addEventListener("mousedown",a=>{a.preventDefault()}),o.addEventListener("click",a=>{a.preventDefault(),this._preventInput=!0,this._searchInput.value=J(t.label),this._hiddenInput&&(this._hiddenInput.value=t.value),this._config.onSelectItem(t,this),this.hideSuggestions(),this._preventInput=!1}),i}_showSuggestions(){if(document.activeElement!=this._searchInput)return;const e=y(this._searchInput.value);this._dropElement.innerHTML="";const t=Object.keys(this._items);let s=0,i=null;const o=[];for(let a=0;a0&&this._config.searchFields.forEach(d=>{const p=y(c[d]);let m=!1;if(this._config.fuzzy)m=K(p,e);else{const E=p.indexOf(e);m=this._config.startsWith?E===0:E>=0}m&&(l=!0)});const F=l||e.length===0;if(u||l){if(s++,c.group&&!o.includes(c.group)){const p=this._createGroup(c.group);this._dropElement.appendChild(p),o.push(c.group)}const d=this._createItem(e,c);if(!i&&F&&(i=d),this._dropElement.appendChild(d),this._config.maximumItems>0&&s>=this._config.maximumItems)break}}if(i&&this._config.autoselectFirst&&(this.removeSelection(),this._moveSelection(_,i)),s===0)if(this._config.notFoundMessage){const a=this._createLi();a.innerHTML=`${this._config.notFoundMessage}`,this._dropElement.appendChild(a),this._showDropdown()}else this.hideSuggestions();else this._showDropdown()}_createLi(){const e=document.createElement("li");return e.setAttribute("role","presentation"),e}_showDropdown(){this._dropElement.classList.add(f),this._dropElement.setAttribute("role","menu"),w(this._searchInput,{"aria-expanded":"true"}),this._positionMenu()}toggleSuggestions(e=!0){this._dropElement.classList.contains(f)?this.hideSuggestions():this.showOrSearch(e)}hideSuggestions(){this._dropElement.classList.remove(f),w(this._searchInput,{"aria-expanded":"false"}),this.removeSelection()}getInput(){return this._searchInput}getDropMenu(){return this._dropElement}_positionMenu(){const e=window.getComputedStyle(this._searchInput),t=this._searchInput.getBoundingClientRect(),s=e.direction==="rtl",i=this._config.fullWidth,o=this._config.fixed;let a=null,r=null;o&&(a=t.x,r=t.y+t.height,s&&!i&&(a-=this._dropElement.offsetWidth-t.width)),this._dropElement.style.transform="unset",i&&(this._dropElement.style.width=this._searchInput.offsetWidth+"px"),a!==null&&(this._dropElement.style.left=a+"px"),r!==null&&(this._dropElement.style.top=r+"px");const c=this._dropElement.getBoundingClientRect(),u=window.innerHeight;if(c.y+c.height>u){const l=i?t.height+4:t.height;this._dropElement.style.transform="translateY(calc(-100.1% - "+l+"px))"}}_fetchData(){this._items={},this._addItems(this._config.items);const e=this._config.datalist;if(e){const t=document.querySelector(`#${e}`);if(t){const s=Array.from(t.children).map(i=>{const o=i.getAttribute("value")??i.innerHTML.toLowerCase(),a=i.innerHTML;return{value:o,label:a}});this._addItems(s)}else console.error(`Datalist not found ${e}`)}this._setHiddenVal(),this._config.server&&!this._config.liveServer&&this._loadFromServer()}_setHiddenVal(){if(this._config.hiddenInput&&!this._config.hiddenValue)for(const[e,t]of Object.entries(this._items))t.label==this._searchInput.value&&(this._hiddenInput.value=e)}_addItems(e){const t=Object.keys(e);for(let s=0;sc.group=o.group),this._addItems(o.items);continue}const a=typeof o=="string"?o:o.label,r=typeof o!="object"?{}:o;r.label=o[this._config.labelField]??a,r.value=o[this._config.valueField]??i,r.label&&(this._items[r.value]=r)}}_loadFromServer(e=!1){this._abortController&&this._abortController.abort(),this._abortController=new AbortController;let t=this._searchInput.dataset.serverParams||{};typeof t=="string"&&(t=JSON.parse(t));const s=Object.assign({},this._config.serverParams,t);if(s[this._config.queryParam]=this._searchInput.value,this._config.noCache&&(s.t=Date.now()),s.related){const r=document.getElementById(s.related);if(r){s.related=r.value;const c=r.getAttribute("name");c&&(s[c]=r.value)}}const i=new URLSearchParams(s);let o=this._config.server,a=Object.assign(this._config.fetchOptions,{method:this._config.serverMethod||"GET",signal:this._abortController.signal});a.method==="POST"?a.body=i:o+="?"+i.toString(),this._searchInput.classList.add(x),fetch(o,a).then(r=>this._config.onServerResponse(r,this)).then(r=>{const c=r[this._config.serverDataKey]||r;this.setData(c),this._setHiddenVal(),this._abortController=null,e&&this._showSuggestions()}).catch(r=>{r.name==="AbortError"||this._abortController.signal.aborted||console.error(r)}).finally(r=>{this._searchInput.classList.remove(x)})}}class Y{post(e){let t="/api/v2/transactions";return P.post(t,e)}}let h;const S={description:"/api/v2/autocomplete/transaction-descriptions",account:"/api/v2/autocomplete/accounts"};let Q=function(){return{count:0,totalAmount:0,transactionType:"unknown",showSuccessMessage:!1,showErrorMessage:!1,entries:[],filters:{source:[],destination:[]},detectTransactionType(){const n=this.entries[0].source_account.type??"unknown",e=this.entries[0].destination_account.type??"unknown";if(n==="unknown"&&e==="unknown"){this.transactionType="unknown",console.warn("Cannot infer transaction type from two unknown accounts.");return}if(n===e&&["Asset account","Loan","Debt","Mortgage"].includes(n)){this.transactionType="transfer",console.log('Transaction type is detected to be "'+this.transactionType+'".');return}if(n==="Asset account"&&["Expense account","Debt","Loan","Mortgage"].includes(e)){this.transactionType="withdrawal",console.log('Transaction type is detected to be "'+this.transactionType+'".');return}if(n==="Asset account"&&e==="unknown"){this.transactionType="withdrawal",console.log('Transaction type is detected to be "'+this.transactionType+'".');return}if(["Debt","Loan","Mortgage"].includes(n)&&e==="Expense account"){this.transactionType="withdrawal",console.log('Transaction type is detected to be "'+this.transactionType+'".');return}if(n==="Revenue account"&&["Asset account","Debt","Loan","Mortgage"].includes(e)){this.transactionType="deposit",console.log('Transaction type is detected to be "'+this.transactionType+'".');return}if(["Debt","Loan","Mortgage"].includes(n)&&e==="Asset account"){this.transactionType="deposit",console.log('Transaction type is detected to be "'+this.transactionType+'".');return}console.warn('Unknown account combination between "'+n+'" and "'+e+'".')},selectSourceAccount(n,e){const t=parseInt(e._searchInput.attributes["data-index"].value);document.querySelector("#form")._x_dataStack[0].$data.entries[t].source_account={id:n.id,name:n.name,type:n.type},console.log("Changed source account into a known "+n.type.toLowerCase())},changedAmount(n){const e=parseInt(n.target.dataset.index);this.entries[e].amount=parseFloat(n.target.value),this.totalAmount=0;for(let t in this.entries)this.entries.hasOwnProperty(t)&&(this.totalAmount=this.totalAmount+parseFloat(this.entries[t].amount));console.log("Changed amount to "+this.totalAmount)},selectDestAccount(n,e){const t=parseInt(e._searchInput.attributes["data-index"].value);document.querySelector("#form")._x_dataStack[0].$data.entries[t].destination_account={id:n.id,name:n.name,type:n.type},console.log("Changed destination account into a known "+n.type.toLowerCase())},changeSourceAccount(n,e){if(typeof n>"u"){const t=parseInt(e._searchInput.attributes["data-index"].value);if(document.querySelector("#form")._x_dataStack[0].$data.entries[t].source_account.name===e._searchInput.value){console.warn('Ignore hallucinated source account name change to "'+e._searchInput.value+'"');return}document.querySelector("#form")._x_dataStack[0].$data.entries[t].source_account={name:e._searchInput.value},console.log('Changed source account into a unknown account called "'+e._searchInput.value+'"')}},changeDestAccount(n,e){if(typeof n>"u"){const t=parseInt(e._searchInput.attributes["data-index"].value);if(document.querySelector("#form")._x_dataStack[0].$data.entries[t].destination_account.name===e._searchInput.value){console.warn('Ignore hallucinated destination account name change to "'+e._searchInput.value+'"');return}document.querySelector("#form")._x_dataStack[0].$data.entries[t].destination_account={name:e._searchInput.value},console.log('Changed destination account into a unknown account called "'+e._searchInput.value+'"')}},showError:!1,showSuccess:!1,addedSplit(){console.log("addedSplit"),I.init("input.ac-source",{server:S.account,serverParams:{types:this.filters.source},fetchOptions:{headers:{"X-CSRF-TOKEN":document.head.querySelector('meta[name="csrf-token"]').content}},hiddenInput:!0,preventBrowserAutocomplete:!0,highlightTyped:!0,liveServer:!0,onChange:this.changeSourceAccount,onSelectItem:this.selectSourceAccount,onRenderItem:function(n,e,t){return n.name_with_balance+'
'+h.t("firefly.account_type_"+n.type)+""}}),I.init("input.ac-dest",{server:S.account,serverParams:{types:this.filters.destination},fetchOptions:{headers:{"X-CSRF-TOKEN":document.head.querySelector('meta[name="csrf-token"]').content}},hiddenInput:!0,preventBrowserAutocomplete:!0,liveServer:!0,highlightTyped:!0,onSelectItem:this.selectDestAccount,onChange:this.changeDestAccount,onRenderItem:function(n,e,t){return n.name_with_balance+'
'+h.t("firefly.account_type_"+n.type)+""}}),this.filters.destination=[],I.init("input.ac-description",{server:S.description,fetchOptions:{headers:{"X-CSRF-TOKEN":document.head.querySelector('meta[name="csrf-token"]').content}},valueField:"id",labelField:"description",highlightTyped:!0,onSelectItem:console.log})},init(){Promise.all([R("language","en_US")]).then(n=>{h=new z;const e=n[0].replace("-","_");h.locale=e,$(h,e).then(()=>{this.addSplit()})}),this.filters.source=["Asset account","Loan","Debt","Mortgage","Revenue account"],this.filters.destination=["Expense account","Loan","Debt","Mortgage","Asset account"]},submitTransaction(){this.detectTransactionType();let n=W(this.entries,this.transactionType),e={group_title:null,fire_webhooks:!1,apply_rules:!1,transactions:n};n.length>1&&(e.group_title=n[0].description);let t=new Y;console.log(e),t.post(e).then(s=>{this.showSuccessMessage=!0,console.log(s),window.location="transactions/show/"+s.data.data.id+"?transaction_group_id="+s.data.data.id+"&message=created"}).catch(s=>{this.showErrorMessage=!0,console.error(s)})},addSplit(){this.entries.push(B())},removeSplit(n){this.entries.splice(n,1),document.querySelector("#split-0-tab").click()},formattedTotalAmount(){return V(this.totalAmount,"EUR")}}},O={transactions:Q,dates:j};function M(){Object.keys(O).forEach(n=>{console.log(`Loading page component "${n}"`);let e=O[n]();Alpine.data(n,()=>e)}),Alpine.start()}document.addEventListener("firefly-iii-bootstrapped",()=>{console.log("Loaded through event listener."),M()});window.bootstrapped&&(console.log("Loaded through window variable."),M()); diff --git a/public/build/assets/dashboard-b749bce8.js b/public/build/assets/dashboard-b749bce8.js deleted file mode 100644 index 767c4e88dd..0000000000 --- a/public/build/assets/dashboard-b749bce8.js +++ /dev/null @@ -1,46 +0,0 @@ -var ve=Object.defineProperty;var be=(t,e,a)=>e in t?ve(t,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[e]=a;var R=(t,e,a)=>(be(t,typeof e!="symbol"?e+"":e,a),a);function bind$4(t,e){return function(){return t.apply(e,arguments)}}const{toString:toString$7}=Object.prototype,{getPrototypeOf}=Object,kindOf=(t=>e=>{const a=toString$7.call(e);return t[a]||(t[a]=a.slice(8,-1).toLowerCase())})(Object.create(null)),kindOfTest=t=>(t=t.toLowerCase(),e=>kindOf(e)===t),typeOfTest=t=>e=>typeof e===t,{isArray:isArray$d}=Array,isUndefined=typeOfTest("undefined");function isBuffer$3(t){return t!==null&&!isUndefined(t)&&t.constructor!==null&&!isUndefined(t.constructor)&&isFunction$6(t.constructor.isBuffer)&&t.constructor.isBuffer(t)}const isArrayBuffer=kindOfTest("ArrayBuffer");function isArrayBufferView(t){let e;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?e=ArrayBuffer.isView(t):e=t&&t.buffer&&isArrayBuffer(t.buffer),e}const isString$1=typeOfTest("string"),isFunction$6=typeOfTest("function"),isNumber$1=typeOfTest("number"),isObject$c=t=>t!==null&&typeof t=="object",isBoolean=t=>t===!0||t===!1,isPlainObject=t=>{if(kindOf(t)!=="object")return!1;const e=getPrototypeOf(t);return(e===null||e===Object.prototype||Object.getPrototypeOf(e)===null)&&!(Symbol.toStringTag in t)&&!(Symbol.iterator in t)},isDate$1=kindOfTest("Date"),isFile=kindOfTest("File"),isBlob=kindOfTest("Blob"),isFileList=kindOfTest("FileList"),isStream=t=>isObject$c(t)&&isFunction$6(t.pipe),isFormData=t=>{let e;return t&&(typeof FormData=="function"&&t instanceof FormData||isFunction$6(t.append)&&((e=kindOf(t))==="formdata"||e==="object"&&isFunction$6(t.toString)&&t.toString()==="[object FormData]"))},isURLSearchParams=kindOfTest("URLSearchParams"),trim$2=t=>t.trim?t.trim():t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");function forEach(t,e,{allOwnKeys:a=!1}={}){if(t===null||typeof t>"u")return;let n,r;if(typeof t!="object"&&(t=[t]),isArray$d(t))for(n=0,r=t.length;n0;)if(r=a[n],e===r.toLowerCase())return r;return null}const _global=(()=>typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global)(),isContextDefined=t=>!isUndefined(t)&&t!==_global;function merge$1(){const{caseless:t}=isContextDefined(this)&&this||{},e={},a=(n,r)=>{const i=t&&findKey$1(e,r)||r;isPlainObject(e[i])&&isPlainObject(n)?e[i]=merge$1(e[i],n):isPlainObject(n)?e[i]=merge$1({},n):isArray$d(n)?e[i]=n.slice():e[i]=n};for(let n=0,r=arguments.length;n(forEach(e,(r,i)=>{a&&isFunction$6(r)?t[i]=bind$4(r,a):t[i]=r},{allOwnKeys:n}),t),stripBOM=t=>(t.charCodeAt(0)===65279&&(t=t.slice(1)),t),inherits=(t,e,a,n)=>{t.prototype=Object.create(e.prototype,n),t.prototype.constructor=t,Object.defineProperty(t,"super",{value:e.prototype}),a&&Object.assign(t.prototype,a)},toFlatObject=(t,e,a,n)=>{let r,i,o;const s={};if(e=e||{},t==null)return e;do{for(r=Object.getOwnPropertyNames(t),i=r.length;i-- >0;)o=r[i],(!n||n(o,t,e))&&!s[o]&&(e[o]=t[o],s[o]=!0);t=a!==!1&&getPrototypeOf(t)}while(t&&(!a||a(t,e))&&t!==Object.prototype);return e},endsWith=(t,e,a)=>{t=String(t),(a===void 0||a>t.length)&&(a=t.length),a-=e.length;const n=t.indexOf(e,a);return n!==-1&&n===a},toArray=t=>{if(!t)return null;if(isArray$d(t))return t;let e=t.length;if(!isNumber$1(e))return null;const a=new Array(e);for(;e-- >0;)a[e]=t[e];return a},isTypedArray$3=(t=>e=>t&&e instanceof t)(typeof Uint8Array<"u"&&getPrototypeOf(Uint8Array)),forEachEntry=(t,e)=>{const n=(t&&t[Symbol.iterator]).call(t);let r;for(;(r=n.next())&&!r.done;){const i=r.value;e.call(t,i[0],i[1])}},matchAll=(t,e)=>{let a;const n=[];for(;(a=t.exec(e))!==null;)n.push(a);return n},isHTMLForm=kindOfTest("HTMLFormElement"),toCamelCase=t=>t.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(a,n,r){return n.toUpperCase()+r}),hasOwnProperty$c=(({hasOwnProperty:t})=>(e,a)=>t.call(e,a))(Object.prototype),isRegExp=kindOfTest("RegExp"),reduceDescriptors=(t,e)=>{const a=Object.getOwnPropertyDescriptors(t),n={};forEach(a,(r,i)=>{let o;(o=e(r,i,t))!==!1&&(n[i]=o||r)}),Object.defineProperties(t,n)},freezeMethods=t=>{reduceDescriptors(t,(e,a)=>{if(isFunction$6(t)&&["arguments","caller","callee"].indexOf(a)!==-1)return!1;const n=t[a];if(isFunction$6(n)){if(e.enumerable=!1,"writable"in e){e.writable=!1;return}e.set||(e.set=()=>{throw Error("Can not rewrite read-only method '"+a+"'")})}})},toObjectSet=(t,e)=>{const a={},n=r=>{r.forEach(i=>{a[i]=!0})};return isArray$d(t)?n(t):n(String(t).split(e)),a},noop$4=()=>{},toFiniteNumber=(t,e)=>(t=+t,Number.isFinite(t)?t:e),ALPHA="abcdefghijklmnopqrstuvwxyz",DIGIT="0123456789",ALPHABET={DIGIT,ALPHA,ALPHA_DIGIT:ALPHA+ALPHA.toUpperCase()+DIGIT},generateString=(t=16,e=ALPHABET.ALPHA_DIGIT)=>{let a="";const{length:n}=e;for(;t--;)a+=e[Math.random()*n|0];return a};function isSpecCompliantForm(t){return!!(t&&isFunction$6(t.append)&&t[Symbol.toStringTag]==="FormData"&&t[Symbol.iterator])}const toJSONObject=t=>{const e=new Array(10),a=(n,r)=>{if(isObject$c(n)){if(e.indexOf(n)>=0)return;if(!("toJSON"in n)){e[r]=n;const i=isArray$d(n)?[]:{};return forEach(n,(o,s)=>{const l=a(o,r+1);!isUndefined(l)&&(i[s]=l)}),e[r]=void 0,i}}return n};return a(t,0)},isAsyncFn=kindOfTest("AsyncFunction"),isThenable=t=>t&&(isObject$c(t)||isFunction$6(t))&&isFunction$6(t.then)&&isFunction$6(t.catch),utils={isArray:isArray$d,isArrayBuffer,isBuffer:isBuffer$3,isFormData,isArrayBufferView,isString:isString$1,isNumber:isNumber$1,isBoolean,isObject:isObject$c,isPlainObject,isUndefined,isDate:isDate$1,isFile,isBlob,isRegExp,isFunction:isFunction$6,isStream,isURLSearchParams,isTypedArray:isTypedArray$3,isFileList,forEach,merge:merge$1,extend,trim:trim$2,stripBOM,inherits,toFlatObject,kindOf,kindOfTest,endsWith,toArray,forEachEntry,matchAll,isHTMLForm,hasOwnProperty:hasOwnProperty$c,hasOwnProp:hasOwnProperty$c,reduceDescriptors,freezeMethods,toObjectSet,toCamelCase,noop:noop$4,toFiniteNumber,findKey:findKey$1,global:_global,isContextDefined,ALPHABET,generateString,isSpecCompliantForm,toJSONObject,isAsyncFn,isThenable};function AxiosError(t,e,a,n,r){Error.call(this),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack,this.message=t,this.name="AxiosError",e&&(this.code=e),a&&(this.config=a),n&&(this.request=n),r&&(this.response=r)}utils.inherits(AxiosError,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:utils.toJSONObject(this.config),code:this.code,status:this.response&&this.response.status?this.response.status:null}}});const prototype$1=AxiosError.prototype,descriptors$1={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED","ERR_NOT_SUPPORT","ERR_INVALID_URL"].forEach(t=>{descriptors$1[t]={value:t}});Object.defineProperties(AxiosError,descriptors$1);Object.defineProperty(prototype$1,"isAxiosError",{value:!0});AxiosError.from=(t,e,a,n,r,i)=>{const o=Object.create(prototype$1);return utils.toFlatObject(t,o,function(l){return l!==Error.prototype},s=>s!=="isAxiosError"),AxiosError.call(o,t.message,e,a,n,r),o.cause=t,o.name=t.name,i&&Object.assign(o,i),o};const httpAdapter=null;function isVisitable(t){return utils.isPlainObject(t)||utils.isArray(t)}function removeBrackets(t){return utils.endsWith(t,"[]")?t.slice(0,-2):t}function renderKey(t,e,a){return t?t.concat(e).map(function(r,i){return r=removeBrackets(r),!a&&i?"["+r+"]":r}).join(a?".":""):e}function isFlatArray(t){return utils.isArray(t)&&!t.some(isVisitable)}const predicates=utils.toFlatObject(utils,{},null,function(e){return/^is[A-Z]/.test(e)});function toFormData(t,e,a){if(!utils.isObject(t))throw new TypeError("target must be an object");e=e||new FormData,a=utils.toFlatObject(a,{metaTokens:!0,dots:!1,indexes:!1},!1,function(v,y){return!utils.isUndefined(y[v])});const n=a.metaTokens,r=a.visitor||c,i=a.dots,o=a.indexes,l=(a.Blob||typeof Blob<"u"&&Blob)&&utils.isSpecCompliantForm(e);if(!utils.isFunction(r))throw new TypeError("visitor must be a function");function u(p){if(p===null)return"";if(utils.isDate(p))return p.toISOString();if(!l&&utils.isBlob(p))throw new AxiosError("Blob is not supported. Use a Buffer instead.");return utils.isArrayBuffer(p)||utils.isTypedArray(p)?l&&typeof Blob=="function"?new Blob([p]):Buffer.from(p):p}function c(p,v,y){let w=p;if(p&&!y&&typeof p=="object"){if(utils.endsWith(v,"{}"))v=n?v:v.slice(0,-2),p=JSON.stringify(p);else if(utils.isArray(p)&&isFlatArray(p)||(utils.isFileList(p)||utils.endsWith(v,"[]"))&&(w=utils.toArray(p)))return v=removeBrackets(v),w.forEach(function(O,C){!(utils.isUndefined(O)||O===null)&&e.append(o===!0?renderKey([v],C,i):o===null?v:v+"[]",u(O))}),!1}return isVisitable(p)?!0:(e.append(renderKey(y,v,i),u(p)),!1)}const d=[],h=Object.assign(predicates,{defaultVisitor:c,convertValue:u,isVisitable});function m(p,v){if(!utils.isUndefined(p)){if(d.indexOf(p)!==-1)throw Error("Circular reference detected in "+v.join("."));d.push(p),utils.forEach(p,function(w,_){(!(utils.isUndefined(w)||w===null)&&r.call(e,w,utils.isString(_)?_.trim():_,v,h))===!0&&m(w,v?v.concat(_):[_])}),d.pop()}}if(!utils.isObject(t))throw new TypeError("data must be an object");return m(t),e}function encode$1(t){const e={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(t).replace(/[!'()~]|%20|%00/g,function(n){return e[n]})}function AxiosURLSearchParams(t,e){this._pairs=[],t&&toFormData(t,this,e)}const prototype=AxiosURLSearchParams.prototype;prototype.append=function(e,a){this._pairs.push([e,a])};prototype.toString=function(e){const a=e?function(n){return e.call(this,n,encode$1)}:encode$1;return this._pairs.map(function(r){return a(r[0])+"="+a(r[1])},"").join("&")};function encode(t){return encodeURIComponent(t).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}function buildURL(t,e,a){if(!e)return t;const n=a&&a.encode||encode,r=a&&a.serialize;let i;if(r?i=r(e,a):i=utils.isURLSearchParams(e)?e.toString():new AxiosURLSearchParams(e,a).toString(n),i){const o=t.indexOf("#");o!==-1&&(t=t.slice(0,o)),t+=(t.indexOf("?")===-1?"?":"&")+i}return t}class InterceptorManager{constructor(){this.handlers=[]}use(e,a,n){return this.handlers.push({fulfilled:e,rejected:a,synchronous:n?n.synchronous:!1,runWhen:n?n.runWhen:null}),this.handlers.length-1}eject(e){this.handlers[e]&&(this.handlers[e]=null)}clear(){this.handlers&&(this.handlers=[])}forEach(e){utils.forEach(this.handlers,function(n){n!==null&&e(n)})}}const InterceptorManager$1=InterceptorManager,transitionalDefaults={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1},URLSearchParams$1=typeof URLSearchParams<"u"?URLSearchParams:AxiosURLSearchParams,FormData$1=typeof FormData<"u"?FormData:null,Blob$1=typeof Blob<"u"?Blob:null,isStandardBrowserEnv=(()=>{let t;return typeof navigator<"u"&&((t=navigator.product)==="ReactNative"||t==="NativeScript"||t==="NS")?!1:typeof window<"u"&&typeof document<"u"})(),isStandardBrowserWebWorkerEnv=(()=>typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&typeof self.importScripts=="function")(),platform={isBrowser:!0,classes:{URLSearchParams:URLSearchParams$1,FormData:FormData$1,Blob:Blob$1},isStandardBrowserEnv,isStandardBrowserWebWorkerEnv,protocols:["http","https","file","blob","url","data"]};function toURLEncodedForm(t,e){return toFormData(t,new platform.classes.URLSearchParams,Object.assign({visitor:function(a,n,r,i){return platform.isNode&&utils.isBuffer(a)?(this.append(n,a.toString("base64")),!1):i.defaultVisitor.apply(this,arguments)}},e))}function parsePropPath(t){return utils.matchAll(/\w+|\[(\w*)]/g,t).map(e=>e[0]==="[]"?"":e[1]||e[0])}function arrayToObject(t){const e={},a=Object.keys(t);let n;const r=a.length;let i;for(n=0;n=a.length;return o=!o&&utils.isArray(r)?r.length:o,l?(utils.hasOwnProp(r,o)?r[o]=[r[o],n]:r[o]=n,!s):((!r[o]||!utils.isObject(r[o]))&&(r[o]=[]),e(a,n,r[o],i)&&utils.isArray(r[o])&&(r[o]=arrayToObject(r[o])),!s)}if(utils.isFormData(t)&&utils.isFunction(t.entries)){const a={};return utils.forEachEntry(t,(n,r)=>{e(parsePropPath(n),r,a,0)}),a}return null}function stringifySafely(t,e,a){if(utils.isString(t))try{return(e||JSON.parse)(t),utils.trim(t)}catch(n){if(n.name!=="SyntaxError")throw n}return(a||JSON.stringify)(t)}const defaults$1={transitional:transitionalDefaults,adapter:platform.isNode?"http":"xhr",transformRequest:[function(e,a){const n=a.getContentType()||"",r=n.indexOf("application/json")>-1,i=utils.isObject(e);if(i&&utils.isHTMLForm(e)&&(e=new FormData(e)),utils.isFormData(e))return r&&r?JSON.stringify(formDataToJSON(e)):e;if(utils.isArrayBuffer(e)||utils.isBuffer(e)||utils.isStream(e)||utils.isFile(e)||utils.isBlob(e))return e;if(utils.isArrayBufferView(e))return e.buffer;if(utils.isURLSearchParams(e))return a.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),e.toString();let s;if(i){if(n.indexOf("application/x-www-form-urlencoded")>-1)return toURLEncodedForm(e,this.formSerializer).toString();if((s=utils.isFileList(e))||n.indexOf("multipart/form-data")>-1){const l=this.env&&this.env.FormData;return toFormData(s?{"files[]":e}:e,l&&new l,this.formSerializer)}}return i||r?(a.setContentType("application/json",!1),stringifySafely(e)):e}],transformResponse:[function(e){const a=this.transitional||defaults$1.transitional,n=a&&a.forcedJSONParsing,r=this.responseType==="json";if(e&&utils.isString(e)&&(n&&!this.responseType||r)){const o=!(a&&a.silentJSONParsing)&&r;try{return JSON.parse(e)}catch(s){if(o)throw s.name==="SyntaxError"?AxiosError.from(s,AxiosError.ERR_BAD_RESPONSE,this,null,this.response):s}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:platform.classes.FormData,Blob:platform.classes.Blob},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};utils.forEach(["delete","get","head","post","put","patch"],t=>{defaults$1.headers[t]={}});const defaults$2=defaults$1,ignoreDuplicateOf=utils.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),parseHeaders=t=>{const e={};let a,n,r;return t&&t.split(` -`).forEach(function(o){r=o.indexOf(":"),a=o.substring(0,r).trim().toLowerCase(),n=o.substring(r+1).trim(),!(!a||e[a]&&ignoreDuplicateOf[a])&&(a==="set-cookie"?e[a]?e[a].push(n):e[a]=[n]:e[a]=e[a]?e[a]+", "+n:n)}),e},$internals=Symbol("internals");function normalizeHeader(t){return t&&String(t).trim().toLowerCase()}function normalizeValue(t){return t===!1||t==null?t:utils.isArray(t)?t.map(normalizeValue):String(t)}function parseTokens(t){const e=Object.create(null),a=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let n;for(;n=a.exec(t);)e[n[1]]=n[2];return e}const isValidHeaderName=t=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(t.trim());function matchHeaderValue(t,e,a,n,r){if(utils.isFunction(n))return n.call(this,e,a);if(r&&(e=a),!!utils.isString(e)){if(utils.isString(n))return e.indexOf(n)!==-1;if(utils.isRegExp(n))return n.test(e)}}function formatHeader(t){return t.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(e,a,n)=>a.toUpperCase()+n)}function buildAccessors(t,e){const a=utils.toCamelCase(" "+e);["get","set","has"].forEach(n=>{Object.defineProperty(t,n+a,{value:function(r,i,o){return this[n].call(this,e,r,i,o)},configurable:!0})})}class AxiosHeaders{constructor(e){e&&this.set(e)}set(e,a,n){const r=this;function i(s,l,u){const c=normalizeHeader(l);if(!c)throw new Error("header name must be a non-empty string");const d=utils.findKey(r,c);(!d||r[d]===void 0||u===!0||u===void 0&&r[d]!==!1)&&(r[d||l]=normalizeValue(s))}const o=(s,l)=>utils.forEach(s,(u,c)=>i(u,c,l));return utils.isPlainObject(e)||e instanceof this.constructor?o(e,a):utils.isString(e)&&(e=e.trim())&&!isValidHeaderName(e)?o(parseHeaders(e),a):e!=null&&i(a,e,n),this}get(e,a){if(e=normalizeHeader(e),e){const n=utils.findKey(this,e);if(n){const r=this[n];if(!a)return r;if(a===!0)return parseTokens(r);if(utils.isFunction(a))return a.call(this,r,n);if(utils.isRegExp(a))return a.exec(r);throw new TypeError("parser must be boolean|regexp|function")}}}has(e,a){if(e=normalizeHeader(e),e){const n=utils.findKey(this,e);return!!(n&&this[n]!==void 0&&(!a||matchHeaderValue(this,this[n],n,a)))}return!1}delete(e,a){const n=this;let r=!1;function i(o){if(o=normalizeHeader(o),o){const s=utils.findKey(n,o);s&&(!a||matchHeaderValue(n,n[s],s,a))&&(delete n[s],r=!0)}}return utils.isArray(e)?e.forEach(i):i(e),r}clear(e){const a=Object.keys(this);let n=a.length,r=!1;for(;n--;){const i=a[n];(!e||matchHeaderValue(this,this[i],i,e,!0))&&(delete this[i],r=!0)}return r}normalize(e){const a=this,n={};return utils.forEach(this,(r,i)=>{const o=utils.findKey(n,i);if(o){a[o]=normalizeValue(r),delete a[i];return}const s=e?formatHeader(i):String(i).trim();s!==i&&delete a[i],a[s]=normalizeValue(r),n[s]=!0}),this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){const a=Object.create(null);return utils.forEach(this,(n,r)=>{n!=null&&n!==!1&&(a[r]=e&&utils.isArray(n)?n.join(", "):n)}),a}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([e,a])=>e+": "+a).join(` -`)}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(e){return e instanceof this?e:new this(e)}static concat(e,...a){const n=new this(e);return a.forEach(r=>n.set(r)),n}static accessor(e){const n=(this[$internals]=this[$internals]={accessors:{}}).accessors,r=this.prototype;function i(o){const s=normalizeHeader(o);n[s]||(buildAccessors(r,o),n[s]=!0)}return utils.isArray(e)?e.forEach(i):i(e),this}}AxiosHeaders.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);utils.reduceDescriptors(AxiosHeaders.prototype,({value:t},e)=>{let a=e[0].toUpperCase()+e.slice(1);return{get:()=>t,set(n){this[a]=n}}});utils.freezeMethods(AxiosHeaders);const AxiosHeaders$1=AxiosHeaders;function transformData(t,e){const a=this||defaults$2,n=e||a,r=AxiosHeaders$1.from(n.headers);let i=n.data;return utils.forEach(t,function(s){i=s.call(a,i,r.normalize(),e?e.status:void 0)}),r.normalize(),i}function isCancel(t){return!!(t&&t.__CANCEL__)}function CanceledError(t,e,a){AxiosError.call(this,t??"canceled",AxiosError.ERR_CANCELED,e,a),this.name="CanceledError"}utils.inherits(CanceledError,AxiosError,{__CANCEL__:!0});function settle(t,e,a){const n=a.config.validateStatus;!a.status||!n||n(a.status)?t(a):e(new AxiosError("Request failed with status code "+a.status,[AxiosError.ERR_BAD_REQUEST,AxiosError.ERR_BAD_RESPONSE][Math.floor(a.status/100)-4],a.config,a.request,a))}const cookies=platform.isStandardBrowserEnv?function(){return{write:function(a,n,r,i,o,s){const l=[];l.push(a+"="+encodeURIComponent(n)),utils.isNumber(r)&&l.push("expires="+new Date(r).toGMTString()),utils.isString(i)&&l.push("path="+i),utils.isString(o)&&l.push("domain="+o),s===!0&&l.push("secure"),document.cookie=l.join("; ")},read:function(a){const n=document.cookie.match(new RegExp("(^|;\\s*)("+a+")=([^;]*)"));return n?decodeURIComponent(n[3]):null},remove:function(a){this.write(a,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}();function isAbsoluteURL(t){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(t)}function combineURLs(t,e){return e?t.replace(/\/+$/,"")+"/"+e.replace(/^\/+/,""):t}function buildFullPath(t,e){return t&&!isAbsoluteURL(e)?combineURLs(t,e):e}const isURLSameOrigin=platform.isStandardBrowserEnv?function(){const e=/(msie|trident)/i.test(navigator.userAgent),a=document.createElement("a");let n;function r(i){let o=i;return e&&(a.setAttribute("href",o),o=a.href),a.setAttribute("href",o),{href:a.href,protocol:a.protocol?a.protocol.replace(/:$/,""):"",host:a.host,search:a.search?a.search.replace(/^\?/,""):"",hash:a.hash?a.hash.replace(/^#/,""):"",hostname:a.hostname,port:a.port,pathname:a.pathname.charAt(0)==="/"?a.pathname:"/"+a.pathname}}return n=r(window.location.href),function(o){const s=utils.isString(o)?r(o):o;return s.protocol===n.protocol&&s.host===n.host}}():function(){return function(){return!0}}();function parseProtocol(t){const e=/^([-+\w]{1,25})(:?\/\/|:)/.exec(t);return e&&e[1]||""}function speedometer(t,e){t=t||10;const a=new Array(t),n=new Array(t);let r=0,i=0,o;return e=e!==void 0?e:1e3,function(l){const u=Date.now(),c=n[i];o||(o=u),a[r]=l,n[r]=u;let d=i,h=0;for(;d!==r;)h+=a[d++],d=d%t;if(r=(r+1)%t,r===i&&(i=(i+1)%t),u-o{const i=r.loaded,o=r.lengthComputable?r.total:void 0,s=i-a,l=n(s),u=i<=o;a=i;const c={loaded:i,total:o,progress:o?i/o:void 0,bytes:s,rate:l||void 0,estimated:l&&o&&u?(o-i)/l:void 0,event:r};c[e?"download":"upload"]=!0,t(c)}}const isXHRAdapterSupported=typeof XMLHttpRequest<"u",xhrAdapter=isXHRAdapterSupported&&function(t){return new Promise(function(a,n){let r=t.data;const i=AxiosHeaders$1.from(t.headers).normalize(),o=t.responseType;let s;function l(){t.cancelToken&&t.cancelToken.unsubscribe(s),t.signal&&t.signal.removeEventListener("abort",s)}utils.isFormData(r)&&(platform.isStandardBrowserEnv||platform.isStandardBrowserWebWorkerEnv?i.setContentType(!1):i.setContentType("multipart/form-data;",!1));let u=new XMLHttpRequest;if(t.auth){const m=t.auth.username||"",p=t.auth.password?unescape(encodeURIComponent(t.auth.password)):"";i.set("Authorization","Basic "+btoa(m+":"+p))}const c=buildFullPath(t.baseURL,t.url);u.open(t.method.toUpperCase(),buildURL(c,t.params,t.paramsSerializer),!0),u.timeout=t.timeout;function d(){if(!u)return;const m=AxiosHeaders$1.from("getAllResponseHeaders"in u&&u.getAllResponseHeaders()),v={data:!o||o==="text"||o==="json"?u.responseText:u.response,status:u.status,statusText:u.statusText,headers:m,config:t,request:u};settle(function(w){a(w),l()},function(w){n(w),l()},v),u=null}if("onloadend"in u?u.onloadend=d:u.onreadystatechange=function(){!u||u.readyState!==4||u.status===0&&!(u.responseURL&&u.responseURL.indexOf("file:")===0)||setTimeout(d)},u.onabort=function(){u&&(n(new AxiosError("Request aborted",AxiosError.ECONNABORTED,t,u)),u=null)},u.onerror=function(){n(new AxiosError("Network Error",AxiosError.ERR_NETWORK,t,u)),u=null},u.ontimeout=function(){let p=t.timeout?"timeout of "+t.timeout+"ms exceeded":"timeout exceeded";const v=t.transitional||transitionalDefaults;t.timeoutErrorMessage&&(p=t.timeoutErrorMessage),n(new AxiosError(p,v.clarifyTimeoutError?AxiosError.ETIMEDOUT:AxiosError.ECONNABORTED,t,u)),u=null},platform.isStandardBrowserEnv){const m=(t.withCredentials||isURLSameOrigin(c))&&t.xsrfCookieName&&cookies.read(t.xsrfCookieName);m&&i.set(t.xsrfHeaderName,m)}r===void 0&&i.setContentType(null),"setRequestHeader"in u&&utils.forEach(i.toJSON(),function(p,v){u.setRequestHeader(v,p)}),utils.isUndefined(t.withCredentials)||(u.withCredentials=!!t.withCredentials),o&&o!=="json"&&(u.responseType=t.responseType),typeof t.onDownloadProgress=="function"&&u.addEventListener("progress",progressEventReducer(t.onDownloadProgress,!0)),typeof t.onUploadProgress=="function"&&u.upload&&u.upload.addEventListener("progress",progressEventReducer(t.onUploadProgress)),(t.cancelToken||t.signal)&&(s=m=>{u&&(n(!m||m.type?new CanceledError(null,t,u):m),u.abort(),u=null)},t.cancelToken&&t.cancelToken.subscribe(s),t.signal&&(t.signal.aborted?s():t.signal.addEventListener("abort",s)));const h=parseProtocol(c);if(h&&platform.protocols.indexOf(h)===-1){n(new AxiosError("Unsupported protocol "+h+":",AxiosError.ERR_BAD_REQUEST,t));return}u.send(r||null)})},knownAdapters={http:httpAdapter,xhr:xhrAdapter};utils.forEach(knownAdapters,(t,e)=>{if(t){try{Object.defineProperty(t,"name",{value:e})}catch{}Object.defineProperty(t,"adapterName",{value:e})}});const adapters$1={getAdapter:t=>{t=utils.isArray(t)?t:[t];const{length:e}=t;let a,n;for(let r=0;rt instanceof AxiosHeaders$1?t.toJSON():t;function mergeConfig(t,e){e=e||{};const a={};function n(u,c,d){return utils.isPlainObject(u)&&utils.isPlainObject(c)?utils.merge.call({caseless:d},u,c):utils.isPlainObject(c)?utils.merge({},c):utils.isArray(c)?c.slice():c}function r(u,c,d){if(utils.isUndefined(c)){if(!utils.isUndefined(u))return n(void 0,u,d)}else return n(u,c,d)}function i(u,c){if(!utils.isUndefined(c))return n(void 0,c)}function o(u,c){if(utils.isUndefined(c)){if(!utils.isUndefined(u))return n(void 0,u)}else return n(void 0,c)}function s(u,c,d){if(d in e)return n(u,c);if(d in t)return n(void 0,u)}const l={url:i,method:i,data:i,baseURL:o,transformRequest:o,transformResponse:o,paramsSerializer:o,timeout:o,timeoutMessage:o,withCredentials:o,adapter:o,responseType:o,xsrfCookieName:o,xsrfHeaderName:o,onUploadProgress:o,onDownloadProgress:o,decompress:o,maxContentLength:o,maxBodyLength:o,beforeRedirect:o,transport:o,httpAgent:o,httpsAgent:o,cancelToken:o,socketPath:o,responseEncoding:o,validateStatus:s,headers:(u,c)=>r(headersToObject(u),headersToObject(c),!0)};return utils.forEach(Object.keys(Object.assign({},t,e)),function(c){const d=l[c]||r,h=d(t[c],e[c],c);utils.isUndefined(h)&&d!==s||(a[c]=h)}),a}const VERSION$1="1.5.0",validators$1={};["object","boolean","number","function","string","symbol"].forEach((t,e)=>{validators$1[t]=function(n){return typeof n===t||"a"+(e<1?"n ":" ")+t}});const deprecatedWarnings={};validators$1.transitional=function(e,a,n){function r(i,o){return"[Axios v"+VERSION$1+"] Transitional option '"+i+"'"+o+(n?". "+n:"")}return(i,o,s)=>{if(e===!1)throw new AxiosError(r(o," has been removed"+(a?" in "+a:"")),AxiosError.ERR_DEPRECATED);return a&&!deprecatedWarnings[o]&&(deprecatedWarnings[o]=!0,console.warn(r(o," has been deprecated since v"+a+" and will be removed in the near future"))),e?e(i,o,s):!0}};function assertOptions(t,e,a){if(typeof t!="object")throw new AxiosError("options must be an object",AxiosError.ERR_BAD_OPTION_VALUE);const n=Object.keys(t);let r=n.length;for(;r-- >0;){const i=n[r],o=e[i];if(o){const s=t[i],l=s===void 0||o(s,i,t);if(l!==!0)throw new AxiosError("option "+i+" must be "+l,AxiosError.ERR_BAD_OPTION_VALUE);continue}if(a!==!0)throw new AxiosError("Unknown option "+i,AxiosError.ERR_BAD_OPTION)}}const validator={assertOptions,validators:validators$1},validators=validator.validators;class Axios{constructor(e){this.defaults=e,this.interceptors={request:new InterceptorManager$1,response:new InterceptorManager$1}}request(e,a){typeof e=="string"?(a=a||{},a.url=e):a=e||{},a=mergeConfig(this.defaults,a);const{transitional:n,paramsSerializer:r,headers:i}=a;n!==void 0&&validator.assertOptions(n,{silentJSONParsing:validators.transitional(validators.boolean),forcedJSONParsing:validators.transitional(validators.boolean),clarifyTimeoutError:validators.transitional(validators.boolean)},!1),r!=null&&(utils.isFunction(r)?a.paramsSerializer={serialize:r}:validator.assertOptions(r,{encode:validators.function,serialize:validators.function},!0)),a.method=(a.method||this.defaults.method||"get").toLowerCase();let o=i&&utils.merge(i.common,i[a.method]);i&&utils.forEach(["delete","get","head","post","put","patch","common"],p=>{delete i[p]}),a.headers=AxiosHeaders$1.concat(o,i);const s=[];let l=!0;this.interceptors.request.forEach(function(v){typeof v.runWhen=="function"&&v.runWhen(a)===!1||(l=l&&v.synchronous,s.unshift(v.fulfilled,v.rejected))});const u=[];this.interceptors.response.forEach(function(v){u.push(v.fulfilled,v.rejected)});let c,d=0,h;if(!l){const p=[dispatchRequest.bind(this),void 0];for(p.unshift.apply(p,s),p.push.apply(p,u),h=p.length,c=Promise.resolve(a);d{if(!n._listeners)return;let i=n._listeners.length;for(;i-- >0;)n._listeners[i](r);n._listeners=null}),this.promise.then=r=>{let i;const o=new Promise(s=>{n.subscribe(s),i=s}).then(r);return o.cancel=function(){n.unsubscribe(i)},o},e(function(i,o,s){n.reason||(n.reason=new CanceledError(i,o,s),a(n.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;const a=this._listeners.indexOf(e);a!==-1&&this._listeners.splice(a,1)}static source(){let e;return{token:new CancelToken(function(r){e=r}),cancel:e}}}const CancelToken$1=CancelToken;function spread(t){return function(a){return t.apply(null,a)}}function isAxiosError(t){return utils.isObject(t)&&t.isAxiosError===!0}const HttpStatusCode={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511};Object.entries(HttpStatusCode).forEach(([t,e])=>{HttpStatusCode[e]=t});const HttpStatusCode$1=HttpStatusCode;function createInstance(t){const e=new Axios$1(t),a=bind$4(Axios$1.prototype.request,e);return utils.extend(a,Axios$1.prototype,e,{allOwnKeys:!0}),utils.extend(a,e,null,{allOwnKeys:!0}),a.create=function(r){return createInstance(mergeConfig(t,r))},a}const axios=createInstance(defaults$2);axios.Axios=Axios$1;axios.CanceledError=CanceledError;axios.CancelToken=CancelToken$1;axios.isCancel=isCancel;axios.VERSION=VERSION$1;axios.toFormData=toFormData;axios.AxiosError=AxiosError;axios.Cancel=axios.CanceledError;axios.all=function(e){return Promise.all(e)};axios.spread=spread;axios.isAxiosError=isAxiosError;axios.mergeConfig=mergeConfig;axios.AxiosHeaders=AxiosHeaders$1;axios.formToJSON=t=>formDataToJSON(utils.isHTMLForm(t)?new FormData(t):t);axios.getAdapter=adapters$1.getAdapter;axios.HttpStatusCode=HttpStatusCode$1;axios.default=axios;const axios$1=axios;var commonjsGlobal=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function getDefaultExportFromCjs(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var assign$1=make_assign(),create$2=make_create(),trim$1=make_trim(),Global$5=typeof window<"u"?window:commonjsGlobal,util$7={assign:assign$1,create:create$2,trim:trim$1,bind:bind$3,slice:slice$2,each:each$9,map:map$2,pluck:pluck$1,isList:isList$1,isFunction:isFunction$5,isObject:isObject$b,Global:Global$5};function make_assign(){return Object.assign?Object.assign:function(e,a,n,r){for(var i=1;i"u"?null:console;if(t){var e=t.warn?t.warn:t.log;e.apply(t,arguments)}}function createStore(t,e,a){a||(a=""),t&&!isList(t)&&(t=[t]),e&&!isList(e)&&(e=[e]);var n=a?"__storejs_"+a+"_":"",r=a?new RegExp("^"+n):null,i=/^[a-zA-Z0-9_\-]*$/;if(!i.test(a))throw new Error("store.js namespaces can only have alphanumerics + underscores and dashes");var o={_namespacePrefix:n,_namespaceRegexp:r,_testStorage:function(l){try{var u="__storejs__test__";l.write(u,u);var c=l.read(u)===u;return l.remove(u),c}catch{return!1}},_assignPluginFnProp:function(l,u){var c=this[u];this[u]=function(){var h=slice$1(arguments,0),m=this;function p(){if(c)return each$8(arguments,function(y,w){h[w]=y}),c.apply(m,h)}var v=[p].concat(h);return l.apply(m,v)}},_serialize:function(l){return JSON.stringify(l)},_deserialize:function(l,u){if(!l)return u;var c="";try{c=JSON.parse(l)}catch{c=l}return c!==void 0?c:u},_addStorage:function(l){this.enabled||this._testStorage(l)&&(this.storage=l,this.enabled=!0)},_addPlugin:function(l){var u=this;if(isList(l)){each$8(l,function(h){u._addPlugin(h)});return}var c=pluck(this.plugins,function(h){return l===h});if(!c){if(this.plugins.push(l),!isFunction$4(l))throw new Error("Plugins must be function values that return objects");var d=l.call(this);if(!isObject$a(d))throw new Error("Plugins must return an object of function properties");each$8(d,function(h,m){if(!isFunction$4(h))throw new Error("Bad plugin property: "+m+" from plugin "+l.name+". Plugins should only return functions.");u._assignPluginFnProp(h,m)})}},addStorage:function(l){_warn("store.addStorage(storage) is deprecated. Use createStore([storages])"),this._addStorage(l)}},s=create$1(o,storeAPI,{plugins:[]});return s.raw={},each$8(s,function(l,u){isFunction$4(l)&&(s.raw[u]=bind$2(s,l))}),each$8(t,function(l){s._addStorage(l)}),each$8(e,function(l){s._addPlugin(l)}),s}var util$5=util$7,Global$4=util$5.Global,localStorage_1={name:"localStorage",read:read$6,write:write$6,each:each$7,remove:remove$5,clearAll:clearAll$5};function localStorage(){return Global$4.localStorage}function read$6(t){return localStorage().getItem(t)}function write$6(t,e){return localStorage().setItem(t,e)}function each$7(t){for(var e=localStorage().length-1;e>=0;e--){var a=localStorage().key(e);t(read$6(a),a)}}function remove$5(t){return localStorage().removeItem(t)}function clearAll$5(){return localStorage().clear()}var util$4=util$7,Global$3=util$4.Global,oldFFGlobalStorage={name:"oldFF-globalStorage",read:read$5,write:write$5,each:each$6,remove:remove$4,clearAll:clearAll$4},globalStorage=Global$3.globalStorage;function read$5(t){return globalStorage[t]}function write$5(t,e){globalStorage[t]=e}function each$6(t){for(var e=globalStorage.length-1;e>=0;e--){var a=globalStorage.key(e);t(globalStorage[a],a)}}function remove$4(t){return globalStorage.removeItem(t)}function clearAll$4(){each$6(function(t,e){delete globalStorage[t]})}var util$3=util$7,Global$2=util$3.Global,oldIEUserDataStorage={name:"oldIE-userDataStorage",write:write$4,read:read$4,each:each$5,remove:remove$3,clearAll:clearAll$3},storageName="storejs",doc$1=Global$2.document,_withStorageEl=_makeIEStorageElFunction(),disable=(Global$2.navigator?Global$2.navigator.userAgent:"").match(/ (MSIE 8|MSIE 9|MSIE 10)\./);function write$4(t,e){if(!disable){var a=fixKey(t);_withStorageEl(function(n){n.setAttribute(a,e),n.save(storageName)})}}function read$4(t){if(!disable){var e=fixKey(t),a=null;return _withStorageEl(function(n){a=n.getAttribute(e)}),a}}function each$5(t){_withStorageEl(function(e){for(var a=e.XMLDocument.documentElement.attributes,n=a.length-1;n>=0;n--){var r=a[n];t(e.getAttribute(r.name),r.name)}})}function remove$3(t){var e=fixKey(t);_withStorageEl(function(a){a.removeAttribute(e),a.save(storageName)})}function clearAll$3(){_withStorageEl(function(t){var e=t.XMLDocument.documentElement.attributes;t.load(storageName);for(var a=e.length-1;a>=0;a--)t.removeAttribute(e[a].name);t.save(storageName)})}var forbiddenCharsRegex=new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]","g");function fixKey(t){return t.replace(/^\d/,"___$&").replace(forbiddenCharsRegex,"___")}function _makeIEStorageElFunction(){if(!doc$1||!doc$1.documentElement||!doc$1.documentElement.addBehavior)return null;var t="script",e,a,n;try{a=new ActiveXObject("htmlfile"),a.open(),a.write("<"+t+">document.w=window'),a.close(),e=a.w.frames[0].document,n=e.createElement("div")}catch{n=doc$1.createElement("div"),e=doc$1.body}return function(r){var i=[].slice.call(arguments,0);i.unshift(n),e.appendChild(n),n.addBehavior("#default#userData"),n.load(storageName),r.apply(this,i),e.removeChild(n)}}var util$2=util$7,Global$1=util$2.Global,trim=util$2.trim,cookieStorage={name:"cookieStorage",read:read$3,write:write$3,each:each$4,remove:remove$2,clearAll:clearAll$2},doc=Global$1.document;function read$3(t){if(!t||!_has(t))return null;var e="(?:^|.*;\\s*)"+escape(t).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";return unescape(doc.cookie.replace(new RegExp(e),"$1"))}function each$4(t){for(var e=doc.cookie.split(/; ?/g),a=e.length-1;a>=0;a--)if(trim(e[a])){var n=e[a].split("="),r=unescape(n[0]),i=unescape(n[1]);t(i,r)}}function write$3(t,e){t&&(doc.cookie=escape(t)+"="+escape(e)+"; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/")}function remove$2(t){!t||!_has(t)||(doc.cookie=escape(t)+"=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/")}function clearAll$2(){each$4(function(t,e){remove$2(e)})}function _has(t){return new RegExp("(?:^|;\\s*)"+escape(t).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=").test(doc.cookie)}var util$1=util$7,Global=util$1.Global,sessionStorage_1={name:"sessionStorage",read:read$2,write:write$2,each:each$3,remove:remove$1,clearAll:clearAll$1};function sessionStorage(){return Global.sessionStorage}function read$2(t){return sessionStorage().getItem(t)}function write$2(t,e){return sessionStorage().setItem(t,e)}function each$3(t){for(var e=sessionStorage().length-1;e>=0;e--){var a=sessionStorage().key(e);t(read$2(a),a)}}function remove$1(t){return sessionStorage().removeItem(t)}function clearAll$1(){return sessionStorage().clear()}var memoryStorage_1={name:"memoryStorage",read:read$1,write:write$1,each:each$2,remove,clearAll},memoryStorage={};function read$1(t){return memoryStorage[t]}function write$1(t,e){memoryStorage[t]=e}function each$2(t){for(var e in memoryStorage)memoryStorage.hasOwnProperty(e)&&t(memoryStorage[e],e)}function remove(t){delete memoryStorage[t]}function clearAll(t){memoryStorage={}}var all=[localStorage_1,oldFFGlobalStorage,oldIEUserDataStorage,cookieStorage,sessionStorage_1,memoryStorage_1],json2$1={},hasRequiredJson2;function requireJson2(){return hasRequiredJson2||(hasRequiredJson2=1,typeof JSON!="object"&&(JSON={}),function(){var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;function f(t){return t<10?"0"+t:t}function this_value(){return this.valueOf()}typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var gap,indent,meta,rep;function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(e){var a=meta[e];return typeof a=="string"?a:"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var a,n,r,i,o=gap,s,l=e[t];switch(l&&typeof l=="object"&&typeof l.toJSON=="function"&&(l=l.toJSON(t)),typeof rep=="function"&&(l=rep.call(e,t,l)),typeof l){case"string":return quote(l);case"number":return isFinite(l)?String(l):"null";case"boolean":case"null":return String(l);case"object":if(!l)return"null";if(gap+=indent,s=[],Object.prototype.toString.apply(l)==="[object Array]"){for(i=l.length,a=0;alastFlushedIndex&&queue.splice(e,1)}function queueFlush(){!flushing&&!flushPending&&(flushPending=!0,queueMicrotask(flushJobs))}function flushJobs(){flushPending=!1,flushing=!0;for(let t=0;tt.effect(e,{scheduler:a=>{shouldSchedule?scheduler(a):a()}}),raw=t.raw}function overrideEffect(t){effect$3=t}function elementBoundEffect(t){let e=()=>{};return[n=>{let r=effect$3(n);return t._x_effects||(t._x_effects=new Set,t._x_runEffects=()=>{t._x_effects.forEach(i=>i())}),t._x_effects.add(r),e=()=>{r!==void 0&&(t._x_effects.delete(r),release(r))},r},()=>{e()}]}function dispatch(t,e,a={}){t.dispatchEvent(new CustomEvent(e,{detail:a,bubbles:!0,composed:!0,cancelable:!0}))}function walk(t,e){if(typeof ShadowRoot=="function"&&t instanceof ShadowRoot){Array.from(t.children).forEach(r=>walk(r,e));return}let a=!1;if(e(t,()=>a=!0),a)return;let n=t.firstElementChild;for(;n;)walk(n,e),n=n.nextElementSibling}function warn(t,...e){console.warn(`Alpine Warning: ${t}`,...e)}var started=!1;function start$1(){started&&warn("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),started=!0,document.body||warn("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` - {# All kinds of variables. #} diff --git a/resources/views/partials/debug-table.twig b/resources/views/partials/debug-table.twig index dcd3734842..9b510aff41 100644 --- a/resources/views/partials/debug-table.twig +++ b/resources/views/partials/debug-table.twig @@ -64,12 +64,16 @@ Timezone - {{ app.timezone }} + [BrowserTZ] + {{ config('app.timezone') }} + [BrowserTZ] App environment {{ config('app.env') }}, debug: {{ app.debug }} + + Layout + {{ config('firefly.layout') }} + Logging {{ config('logging.level') }}, {{ config('logging.default') }} / {{ app.audit_log_channel }} @@ -98,6 +102,14 @@ Stateful domains {{ app.stateful_domains }} + + Last cron job + {{ app.last_cronjob }} ({{ app.last_cronjob_ago }}) + + + Mailer + {{ config('mail.default') }} + @@ -118,7 +130,7 @@ User flags - {{ user.user_flags }} + {{ user.user_flags | raw }} Session start diff --git a/resources/views/v2/transactions/create.blade.php b/resources/views/v2/transactions/create.blade.php index 1607b417a0..c237d7dbb6 100644 --- a/resources/views/v2/transactions/create.blade.php +++ b/resources/views/v2/transactions/create.blade.php @@ -5,7 +5,7 @@ @section('content')
-
+