Compare commits

...

53 Commits

Author SHA1 Message Date
github-actions[bot]
35447f5eee Merge pull request #10843 from firefly-iii/release-1756727799
🤖 Automatically merge the PR into the develop branch.
2025-09-01 13:56:46 +02:00
JC5
7c6fcb5731 🤖 Auto commit for release 'develop' on 2025-09-01 2025-09-01 13:56:39 +02:00
Sander Dorigo
fabd9bf765 Merge branch 'develop' of https://github.com/firefly-iii/firefly-iii into develop 2025-09-01 13:38:39 +02:00
Sander Dorigo
6352d26633 fix argument 2025-09-01 13:38:32 +02:00
github-actions[bot]
ebef145bd6 Merge pull request #10842 from firefly-iii/release-1756723300
🤖 Automatically merge the PR into the develop branch.
2025-09-01 12:41:48 +02:00
JC5
acc89eb5f9 🤖 Auto commit for release 'develop' on 2025-09-01 2025-09-01 12:41:40 +02:00
Sander Dorigo
6523596415 fix bad call 2025-09-01 12:36:36 +02:00
github-actions[bot]
b6c2d23116 Merge pull request #10838 from firefly-iii/release-1756697534
🤖 Automatically merge the PR into the develop branch.
2025-09-01 05:32:22 +02:00
JC5
2a123354f9 🤖 Auto commit for release 'develop' on 2025-09-01 2025-09-01 05:32:14 +02:00
James Cole
1e7ea4b76c Improve account list and view. 2025-08-31 19:20:02 +02:00
James Cole
d959526eb3 Fix #10837 2025-08-31 19:07:45 +02:00
James Cole
8846ee9091 Fix #10827 2025-08-30 07:51:28 +02:00
github-actions[bot]
6eb8d0fc8c Merge pull request #10826 from firefly-iii/release-1756445011
🤖 Automatically merge the PR into the develop branch.
2025-08-29 07:23:42 +02:00
JC5
1b0e16b6a5 🤖 Auto commit for release 'develop' on 2025-08-29 2025-08-29 07:23:32 +02:00
James Cole
2e4df28288 Less logging. 2025-08-29 06:51:20 +02:00
James Cole
f3b7a3015d Fix #10824 2025-08-27 19:00:12 +02:00
James Cole
5de5e08b1d Fix #10820 2025-08-26 16:05:36 +02:00
James Cole
0a116cd04c Add API autocomplete tests. 2025-08-25 17:17:51 +02:00
James Cole
fd32a692c1 Add some API tests. 2025-08-25 15:31:51 +02:00
James Cole
1ac762aba8 Merge branch 'develop' of github.com:firefly-iii/firefly-iii into develop 2025-08-25 15:31:15 +02:00
James Cole
315dc532b6 Fix #10819 2025-08-25 15:31:07 +02:00
github-actions[bot]
e19ed1be15 Merge pull request #10817 from firefly-iii/release-1756092462
🤖 Automatically merge the PR into the develop branch.
2025-08-25 05:27:50 +02:00
JC5
cbb0621fd9 🤖 Auto commit for release 'develop' on 2025-08-25 2025-08-25 05:27:42 +02:00
James Cole
049cbab861 Remove superfluous logging. 2025-08-24 20:31:12 +02:00
James Cole
28b620fb5c Remove superfluous logging. 2025-08-24 20:30:40 +02:00
James Cole
c183f91ff6 Add issue to changelog 2025-08-24 20:29:39 +02:00
github-actions[bot]
172efae41c Merge pull request #10816 from firefly-iii/release-1756060004
🤖 Automatically merge the PR into the develop branch.
2025-08-24 20:26:54 +02:00
JC5
756e857ba0 🤖 Auto commit for release 'develop' on 2025-08-24 2025-08-24 20:26:44 +02:00
James Cole
1cde7aab0c Fix #10815 2025-08-24 20:14:02 +02:00
James Cole
2d67eece5d Various code cleanup. 2025-08-24 17:14:07 +02:00
James Cole
b1f79c4c0f Fix #10814 2025-08-24 13:31:00 +02:00
James Cole
33bd2ceae8 Fix amounts in transaction show. 2025-08-24 13:30:41 +02:00
James Cole
e68850f192 Fix changelog. 2025-08-24 06:51:48 +02:00
James Cole
450ac7e6ee Fix #10813 2025-08-24 06:51:28 +02:00
James Cole
91f52b5dbc Add copyright statements. 2025-08-23 11:26:04 +02:00
James Cole
eed2405d76 Update changelog before I forget about it. 2025-08-23 11:17:05 +02:00
github-actions[bot]
c956df7790 Merge pull request #10809 from firefly-iii/release-1755940492
🤖 Automatically merge the PR into the develop branch.
2025-08-23 11:15:02 +02:00
JC5
0fdccec6a8 🤖 Auto commit for release 'develop' on 2025-08-23 2025-08-23 11:14:52 +02:00
James Cole
8ded54d7a8 Fix #10808 2025-08-23 08:56:25 +02:00
James Cole
bb1b4ca5ca Fix #10807 2025-08-23 08:54:50 +02:00
James Cole
e90d60113b Extra validation and a new config variable for #10806 2025-08-23 08:47:34 +02:00
James Cole
d95dada0e0 Update changelog for #10804 2025-08-22 20:20:07 +02:00
James Cole
8722456595 Fix #10804 2025-08-22 20:19:52 +02:00
James Cole
b5ad226451 Remove unused headers. 2025-08-22 15:45:39 +02:00
James Cole
ddb0e66651 Update changelog. 2025-08-22 15:45:05 +02:00
James Cole
e802899608 Pre-filter expenses, fixes #10803 2025-08-22 11:53:08 +02:00
James Cole
0894d3bf42 Fix #10802 2025-08-22 11:09:17 +02:00
James Cole
80bcfd3bcd Small issues to fix #5532 2025-08-22 09:52:27 +02:00
James Cole
8c410f42bd Expand changelog. 2025-08-22 09:15:34 +02:00
James Cole
7a1021dffc Add spent + earned info to category chart. 2025-08-22 09:15:13 +02:00
github-actions[bot]
63883c9a84 Merge pull request #10801 from firefly-iii/release-1755840718
🤖 Automatically merge the PR into the develop branch.
2025-08-22 07:32:06 +02:00
JC5
50d7f9d1ec 🤖 Auto commit for release 'develop' on 2025-08-22 2025-08-22 07:31:58 +02:00
James Cole
ebc7ea0eb6 Fix amount display 2025-08-22 07:28:09 +02:00
95 changed files with 2969 additions and 1324 deletions

View File

@@ -1253,16 +1253,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1" "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1", "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1", "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1327,7 +1327,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v7.3.2" "source": "https://github.com/symfony/console/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -1347,7 +1347,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-30T17:13:41+00:00" "time": "2025-08-25T06:35:40+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -1418,16 +1418,16 @@
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v7.3.0", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
"reference": "497f73ac996a598c92409b44ac43b6690c4f666d" "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
"reference": "497f73ac996a598c92409b44ac43b6690c4f666d", "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1478,7 +1478,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -1489,12 +1489,16 @@
"url": "https://github.com/fabpot", "url": "https://github.com/fabpot",
"type": "github" "type": "github"
}, },
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{ {
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-04-22T09:11:45+00:00" "time": "2025-08-13T11:49:31+00:00"
}, },
{ {
"name": "symfony/event-dispatcher-contracts", "name": "symfony/event-dispatcher-contracts",
@@ -1712,16 +1716,16 @@
}, },
{ {
"name": "symfony/options-resolver", "name": "symfony/options-resolver",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/options-resolver.git", "url": "https://github.com/symfony/options-resolver.git",
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37" "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37", "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37", "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1759,7 +1763,7 @@
"options" "options"
], ],
"support": { "support": {
"source": "https://github.com/symfony/options-resolver/tree/v7.3.2" "source": "https://github.com/symfony/options-resolver/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -1779,7 +1783,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-15T11:36:08+00:00" "time": "2025-08-05T10:16:07+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
@@ -2282,16 +2286,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v7.3.0", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" "reference": "32241012d521e2e8a9d713adb0812bb773b907f1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1",
"reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "reference": "32241012d521e2e8a9d713adb0812bb773b907f1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2323,7 +2327,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v7.3.0" "source": "https://github.com/symfony/process/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -2334,12 +2338,16 @@
"url": "https://github.com/fabpot", "url": "https://github.com/fabpot",
"type": "github" "type": "github"
}, },
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{ {
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-04-17T09:11:12+00:00" "time": "2025-08-18T09:42:54+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
@@ -2488,16 +2496,16 @@
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2555,7 +2563,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v7.3.2" "source": "https://github.com/symfony/string/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -2575,7 +2583,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-10T08:47:49+00:00" "time": "2025-08-25T06:35:40+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],

View File

@@ -114,6 +114,7 @@ class AccountController extends Controller
'id' => (string) $account->id, 'id' => (string) $account->id,
'name' => $account->name, 'name' => $account->name,
'name_with_balance' => $nameWithBalance, 'name_with_balance' => $nameWithBalance,
'active' => $account->active,
'type' => $account->accountType->type, 'type' => $account->accountType->type,
'currency_id' => (string) $useCurrency->id, 'currency_id' => (string) $useCurrency->id,
'currency_name' => $useCurrency->name, 'currency_name' => $useCurrency->name,

View File

@@ -69,6 +69,7 @@ class BudgetController extends Controller
static fn (Budget $item) => [ static fn (Budget $item) => [
'id' => (string) $item->id, 'id' => (string) $item->id,
'name' => $item->name, 'name' => $item->name,
'active' => $item->active,
] ]
); );

View File

@@ -69,6 +69,7 @@ class RecurrenceController extends Controller
'id' => (string) $recurrence->id, 'id' => (string) $recurrence->id,
'name' => $recurrence->title, 'name' => $recurrence->title,
'description' => $recurrence->description, 'description' => $recurrence->description,
'active' => $recurrence->active,
]; ];
} }

View File

@@ -69,6 +69,7 @@ class RuleController extends Controller
'id' => (string)$rule->id, 'id' => (string)$rule->id,
'name' => $rule->title, 'name' => $rule->title,
'description' => $rule->description, 'description' => $rule->description,
'active' => $rule->active,
]; ];
} }

View File

@@ -69,6 +69,7 @@ class RuleGroupController extends Controller
'id' => (string) $group->id, 'id' => (string) $group->id,
'name' => $group->title, 'name' => $group->title,
'description' => $group->description, 'description' => $group->description,
'active' => $group->active,
]; ];
} }

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* BalanceController.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Chart; namespace FireflyIII\Api\V1\Controllers\Chart;

View File

@@ -97,13 +97,14 @@ class CategoryController extends Controller
$collector = app(GroupCollectorInterface::class); $collector = app(GroupCollectorInterface::class);
$collector->setRange($start, $end)->withAccountInformation(); $collector->setRange($start, $end)->withAccountInformation();
$collector->setXorAccounts($accounts)->withCategoryInformation(); $collector->setXorAccounts($accounts)->withCategoryInformation();
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::RECONCILIATION->value]); $collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value]);
$journals = $collector->getExtractedJournals(); $journals = $collector->getExtractedJournals();
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
// find journal: // find journal:
$journalCurrencyId = (int)$journal['currency_id']; $journalCurrencyId = (int)$journal['currency_id'];
$type = $journal['transaction_type_type'];
$currency = $currencies[$journalCurrencyId] ?? $this->currencyRepos->find($journalCurrencyId); $currency = $currencies[$journalCurrencyId] ?? $this->currencyRepos->find($journalCurrencyId);
$currencies[$journalCurrencyId] = $currency; $currencies[$journalCurrencyId] = $currency;
$currencyId = (int)$currency->id; $currencyId = (int)$currency->id;
@@ -111,7 +112,7 @@ class CategoryController extends Controller
$currencyCode = (string)$currency->code; $currencyCode = (string)$currency->code;
$currencySymbol = (string)$currency->symbol; $currencySymbol = (string)$currency->symbol;
$currencyDecimalPlaces = (int)$currency->decimal_places; $currencyDecimalPlaces = (int)$currency->decimal_places;
$amount = Steam::positive($journal['amount']); $amount = Steam::positive((string)$journal['amount']);
$pcAmount = null; $pcAmount = null;
// overrule if necessary: // overrule if necessary:
@@ -151,22 +152,36 @@ class CategoryController extends Controller
'type' => 'bar', 'type' => 'bar',
'entries' => [ 'entries' => [
'spent' => '0', 'spent' => '0',
'earned' => '0',
], ],
'pc_entries' => [ 'pc_entries' => [
'spent' => '0', 'spent' => '0',
'earned' => '0',
], ],
]; ];
// add monies // add monies
$return[$key]['entries']['spent'] = bcadd($return[$key]['entries']['spent'], (string)$amount); // expenses to spent
if (TransactionTypeEnum::WITHDRAWAL->value === $type) {
$return[$key]['entries']['spent'] = bcadd($return[$key]['entries']['spent'], $amount);
if (null !== $pcAmount) { if (null !== $pcAmount) {
$return[$key]['pc_entries']['spent'] = bcadd($return[$key]['pc_entries']['spent'], (string)$pcAmount); $return[$key]['pc_entries']['spent'] = bcadd($return[$key]['pc_entries']['spent'], $pcAmount);
}
continue;
}
// positive amount = earned
if (TransactionTypeEnum::DEPOSIT->value === $type) {
$return[$key]['entries']['earned'] = bcadd($return[$key]['entries']['earned'], $amount);
if (null !== $pcAmount) {
$return[$key]['pc_entries']['earned'] = bcadd($return[$key]['pc_entries']['earned'], $pcAmount);
}
} }
} }
$return = array_values($return); $return = array_values($return);
// order by amount // order by amount
usort($return, static fn (array $a, array $b) => (float)$a['entries']['spent'] < (float)$b['entries']['spent'] ? 1 : -1); usort($return, static fn (array $a, array $b) => ((float)$a['entries']['spent'] + (float)$a['entries']['earned']) < ((float)$b['entries']['spent'] + (float)$b['entries']['earned']) ? 1 : -1);
return response()->json($this->clean($return)); return response()->json($this->clean($return));
} }

View File

@@ -108,12 +108,7 @@ abstract class Controller extends BaseController
{ {
$bag = new ParameterBag(); $bag = new ParameterBag();
$page = (int)request()->get('page'); $page = (int)request()->get('page');
if ($page < 1) { $page = min(max(1, $page), 2 ** 16);
$page = 1;
}
if ($page > 2 ** 16) {
$page = 2 ** 16;
}
$bag->set('page', $page); $bag->set('page', $page);
// some date fields: // some date fields:
@@ -131,20 +126,16 @@ abstract class Controller extends BaseController
$obj = null; $obj = null;
if (null !== $date) { if (null !== $date) {
try { try {
$obj = Carbon::parse((string)$date); $obj = Carbon::parse((string)$date, config('app.timezone'));
} catch (InvalidFormatException $e) { } catch (InvalidFormatException $e) {
// don't care // don't care
Log::warning( Log::warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', substr((string)$date, 0, 20), $e->getMessage()));
sprintf(
'Ignored invalid date "%s" in API controller parameter check: %s',
substr((string)$date, 0, 20),
$e->getMessage()
)
);
} }
} }
if ($obj instanceof Carbon) {
$bag->set($field, $obj); $bag->set($field, $obj);
} }
}
// integer fields: // integer fields:
$integers = ['limit']; $integers = ['limit'];

View File

@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Account; namespace FireflyIII\Api\V1\Controllers\Models\Account;
use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Account\ShowRequest;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@@ -33,7 +34,6 @@ use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection; use League\Fractal\Resource\Collection as FractalCollection;
@@ -71,23 +71,23 @@ class ShowController extends Controller
* *
* @throws FireflyException * @throws FireflyException
*/ */
public function index(Request $request): JsonResponse public function index(ShowRequest $request): JsonResponse
{ {
$manager = $this->getManager(); $manager = $this->getManager();
$type = $request->get('type') ?? 'all'; $params = $request->getParameters();
$this->parameters->set('type', $type); $this->parameters->set('type', $params['type']);
// types to get, page size: // types to get, page size:
$types = $this->mapAccountTypes($this->parameters->get('type')); $types = $this->mapAccountTypes($params['type']);
$pageSize = $this->parameters->get('limit');
// get list of accounts. Count it and split it. // get list of accounts. Count it and split it.
$this->repository->resetAccountOrder(); $this->repository->resetAccountOrder();
$collection = $this->repository->getAccountsByType($types, $this->parameters->get('sort') ?? []); // TODO fix sort.
$collection = $this->repository->getAccountsByType($types, null);
$count = $collection->count(); $count = $collection->count();
// continue sort: // continue sort:
$accounts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $accounts = $collection->slice(($this->parameters->get('page') - 1) * $params['limit'], $params['limit']);
// enrich // enrich
/** @var User $admin */ /** @var User $admin */
@@ -98,7 +98,7 @@ class ShowController extends Controller
$accounts = $enrichment->enrich($accounts); $accounts = $enrichment->enrich($accounts);
// make paginator: // make paginator:
$paginator = new LengthAwarePaginator($accounts, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($accounts, $count, $params['limit'], $this->parameters->get('page'));
$paginator->setPath(route('api.v1.accounts.index').$this->buildParams()); $paginator->setPath(route('api.v1.accounts.index').$this->buildParams());
/** @var AccountTransformer $transformer */ /** @var AccountTransformer $transformer */

View File

@@ -86,7 +86,7 @@ class UpdateController extends Controller
$admin = auth()->user(); $admin = auth()->user();
$enrichment = new BudgetLimitEnrichment(); $enrichment = new BudgetLimitEnrichment();
$enrichment->setUser($admin); $enrichment->setUser($admin);
$budgetLimit = $enrichment->enrich($budgetLimit); $budgetLimit = $enrichment->enrichSingle($budgetLimit);
/** @var BudgetLimitTransformer $transformer */ /** @var BudgetLimitTransformer $transformer */
$transformer = app(BudgetLimitTransformer::class); $transformer = app(BudgetLimitTransformer::class);

View File

@@ -0,0 +1,126 @@
<?php
declare(strict_types=1);
/*
* TriggerController.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Generic\SingleDateRequest;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Jobs\CreateRecurringTransactions;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
class TriggerController extends Controller
{
private RecurringRepositoryInterface $repository;
/**
* RecurrenceController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
public function trigger(SingleDateRequest $request, Recurrence $recurrence): JsonResponse
{
// find recurrence occurrence for this date and trigger it.
// grab the date from the last time the recurrence fired:
$backupDate = $recurrence->latest_date;
$date = $request->getDate();
// fire the recurring cron job on the given date, then post-date the created transaction.
Log::info(sprintf('Trigger: will now fire recurring cron job task for date "%s".', $date->format('Y-m-d H:i:s')));
/** @var CreateRecurringTransactions $job */
$job = app(CreateRecurringTransactions::class);
$job->setRecurrences(new Collection()->push($recurrence));
$job->setDate($date);
$job->setForce(false);
$job->handle();
Log::debug('Done with recurrence.');
$groups = $job->getGroups();
$this->repository->markGroupsAsNow($groups);
$recurrence->latest_date = $backupDate;
$recurrence->latest_date_tz = $backupDate?->format('e');
$recurrence->save();
Preferences::mark();
// enrich groups and return them:
if (0 === $groups->count()) {
$paginator = new LengthAwarePaginator(new Collection(), 0, 1);
}
if ($groups->count() > 0) {
/** @var User $admin */
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector
->setUser($admin)
->setIds($groups->pluck('id')->toArray())
->withAPIInformation()
;
$paginator = $collector->getPaginatedGroups();
}
$manager = $this->getManager();
$paginator->setPath(route('api.v1.recurrences.trigger', [$recurrence->id]).$this->buildParams());
// enrich
$admin = auth()->user();
$enrichment = new TransactionGroupEnrichment();
$enrichment->setUser($admin);
$transactions = $enrichment->enrich($paginator->getCollection());
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
}

View File

@@ -64,6 +64,7 @@ class ChartRequest extends FormRequest
'end' => 'required|date|after:1970-01-02|before:2038-01-17|after_or_equal:start', 'end' => 'required|date|after:1970-01-02|before:2038-01-17|after_or_equal:start',
'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))), 'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))),
'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))), 'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))),
'accounts' => 'nullable|array',
'accounts.*' => 'exists:accounts,id', 'accounts.*' => 'exists:accounts,id',
]; ];

View File

@@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
/*
* ShowRequest.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace FireflyIII\Api\V1\Requests\Models\Account;
use Carbon\Carbon;
use FireflyIII\Models\Preference;
use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class ShowRequest extends FormRequest
{
use AccountFilter;
use ConvertsDataTypes;
public function getParameters(): array
{
$limit = $this->convertInteger('limit');
if (0 === $limit) {
// get default for user:
/** @var User $user */
$user = auth()->user();
/** @var Preference $pageSize */
$limit = (int)Preferences::getForUser($user, 'listPageSize', 50)->data;
}
$page = $this->convertInteger('page');
$page = min(max(1, $page), 2 ** 16);
return [
'type' => $this->convertString('type', 'all'),
'limit' => $limit,
'sort' => $this->convertString('sort', 'order'),
'page' => $page,
];
}
public function rules(): array
{
$keys = implode(',', array_keys($this->types));
return [
'date' => 'date',
'start' => 'date|present_with:end|before_or_equal:end|before:2038-01-17|after:1970-01-02',
'end' => 'date|present_with:start|after_or_equal:start|before:2038-01-17|after:1970-01-02',
'sort' => 'in:active,iban,name,order,-active,-iban,-name,-order', // TODO improve me.
'type' => sprintf('in:%s', $keys),
'limit' => 'numeric|min:1|max:131337',
'page' => 'numeric|min:1|max:131337',
];
}
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator): void {
if ($validator->failed()) {
return;
}
$data = $validator->getData();
if (array_key_exists('date', $data) && array_key_exists('start', $data) && array_key_exists('end', $data)) {
// assume valid dates, before we got here.
$start = Carbon::parse($data['start'], config('app.timezone'))->startOfDay();
$end = Carbon::parse($data['end'], config('app.timezone'))->endOfDay();
$date = Carbon::parse($data['date'], config('app.timezone'));
if (!$date->between($start, $end)) {
$validator->errors()->add('date', (string)trans('validation.between_date'));
}
}
}
);
}
}

View File

@@ -78,7 +78,7 @@ class StoreRequest extends FormRequest
'object_group_id' => 'numeric|belongsToUser:object_groups,id', 'object_group_id' => 'numeric|belongsToUser:object_groups,id',
'object_group_title' => ['min:1', 'max:255'], 'object_group_title' => ['min:1', 'max:255'],
'target_amount' => ['required', new IsValidZeroOrMoreAmount()], 'target_amount' => ['required', new IsValidZeroOrMoreAmount()],
'start_date' => 'date|nullable', 'start_date' => 'required|date|after:1970-01-01|before:2038-01-17',
'transaction_currency_id' => 'exists:transaction_currencies,id|required_without:transaction_currency_code', 'transaction_currency_id' => 'exists:transaction_currencies,id|required_without:transaction_currency_code',
'transaction_currency_code' => 'exists:transaction_currencies,code|required_without:transaction_currency_id', 'transaction_currency_code' => 'exists:transaction_currencies,code|required_without:transaction_currency_id',
'target_date' => 'date|nullable|after:start_date', 'target_date' => 'date|nullable|after:start_date',

View File

@@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1);
/* /*
* ValidatesEnvironmentVariables.php * ValidatesEnvironmentVariables.php
* Copyright (c) 2025 james@firefly-iii.org. * Copyright (c) 2025 james@firefly-iii.org
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
* *
@@ -18,9 +18,11 @@ declare(strict_types=1);
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
declare(strict_types=1);
namespace FireflyIII\Console\Commands\Integrity; namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;

View File

@@ -133,6 +133,9 @@ class OutputsInstructions extends Command
if ('03-31' === $today) { if ('03-31' === $today) {
$colors = ['bright-blue', 'bright-red', 'white', 'white', 'bright-red', 'bright-blue', 'default', 'default']; $colors = ['bright-blue', 'bright-red', 'white', 'white', 'bright-red', 'bright-blue', 'default', 'default'];
} }
if ('ru_RU' === config('firefly.default_language')) {
$colors = ['blue', 'blue', 'blue', 'yellow', 'yellow', 'yellow', 'default', 'default'];
}
$this->line(sprintf('<fg=%s> ______ _ __ _ _____ _____ _____ </>', $colors[0])); $this->line(sprintf('<fg=%s> ______ _ __ _ _____ _____ _____ </>', $colors[0]));
$this->line(sprintf('<fg=%s> | ____(_) / _| | |_ _|_ _|_ _| </>', $colors[1])); $this->line(sprintf('<fg=%s> | ____(_) / _| | |_ _|_ _|_ _| </>', $colors[1]));
@@ -245,7 +248,31 @@ class OutputsInstructions extends Command
'Be there or forever wonder.', 'Be there or forever wonder.',
'A year from now you will wish you had started today.', 'A year from now you will wish you had started today.',
]; ];
$addQuotes = true;
// fuck the Russian aggression in Ukraine.
// There is no point even trying to be neutral, because you cant. When I say you cant be neutral on
// a moving train, it means the world is already moving in certain directions. Children are going
// hungry, wars are taking place. In a situation like that, to be neutral or to try to be neutral,
// to stand aside, not to take a stand, not to participate, is to collaborate with whatever is
// going on, to allow that to happen.
if ('ru_RU' === config('firefly.default_language')) {
$addQuotes = false;
$lines = [
'🇺🇦 Слава Україні!',
'🇺🇦 Slava Ukraini!',
];
}
$random = random_int(0, count($lines) - 1); $random = random_int(0, count($lines) - 1);
if ($addQuotes) {
$this->line(sprintf(' "%s"', $lines[$random])); $this->line(sprintf(' "%s"', $lines[$random]));
return;
}
$this->line(sprintf(' %s', $lines[$random]));
} }
} }

View File

@@ -1,9 +1,9 @@
<?php <?php
declare(strict_types=1);
/* /*
* RecalculatesRunningBalance.php * RecalculatesRunningBalance.php
* Copyright (c) 2025 james@firefly-iii.org. * Copyright (c) 2025 james@firefly-iii.org
* *
* This file is part of Firefly III (https://github.com/firefly-iii). * This file is part of Firefly III (https://github.com/firefly-iii).
* *
@@ -18,9 +18,11 @@ declare(strict_types=1);
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
declare(strict_types=1);
namespace FireflyIII\Console\Commands\System; namespace FireflyIII\Console\Commands\System;
use FireflyIII\Console\Commands\ShowsFriendlyMessages; use FireflyIII\Console\Commands\ShowsFriendlyMessages;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* ResetsErrorMailLimit.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Console\Commands\System; namespace FireflyIII\Console\Commands\System;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* UpgradesWebhooks.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Console\Commands\Upgrade; namespace FireflyIII\Console\Commands\Upgrade;

View File

@@ -1,6 +1,27 @@
<?php <?php
/*
* WarnUserAboutBill.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Events\Model\Bill; namespace FireflyIII\Events\Model\Bill;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* WarnUserAboutOverdueSubscriptions.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Events\Model\Bill; namespace FireflyIII\Events\Model\Bill;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* ChangedName.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Events\Model\PiggyBank; namespace FireflyIII\Events\Model\PiggyBank;

View File

@@ -111,7 +111,7 @@ class BillEventHandler
$bill = $event->bill; $bill = $event->bill;
/** @var bool $preference */ /** @var bool $preference */
Preferences::getForUser($bill->user, 'notification_bill_reminder', true)->data; $preference = Preferences::getForUser($bill->user, 'notification_bill_reminder', true)->data;
if (true === $preference) { if (true === $preference) {
Log::debug('Bill reminder is true!'); Log::debug('Bill reminder is true!');

View File

@@ -40,7 +40,7 @@ class WebhookEventHandler
{ {
Log::debug(sprintf('Now in %s', __METHOD__)); Log::debug(sprintf('Now in %s', __METHOD__));
if (false === config('firefly.feature_flags.webhooks') || false === config('firefly.allow_webhooks')) { if (false === config('firefly.feature_flags.webhooks') || false === config('firefly.allow_webhooks')) {
Log::info('Webhook event handler is disabled, do not run sendWebhookMessages().'); Log::debug('Webhook event handler is disabled, do not run sendWebhookMessages().');
return; return;
} }

View File

@@ -72,7 +72,7 @@ class TransactionObserver
} }
$transaction->saveQuietly(); $transaction->saveQuietly();
Log::debug('Transaction primary currency amounts are updated.'); Log::debug(sprintf('Transaction #%d primary currency amounts are updated.', $transaction->id));
} }
public function deleting(?Transaction $transaction): void public function deleting(?Transaction $transaction): void

View File

@@ -861,8 +861,9 @@ class GroupCollector implements GroupCollectorInterface
return new LengthAwarePaginator($set, $this->total, $total, 1); return new LengthAwarePaginator($set, $this->total, $total, 1);
} }
$limit = $this->limit ?? 1;
return new LengthAwarePaginator($set, $this->total, $this->limit, $this->page); return new LengthAwarePaginator($set, $this->total, $limit, $this->page);
} }
/** /**

View File

@@ -158,18 +158,8 @@ class ShowController extends Controller
Log::debug('End collect transactions'); Log::debug('End collect transactions');
$timer->stop('collection'); $timer->stop('collection');
// enrich data in arrays.
// enrich
// $enrichment = new TransactionGroupEnrichment();
// $enrichment->setUser(auth()->user());
// $groups->setCollection($enrichment->enrich($groups->getCollection()));
$groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')])); $groups->setPath(route('accounts.show', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]));
$showAll = false; $showAll = false;
// correct
$now = today()->endOfDay(); $now = today()->endOfDay();
if ($now->gt($end) || $now->lt($start)) { if ($now->gt($end) || $now->lt($start)) {
$now = $end; $now = $end;

View File

@@ -37,6 +37,7 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Facades\Preferences; use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
use FireflyIII\Support\Http\Controllers\AugumentData; use FireflyIII\Support\Http\Controllers\AugumentData;
use FireflyIII\Support\Http\Controllers\ChartGeneration; use FireflyIII\Support\Http\Controllers\ChartGeneration;
use FireflyIII\Support\Http\Controllers\DateCalculation; use FireflyIII\Support\Http\Controllers\DateCalculation;
@@ -504,6 +505,7 @@ class AccountController extends Controller
Log::debug(sprintf('Step is %s', $step)); Log::debug(sprintf('Step is %s', $step));
$locale = Steam::getLocale(); $locale = Steam::getLocale();
$return = []; $return = [];
$converter = new ExchangeRateConverter();
// fix for issue https://github.com/firefly-iii/firefly-iii/issues/8041 // 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. // have to make sure this chart is always based on the balance at the END of the period.
@@ -512,10 +514,10 @@ class AccountController extends Controller
$current = app('navigation')->endOfX($current, $step, null); $current = app('navigation')->endOfX($current, $step, null);
$format = (string)trans('config.month_and_day_js', [], $locale); $format = (string)trans('config.month_and_day_js', [], $locale);
$accountCurrency = $this->accountRepository->getAccountCurrency($account); $accountCurrency = $this->accountRepository->getAccountCurrency($account);
Log::debug('Get and filter balance for entire range start');
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToPrimary); $range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToPrimary);
$range = Steam::filterAccountBalances($range, $account, $this->convertToPrimary, $accountCurrency); $range = Steam::filterAccountBalances($range, $account, $this->convertToPrimary, $accountCurrency);
Log::debug('Get and filter balance for entire range end');
// temp, get end balance. // temp, get end balance.
Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String())); Log::debug(sprintf('period: Call finalAccountBalance with date/time "%s"', $end->toIso8601String()));
Steam::finalAccountBalance($account, $end); Steam::finalAccountBalance($account, $end);
@@ -552,7 +554,15 @@ class AccountController extends Controller
$carbon = Carbon::createFromFormat('Y-m-d', $newRange[$expectedIndex]['date'])->endOfDay(); $carbon = Carbon::createFromFormat('Y-m-d', $newRange[$expectedIndex]['date'])->endOfDay();
} }
} }
Log::debug(sprintf('momentBalance is now %s', json_encode($momentBalance))); Log::debug(sprintf('momentBalance[%s] is now %s', $current->format('Y-m-d H:i:s'), json_encode($momentBalance)));
// check, perhaps recalculate the amount in currency X if the
if ($accountCurrency->id !== $this->primaryCurrency->id && $this->convertToPrimary && array_key_exists($accountCurrency->code, $momentBalance)) {
$converted = $converter->convert($accountCurrency, $this->primaryCurrency, $current, $momentBalance[$accountCurrency->code]);
$momentBalance['pc_balance'] = $converted;
}
$return = $this->updateChartKeys($return, $momentBalance); $return = $this->updateChartKeys($return, $momentBalance);
$previous = $momentBalance; $previous = $momentBalance;

View File

@@ -28,8 +28,7 @@ use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\TriggerRecurrenceRequest; use FireflyIII\Http\Requests\TriggerRecurrenceRequest;
use FireflyIII\Jobs\CreateRecurringTransactions; use FireflyIII\Jobs\CreateRecurringTransactions;
use FireflyIII\Models\Recurrence; use FireflyIII\Models\Recurrence;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@@ -58,20 +57,11 @@ class TriggerController extends Controller
app('log')->debug('Done with recurrence.'); app('log')->debug('Done with recurrence.');
$groups = $job->getGroups(); $groups = $job->getGroups();
$this->repository->markGroupsAsNow($groups);
/** @var TransactionGroup $group */
foreach ($groups as $group) {
/** @var TransactionJournal $journal */
foreach ($group->transactionJournals as $journal) {
app('log')->debug(sprintf('Set date of journal #%d to today!', $journal->id));
$journal->date = today(config('app.timezone'));
$journal->save();
}
}
$recurrence->latest_date = $backupDate; $recurrence->latest_date = $backupDate;
$recurrence->latest_date_tz = $backupDate?->format('e'); $recurrence->latest_date_tz = $backupDate?->format('e');
$recurrence->save(); $recurrence->save();
app('preferences')->mark(); Preferences::mark();
if (0 === $groups->count()) { if (0 === $groups->count()) {
$request->session()->flash('info', (string) trans('firefly.no_new_transaction_in_recurrence')); $request->session()->flash('info', (string) trans('firefly.no_new_transaction_in_recurrence'));

View File

@@ -25,7 +25,6 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Rule; namespace FireflyIII\Http\Controllers\Rule;
use Throwable; use Throwable;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SelectTransactionsRequest; use FireflyIII\Http\Requests\SelectTransactionsRequest;
@@ -74,20 +73,16 @@ class SelectController extends Controller
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$accounts = implode(',', $request->get('accounts')); $accounts = implode(',', $request->get('accounts'));
$startDate = new Carbon($request->get('start'));
$endDate = new Carbon($request->get('end'));
// create new rule engine: // create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class); $newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user); $newRuleEngine->setUser($user);
// add extra operators: // add extra operators:
$newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]);
$newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]);
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]); $newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);
// set rules: // set rules:
$newRuleEngine->setRules(new Collection([$rule])); $newRuleEngine->setRules(new Collection()->push($rule));
$newRuleEngine->fire(); $newRuleEngine->fire();
$resultCount = $newRuleEngine->getResults(); $resultCount = $newRuleEngine->getResults();
@@ -107,11 +102,9 @@ class SelectController extends Controller
return redirect(route('rules.index')); return redirect(route('rules.index'));
} }
// does the user have shared accounts? // does the user have shared accounts?
$first = session('first', today(config('app.timezone'))->subYear())->format('Y-m-d');
$today = today(config('app.timezone'))->format('Y-m-d');
$subTitle = (string) trans('firefly.apply_rule_selection', ['title' => $rule->title]); $subTitle = (string) trans('firefly.apply_rule_selection', ['title' => $rule->title]);
return view('rules.rule.select-transactions', compact('first', 'today', 'rule', 'subTitle')); return view('rules.rule.select-transactions', compact('rule', 'subTitle'));
} }
/** /**

View File

@@ -25,11 +25,9 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers\RuleGroup; namespace FireflyIII\Http\Controllers\RuleGroup;
use Exception; use Exception;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller; use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\SelectTransactionsRequest; use FireflyIII\Http\Requests\SelectTransactionsRequest;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\Engine\RuleEngineInterface; use FireflyIII\TransactionRules\Engine\RuleEngineInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
@@ -42,8 +40,6 @@ use Illuminate\View\View;
*/ */
class ExecutionController extends Controller class ExecutionController extends Controller
{ {
private RuleGroupRepositoryInterface $ruleGroupRepository;
/** /**
* ExecutionController constructor. * ExecutionController constructor.
*/ */
@@ -56,7 +52,6 @@ class ExecutionController extends Controller
app('view')->share('title', (string) trans('firefly.rules')); app('view')->share('title', (string) trans('firefly.rules'));
app('view')->share('mainTitleIcon', 'fa-random'); app('view')->share('mainTitleIcon', 'fa-random');
$this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
return $next($request); return $next($request);
} }
@@ -74,15 +69,11 @@ class ExecutionController extends Controller
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$accounts = implode(',', $request->get('accounts')); $accounts = implode(',', $request->get('accounts'));
$startDate = new Carbon($request->get('start'));
$endDate = new Carbon($request->get('end'));
// create new rule engine: // create new rule engine:
$newRuleEngine = app(RuleEngineInterface::class); $newRuleEngine = app(RuleEngineInterface::class);
$newRuleEngine->setUser($user); $newRuleEngine->setUser($user);
// add extra operators: // add extra operators:
$newRuleEngine->addOperator(['type' => 'date_after', 'value' => $startDate->format('Y-m-d')]);
$newRuleEngine->addOperator(['type' => 'date_before', 'value' => $endDate->format('Y-m-d')]);
$newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]); $newRuleEngine->addOperator(['type' => 'account_id', 'value' => $accounts]);
// set rules: // set rules:
@@ -104,10 +95,8 @@ class ExecutionController extends Controller
*/ */
public function selectTransactions(RuleGroup $ruleGroup) public function selectTransactions(RuleGroup $ruleGroup)
{ {
$first = session('first')->format('Y-m-d');
$today = today(config('app.timezone'))->format('Y-m-d');
$subTitle = (string) trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]); $subTitle = (string) trans('firefly.apply_rule_group_selection', ['title' => $ruleGroup->title]);
return view('rules.rule-group.select-transactions', compact('first', 'today', 'ruleGroup', 'subTitle')); return view('rules.rule-group.select-transactions', compact('ruleGroup', 'subTitle'));
} }
} }

View File

@@ -337,6 +337,9 @@ class ConvertController extends Controller
'type' => $transactionType->type, 'type' => $transactionType->type,
]; ];
$sourceTransaction = $journal->transactions()->where('amount', '<', 0)->first();
$amount = $sourceTransaction?->amount ?? '0';
// also set the currency to the currency of the source account, in case you're converting a deposit into a transfer. // also set the currency to the currency of the source account, in case you're converting a deposit into a transfer.
if (TransactionTypeEnum::TRANSFER->value === $transactionType->type && TransactionTypeEnum::DEPOSIT->value === $journal->transactionType->type) { if (TransactionTypeEnum::TRANSFER->value === $transactionType->type && TransactionTypeEnum::DEPOSIT->value === $journal->transactionType->type) {
$source = $this->accountRepository->find((int) $sourceId); $source = $this->accountRepository->find((int) $sourceId);
@@ -346,7 +349,20 @@ class ConvertController extends Controller
if ($sourceCurrency instanceof TransactionCurrency && $destCurrency instanceof TransactionCurrency && $sourceCurrency->code !== $destCurrency->code) { if ($sourceCurrency instanceof TransactionCurrency && $destCurrency instanceof TransactionCurrency && $sourceCurrency->code !== $destCurrency->code) {
$update['currency_id'] = $sourceCurrency->id; $update['currency_id'] = $sourceCurrency->id;
$update['foreign_currency_id'] = $destCurrency->id; $update['foreign_currency_id'] = $destCurrency->id;
$update['foreign_amount'] = '1'; // not the best solution but at this point the amount is hard to get. $update['foreign_amount'] = Steam::positive($amount); // not the best solution but at this point the amount is hard to get.
}
}
// same thing for converting a withdrawal into a transfer, but with the currency of the destination account.
if (TransactionTypeEnum::TRANSFER->value === $transactionType->type && TransactionTypeEnum::WITHDRAWAL->value === $journal->transactionType->type) {
$source = $this->accountRepository->find((int) $sourceId);
$sourceCurrency = $this->accountRepository->getAccountCurrency($source);
$dest = $this->accountRepository->find((int) $destinationId);
$destCurrency = $this->accountRepository->getAccountCurrency($dest);
if ($sourceCurrency instanceof TransactionCurrency && $destCurrency instanceof TransactionCurrency && $sourceCurrency->code !== $destCurrency->code) {
$update['currency_id'] = $sourceCurrency->id;
$update['foreign_currency_id'] = $destCurrency->id;
$update['foreign_amount'] = Steam::positive($amount); // not the best solution but at this point the amount is hard to get.
} }
} }

View File

@@ -41,8 +41,6 @@ class SelectTransactionsRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'start' => 'required|date|after:1970-01-02|before:2038-01-17|before:end|required_with:end',
'end' => 'required|date|after:1970-01-02|before:2038-01-17|after:start|required_with:start',
'accounts' => 'required', 'accounts' => 'required',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts', 'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
]; ];

View File

@@ -37,6 +37,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/** /**
* Class CreateAutoBudgetLimits * Class CreateAutoBudgetLimits
@@ -59,7 +60,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
$newDate = clone $date; $newDate = clone $date;
$newDate->startOfDay(); $newDate->startOfDay();
$this->date = $newDate; $this->date = $newDate;
app('log')->debug(sprintf('Created new CreateAutoBudgetLimits("%s")', $this->date->format('Y-m-d'))); Log::debug(sprintf('Created new CreateAutoBudgetLimits("%s")', $this->date->format('Y-m-d')));
} }
} }
@@ -70,9 +71,9 @@ class CreateAutoBudgetLimits implements ShouldQueue
*/ */
public function handle(): void public function handle(): void
{ {
app('log')->debug(sprintf('Now at start of CreateAutoBudgetLimits() job for %s.', $this->date->format('D d M Y'))); Log::debug(sprintf('Now at start of CreateAutoBudgetLimits() job for %s.', $this->date->format('D d M Y')));
$autoBudgets = AutoBudget::get(); $autoBudgets = AutoBudget::get();
app('log')->debug(sprintf('Found %d auto budgets.', $autoBudgets->count())); Log::debug(sprintf('Found %d auto budgets.', $autoBudgets->count()));
foreach ($autoBudgets as $autoBudget) { foreach ($autoBudgets as $autoBudget) {
$this->handleAutoBudget($autoBudget); $this->handleAutoBudget($autoBudget);
} }
@@ -84,18 +85,18 @@ class CreateAutoBudgetLimits implements ShouldQueue
private function handleAutoBudget(AutoBudget $autoBudget): void private function handleAutoBudget(AutoBudget $autoBudget): void
{ {
if (null === $autoBudget->budget) { if (null === $autoBudget->budget) {
app('log')->info(sprintf('Auto budget #%d is associated with a deleted budget.', $autoBudget->id)); Log::info(sprintf('Auto budget #%d is associated with a deleted budget.', $autoBudget->id));
$autoBudget->delete(); $autoBudget->delete();
return; return;
} }
if (false === $autoBudget->budget->active) { if (false === $autoBudget->budget->active) {
app('log')->info(sprintf('Auto budget #%d is associated with an inactive budget.', $autoBudget->id)); Log::info(sprintf('Auto budget #%d is associated with an inactive budget.', $autoBudget->id));
return; return;
} }
if (!$this->isMagicDay($autoBudget)) { if (!$this->isMagicDay($autoBudget)) {
app('log')->info( Log::info(
sprintf( sprintf(
'Today (%s) is not a magic day for %s auto-budget #%d (part of budget #%d "%s")', 'Today (%s) is not a magic day for %s auto-budget #%d (part of budget #%d "%s")',
$this->date->format('Y-m-d'), $this->date->format('Y-m-d'),
@@ -105,11 +106,11 @@ class CreateAutoBudgetLimits implements ShouldQueue
$autoBudget->budget->name $autoBudget->budget->name
) )
); );
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
return; return;
} }
app('log')->info( Log::info(
sprintf( sprintf(
'Today (%s) is a magic day for %s auto-budget #%d (part of budget #%d "%s")', 'Today (%s) is a magic day for %s auto-budget #%d (part of budget #%d "%s")',
$this->date->format('Y-m-d'), $this->date->format('Y-m-d'),
@@ -131,7 +132,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
// that's easy: create one. // that's easy: create one.
// do nothing else. // do nothing else.
$this->createBudgetLimit($autoBudget, $start, $end); $this->createBudgetLimit($autoBudget, $start, $end);
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
return; return;
} }
@@ -139,18 +140,18 @@ class CreateAutoBudgetLimits implements ShouldQueue
if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ROLLOVER->value === (int) $autoBudget->auto_budget_type) { if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ROLLOVER->value === (int) $autoBudget->auto_budget_type) {
// budget limit exists already, // budget limit exists already,
$this->createRollover($autoBudget); $this->createRollover($autoBudget);
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
return; return;
} }
if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ADJUSTED->value === (int) $autoBudget->auto_budget_type) { if (!$budgetLimit instanceof BudgetLimit && AutoBudgetType::AUTO_BUDGET_ADJUSTED->value === (int) $autoBudget->auto_budget_type) {
// budget limit exists already, // budget limit exists already,
$this->createAdjustedLimit($autoBudget); $this->createAdjustedLimit($autoBudget);
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
return; return;
} }
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
} }
/** /**
@@ -193,7 +194,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
private function findBudgetLimit(Budget $budget, Carbon $start, Carbon $end): ?BudgetLimit private function findBudgetLimit(Budget $budget, Carbon $start, Carbon $end): ?BudgetLimit
{ {
app('log')->debug( Log::debug(
sprintf( sprintf(
'Going to find a budget limit for budget #%d ("%s") between %s and %s', 'Going to find a budget limit for budget #%d ("%s") between %s and %s',
$budget->id, $budget->id,
@@ -212,21 +213,21 @@ class CreateAutoBudgetLimits implements ShouldQueue
private function createBudgetLimit(AutoBudget $autoBudget, Carbon $start, Carbon $end, ?string $amount = null): void private function createBudgetLimit(AutoBudget $autoBudget, Carbon $start, Carbon $end, ?string $amount = null): void
{ {
app('log')->debug(sprintf('No budget limit exist. Must create one for auto-budget #%d', $autoBudget->id)); Log::debug(sprintf('No budget limit exist. Must create one for auto-budget #%d', $autoBudget->id));
if (null !== $amount) { if (null !== $amount) {
app('log')->debug(sprintf('Amount is overruled and will be set to %s', $amount)); Log::debug(sprintf('Amount is overruled and will be set to %s', $amount));
} }
$budgetLimit = new BudgetLimit(); $budgetLimit = new BudgetLimit();
$budgetLimit->budget()->associate($autoBudget->budget); $budgetLimit->budget()->associate($autoBudget->budget);
$budgetLimit->transactionCurrency()->associate($autoBudget->transactionCurrency); $budgetLimit->transactionCurrency()->associate($autoBudget->transactionCurrency);
$budgetLimit->start_date = $start; $budgetLimit->start_date = clone $start;
$budgetLimit->end_date = $end; $budgetLimit->end_date = clone $end;
$budgetLimit->amount = $amount ?? $autoBudget->amount; $budgetLimit->amount = $amount ?? $autoBudget->amount;
$budgetLimit->period = $autoBudget->period; $budgetLimit->period = $autoBudget->period;
$budgetLimit->generated = 1; $budgetLimit->generated = 1;
$budgetLimit->save(); $budgetLimit->save();
app('log')->debug(sprintf('Created budget limit #%d.', $budgetLimit->id)); Log::debug(sprintf('Created budget limit #%d.', $budgetLimit->id));
} }
/** /**
@@ -234,7 +235,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
*/ */
private function createRollover(AutoBudget $autoBudget): void private function createRollover(AutoBudget $autoBudget): void
{ {
app('log')->debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id));
// current period: // current period:
$start = app('navigation')->startOfPeriod($this->date, $autoBudget->period); $start = app('navigation')->startOfPeriod($this->date, $autoBudget->period);
$end = app('navigation')->endOfPeriod($start, $autoBudget->period); $end = app('navigation')->endOfPeriod($start, $autoBudget->period);
@@ -243,7 +244,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
$previousStart = app('navigation')->subtractPeriod($start, $autoBudget->period); $previousStart = app('navigation')->subtractPeriod($start, $autoBudget->period);
$previousEnd = app('navigation')->endOfPeriod($previousStart, $autoBudget->period); $previousEnd = app('navigation')->endOfPeriod($previousStart, $autoBudget->period);
app('log')->debug( Log::debug(
sprintf( sprintf(
'Current period is %s-%s, so previous period is %s-%s', 'Current period is %s-%s, so previous period is %s-%s',
$start->format('Y-m-d'), $start->format('Y-m-d'),
@@ -257,44 +258,44 @@ class CreateAutoBudgetLimits implements ShouldQueue
$budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd);
if (!$budgetLimit instanceof BudgetLimit) { if (!$budgetLimit instanceof BudgetLimit) {
app('log')->debug('No budget limit exists in previous period, so create one.'); Log::debug('No budget limit exists in previous period, so create one.');
// if not, create it and we're done. // if not, create it and we're done.
$this->createBudgetLimit($autoBudget, $start, $end); $this->createBudgetLimit($autoBudget, $start, $end);
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
return; return;
} }
app('log')->debug('Budget limit exists for previous period.'); Log::debug('Budget limit exists for previous period.');
// if has one, calculate expenses and use that as a base. // if has one, calculate expenses and use that as a base.
$repository = app(OperationsRepositoryInterface::class); $repository = app(OperationsRepositoryInterface::class);
$repository->setUser($autoBudget->budget->user); $repository->setUser($autoBudget->budget->user);
$spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency); $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency);
$currencyId = $autoBudget->transaction_currency_id; $currencyId = $autoBudget->transaction_currency_id;
$spentAmount = $spent[$currencyId]['sum'] ?? '0'; $spentAmount = $spent[$currencyId]['sum'] ?? '0';
app('log')->debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount));
// if you spent more in previous budget period, than whatever you had previous budget period, the amount resets // if you spent more in previous budget period, than whatever you had previous budget period, the amount resets
// previous budget limit + spent // previous budget limit + spent
$budgetLeft = bcadd($budgetLimit->amount, $spentAmount); $budgetLeft = bcadd($budgetLimit->amount, $spentAmount);
$totalAmount = $autoBudget->amount; $totalAmount = $autoBudget->amount;
app('log')->debug(sprintf('Total amount left for previous budget period is %s', $budgetLeft)); Log::debug(sprintf('Total amount left for previous budget period is %s', $budgetLeft));
if (-1 !== bccomp('0', $budgetLeft)) { if (-1 !== bccomp('0', $budgetLeft)) {
app('log')->info(sprintf('The amount left is negative, so it will be reset to %s.', $totalAmount)); Log::info(sprintf('The amount left is negative, so it will be reset to %s.', $totalAmount));
} }
if (1 !== bccomp('0', $budgetLeft)) { if (1 !== bccomp('0', $budgetLeft)) {
$totalAmount = bcadd($budgetLeft, $totalAmount); $totalAmount = bcadd($budgetLeft, $totalAmount);
app('log')->info(sprintf('The amount left is positive, so the new amount will be %s.', $totalAmount)); Log::info(sprintf('The amount left is positive, so the new amount will be %s.', $totalAmount));
} }
// create budget limit: // create budget limit:
$this->createBudgetLimit($autoBudget, $start, $end, $totalAmount); $this->createBudgetLimit($autoBudget, $start, $end, $totalAmount);
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
} }
private function createAdjustedLimit(AutoBudget $autoBudget): void private function createAdjustedLimit(AutoBudget $autoBudget): void
{ {
app('log')->debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Will now manage rollover for auto budget #%d', $autoBudget->id));
// current period: // current period:
$start = app('navigation')->startOfPeriod($this->date, $autoBudget->period); $start = app('navigation')->startOfPeriod($this->date, $autoBudget->period);
$end = app('navigation')->endOfPeriod($start, $autoBudget->period); $end = app('navigation')->endOfPeriod($start, $autoBudget->period);
@@ -303,7 +304,7 @@ class CreateAutoBudgetLimits implements ShouldQueue
$previousStart = app('navigation')->subtractPeriod($start, $autoBudget->period); $previousStart = app('navigation')->subtractPeriod($start, $autoBudget->period);
$previousEnd = app('navigation')->endOfPeriod($previousStart, $autoBudget->period); $previousEnd = app('navigation')->endOfPeriod($previousStart, $autoBudget->period);
app('log')->debug( Log::debug(
sprintf( sprintf(
'Current period is %s-%s, so previous period is %s-%s', 'Current period is %s-%s, so previous period is %s-%s',
$start->format('Y-m-d'), $start->format('Y-m-d'),
@@ -317,13 +318,13 @@ class CreateAutoBudgetLimits implements ShouldQueue
$budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd); $budgetLimit = $this->findBudgetLimit($autoBudget->budget, $previousStart, $previousEnd);
if (!$budgetLimit instanceof BudgetLimit) { if (!$budgetLimit instanceof BudgetLimit) {
app('log')->debug('No budget limit exists in previous period, so create one.'); Log::debug('No budget limit exists in previous period, so create one.');
// if not, create standard amount, and we're done. // if not, create standard amount, and we're done.
$this->createBudgetLimit($autoBudget, $start, $end); $this->createBudgetLimit($autoBudget, $start, $end);
return; return;
} }
app('log')->debug('Budget limit exists for previous period.'); Log::debug('Budget limit exists for previous period.');
// if has one, calculate expenses and use that as a base. // if has one, calculate expenses and use that as a base.
$repository = app(OperationsRepositoryInterface::class); $repository = app(OperationsRepositoryInterface::class);
@@ -331,31 +332,31 @@ class CreateAutoBudgetLimits implements ShouldQueue
$spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency); $spent = $repository->sumExpenses($previousStart, $previousEnd, null, new Collection([$autoBudget->budget]), $autoBudget->transactionCurrency);
$currencyId = $autoBudget->transaction_currency_id; $currencyId = $autoBudget->transaction_currency_id;
$spentAmount = $spent[$currencyId]['sum'] ?? '0'; $spentAmount = $spent[$currencyId]['sum'] ?? '0';
app('log')->debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount)); Log::debug(sprintf('Spent in previous budget period (%s-%s) is %s', $previousStart->format('Y-m-d'), $previousEnd->format('Y-m-d'), $spentAmount));
// what you spent in previous period PLUS the amount for the current period, // what you spent in previous period PLUS the amount for the current period,
// if that is more than zero, that's the amount that will be set. // if that is more than zero, that's the amount that will be set.
$budgetAvailable = bcadd(bcadd($budgetLimit->amount, $autoBudget->amount), $spentAmount); $budgetAvailable = bcadd(bcadd($budgetLimit->amount, $autoBudget->amount), $spentAmount);
$totalAmount = $autoBudget->amount; $totalAmount = $autoBudget->amount;
app('log')->debug(sprintf('Total amount available for current budget period is %s', $budgetAvailable)); Log::debug(sprintf('Total amount available for current budget period is %s', $budgetAvailable));
if (-1 !== bccomp($budgetAvailable, $totalAmount)) { if (-1 !== bccomp($budgetAvailable, $totalAmount)) {
app('log')->info(sprintf('There is no overspending, no need to adjust. Budget limit amount will be %s.', $budgetAvailable)); Log::info(sprintf('There is no overspending, no need to adjust. Budget limit amount will be %s.', $budgetAvailable));
// create budget limit: // create budget limit:
$this->createBudgetLimit($autoBudget, $start, $end, $budgetAvailable); $this->createBudgetLimit($autoBudget, $start, $end, $budgetAvailable);
} }
if (1 !== bccomp($budgetAvailable, $totalAmount) && 1 === bccomp($budgetAvailable, '0')) { if (1 !== bccomp($budgetAvailable, $totalAmount) && 1 === bccomp($budgetAvailable, '0')) {
app('log')->info(sprintf('There was overspending, so the new amount will be %s.', $budgetAvailable)); Log::info(sprintf('There was overspending, so the new amount will be %s.', $budgetAvailable));
// create budget limit: // create budget limit:
$this->createBudgetLimit($autoBudget, $start, $end, $budgetAvailable); $this->createBudgetLimit($autoBudget, $start, $end, $budgetAvailable);
} }
if (1 !== bccomp($budgetAvailable, $totalAmount) && -1 === bccomp($budgetAvailable, '0')) { if (1 !== bccomp($budgetAvailable, $totalAmount) && -1 === bccomp($budgetAvailable, '0')) {
app('log')->info('There was overspending, but so much even this period cant fix that. Reset it to 1.'); Log::info('There was overspending, but so much even this period cant fix that. Reset it to 1.');
// create budget limit: // create budget limit:
$this->createBudgetLimit($autoBudget, $start, $end, '1'); $this->createBudgetLimit($autoBudget, $start, $end, '1');
} }
app('log')->debug(sprintf('Done with auto budget #%d', $autoBudget->id)); Log::debug(sprintf('Done with auto budget #%d', $autoBudget->id));
} }
public function setDate(Carbon $date): void public function setDate(Carbon $date): void

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* WebhookDelivery.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* WebhookResponse.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* WebhookTrigger.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* SubscriptionsOverdueReminder.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Notifications\User; namespace FireflyIII\Notifications\User;

View File

@@ -35,6 +35,7 @@ use FireflyIII\Models\RecurrenceMeta;
use FireflyIII\Models\RecurrenceRepetition; use FireflyIII\Models\RecurrenceRepetition;
use FireflyIII\Models\RecurrenceTransaction; use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Models\RecurrenceTransactionMeta; use FireflyIII\Models\RecurrenceTransactionMeta;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta; use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Services\Internal\Destroy\RecurrenceDestroyService; use FireflyIII\Services\Internal\Destroy\RecurrenceDestroyService;
@@ -582,4 +583,17 @@ class RecurringRepository implements RecurringRepositoryInterface, UserGroupInte
return $service->update($recurrence, $data); return $service->update($recurrence, $data);
} }
public function markGroupsAsNow(Collection $groups): void
{
/** @var TransactionGroup $group */
foreach ($groups as $group) {
/** @var TransactionJournal $journal */
foreach ($group->transactionJournals as $journal) {
Log::debug(sprintf('Set date of journal #%d to today!', $journal->id));
$journal->date = now(config('app.timezone'));
$journal->save();
}
}
}
} }

View File

@@ -139,6 +139,8 @@ interface RecurringRepositoryInterface
*/ */
public function getXOccurrencesSince(RecurrenceRepetition $repetition, Carbon $date, Carbon $afterDate, int $count): array; public function getXOccurrencesSince(RecurrenceRepetition $repetition, Carbon $date, Carbon $afterDate, int $count): array;
public function markGroupsAsNow(Collection $groups): void;
/** /**
* Parse the repetition in a string that is user readable. * Parse the repetition in a string that is user readable.
*/ */

View File

@@ -52,6 +52,7 @@ class EitherConfigKey
'firefly.languages', 'firefly.languages',
'app.timezone', 'app.timezone',
'firefly.valid_view_ranges', 'firefly.valid_view_ranges',
'firefly.preselected_accounts',
// triggers and actions: // triggers and actions:
'firefly.rule-actions', 'firefly.rule-actions',

View File

@@ -103,7 +103,7 @@ class ExchangeRateConverter
// find in cache // find in cache
if (null !== $res) { if (null !== $res) {
Log::debug(sprintf('ExchangeRateConverter: Return cached rate from %s to %s on %s.', $from->code, $to->code, $date->format('Y-m-d'))); Log::debug(sprintf('ExchangeRateConverter: Return cached rate (%s) from %s to %s on %s.', $res, $from->code, $to->code, $date->format('Y-m-d')));
return $res; return $res;
} }

View File

@@ -249,14 +249,14 @@ class AccountEnrichment implements EnrichmentInterface
'opening_balance_date' => null, 'opening_balance_date' => null,
'opening_balance_amount' => null, 'opening_balance_amount' => null,
'account_number' => null, 'account_number' => null,
'notes' => $notes[$id] ?? null, 'notes' => $this->notes[$id] ?? null,
'last_activity' => $this->lastActivities[$id] ?? null, 'last_activity' => $this->lastActivities[$id] ?? null,
]; ];
// add object group if available // add object group if available
if (array_key_exists($id, $this->mappedObjects)) { if (array_key_exists($id, $this->mappedObjects)) {
$key = $this->mappedObjects[$id]; $key = $this->mappedObjects[$id];
$meta['object_group_id'] = $this->objectGroups[$key]['id']; $meta['object_group_id'] = (string) $this->objectGroups[$key]['id'];
$meta['object_group_title'] = $this->objectGroups[$key]['title']; $meta['object_group_title'] = $this->objectGroups[$key]['title'];
$meta['object_group_order'] = $this->objectGroups[$key]['order']; $meta['object_group_order'] = $this->objectGroups[$key]['order'];
} }
@@ -327,6 +327,7 @@ class AccountEnrichment implements EnrichmentInterface
$openingBalance = null; $openingBalance = null;
$pcOpeningBalance = null; $pcOpeningBalance = null;
} }
$meta['current_balance_date'] = $this->getDate();
$meta['balances'] = [ $meta['balances'] = [
'current_balance' => $currentBalance, 'current_balance' => $currentBalance,
'pc_current_balance' => $pcCurrentBalance, 'pc_current_balance' => $pcCurrentBalance,
@@ -378,13 +379,17 @@ class AccountEnrichment implements EnrichmentInterface
public function setDate(?Carbon $date): void public function setDate(?Carbon $date): void
{ {
if (null !== $date) {
$date->endOfDay();
Log::debug(sprintf('Date is now %s', $date->toW3cString()));
}
$this->date = $date; $this->date = $date;
} }
public function getDate(): Carbon public function getDate(): Carbon
{ {
if (null === $this->date) { if (null === $this->date) {
return today(); return now();
} }
return $this->date; return $this->date;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* BudgetEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
@@ -117,7 +138,7 @@ class BudgetEnrichment implements EnrichmentInterface
// add object group if available // add object group if available
if (array_key_exists($id, $this->mappedObjects)) { if (array_key_exists($id, $this->mappedObjects)) {
$key = $this->mappedObjects[$id]; $key = $this->mappedObjects[$id];
$meta['object_group_id'] = $this->objectGroups[$key]['id']; $meta['object_group_id'] = (string) $this->objectGroups[$key]['id'];
$meta['object_group_title'] = $this->objectGroups[$key]['title']; $meta['object_group_title'] = $this->objectGroups[$key]['title'];
$meta['object_group_order'] = $this->objectGroups[$key]['order']; $meta['object_group_order'] = $this->objectGroups[$key]['order'];
} }

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* BudgetLimitEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
@@ -135,6 +156,7 @@ class BudgetLimitEnrichment implements EnrichmentInterface
/** @var BudgetLimit $budgetLimit */ /** @var BudgetLimit $budgetLimit */
foreach ($this->collection as $budgetLimit) { foreach ($this->collection as $budgetLimit) {
$id = (int)$budgetLimit->id; $id = (int)$budgetLimit->id;
$filteredExpenses = $this->filterToBudget($expenses, $budgetLimit->budget_id);
$filteredExpenses = $repository->sumCollectedExpenses($expenses, $budgetLimit->start_date, $budgetLimit->end_date, $budgetLimit->transactionCurrency, false); $filteredExpenses = $repository->sumCollectedExpenses($expenses, $budgetLimit->start_date, $budgetLimit->end_date, $budgetLimit->transactionCurrency, false);
$this->expenses[$id] = array_values($filteredExpenses); $this->expenses[$id] = array_values($filteredExpenses);
@@ -175,4 +197,11 @@ class BudgetLimitEnrichment implements EnrichmentInterface
}, $first); }, $first);
}, $this->expenses); }, $this->expenses);
} }
private function filterToBudget(array $expenses, int $budget): array
{
return array_filter($expenses, function (array $item) use ($budget) {
return (int)$item['budget_id'] === $budget;
});
}
} }

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* CategoryEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* PiggyBankEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
@@ -105,7 +126,7 @@ class PiggyBankEnrichment implements EnrichmentInterface
'pc_current_amount' => '0', 'pc_current_amount' => '0',
]; ];
} }
$this->amounts[$id][$accountId]['current_amount'] = bcadd($this->amounts[$id][$accountId]['current_amount'], $item->current_amount); $this->amounts[$id][$accountId]['current_amount'] = bcadd($this->amounts[$id][$accountId]['current_amount'], (string) $item->current_amount);
if (null !== $this->amounts[$id][$accountId]['pc_current_amount'] && null !== $item->native_current_amount) { if (null !== $this->amounts[$id][$accountId]['pc_current_amount'] && null !== $item->native_current_amount) {
$this->amounts[$id][$accountId]['pc_current_amount'] = bcadd($this->amounts[$id][$accountId]['pc_current_amount'], $item->native_current_amount); $this->amounts[$id][$accountId]['pc_current_amount'] = bcadd($this->amounts[$id][$accountId]['pc_current_amount'], $item->native_current_amount);
} }

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* PiggyBankEventEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* RecurringEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
@@ -38,7 +59,7 @@ class RecurringEnrichment implements EnrichmentInterface
private Collection $collection; private Collection $collection;
private array $ids = []; private array $ids = [];
private array $transactionTypeIds = []; private array $transactionTypeIds = [];
private array $transactionTypes = []; // private array $transactionTypes = [];
private array $notes = []; private array $notes = [];
private array $repetitions = []; private array $repetitions = [];
private array $transactions = []; private array $transactions = [];
@@ -110,11 +131,11 @@ class RecurringEnrichment implements EnrichmentInterface
$this->ids = array_unique($this->ids); $this->ids = array_unique($this->ids);
// collect transaction types. // collect transaction types.
$transactionTypes = TransactionType::whereIn('id', array_unique($this->transactionTypeIds))->get(); // $transactionTypes = TransactionType::whereIn('id', array_unique($this->transactionTypeIds))->get();
foreach ($transactionTypes as $transactionType) { // foreach ($transactionTypes as $transactionType) {
$id = (int)$transactionType->id; // $id = (int)$transactionType->id;
$this->transactionTypes[$id] = TransactionTypeEnum::from($transactionType->type); // $this->transactionTypes[$id] = TransactionTypeEnum::from($transactionType->type);
} // }
} }
private function collectRepetitions(): void private function collectRepetitions(): void
@@ -379,7 +400,7 @@ class RecurringEnrichment implements EnrichmentInterface
private function collectTransactionMetaData(): void private function collectTransactionMetaData(): void
{ {
$ids = array_keys($this->transactions); $ids = array_keys($this->transactions);
$meta = RecurrenceTransactionMeta::whereIn('rt_id', $ids)->get(); $meta = RecurrenceTransactionMeta::whereNull('deleted_at')->whereIn('rt_id', $ids)->get();
// other meta-data to be collected: // other meta-data to be collected:
$billIds = []; $billIds = [];
$piggyBankIds = []; $piggyBankIds = [];
@@ -389,8 +410,15 @@ class RecurringEnrichment implements EnrichmentInterface
foreach ($meta as $entry) { foreach ($meta as $entry) {
$id = (int)$entry->id; $id = (int)$entry->id;
$transactionId = (int)$entry->rt_id; $transactionId = (int)$entry->rt_id;
$recurrenceId = $this->recurrenceIds[$transactionId];
$name = (string)$entry->name; // this should refer to another array, were rtIds can be used to find the recurrence.
$recurrenceId = $this->recurrenceIds[$transactionId] ?? 0;
$name = (string)$entry->name ?? '';
if (0 === $recurrenceId) {
Log::error(sprintf('Could not find recurrence ID for recurrence transaction ID %d', $transactionId));
continue;
}
switch ($name) { switch ($name) {
default: default:

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* SubscriptionEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;
@@ -101,7 +122,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
// add object group if available // add object group if available
if (array_key_exists($id, $this->mappedObjects)) { if (array_key_exists($id, $this->mappedObjects)) {
$key = $this->mappedObjects[$id]; $key = $this->mappedObjects[$id];
$meta['object_group_id'] = $objectGroups[$key]['id']; $meta['object_group_id'] = (string) $objectGroups[$key]['id'];
$meta['object_group_title'] = $objectGroups[$key]['title']; $meta['object_group_title'] = $objectGroups[$key]['title'];
$meta['object_group_order'] = $objectGroups[$key]['order']; $meta['object_group_order'] = $objectGroups[$key]['order'];
} }
@@ -362,7 +383,7 @@ class SubscriptionEnrichment implements EnrichmentInterface
Log::debug(sprintf('[b] Last paid date is: %s', $return->format('Y-m-d'))); Log::debug(sprintf('[b] Last paid date is: %s', $return->format('Y-m-d')));
} }
} }
Log::debug(sprintf('[c] Last paid date is: "%s"', $return?->format('Y-m-d'))); // Log::debug(sprintf('[c] Last paid date is: "%s"', $return?->format('Y-m-d')));
return $return; return $return;
} }

View File

@@ -143,9 +143,9 @@ class TransactionGroupEnrichment implements EnrichmentInterface
continue; continue;
} }
if (in_array($name, $this->dateFields, true)) { if (in_array($name, $this->dateFields, true)) {
Log::debug(sprintf('Meta data for "%s" is a date : "%s"', $name, $data)); // Log::debug(sprintf('Meta data for "%s" is a date : "%s"', $name, $data));
$this->metaData[$entry['transaction_journal_id']][$name] = Carbon::parse($data, config('app.timezone')); $this->metaData[$entry['transaction_journal_id']][$name] = Carbon::parse($data, config('app.timezone'));
Log::debug(sprintf('Meta data for "%s" converts to: "%s"', $name, $this->metaData[$entry['transaction_journal_id']][$name]->toW3CString())); // Log::debug(sprintf('Meta data for "%s" converts to: "%s"', $name, $this->metaData[$entry['transaction_journal_id']][$name]->toW3CString()));
continue; continue;
} }

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* WebhookEnrichment.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\JsonApi\Enrichments; namespace FireflyIII\Support\JsonApi\Enrichments;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* RecalculatesAvailableBudgetsTrait.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\Observers; namespace FireflyIII\Support\Observers;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* ValidatesWebhooks.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\Request; namespace FireflyIII\Support\Request;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* PreferencesSingleton.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace FireflyIII\Support\Singleton; namespace FireflyIII\Support\Singleton;

View File

@@ -224,6 +224,7 @@ class Steam
*/ */
$request = clone $start; $request = clone $start;
$request->subDay()->endOfDay(); $request->subDay()->endOfDay();
Log::debug('Get first balance to start.');
Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String())); Log::debug(sprintf('finalAccountBalanceInRange: Call finalAccountBalance with date/time "%s"', $request->toIso8601String()));
$startBalance = $this->finalAccountBalance($account, $request); $startBalance = $this->finalAccountBalance($account, $request);
$primaryCurrency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); $primaryCurrency = Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup);
@@ -315,7 +316,7 @@ class Steam
Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance); Log::debug(sprintf('Updated entry [%s]', $carbonKey), $currentBalance);
} }
$cache->store($balances); $cache->store($balances);
Log::debug('End of method'); Log::debug('End of method finalAccountBalanceInRange');
return $balances; return $balances;
} }

View File

@@ -78,10 +78,6 @@ class AccountTransformer extends AbstractTransformer
$zoomLevel = $account->meta['location']['zoom_level'] ?? null; $zoomLevel = $account->meta['location']['zoom_level'] ?? null;
$order = $account->order; $order = $account->order;
// date (for balance etc.)
$date = $this->getDate();
$date->endOfDay();
// get primary currency as fallback: // get primary currency as fallback:
$currency = $this->primary; // assume primary currency $currency = $this->primary; // assume primary currency
if ($hasCurrencySettings) { if ($hasCurrencySettings) {
@@ -141,7 +137,7 @@ class AccountTransformer extends AbstractTransformer
'debt_amount' => $account->meta['balances']['debt_amount'], 'debt_amount' => $account->meta['balances']['debt_amount'],
'pc_debt_amount' => $account->meta['balances']['pc_debt_amount'], 'pc_debt_amount' => $account->meta['balances']['pc_debt_amount'],
'current_balance_date' => $date->toAtomString(), 'current_balance_date' => $account->meta['current_balance_date']->toAtomString(),
'notes' => $account->meta['notes'] ?? null, 'notes' => $account->meta['notes'] ?? null,
'monthly_payment_date' => $monthlyPaymentDate, 'monthly_payment_date' => $monthlyPaymentDate,
'credit_card_type' => $creditCardType, 'credit_card_type' => $creditCardType,

View File

@@ -3,6 +3,41 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## 6.4.0 - 2025-09-01
### Added
- [Issue 5532](https://github.com/firefly-iii/firefly-iii/issues/5532) (Asset prices and exchange rates) reported by @svozniuk
- [Discussion 10725](https://github.com/orgs/firefly-iii/discussions/10725) (New webhook triggers) started by @Billos. See the [documentation](https://docs.firefly-iii.org/how-to/firefly-iii/features/webhooks/).
### Changed
- Initial release.
### Fixed
- [Issue 10790](https://github.com/firefly-iii/firefly-iii/issues/10790) (Undefined variable $occurrences) reported by @senna1992
- [Issue 10791](https://github.com/firefly-iii/firefly-iii/issues/10791) (Clone and edit a transaction with a different currency doesn't clear the foreign transaction amount) reported by @jxtxzzw
- [Issue 10794](https://github.com/firefly-iii/firefly-iii/issues/10794) (Error with recurring transaction) reported by @MaximSN
- [Issue 10799](https://github.com/firefly-iii/firefly-iii/issues/10799) (Budget - "Left (per day)" not showing the correct value) reported by @GensHaze
- [Issue 10802](https://github.com/firefly-iii/firefly-iii/issues/10802) (Crash when trying to update a budget limit) reported by @Billos
- [Issue 10803](https://github.com/firefly-iii/firefly-iii/issues/10803) (Issue in /v1/budget-limits spent attribute) reported by @Billos
- [Issue 10804](https://github.com/firefly-iii/firefly-iii/issues/10804) (No notes information included in the "List all accounts" API call) reported by @gpampuro
- [Issue 10808](https://github.com/firefly-iii/firefly-iii/issues/10808) (cron job Error: Undefined variable $preference) reported by @MexerSam
- [Issue 10813](https://github.com/firefly-iii/firefly-iii/issues/10813) (Error "Argument #2 ($symbol) must be of type string" while try open subscriptions section) reported by @mrResident
- [Issue 10819](https://github.com/firefly-iii/firefly-iii/issues/10819) (Internal Server Error when trying to open piggy banks) reported by @noantiq
- [Issue 10820](https://github.com/firefly-iii/firefly-iii/issues/10820) (Unable to search date 1970-01-01 to apply rule.) reported by @Kage1
- [Issue 10824](https://github.com/firefly-iii/firefly-iii/issues/10824) (Converting withdrawal to transfer to account in different currency doesn't allow setting correct currencies) reported by @avee87
### API
- [Issue 8345](https://github.com/firefly-iii/firefly-iii/issues/8345) (API: Distinguish spent & earned at `/v2/chart/category/dashboard` (or future `v2/categories`)) reported by @dreautall
- [Issue 10804](https://github.com/firefly-iii/firefly-iii/issues/10804) (No notes information included in the "List all accounts" API call) reported by @gpampuro
- [Issue 10806](https://github.com/firefly-iii/firefly-iii/issues/10806) (API: `/v1/chart/balance/balance` has undocumented `period` parameter) reported by @dreautall
- [Issue 10807](https://github.com/firefly-iii/firefly-iii/issues/10807) (API: `/v1/bills` field `object_group_id` returns int, should be string) reported by @dreautall
- [Issue 10815](https://github.com/firefly-iii/firefly-iii/issues/10815) (API: `/v1/accounts` balance is off by a day) reported by @dreautall
- [Issue 10827](https://github.com/firefly-iii/firefly-iii/issues/10827) (Trigger Recurrence by API) reported by @MexerSam
## 6.3.2 - 2025-08-20 ## 6.3.2 - 2025-08-20
### Fixed ### Fixed

324
composer.lock generated
View File

@@ -1244,22 +1244,22 @@
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.9.3", "version": "7.10.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/guzzle.git", "url": "https://github.com/guzzle/guzzle.git",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"guzzlehttp/promises": "^1.5.3 || ^2.0.3", "guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.7.0", "guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0", "php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0", "psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0" "symfony/deprecation-contracts": "^2.2 || ^3.0"
@@ -1350,7 +1350,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/guzzle/issues", "issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.9.3" "source": "https://github.com/guzzle/guzzle/tree/7.10.0"
}, },
"funding": [ "funding": [
{ {
@@ -1366,20 +1366,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-03-27T13:37:11+00:00" "time": "2025-08-23T22:36:01+00:00"
}, },
{ {
"name": "guzzlehttp/promises", "name": "guzzlehttp/promises",
"version": "2.2.0", "version": "2.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/promises.git", "url": "https://github.com/guzzle/promises.git",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" "reference": "481557b130ef3790cf82b713667b43030dc9c957"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", "reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1387,7 +1387,7 @@
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.39 || ^9.6.20" "phpunit/phpunit": "^8.5.44 || ^9.6.25"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@@ -1433,7 +1433,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/promises/issues", "issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.2.0" "source": "https://github.com/guzzle/promises/tree/2.3.0"
}, },
"funding": [ "funding": [
{ {
@@ -1449,20 +1449,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-03-27T13:27:01+00:00" "time": "2025-08-22T14:34:08+00:00"
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.7.1", "version": "2.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" "reference": "21dc724a0583619cd1652f673303492272778051"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", "reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1478,7 +1478,7 @@
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0", "http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.39 || ^9.6.20" "phpunit/phpunit": "^8.5.44 || ^9.6.25"
}, },
"suggest": { "suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@@ -1549,7 +1549,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.7.1" "source": "https://github.com/guzzle/psr7/tree/2.8.0"
}, },
"funding": [ "funding": [
{ {
@@ -1565,20 +1565,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-03-27T12:30:47+00:00" "time": "2025-08-23T21:21:41+00:00"
}, },
{ {
"name": "guzzlehttp/uri-template", "name": "guzzlehttp/uri-template",
"version": "v1.0.4", "version": "v1.0.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/uri-template.git", "url": "https://github.com/guzzle/uri-template.git",
"reference": "30e286560c137526eccd4ce21b2de477ab0676d2" "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1",
"reference": "30e286560c137526eccd4ce21b2de477ab0676d2", "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1587,7 +1587,7 @@
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.36 || ^9.6.15", "phpunit/phpunit": "^8.5.44 || ^9.6.25",
"uri-template/tests": "1.0.0" "uri-template/tests": "1.0.0"
}, },
"type": "library", "type": "library",
@@ -1635,7 +1635,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/uri-template/issues", "issues": "https://github.com/guzzle/uri-template/issues",
"source": "https://github.com/guzzle/uri-template/tree/v1.0.4" "source": "https://github.com/guzzle/uri-template/tree/v1.0.5"
}, },
"funding": [ "funding": [
{ {
@@ -1651,7 +1651,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-02-03T10:55:03+00:00" "time": "2025-08-22T14:27:06+00:00"
}, },
{ {
"name": "jc5/google2fa-laravel", "name": "jc5/google2fa-laravel",
@@ -1878,16 +1878,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v12.25.0", "version": "v12.26.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "2ee2ba94ae60efd24c7a787cbb1a2f82f714bb20" "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/2ee2ba94ae60efd24c7a787cbb1a2f82f714bb20", "url": "https://api.github.com/repos/laravel/framework/zipball/085a367a32ba86fcfa647bfc796098ae6f795b09",
"reference": "2ee2ba94ae60efd24c7a787cbb1a2f82f714bb20", "reference": "085a367a32ba86fcfa647bfc796098ae6f795b09",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1927,9 +1927,9 @@
"symfony/http-kernel": "^7.2.0", "symfony/http-kernel": "^7.2.0",
"symfony/mailer": "^7.2.0", "symfony/mailer": "^7.2.0",
"symfony/mime": "^7.2.0", "symfony/mime": "^7.2.0",
"symfony/polyfill-php83": "^1.31", "symfony/polyfill-php83": "^1.33",
"symfony/polyfill-php84": "^1.31", "symfony/polyfill-php84": "^1.33",
"symfony/polyfill-php85": "^1.31", "symfony/polyfill-php85": "^1.33",
"symfony/process": "^7.2.0", "symfony/process": "^7.2.0",
"symfony/routing": "^7.2.0", "symfony/routing": "^7.2.0",
"symfony/uid": "^7.2.0", "symfony/uid": "^7.2.0",
@@ -1997,7 +1997,7 @@
"league/flysystem-read-only": "^3.25.1", "league/flysystem-read-only": "^3.25.1",
"league/flysystem-sftp-v3": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10", "mockery/mockery": "^1.6.10",
"orchestra/testbench-core": "^10.6.0", "orchestra/testbench-core": "^10.6.3",
"pda/pheanstalk": "^5.0.6|^7.0.0", "pda/pheanstalk": "^5.0.6|^7.0.0",
"php-http/discovery": "^1.15", "php-http/discovery": "^1.15",
"phpstan/phpstan": "^2.0", "phpstan/phpstan": "^2.0",
@@ -2091,7 +2091,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2025-08-18T22:20:52+00:00" "time": "2025-08-29T14:15:53+00:00"
}, },
{ {
"name": "laravel/passport", "name": "laravel/passport",
@@ -5827,23 +5827,23 @@
}, },
{ {
"name": "rcrowe/twigbridge", "name": "rcrowe/twigbridge",
"version": "v0.14.5", "version": "v0.14.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/rcrowe/TwigBridge.git", "url": "https://github.com/rcrowe/TwigBridge.git",
"reference": "88c83c9658a2c029c64ec80dd8a15d5a67433ac4" "reference": "0798ee4b5e5b943d0200850acaa87ccd82e2fe45"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/88c83c9658a2c029c64ec80dd8a15d5a67433ac4", "url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/0798ee4b5e5b943d0200850acaa87ccd82e2fe45",
"reference": "88c83c9658a2c029c64ec80dd8a15d5a67433ac4", "reference": "0798ee4b5e5b943d0200850acaa87ccd82e2fe45",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/support": "^9|^10|^11|^12", "illuminate/support": "^9|^10|^11|^12",
"illuminate/view": "^9|^10|^11|^12", "illuminate/view": "^9|^10|^11|^12",
"php": "^8.1", "php": "^8.1",
"twig/twig": "~3.12" "twig/twig": "~3.21"
}, },
"require-dev": { "require-dev": {
"ext-json": "*", "ext-json": "*",
@@ -5893,22 +5893,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/rcrowe/TwigBridge/issues", "issues": "https://github.com/rcrowe/TwigBridge/issues",
"source": "https://github.com/rcrowe/TwigBridge/tree/v0.14.5" "source": "https://github.com/rcrowe/TwigBridge/tree/v0.14.6"
}, },
"time": "2025-04-18T18:48:57+00:00" "time": "2025-08-20T11:25:49+00:00"
}, },
{ {
"name": "spatie/backtrace", "name": "spatie/backtrace",
"version": "1.7.4", "version": "1.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/spatie/backtrace.git", "url": "https://github.com/spatie/backtrace.git",
"reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe" "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/spatie/backtrace/zipball/cd37a49fce7137359ac30ecc44ef3e16404cccbe", "url": "https://api.github.com/repos/spatie/backtrace/zipball/8c0f16a59ae35ec8c62d85c3c17585158f430110",
"reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe", "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -5946,7 +5946,8 @@
"spatie" "spatie"
], ],
"support": { "support": {
"source": "https://github.com/spatie/backtrace/tree/1.7.4" "issues": "https://github.com/spatie/backtrace/issues",
"source": "https://github.com/spatie/backtrace/tree/1.8.1"
}, },
"funding": [ "funding": [
{ {
@@ -5958,7 +5959,7 @@
"type": "other" "type": "other"
} }
], ],
"time": "2025-05-08T15:41:09+00:00" "time": "2025-08-26T08:22:30+00:00"
}, },
{ {
"name": "spatie/error-solutions", "name": "spatie/error-solutions",
@@ -6663,16 +6664,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1" "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1", "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1", "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -6737,7 +6738,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v7.3.2" "source": "https://github.com/symfony/console/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -6757,7 +6758,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-30T17:13:41+00:00" "time": "2025-08-25T06:35:40+00:00"
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
@@ -6974,16 +6975,16 @@
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v7.3.0", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
"reference": "497f73ac996a598c92409b44ac43b6690c4f666d" "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
"reference": "497f73ac996a598c92409b44ac43b6690c4f666d", "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -7034,7 +7035,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -7045,12 +7046,16 @@
"url": "https://github.com/fabpot", "url": "https://github.com/fabpot",
"type": "github" "type": "github"
}, },
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{ {
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-04-22T09:11:45+00:00" "time": "2025-08-13T11:49:31+00:00"
}, },
{ {
"name": "symfony/event-dispatcher-contracts", "name": "symfony/event-dispatcher-contracts",
@@ -7266,16 +7271,16 @@
}, },
{ {
"name": "symfony/http-client", "name": "symfony/http-client",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-client.git", "url": "https://github.com/symfony/http-client.git",
"reference": "1c064a0c67749923483216b081066642751cc2c7" "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7", "url": "https://api.github.com/repos/symfony/http-client/zipball/333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019",
"reference": "1c064a0c67749923483216b081066642751cc2c7", "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -7283,6 +7288,7 @@
"psr/log": "^1|^2|^3", "psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3", "symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "~3.4.4|^3.5.2", "symfony/http-client-contracts": "~3.4.4|^3.5.2",
"symfony/polyfill-php83": "^1.29",
"symfony/service-contracts": "^2.5|^3" "symfony/service-contracts": "^2.5|^3"
}, },
"conflict": { "conflict": {
@@ -7341,7 +7347,7 @@
"http" "http"
], ],
"support": { "support": {
"source": "https://github.com/symfony/http-client/tree/v7.3.2" "source": "https://github.com/symfony/http-client/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -7361,7 +7367,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-15T11:36:08+00:00" "time": "2025-08-27T07:45:05+00:00"
}, },
{ {
"name": "symfony/http-client-contracts", "name": "symfony/http-client-contracts",
@@ -7443,16 +7449,16 @@
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-foundation.git", "url": "https://github.com/symfony/http-foundation.git",
"reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6" "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/6877c122b3a6cc3695849622720054f6e6fa5fa6", "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00",
"reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6", "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -7502,7 +7508,7 @@
"description": "Defines an object-oriented layer for the HTTP specification", "description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.3.2" "source": "https://github.com/symfony/http-foundation/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -7522,20 +7528,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-10T08:47:49+00:00" "time": "2025-08-20T08:04:18+00:00"
}, },
{ {
"name": "symfony/http-kernel", "name": "symfony/http-kernel",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-kernel.git", "url": "https://github.com/symfony/http-kernel.git",
"reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c" "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/6ecc895559ec0097e221ed2fd5eb44d5fede083c", "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b",
"reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c", "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -7620,7 +7626,7 @@
"description": "Provides a structured process for converting a Request into a Response", "description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.3.2" "source": "https://github.com/symfony/http-kernel/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -7640,20 +7646,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-31T10:45:04+00:00" "time": "2025-08-29T08:23:45+00:00"
}, },
{ {
"name": "symfony/mailer", "name": "symfony/mailer",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mailer.git", "url": "https://github.com/symfony/mailer.git",
"reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b" "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/d43e84d9522345f96ad6283d5dfccc8c1cfc299b", "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575",
"reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b", "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -7704,7 +7710,7 @@
"description": "Helps sending emails", "description": "Helps sending emails",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/mailer/tree/v7.3.2" "source": "https://github.com/symfony/mailer/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -7724,7 +7730,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-15T11:36:08+00:00" "time": "2025-08-13T11:49:31+00:00"
}, },
{ {
"name": "symfony/mailgun-mailer", "name": "symfony/mailgun-mailer",
@@ -7885,16 +7891,16 @@
}, },
{ {
"name": "symfony/options-resolver", "name": "symfony/options-resolver",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/options-resolver.git", "url": "https://github.com/symfony/options-resolver.git",
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37" "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37", "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37", "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -7932,7 +7938,7 @@
"options" "options"
], ],
"support": { "support": {
"source": "https://github.com/symfony/options-resolver/tree/v7.3.2" "source": "https://github.com/symfony/options-resolver/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -7952,7 +7958,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-15T11:36:08+00:00" "time": "2025-08-05T10:16:07+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
@@ -8785,16 +8791,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v7.3.0", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" "reference": "32241012d521e2e8a9d713adb0812bb773b907f1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1",
"reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "reference": "32241012d521e2e8a9d713adb0812bb773b907f1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -8826,7 +8832,7 @@
"description": "Executes commands in sub-processes", "description": "Executes commands in sub-processes",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/process/tree/v7.3.0" "source": "https://github.com/symfony/process/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -8837,12 +8843,16 @@
"url": "https://github.com/fabpot", "url": "https://github.com/fabpot",
"type": "github" "type": "github"
}, },
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{ {
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-04-17T09:11:12+00:00" "time": "2025-08-18T09:42:54+00:00"
}, },
{ {
"name": "symfony/psr-http-message-bridge", "name": "symfony/psr-http-message-bridge",
@@ -9097,16 +9107,16 @@
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9164,7 +9174,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v7.3.2" "source": "https://github.com/symfony/string/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -9184,20 +9194,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-10T08:47:49+00:00" "time": "2025-08-25T06:35:40+00:00"
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation.git", "url": "https://github.com/symfony/translation.git",
"reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90" "reference": "e0837b4cbcef63c754d89a4806575cada743a38d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/81b48f4daa96272efcce9c7a6c4b58e629df3c90", "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d",
"reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90", "reference": "e0837b4cbcef63c754d89a4806575cada743a38d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9264,7 +9274,7 @@
"description": "Provides tools to internationalize your application", "description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/translation/tree/v7.3.2" "source": "https://github.com/symfony/translation/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -9284,7 +9294,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-30T17:31:46+00:00" "time": "2025-08-01T21:02:37+00:00"
}, },
{ {
"name": "symfony/translation-contracts", "name": "symfony/translation-contracts",
@@ -9440,16 +9450,16 @@
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "53205bea27450dc5c65377518b3275e126d45e75" "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f",
"reference": "53205bea27450dc5c65377518b3275e126d45e75", "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9503,7 +9513,7 @@
"dump" "dump"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.3.2" "source": "https://github.com/symfony/var-dumper/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -9523,20 +9533,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-29T20:02:46+00:00" "time": "2025-08-13T11:49:31+00:00"
}, },
{ {
"name": "symfony/var-exporter", "name": "symfony/var-exporter",
"version": "v7.3.2", "version": "v7.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-exporter.git", "url": "https://github.com/symfony/var-exporter.git",
"reference": "05b3e90654c097817325d6abd284f7938b05f467" "reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/05b3e90654c097817325d6abd284f7938b05f467", "url": "https://api.github.com/repos/symfony/var-exporter/zipball/d4dfcd2a822cbedd7612eb6fbd260e46f87b7137",
"reference": "05b3e90654c097817325d6abd284f7938b05f467", "reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9584,7 +9594,7 @@
"serialize" "serialize"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-exporter/tree/v7.3.2" "source": "https://github.com/symfony/var-exporter/tree/v7.3.3"
}, },
"funding": [ "funding": [
{ {
@@ -9604,7 +9614,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-10T08:47:49+00:00" "time": "2025-08-18T13:10:53+00:00"
}, },
{ {
"name": "thecodingmachine/safe", "name": "thecodingmachine/safe",
@@ -10726,16 +10736,16 @@
}, },
{ {
"name": "larastan/larastan", "name": "larastan/larastan",
"version": "v3.6.0", "version": "v3.6.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/larastan/larastan.git", "url": "https://github.com/larastan/larastan.git",
"reference": "6431d010dd383a9279eb8874a76ddb571738564a" "reference": "3c223047e374befd1b64959784685d6ecccf66aa"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/6431d010dd383a9279eb8874a76ddb571738564a", "url": "https://api.github.com/repos/larastan/larastan/zipball/3c223047e374befd1b64959784685d6ecccf66aa",
"reference": "6431d010dd383a9279eb8874a76ddb571738564a", "reference": "3c223047e374befd1b64959784685d6ecccf66aa",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10803,7 +10813,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/larastan/larastan/issues", "issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v3.6.0" "source": "https://github.com/larastan/larastan/tree/v3.6.1"
}, },
"funding": [ "funding": [
{ {
@@ -10811,7 +10821,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-07-11T06:52:52+00:00" "time": "2025-08-25T07:24:56+00:00"
}, },
{ {
"name": "laravel-json-api/testing", "name": "laravel-json-api/testing",
@@ -11473,34 +11483,34 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "12.3.2", "version": "12.3.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "086553c5b2e0e1e20293d782d788ab768202b621" "reference": "96dc0466673e215bf5536301039017f03cd45c6b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/086553c5b2e0e1e20293d782d788ab768202b621", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/96dc0466673e215bf5536301039017f03cd45c6b",
"reference": "086553c5b2e0e1e20293d782d788ab768202b621", "reference": "96dc0466673e215bf5536301039017f03cd45c6b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-libxml": "*", "ext-libxml": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"nikic/php-parser": "^5.4.0", "nikic/php-parser": "^5.6.1",
"php": ">=8.3", "php": ">=8.3",
"phpunit/php-file-iterator": "^6.0", "phpunit/php-file-iterator": "^6.0",
"phpunit/php-text-template": "^5.0", "phpunit/php-text-template": "^5.0",
"sebastian/complexity": "^5.0", "sebastian/complexity": "^5.0",
"sebastian/environment": "^8.0", "sebastian/environment": "^8.0.3",
"sebastian/lines-of-code": "^4.0", "sebastian/lines-of-code": "^4.0",
"sebastian/version": "^6.0", "sebastian/version": "^6.0",
"theseer/tokenizer": "^1.2.3" "theseer/tokenizer": "^1.2.3"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^12.1" "phpunit/phpunit": "^12.3.7"
}, },
"suggest": { "suggest": {
"ext-pcov": "PHP extension that provides line coverage", "ext-pcov": "PHP extension that provides line coverage",
@@ -11538,7 +11548,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.2" "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.5"
}, },
"funding": [ "funding": [
{ {
@@ -11558,7 +11568,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-07-29T06:19:24+00:00" "time": "2025-09-01T08:07:42+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@@ -11807,16 +11817,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "12.3.6", "version": "12.3.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "a2cab3224f687150ac2f3cc13d99b64ba1e1d088" "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2cab3224f687150ac2f3cc13d99b64ba1e1d088", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b8fa997c49682979ad6bfaa0d7fb25f54954965e",
"reference": "a2cab3224f687150ac2f3cc13d99b64ba1e1d088", "reference": "b8fa997c49682979ad6bfaa0d7fb25f54954965e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -11830,7 +11840,7 @@
"phar-io/manifest": "^2.0.4", "phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1", "phar-io/version": "^3.2.1",
"php": ">=8.3", "php": ">=8.3",
"phpunit/php-code-coverage": "^12.3.2", "phpunit/php-code-coverage": "^12.3.3",
"phpunit/php-file-iterator": "^6.0.0", "phpunit/php-file-iterator": "^6.0.0",
"phpunit/php-invoker": "^6.0.0", "phpunit/php-invoker": "^6.0.0",
"phpunit/php-text-template": "^5.0.0", "phpunit/php-text-template": "^5.0.0",
@@ -11884,7 +11894,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.6" "source": "https://github.com/sebastianbergmann/phpunit/tree/12.3.7"
}, },
"funding": [ "funding": [
{ {
@@ -11908,7 +11918,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-08-20T14:43:23+00:00" "time": "2025-08-28T05:15:46+00:00"
}, },
{ {
"name": "rector/rector", "name": "rector/rector",
@@ -12400,16 +12410,16 @@
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
"version": "8.0.0", "version": "8.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git", "url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc" "reference": "ef1377171613d09edd25b7816f05be8313f9115d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/570a2aeb26d40f057af686d63c4e99b075fb6cbc", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d",
"reference": "570a2aeb26d40f057af686d63c4e99b075fb6cbc", "reference": "ef1377171613d09edd25b7816f05be8313f9115d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -12450,15 +12460,27 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues", "issues": "https://github.com/sebastianbergmann/global-state/issues",
"security": "https://github.com/sebastianbergmann/global-state/security/policy", "security": "https://github.com/sebastianbergmann/global-state/security/policy",
"source": "https://github.com/sebastianbergmann/global-state/tree/8.0.0" "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2"
}, },
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
"type": "github" "type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
"type": "tidelift"
} }
], ],
"time": "2025-02-07T04:56:59+00:00" "time": "2025-08-29T11:29:25+00:00"
}, },
{ {
"name": "sebastian/lines-of-code", "name": "sebastian/lines-of-code",

View File

@@ -78,8 +78,8 @@ return [
'running_balance_column' => env('USE_RUNNING_BALANCE', false), 'running_balance_column' => env('USE_RUNNING_BALANCE', false),
// see cer.php for exchange rates feature flag. // see cer.php for exchange rates feature flag.
], ],
'version' => 'develop/2025-08-22', 'version' => 'develop/2025-09-01',
'build_time' => 1755838953, 'build_time' => 1756727696,
'api_version' => '2.1.0', // field is no longer used. 'api_version' => '2.1.0', // field is no longer used.
'db_version' => 26, 'db_version' => 26,

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* webhooks.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
// this is hard coded, which is unfortunate. // this is hard coded, which is unfortunate.

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* 2025_07_10_065736_rename_tag_mode.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* 2025_08_19_180459_create_webhook_details_tables.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* WebhookDataSeeder.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace Database\Seeders; namespace Database\Seeders;
use FireflyIII\Enums\WebhookTrigger; use FireflyIII\Enums\WebhookTrigger;

297
package-lock.json generated
View File

@@ -2592,9 +2592,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz",
"integrity": "sha512-lTahKRJip0knffA/GTNFJMrToD+CM+JJ+Qt5kjzBK/sFQ0EWqfKW3AYQSlZXN98tX0lx66083U9JYIMioMMK7g==", "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -2606,9 +2606,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz",
"integrity": "sha512-uqxkb3RJLzlBbh/bbNQ4r7YpSZnjgMgyoEOY7Fy6GCbelkDSAzeiogxMG9TfLsBbqmGsdDObo3mzGqa8hps4MA==", "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2620,9 +2620,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz",
"integrity": "sha512-tV6reObmxBDS4DDyLzTDIpymthNlxrLBGAoQx6m2a7eifSNEZdkXQl1PE4ZjCkEDPVgNXSzND/k9AQ3mC4IOEQ==", "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2634,9 +2634,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz",
"integrity": "sha512-XuJRPTnMk1lwsSnS3vYyVMu4x/+WIw1MMSiqj5C4j3QOWsMzbJEK90zG+SWV1h0B1ABGCQ0UZUjti+TQK35uHQ==", "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2648,9 +2648,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz",
"integrity": "sha512-79BAm8Ag/tmJ5asCqgOXsb3WY28Rdd5Lxj8ONiQzWzy9LvWORd5qVuOnjlqiWWZJw+dWewEktZb5yiM1DLLaHw==", "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2662,9 +2662,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz",
"integrity": "sha512-OQ2/ZDGzdOOlyfqBiip0ZX/jVFekzYrGtUsqAfLDbWy0jh1PUU18+jYp8UMpqhly5ltEqotc2miLngf9FPSWIA==", "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2676,9 +2676,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz",
"integrity": "sha512-HZZBXJL1udxlCVvoVadstgiU26seKkHbbAMLg7680gAcMnRNP9SAwTMVet02ANA94kXEI2VhBnXs4e5nf7KG2A==", "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -2690,9 +2690,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz",
"integrity": "sha512-sZ5p2I9UA7T950JmuZ3pgdKA6+RTBr+0FpK427ExW0t7n+QwYOcmDTK/aRlzoBrWyTpJNlS3kacgSlSTUg6P/Q==", "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -2704,9 +2704,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz",
"integrity": "sha512-3hBFoqPyU89Dyf1mQRXCdpc6qC6At3LV6jbbIOZd72jcx7xNk3aAp+EjzAtN6sDlmHFzsDJN5yeUySvorWeRXA==", "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2718,9 +2718,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz",
"integrity": "sha512-49J4FnMHfGodJWPw73Ve+/hsPjZgcXQGkmqBGZFvltzBKRS+cvMiWNLadOMXKGnYRhs1ToTGM0sItKISoSGUNA==", "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2732,9 +2732,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz",
"integrity": "sha512-4yYU8p7AneEpQkRX03pbpLmE21z5JNys16F1BZBZg5fP9rIlb0TkeQjn5du5w4agConCCEoYIG57sNxjryHEGg==", "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -2746,9 +2746,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-ppc64-gnu": { "node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz",
"integrity": "sha512-fAiq+J28l2YMWgC39jz/zPi2jqc0y3GSRo1yyxlBHt6UN0yYgnegHSRPa3pnHS5amT/efXQrm0ug5+aNEu9UuQ==", "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -2760,9 +2760,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz",
"integrity": "sha512-daoT0PMENNdjVYYU9xec30Y2prb1AbEIbb64sqkcQcSaR0zYuKkoPuhIztfxuqN82KYCKKrj+tQe4Gi7OSm1ow==", "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -2774,9 +2774,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-musl": { "node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz",
"integrity": "sha512-JNyXaAhWtdzfXu5pUcHAuNwGQKevR+6z/poYQKVW+pLaYOj9G1meYc57/1Xv2u4uTxfu9qEWmNTjv/H/EpAisw==", "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -2788,9 +2788,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz",
"integrity": "sha512-U/CHbqKSwEQyZXjCpY43/GLYcTVKEXeRHw0rMBJP7fP3x6WpYG4LTJWR3ic6TeYKX6ZK7mrhltP4ppolyVhLVQ==", "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -2802,9 +2802,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz",
"integrity": "sha512-uTLEakjxOTElfeZIGWkC34u2auLHB1AYS6wBjPGI00bWdxdLcCzK5awjs25YXpqB9lS8S0vbO0t9ZcBeNibA7g==", "integrity": "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2816,9 +2816,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz",
"integrity": "sha512-Ft+d/9DXs30BK7CHCTX11FtQGHUdpNDLJW0HHLign4lgMgBcPFN3NkdIXhC5r9iwsMwYreBBc4Rho5ieOmKNVQ==", "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2829,10 +2829,24 @@
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz",
"integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz",
"integrity": "sha512-N9X5WqGYzZnjGAFsKSfYFtAShYjwOmFJoWbLg3dYixZOZqU7hdMq+/xyS14zKLhFhZDhP9VfkzQnsdk0ZDS9IA==", "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2844,9 +2858,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz",
"integrity": "sha512-O+KcfeCORZADEY8oQJk4HK8wtEOCRE4MdOkb8qGZQNun3jzmj2nmhV/B/ZaaZOkPmJyvm/gW9n0gsB4eRa1eiQ==", "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -2858,9 +2872,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.47.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz",
"integrity": "sha512-CpKnYa8eHthJa3c+C38v/E+/KZyF1Jdh2Cz3DyKZqEWYgrM1IHFArXNWvBLPQCKUEsAqqKX27tTqVEFbDNUcOA==", "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -3256,42 +3270,42 @@
} }
}, },
"node_modules/@vue/compiler-core": { "node_modules/@vue/compiler-core": {
"version": "3.5.19", "version": "3.5.20",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.19.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz",
"integrity": "sha512-/afpyvlkrSNYbPo94Qu8GtIOWS+g5TRdOvs6XZNw6pWQQmj5pBgSZvEPOIZlqWq0YvoUhDDQaQ2TnzuJdOV4hA==", "integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.28.3", "@babel/parser": "^7.28.3",
"@vue/shared": "3.5.19", "@vue/shared": "3.5.20",
"entities": "^4.5.0", "entities": "^4.5.0",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
} }
}, },
"node_modules/@vue/compiler-dom": { "node_modules/@vue/compiler-dom": {
"version": "3.5.19", "version": "3.5.20",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.19.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz",
"integrity": "sha512-Drs6rPHQZx/pN9S6ml3Z3K/TWCIRPvzG2B/o5kFK9X0MNHt8/E+38tiRfojufrYBfA6FQUFB2qBBRXlcSXWtOA==", "integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-core": "3.5.19", "@vue/compiler-core": "3.5.20",
"@vue/shared": "3.5.19" "@vue/shared": "3.5.20"
} }
}, },
"node_modules/@vue/compiler-sfc": { "node_modules/@vue/compiler-sfc": {
"version": "3.5.19", "version": "3.5.20",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.19.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.20.tgz",
"integrity": "sha512-YWCm1CYaJ+2RvNmhCwI7t3I3nU+hOrWGWMsn+Z/kmm1jy5iinnVtlmkiZwbLlbV1SRizX7vHsc0/bG5dj0zRTg==", "integrity": "sha512-SFcxapQc0/feWiSBfkGsa1v4DOrnMAQSYuvDMpEaxbpH5dKbnEM5KobSNSgU+1MbHCl+9ftm7oQWxvwDB6iBfw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.28.3", "@babel/parser": "^7.28.3",
"@vue/compiler-core": "3.5.19", "@vue/compiler-core": "3.5.20",
"@vue/compiler-dom": "3.5.19", "@vue/compiler-dom": "3.5.20",
"@vue/compiler-ssr": "3.5.19", "@vue/compiler-ssr": "3.5.20",
"@vue/shared": "3.5.19", "@vue/shared": "3.5.20",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"magic-string": "^0.30.17", "magic-string": "^0.30.17",
"postcss": "^8.5.6", "postcss": "^8.5.6",
@@ -3299,14 +3313,14 @@
} }
}, },
"node_modules/@vue/compiler-ssr": { "node_modules/@vue/compiler-ssr": {
"version": "3.5.19", "version": "3.5.20",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.19.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.20.tgz",
"integrity": "sha512-/wx0VZtkWOPdiQLWPeQeqpHWR/LuNC7bHfSX7OayBTtUy8wur6vT6EQIX6Et86aED6J+y8tTw43qo2uoqGg5sw==", "integrity": "sha512-RSl5XAMc5YFUXpDQi+UQDdVjH9FnEpLDHIALg5J0ITHxkEzJ8uQLlo7CIbjPYqmZtt6w0TsIPbo1izYXwDG7JA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.19", "@vue/compiler-dom": "3.5.20",
"@vue/shared": "3.5.19" "@vue/shared": "3.5.20"
} }
}, },
"node_modules/@vue/component-compiler-utils": { "node_modules/@vue/component-compiler-utils": {
@@ -3388,9 +3402,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vue/shared": { "node_modules/@vue/shared": {
"version": "3.5.19", "version": "3.5.20",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.19.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz",
"integrity": "sha512-IhXCOn08wgKrLQxRFKKlSacWg4Goi1BolrdEeLYn6tgHjJNXVrWJ5nzoxZqNwl5p88aLlQ8LOaoMa3AYvaKJ/Q==", "integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -4170,9 +4184,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/bootstrap": { "node_modules/bootstrap": {
"version": "5.3.7", "version": "5.3.8",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
"integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@@ -4326,9 +4340,9 @@
} }
}, },
"node_modules/browserslist": { "node_modules/browserslist": {
"version": "4.25.3", "version": "4.25.4",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz",
"integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==", "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -4346,8 +4360,8 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001735", "caniuse-lite": "^1.0.30001737",
"electron-to-chromium": "^1.5.204", "electron-to-chromium": "^1.5.211",
"node-releases": "^2.0.19", "node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.3" "update-browserslist-db": "^1.1.3"
}, },
@@ -4486,9 +4500,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001736", "version": "1.0.30001739",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001736.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz",
"integrity": "sha512-ImpN5gLEY8gWeqfLUyEF4b7mYWcYoR2Si1VhnrbM4JizRFmfGaAQ12PhNykq6nvI4XvKLrsp8Xde74D5phJOSw==", "integrity": "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -5700,9 +5714,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.208", "version": "1.5.211",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.208.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz",
"integrity": "sha512-ozZyibehoe7tOhNaf16lKmljVf+3npZcJIEbJRVftVsmAg5TeA1mGS9dVCZzOwr2xT7xK15V0p7+GZqSPgkuPg==", "integrity": "sha512-IGBvimJkotaLzFnwIVgW9/UD/AOJ2tByUmeOrtqBfACSbAw5b1G0XpvdaieKyc7ULmbwXVx+4e4Be8pOPBrYkw==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@@ -6159,9 +6173,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-uri": { "node_modules/fast-uri": {
"version": "3.0.6", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -7052,9 +7066,9 @@
} }
}, },
"node_modules/i18next": { "node_modules/i18next": {
"version": "25.4.0", "version": "25.4.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.4.0.tgz", "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.4.2.tgz",
"integrity": "sha512-UH5aiamXsO3cfrZFurCHiB6YSs3C+s+XY9UaJllMMSbmaoXILxFgqDEZu4NbfzJFjmUo3BNMa++Rjkr3ofjfLw==", "integrity": "sha512-gD4T25a6ovNXsfXY1TwHXXXLnD/K2t99jyYMCSimSCBnBRJVQr5j+VAaU83RJCPzrTGhVQ6dqIga66xO2rtd5g==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@@ -7818,9 +7832,9 @@
} }
}, },
"node_modules/laravel-vite-plugin": { "node_modules/laravel-vite-plugin": {
"version": "2.0.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.0.0.tgz", "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.0.1.tgz",
"integrity": "sha512-pnaKHInJgiWpG/g+LmaISHl7D/1s5wnOXnrGiBdt4NOs+tYZRw0v/ZANELGX2/dGgHyEzO+iZ6x4idpoK04z/Q==", "integrity": "sha512-zQuvzWfUKQu9oNVi1o0RZAJCwhGsdhx4NEOyrVQwJHaWDseGP9tl7XUPLY2T8Cj6+IrZ6lmyxlR1KC8unf3RLA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -10123,9 +10137,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.47.1", "version": "4.50.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.47.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.0.tgz",
"integrity": "sha512-iasGAQoZ5dWDzULEUX3jiW0oB1qyFOepSyDyoU6S/OhVlDIwj5knI5QBa5RRQ0sK7OE0v+8VIi2JuV+G+3tfNg==", "integrity": "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -10139,26 +10153,27 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.47.1", "@rollup/rollup-android-arm-eabi": "4.50.0",
"@rollup/rollup-android-arm64": "4.47.1", "@rollup/rollup-android-arm64": "4.50.0",
"@rollup/rollup-darwin-arm64": "4.47.1", "@rollup/rollup-darwin-arm64": "4.50.0",
"@rollup/rollup-darwin-x64": "4.47.1", "@rollup/rollup-darwin-x64": "4.50.0",
"@rollup/rollup-freebsd-arm64": "4.47.1", "@rollup/rollup-freebsd-arm64": "4.50.0",
"@rollup/rollup-freebsd-x64": "4.47.1", "@rollup/rollup-freebsd-x64": "4.50.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.47.1", "@rollup/rollup-linux-arm-gnueabihf": "4.50.0",
"@rollup/rollup-linux-arm-musleabihf": "4.47.1", "@rollup/rollup-linux-arm-musleabihf": "4.50.0",
"@rollup/rollup-linux-arm64-gnu": "4.47.1", "@rollup/rollup-linux-arm64-gnu": "4.50.0",
"@rollup/rollup-linux-arm64-musl": "4.47.1", "@rollup/rollup-linux-arm64-musl": "4.50.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.47.1", "@rollup/rollup-linux-loongarch64-gnu": "4.50.0",
"@rollup/rollup-linux-ppc64-gnu": "4.47.1", "@rollup/rollup-linux-ppc64-gnu": "4.50.0",
"@rollup/rollup-linux-riscv64-gnu": "4.47.1", "@rollup/rollup-linux-riscv64-gnu": "4.50.0",
"@rollup/rollup-linux-riscv64-musl": "4.47.1", "@rollup/rollup-linux-riscv64-musl": "4.50.0",
"@rollup/rollup-linux-s390x-gnu": "4.47.1", "@rollup/rollup-linux-s390x-gnu": "4.50.0",
"@rollup/rollup-linux-x64-gnu": "4.47.1", "@rollup/rollup-linux-x64-gnu": "4.50.0",
"@rollup/rollup-linux-x64-musl": "4.47.1", "@rollup/rollup-linux-x64-musl": "4.50.0",
"@rollup/rollup-win32-arm64-msvc": "4.47.1", "@rollup/rollup-openharmony-arm64": "4.50.0",
"@rollup/rollup-win32-ia32-msvc": "4.47.1", "@rollup/rollup-win32-arm64-msvc": "4.50.0",
"@rollup/rollup-win32-x64-msvc": "4.47.1", "@rollup/rollup-win32-ia32-msvc": "4.50.0",
"@rollup/rollup-win32-x64-msvc": "4.50.0",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@@ -10214,9 +10229,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.90.0", "version": "1.91.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz",
"integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", "integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -11005,13 +11020,17 @@
} }
}, },
"node_modules/tapable": { "node_modules/tapable": {
"version": "2.2.2", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz",
"integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
} }
}, },
"node_modules/terser": { "node_modules/terser": {
@@ -11527,9 +11546,9 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "7.1.3", "version": "7.1.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.4.tgz",
"integrity": "sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==", "integrity": "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View File

@@ -1,4 +1,25 @@
<?php <?php
/*
* index.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
use Illuminate\Contracts\Http\Kernel; use Illuminate\Contracts\Http\Kernel;

View File

@@ -107,7 +107,7 @@
"multi_account_warning_withdrawal": "Bedenken Sie, dass das Quellkonto nachfolgender Aufteilungen von dem, was in der ersten Aufteilung der Abhebung definiert ist, au\u00dfer Kraft gesetzt wird.", "multi_account_warning_withdrawal": "Bedenken Sie, dass das Quellkonto nachfolgender Aufteilungen von dem, was in der ersten Aufteilung der Abhebung definiert ist, au\u00dfer Kraft gesetzt wird.",
"multi_account_warning_deposit": "Bedenken Sie, dass das Zielkonto nachfolgender Aufteilungen von dem, was in der ersten Aufteilung der Einnahmen definiert ist, au\u00dfer Kraft gesetzt wird.", "multi_account_warning_deposit": "Bedenken Sie, dass das Zielkonto nachfolgender Aufteilungen von dem, was in der ersten Aufteilung der Einnahmen definiert ist, au\u00dfer Kraft gesetzt wird.",
"multi_account_warning_transfer": "Bedenken Sie, dass das Quell- und Zielkonto nachfolgender Aufteilungen durch das, was in der ersten Aufteilung der \u00dcbertragung definiert ist, au\u00dfer Kraft gesetzt wird.", "multi_account_warning_transfer": "Bedenken Sie, dass das Quell- und Zielkonto nachfolgender Aufteilungen durch das, was in der ersten Aufteilung der \u00dcbertragung definiert ist, au\u00dfer Kraft gesetzt wird.",
"webhook_trigger_ANY": "After any event", "webhook_trigger_ANY": "Nach jedem Ereignis",
"webhook_trigger_STORE_TRANSACTION": "Nach Erstellen einer Buchung", "webhook_trigger_STORE_TRANSACTION": "Nach Erstellen einer Buchung",
"webhook_trigger_UPDATE_TRANSACTION": "Nach Aktualisierung einer Buchung", "webhook_trigger_UPDATE_TRANSACTION": "Nach Aktualisierung einer Buchung",
"webhook_trigger_DESTROY_TRANSACTION": "Nach dem L\u00f6schen einer Buchung", "webhook_trigger_DESTROY_TRANSACTION": "Nach dem L\u00f6schen einer Buchung",
@@ -116,7 +116,7 @@
"webhook_trigger_DESTROY_BUDGET": "Nach dem L\u00f6schen des Budgets", "webhook_trigger_DESTROY_BUDGET": "Nach dem L\u00f6schen des Budgets",
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "Nach dem \u00c4ndern des budgetierten Betrags", "webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "Nach dem \u00c4ndern des budgetierten Betrags",
"webhook_response_TRANSACTIONS": "Buchungsdetails", "webhook_response_TRANSACTIONS": "Buchungsdetails",
"webhook_response_RELEVANT": "Relevant details", "webhook_response_RELEVANT": "Relevante Details",
"webhook_response_ACCOUNTS": "Kontodetails", "webhook_response_ACCOUNTS": "Kontodetails",
"webhook_response_NONE": "Keine Details", "webhook_response_NONE": "Keine Details",
"webhook_delivery_JSON": "JSON", "webhook_delivery_JSON": "JSON",

View File

@@ -107,7 +107,7 @@
"multi_account_warning_withdrawal": "Gardez en t\u00eate que le compte source des s\u00e9parations suivantes peut \u00eatre remplac\u00e9 par celui de la premi\u00e8re s\u00e9paration de la d\u00e9pense.", "multi_account_warning_withdrawal": "Gardez en t\u00eate que le compte source des s\u00e9parations suivantes peut \u00eatre remplac\u00e9 par celui de la premi\u00e8re s\u00e9paration de la d\u00e9pense.",
"multi_account_warning_deposit": "Gardez en t\u00eate que le compte de destination des s\u00e9parations suivantes peut \u00eatre remplac\u00e9 par celui de la premi\u00e8re s\u00e9paration du d\u00e9p\u00f4t.", "multi_account_warning_deposit": "Gardez en t\u00eate que le compte de destination des s\u00e9parations suivantes peut \u00eatre remplac\u00e9 par celui de la premi\u00e8re s\u00e9paration du d\u00e9p\u00f4t.",
"multi_account_warning_transfer": "Gardez en t\u00eate que les comptes source et de destination des s\u00e9parations suivantes peuvent \u00eatre remplac\u00e9s par ceux de la premi\u00e8re s\u00e9paration du transfert.", "multi_account_warning_transfer": "Gardez en t\u00eate que les comptes source et de destination des s\u00e9parations suivantes peuvent \u00eatre remplac\u00e9s par ceux de la premi\u00e8re s\u00e9paration du transfert.",
"webhook_trigger_ANY": "After any event", "webhook_trigger_ANY": "Apr\u00e8s n'importe quel \u00e9v\u00e9nement",
"webhook_trigger_STORE_TRANSACTION": "Apr\u00e8s la cr\u00e9ation de l'op\u00e9ration", "webhook_trigger_STORE_TRANSACTION": "Apr\u00e8s la cr\u00e9ation de l'op\u00e9ration",
"webhook_trigger_UPDATE_TRANSACTION": "Apr\u00e8s la mise \u00e0 jour de l'op\u00e9ration", "webhook_trigger_UPDATE_TRANSACTION": "Apr\u00e8s la mise \u00e0 jour de l'op\u00e9ration",
"webhook_trigger_DESTROY_TRANSACTION": "Apr\u00e8s la suppression de l'op\u00e9ration", "webhook_trigger_DESTROY_TRANSACTION": "Apr\u00e8s la suppression de l'op\u00e9ration",
@@ -116,7 +116,7 @@
"webhook_trigger_DESTROY_BUDGET": "Apr\u00e8s la suppression du budget", "webhook_trigger_DESTROY_BUDGET": "Apr\u00e8s la suppression du budget",
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "Apr\u00e8s le changement du montant budg\u00e9tis\u00e9", "webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "Apr\u00e8s le changement du montant budg\u00e9tis\u00e9",
"webhook_response_TRANSACTIONS": "D\u00e9tails de l'op\u00e9ration", "webhook_response_TRANSACTIONS": "D\u00e9tails de l'op\u00e9ration",
"webhook_response_RELEVANT": "Relevant details", "webhook_response_RELEVANT": "D\u00e9tails pertinents",
"webhook_response_ACCOUNTS": "D\u00e9tails du compte", "webhook_response_ACCOUNTS": "D\u00e9tails du compte",
"webhook_response_NONE": "Aucun d\u00e9tail", "webhook_response_NONE": "Aucun d\u00e9tail",
"webhook_delivery_JSON": "JSON", "webhook_delivery_JSON": "JSON",

View File

@@ -160,7 +160,7 @@
"url": "URL", "url": "URL",
"active": "Actief", "active": "Actief",
"interest_date": "Rentedatum", "interest_date": "Rentedatum",
"administration_currency": "Primary currency", "administration_currency": "Standaardvaluta",
"title": "Titel", "title": "Titel",
"date": "Datum", "date": "Datum",
"book_date": "Boekdatum", "book_date": "Boekdatum",
@@ -180,7 +180,7 @@
"list": { "list": {
"title": "Titel", "title": "Titel",
"active": "Actief?", "active": "Actief?",
"primary_currency": "Primary currency", "primary_currency": "Standaardvaluta",
"trigger": "Trigger", "trigger": "Trigger",
"response": "Reactie", "response": "Reactie",
"delivery": "Bericht", "delivery": "Bericht",

View File

@@ -3,8 +3,8 @@
"administrations_page_title": "Finan\u010dne administracije", "administrations_page_title": "Finan\u010dne administracije",
"administrations_index_menu": "Finan\u010dne administracije", "administrations_index_menu": "Finan\u010dne administracije",
"expires_at": "Pote\u010de ob", "expires_at": "Pote\u010de ob",
"temp_administrations_introduction": "Firefly III will soon get the ability to manage multiple financial administrations. Right now, you only have the one. You can set the title of this administration and its primary currency. This replaces the previous setting where you would set your \"default currency\". This setting is now tied to the financial administration and can be different per administration.", "temp_administrations_introduction": "Firefly III bo kmalu dobil mo\u017enost upravljanja ve\u010d finan\u010dnih administracij. Trenutno imate samo eno. Nastavite lahko naziv te administracije in njeno glavno valuto. To nadome\u0161\u010da prej\u0161njo nastavitev, kjer bi nastavili svojo \"privzeto valuto\". Ta nastavitev je zdaj vezana na finan\u010dno administracijo in se lahko razlikuje glede na administracijo.",
"administration_currency_form_help": "It may take a long time for the page to load if you change the primary currency because transaction may need to be converted to your (new) primary currency.", "administration_currency_form_help": "\u010ce spremenite doma\u010do valuto, lahko traja dolgo \u010dasa, da se stran nalo\u017ei, ker bo transakcijo morda treba pretvoriti v va\u0161o (novo) doma\u010do valuto.",
"administrations_page_edit_sub_title_js": "Uredi finan\u010dno administracijo \"{title}\"", "administrations_page_edit_sub_title_js": "Uredi finan\u010dno administracijo \"{title}\"",
"table": "Tabela", "table": "Tabela",
"welcome_back": "Kaj vse se dogaja?", "welcome_back": "Kaj vse se dogaja?",
@@ -102,23 +102,23 @@
"profile_oauth_client_secret_title": "Skrivna koda odjemalca", "profile_oauth_client_secret_title": "Skrivna koda odjemalca",
"profile_oauth_client_secret_expl": "Tukaj je skrivna koda va\u0161ega odjemalca. To je edini \u010das, da bo prikazana, zato je ne izgubite! Zdaj lahko uporabite to skrivno kodo za po\u0161iljanje zahtev API.", "profile_oauth_client_secret_expl": "Tukaj je skrivna koda va\u0161ega odjemalca. To je edini \u010das, da bo prikazana, zato je ne izgubite! Zdaj lahko uporabite to skrivno kodo za po\u0161iljanje zahtev API.",
"profile_oauth_confidential": "Zaupno", "profile_oauth_confidential": "Zaupno",
"profile_oauth_confidential_help": "Require the client to authenticate with a secret. Confidential clients can hold credentials in a secure way without exposing them to unauthorized parties. Public applications, such as native desktop or JavaScript SPA applications, are unable to hold secrets securely.", "profile_oauth_confidential_help": "Od odjemalca zahtevajte avtentikacijo s skrivno kodo. Zaupni odjemalci imajo lahko poverilnice na varen na\u010din, ne da bi jih izpostavili nepoobla\u0161\u010denim osebam. Javne aplikacije, kot so izvorne namizne aplikacije ali aplikacije JavaScript SPA, ne morejo varno hraniti skrivnih kod.",
"multi_account_warning_unknown": "Odvisno od vrste transakcije, ki jo ustvarite, lahko izvorni in\/ali ciljni ra\u010dun poznej\u0161ih razdelitev preglasi tisto, kar je definirano v prvi razdelitvi transakcije.", "multi_account_warning_unknown": "Odvisno od vrste transakcije, ki jo ustvarite, lahko izvorni in\/ali ciljni ra\u010dun poznej\u0161ih razdelitev preglasi tisto, kar je definirano v prvi razdelitvi transakcije.",
"multi_account_warning_withdrawal": "Upo\u0161tevajte, da bo izvorni ra\u010dun poznej\u0161ih razdelitev preglasilo tisto, kar je definirano v prvi razdelitvi odliva.", "multi_account_warning_withdrawal": "Upo\u0161tevajte, da bo izvorni ra\u010dun poznej\u0161ih razdelitev preglasilo tisto, kar je definirano v prvi razdelitvi odliva.",
"multi_account_warning_deposit": "Upo\u0161tevajte, da bo ciljni ra\u010dun poznej\u0161ih delitev preglasilo tisto, kar je opredeljeno v prvi delitvi priliva.", "multi_account_warning_deposit": "Upo\u0161tevajte, da bo ciljni ra\u010dun poznej\u0161ih delitev preglasilo tisto, kar je opredeljeno v prvi delitvi priliva.",
"multi_account_warning_transfer": "Upo\u0161tevajte, da bo izvorni + ciljni ra\u010dun poznej\u0161ih razdelitev preglasilo tisto, kar je definirano v prvi razdelitvi prenosa.", "multi_account_warning_transfer": "Upo\u0161tevajte, da bo izvorni + ciljni ra\u010dun poznej\u0161ih razdelitev preglasilo tisto, kar je definirano v prvi razdelitvi prenosa.",
"webhook_trigger_ANY": "After any event", "webhook_trigger_ANY": "Po katerem koli dogodku",
"webhook_trigger_STORE_TRANSACTION": "Po ustvarjanju transakcije", "webhook_trigger_STORE_TRANSACTION": "Po ustvarjanju transakcije",
"webhook_trigger_UPDATE_TRANSACTION": "Po posodabljanju transakcije", "webhook_trigger_UPDATE_TRANSACTION": "Po posodabljanju transakcije",
"webhook_trigger_DESTROY_TRANSACTION": "Po brisanju transakcije", "webhook_trigger_DESTROY_TRANSACTION": "Po brisanju transakcije",
"webhook_trigger_STORE_BUDGET": "After budget creation", "webhook_trigger_STORE_BUDGET": "Po izdelavi prora\u010duna",
"webhook_trigger_UPDATE_BUDGET": "After budget update", "webhook_trigger_UPDATE_BUDGET": "Po posodobitvi prora\u010duna",
"webhook_trigger_DESTROY_BUDGET": "After budget delete", "webhook_trigger_DESTROY_BUDGET": "Po izbrisu prora\u010duna",
"webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "After budgeted amount change", "webhook_trigger_STORE_UPDATE_BUDGET_LIMIT": "Po spremembi zneska v prora\u010dunu",
"webhook_response_TRANSACTIONS": "Podrobnosti transakcije", "webhook_response_TRANSACTIONS": "Podrobnosti transakcije",
"webhook_response_RELEVANT": "Relevant details", "webhook_response_RELEVANT": "Relevantni podatki",
"webhook_response_ACCOUNTS": "Podrobnosti ra\u010duna", "webhook_response_ACCOUNTS": "Podrobnosti ra\u010duna",
"webhook_response_NONE": "No details", "webhook_response_NONE": "Ni podrobnosti",
"webhook_delivery_JSON": "JSON", "webhook_delivery_JSON": "JSON",
"actions": "Dejanja", "actions": "Dejanja",
"meta_data": "Meta podatki", "meta_data": "Meta podatki",
@@ -160,7 +160,7 @@
"url": "URL", "url": "URL",
"active": "Aktivno", "active": "Aktivno",
"interest_date": "Datum obresti", "interest_date": "Datum obresti",
"administration_currency": "Primary currency", "administration_currency": "Primarna valuta",
"title": "Naslov", "title": "Naslov",
"date": "Datum", "date": "Datum",
"book_date": "Datum knji\u017eenja", "book_date": "Datum knji\u017eenja",
@@ -180,7 +180,7 @@
"list": { "list": {
"title": "Naslov", "title": "Naslov",
"active": "Aktiviran?", "active": "Aktiviran?",
"primary_currency": "Primary currency", "primary_currency": "Primarna valuta",
"trigger": "Spro\u017eilec", "trigger": "Spro\u017eilec",
"response": "Odziv", "response": "Odziv",
"delivery": "Dostava", "delivery": "Dostava",

View File

@@ -32,6 +32,7 @@ import {showWizardButton} from "../../support/page-settings/show-wizard-button.j
import {setVariable} from "../../store/set-variable.js"; import {setVariable} from "../../store/set-variable.js";
import {getVariables} from "../../store/get-variables.js"; import {getVariables} from "../../store/get-variables.js";
import pageNavigation from "../../support/page-navigation.js"; import pageNavigation from "../../support/page-navigation.js";
import {getVariable} from "../../store/get-variable.js";
// set type from URL // set type from URL
@@ -56,12 +57,12 @@ if(sortingColumn[0] === '-') {
page = parseInt(params.page ?? 1); page = parseInt(params.page ?? 1);
showInternalsButton(); showInternalsButton();
showWizardButton(); showWizardButton();
// TODO currency conversion // TODO currency conversion
// TODO page cleanup and recycle for transaction lists. // TODO page cleanup and recycle for transaction lists.
// TODO process startPeriod and endPeriod.
let index = function () { let index = function () {
return { return {
@@ -73,9 +74,9 @@ let index = function () {
show: false, text: '', url: '', show: false, text: '', url: '',
}, wait: { }, wait: {
show: false, text: '', show: false, text: '',
} }
}, },
convertToPrimary: false,
totalPages: 1, totalPages: 1,
page: 1, page: 1,
pageUrl: '', pageUrl: '',
@@ -259,6 +260,7 @@ let index = function () {
{name: this.getPreferenceKey('sd'), default: ''}, {name: this.getPreferenceKey('sd'), default: ''},
{name: this.getPreferenceKey('filters'), default: this.filters}, {name: this.getPreferenceKey('filters'), default: this.filters},
{name: this.getPreferenceKey('grouped'), default: true}, {name: this.getPreferenceKey('grouped'), default: true},
{name: 'convert_to_primary', default: false},
]).then((res) => { ]).then((res) => {
// process columns: // process columns:
for (let k in res[0]) { for (let k in res[0]) {
@@ -283,6 +285,9 @@ let index = function () {
// group accounts // group accounts
this.pageOptions.groupedAccounts = res[4]; this.pageOptions.groupedAccounts = res[4];
// convert to primary?
this.convertToPrimary = res[5];
this.loadAccounts(); this.loadAccounts();
}); });
}, },
@@ -348,7 +353,6 @@ let index = function () {
if('asc' === this.pageOptions.sortDirection && '' !== sorting) { if('asc' === this.pageOptions.sortDirection && '' !== sorting) {
sorting = '-' + sorting; sorting = '-' + sorting;
} }
//const sorting = [{column: this.pageOptions.sortingColumn, direction: this.pageOptions.sortDirection}];
// filter instructions // filter instructions
let filters = {}; let filters = {};
@@ -371,20 +375,20 @@ let index = function () {
sort: sorting, sort: sorting,
filter: filters, filter: filters,
active: active, active: active,
currentMoment: today, date: format(today,'yyyy-MM-dd'),
type: type, type: type,
page: this.page, page: this.page,
startPeriod: start, // startPeriod: start,
endPeriod: end // endPeriod: end
}; };
if (!this.tableColumns.balance_difference.enabled) { if (!this.tableColumns.balance_difference.enabled) {
delete params.startPeriod; // delete params.startPeriod;
delete params.endPeriod; // delete params.endPeriod;
} }
this.accounts = []; this.accounts = [];
let groupedAccounts = {}; let groupedAccounts = {};
// one page only.o // one page only
(new Get()).index(params).then(response => { (new Get()).index(params).then(response => {
this.totalPages = response.meta.pagination.total_pages; this.totalPages = response.meta.pagination.total_pages;
for (let i = 0; i < response.data.length; i++) { for (let i = 0; i < response.data.length; i++) {
@@ -406,9 +410,9 @@ let index = function () {
liability_direction: current.attributes.liability_direction, liability_direction: current.attributes.liability_direction,
interest: current.attributes.interest, interest: current.attributes.interest,
interest_period: current.attributes.interest_period, interest_period: current.attributes.interest_period,
balance: current.attributes.balance, // balance: current.attributes.balance,
pc_balance: current.attributes.pc_balance, // pc_balance: current.attributes.pc_balance,
balances: current.attributes.balances, // balances: current.attributes.balances,
}; };
// get group info: // get group info:
let groupId = current.attributes.object_group_id; let groupId = current.attributes.object_group_id;
@@ -426,10 +430,9 @@ let index = function () {
} }
} }
groupedAccounts[groupId].accounts.push(account); groupedAccounts[groupId].accounts.push(account);
}
}
//this.accounts.push(account);
}
}
// order grouped accounts by order. // order grouped accounts by order.
let sortable = []; let sortable = [];
for (let set in groupedAccounts) { for (let set in groupedAccounts) {

View File

@@ -119,6 +119,7 @@ return [
'between.file' => 'The :attribute must be between :min and :max kilobytes.', 'between.file' => 'The :attribute must be between :min and :max kilobytes.',
'between.string' => 'The :attribute must be between :min and :max characters.', 'between.string' => 'The :attribute must be between :min and :max characters.',
'between.array' => 'The :attribute must have between :min and :max items.', 'between.array' => 'The :attribute must have between :min and :max items.',
'between_date' => 'The date must be between the given start and end date.',
'boolean' => 'The :attribute field must be true or false.', 'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.', 'confirmed' => 'The :attribute confirmation does not match.',
'date' => 'The :attribute is not a valid date.', 'date' => 'The :attribute is not a valid date.',

View File

@@ -68,7 +68,7 @@
> >
~ {{ formatAmountBySymbol((entry.amount_max + entry.amount_min)/2, entry.currency_symbol, entry.currency_decimal_places) }} ~ {{ formatAmountBySymbol((entry.amount_max + entry.amount_min)/2, entry.currency_symbol, entry.currency_decimal_places) }}
{% if '0' != entry.pc_amount_max %} {% if '0' != entry.pc_amount_max and null != entry.pc_amount_max %}
(~ {{ formatAmountBySymbol((entry.pc_amount_max + entry.pc_amount_min)/2, primaryCurrency.symbol, primaryCurrency.decimal_places) }}) (~ {{ formatAmountBySymbol((entry.pc_amount_max + entry.pc_amount_min)/2, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% endif %} {% endif %}
</span> </span>

View File

@@ -24,8 +24,6 @@
</p> </p>
<div class="row"> <div class="row">
<div class="col-lg-6 col-md-8 col-sm-12 col-xs-12"> <div class="col-lg-6 col-md-8 col-sm-12 col-xs-12">
{{ ExpandedForm.date('start', first) }}
{{ ExpandedForm.date('end', today) }}
{{ AccountForm.assetAccountCheckList('accounts', {'select_all': true,'class': 'account-checkbox', 'label': trans('firefly.include_transactions_from_accounts') }) }} {{ AccountForm.assetAccountCheckList('accounts', {'select_all': true,'class': 'account-checkbox', 'label': trans('firefly.include_transactions_from_accounts') }) }}
</div> </div>
</div> </div>

View File

@@ -23,8 +23,6 @@
</p> </p>
<div class="row"> <div class="row">
<div class="col-lg-6 col-md-8 col-sm-12 col-xs-12"> <div class="col-lg-6 col-md-8 col-sm-12 col-xs-12">
{{ ExpandedForm.date('start', first) }}
{{ ExpandedForm.date('end', today) }}
{{ AccountForm.assetAccountCheckList('accounts', {'select_all': true, 'class': 'account-checkbox', 'label': trans('firefly.include_transactions_from_accounts') }) }} {{ AccountForm.assetAccountCheckList('accounts', {'select_all': true, 'class': 'account-checkbox', 'label': trans('firefly.include_transactions_from_accounts') }) }}
</div> </div>
</div> </div>

View File

@@ -160,12 +160,13 @@
<td> <td>
{% for amount in amounts %} {% for amount in amounts %}
{% if first.transaction_type_type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
{% elseif first.transaction_type_type == 'Deposit' %}
{{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %} {{ formatAmountBySymbol(amount.amount,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
{% elseif first.transaction_type_type == 'Deposit' %}
{{ formatAmountBySymbol(amount.amount*-1,amount.symbol, amount.decimal_places) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
{% elseif first.transaction_type_type == 'Transfer' %} {% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
{{ formatAmountBySymbol(amount.amount, amount.symbol, amount.decimal_places, false) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
{{ formatAmountBySymbol(amount.amount*-1, amount.symbol, amount.decimal_places, false) }}{% if loop.index0 != amounts|length -1 %}, {% endif %}
</span> </span>
{% elseif first.transaction_type_type == 'Opening balance' %} {% elseif first.transaction_type_type == 'Opening balance' %}
{# Opening balance stored amount is always negative: find out which way the money goes #} {# Opening balance stored amount is always negative: find out which way the money goes #}
@@ -289,7 +290,6 @@
<table class="table"> <table class="table">
<tr> <tr>
<td colspan="2"> <td colspan="2">
<!-- type is: "{{ first.transaction_type_type }}" -->
{% if 'Cash account' == journal.source_account_type %} {% if 'Cash account' == journal.source_account_type %}
<span class="text-success">({{ 'cash'|_ }})</span> <span class="text-success">({{ 'cash'|_ }})</span>
{% else %} {% else %}
@@ -298,12 +298,12 @@
{% endif %} {% endif %}
{% if first.transaction_type_type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places) }}
{% elseif first.transaction_type_type == 'Deposit' %}
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places) }} {{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places) }}
{% elseif first.transaction_type_type == 'Deposit' %}
{{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places) }}
{% elseif first.transaction_type_type == 'Transfer' or first.transaction_type_type == 'Opening balance' %} {% elseif first.transaction_type_type == 'Transfer' or first.transaction_type_type == 'Opening balance' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places, false) }} {{ formatAmountBySymbol(journal.amount*-1, journal.currency_symbol, journal.currency_decimal_places, false) }}
</span> </span>
{% elseif first.transaction_type_type == 'Liability credit' %} {% elseif first.transaction_type_type == 'Liability credit' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
@@ -314,12 +314,12 @@
<!-- do primary currency amount --> <!-- do primary currency amount -->
{% if null != journal.pc_amount and primaryCurrency.id != journal.currency_id %} {% if null != journal.pc_amount and primaryCurrency.id != journal.currency_id %}
{% if first.transaction_type_type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
({{ formatAmountBySymbol(journal.pc_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }}) ({{ formatAmountBySymbol(journal.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.pc_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Transfer' %} {% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
({{ formatAmountBySymbol(journal.pc_amount, primaryCurrency.symbol, primaryCurrency.decimal_places, false) }}) ({{ formatAmountBySymbol(journal.pc_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places, false) }})
</span> </span>
{% endif %} {% endif %}
{% endif %} {% endif %}
@@ -327,12 +327,12 @@
<!-- do foreign amount --> <!-- do foreign amount -->
{% if null != journal.foreign_amount %} {% if null != journal.foreign_amount %}
{% if first.transaction_type_type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }}) ({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})
{% elseif first.transaction_type_type == 'Transfer' %} {% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places, false) }}) ({{ formatAmountBySymbol(journal.foreign_amount*-1, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places, false) }})
</span> </span>
{% endif %} {% endif %}
{% endif %} {% endif %}
@@ -340,12 +340,12 @@
<!-- do foreign PC amount --> <!-- do foreign PC amount -->
{% if null != journal.pc_foreign_amount %} {% if null != journal.pc_foreign_amount %}
{% if first.transaction_type_type == 'Withdrawal' %} {% if first.transaction_type_type == 'Withdrawal' %}
({{ formatAmountBySymbol(journal.pc_foreign_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.pc_foreign_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }}) ({{ formatAmountBySymbol(journal.pc_foreign_amount, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Deposit' %}
({{ formatAmountBySymbol(journal.pc_foreign_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places) }})
{% elseif first.transaction_type_type == 'Transfer' %} {% elseif first.transaction_type_type == 'Transfer' %}
<span class="text-info money-transfer"> <span class="text-info money-transfer">
({{ formatAmountBySymbol(journal.pc_foreign_amount, primaryCurrency.symbol, primaryCurrency.decimal_places, false) }}) ({{ formatAmountBySymbol(journal.pc_foreign_amount*-1, primaryCurrency.symbol, primaryCurrency.decimal_places, false) }})
</span> </span>
{% endif %} {% endif %}
{% endif %} {% endif %}
@@ -441,7 +441,7 @@
<td> <td>
{% for tag in journal.tags %} {% for tag in journal.tags %}
<h4 style="display: inline;"><a class="label label-success" <h4 style="display: inline;"><a class="label label-success"
href="{{ route('tags.show', tag.id) }}"> href="{{ route('tags.show', [tag.id]) }}">
<span class="fa fa-fw fa-tag"></span>{{ tag.tag }}</a> <span class="fa fa-fw fa-tag"></span>{{ tag.tag }}</a>
</h4> </h4>
{% endfor %} {% endfor %}

View File

@@ -10,7 +10,7 @@
<h3 class="card-title">{{ __('firefly.net_worth') }}</h3> <h3 class="card-title">{{ __('firefly.net_worth') }}</h3>
</div> </div>
<div class="card-body"> <div class="card-body">
TODO Not yet implemented.
</div> </div>
</div> </div>
</div> </div>
@@ -20,17 +20,17 @@
<h3 class="card-title">{{ __('firefly.in_out_period') }}</h3> <h3 class="card-title">{{ __('firefly.in_out_period') }}</h3>
</div> </div>
<div class="card-body"> <div class="card-body">
TODO Not yet implemented.
</div> </div>
</div> </div>
</div> </div>
<div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-xs-12"> <div class="col-xl-4 col-lg-6 col-md-12 col-sm-12 col-xs-12">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h3 class="card-title">TODO</h3> <h3 class="card-title">Not yet implemented.</h3>
</div> </div>
<div class="card-body"> <div class="card-body">
TODO Not yet implemented.
</div> </div>
</div> </div>
</div> </div>
@@ -262,17 +262,14 @@
</template> </template>
</td> </td>
<td x-show="tableColumns.current_balance.visible && tableColumns.current_balance.enabled"> <td x-show="tableColumns.current_balance.visible && tableColumns.current_balance.enabled">
<template x-if="null !== account.balance"> <span x-show="parseFloat(account.current_balance) < 0.0" class="text-danger"
<template x-for="balance in account.balance"> x-text="formatMoney(account.current_balance, account.currency_code)"></span>
<span> <span x-show="parseFloat(account.current_balance) === 0.0" class="text-muted"
<span x-show="parseFloat(balance.balance) < 0.0" class="text-danger" x-text="formatMoney(account.current_balance, account.currency_code)"></span>
x-text="formatMoney(balance.balance, balance.currency_code)"></span> <span x-show="parseFloat(account.current_balance) > 0.0" class="text-success"
<span x-show="parseFloat(balance.balance) === 0.0" class="text-muted" x-text="formatMoney(account.current_balance, account.currency_code)"></span>
x-text="formatMoney(balance.balance, balance.currency_code)"></span> <template x-if="null !== account.pc_current_balance">
<span x-show="parseFloat(balance.balance) > 0.0" class="text-success" <span>PC current balance TODO.</span>
x-text="formatMoney(balance.balance, balance.currency_code)"></span>
</span>
</template>
</template> </template>
</td> </td>
<td x-show="tableColumns.amount_due.visible && tableColumns.amount_due.enabled"> <td x-show="tableColumns.amount_due.visible && tableColumns.amount_due.enabled">

View File

@@ -75,7 +75,7 @@
<ul class="list-unstyled list-no-margin"> <ul class="list-unstyled list-no-margin">
<template x-for="transaction in group.transactions"> <template x-for="transaction in group.transactions">
<li> <li>
@include('partials.elements.amount', ['convertToPrimary' => true,'type' => 'transaction.type','amount' => 'transaction.amount','primary' => 'transaction.amount']) @include('partials.elements.amount', ['convertToPrimary' => $convertToPrimary,'type' => 'transaction.type','amount' => 'transaction.amount', 'primary' => 'transaction.pc_amount'])
</li> </li>
</template> </template>
</ul> </ul>

View File

@@ -57,11 +57,21 @@
</template> </template>
@else @else
<template x-if="{{ $amount }}_raw < 0"> <template x-if="{{ $amount }}_raw < 0">
<span>
<template x-if="'transfer' === {{ $type }}">
<span class="text-primary">
<span x-text="{{ $amount }}"></span>
</span>
</template>
<template x-if="'transfer' !== {{ $type }}">
<span class="text-danger"> <span class="text-danger">
<span x-text="{{ $amount }}"></span> <span x-text="{{ $amount }}"></span>
</span> </span>
</template> </template>
</span>
</template>
<template x-if="{{ $amount }}_raw >= 0"> <template x-if="{{ $amount }}_raw >= 0">
<span>
<template x-if="'transfer' === {{ $type }}"> <template x-if="'transfer' === {{ $type }}">
<span class="text-primary"> <span class="text-primary">
<span x-text="{{ $amount }}"></span> <span x-text="{{ $amount }}"></span>
@@ -72,5 +82,6 @@
<span x-text="{{ $amount }}"></span> <span x-text="{{ $amount }}"></span>
</span> </span>
</template> </template>
</span>
</template> </template>
@endif @endif

View File

@@ -48,6 +48,7 @@ Route::group(
// Auto complete routes // Auto complete routes
Route::get('accounts', ['uses' => 'AccountController@accounts', 'as' => 'accounts']); Route::get('accounts', ['uses' => 'AccountController@accounts', 'as' => 'accounts']);
Route::get('bills', ['uses' => 'BillController@bills', 'as' => 'bills']); Route::get('bills', ['uses' => 'BillController@bills', 'as' => 'bills']);
Route::get('subscriptions', ['uses' => 'BillController@bills', 'as' => 'subscriptions']);
Route::get('budgets', ['uses' => 'BudgetController@budgets', 'as' => 'budgets']); Route::get('budgets', ['uses' => 'BudgetController@budgets', 'as' => 'budgets']);
Route::get('categories', ['uses' => 'CategoryController@categories', 'as' => 'categories']); Route::get('categories', ['uses' => 'CategoryController@categories', 'as' => 'categories']);
Route::get('currencies', ['uses' => 'CurrencyController@currencies', 'as' => 'currencies']); Route::get('currencies', ['uses' => 'CurrencyController@currencies', 'as' => 'currencies']);
@@ -504,6 +505,7 @@ Route::group(
Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']); Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']);
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']); Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
Route::get('{recurrence}', ['uses' => 'ShowController@show', 'as' => 'show']); Route::get('{recurrence}', ['uses' => 'ShowController@show', 'as' => 'show']);
Route::post('{recurrence}/trigger', ['uses' => 'TriggerController@trigger', 'as' => 'trigger']);
Route::put('{recurrence}', ['uses' => 'UpdateController@update', 'as' => 'update']); Route::put('{recurrence}', ['uses' => 'UpdateController@update', 'as' => 'update']);
Route::delete('{recurrence}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']); Route::delete('{recurrence}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);

View File

@@ -0,0 +1,147 @@
<?php
/*
* BillControllerTest.php
* Copyright (c) 2024 tasnim0tantawi
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace Tests\integration\Api\Autocomplete;
use FireflyIII\Models\Recurrence;
use FireflyIII\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* Class BillControllerTest
*
* @internal
*
* @coversNothing
*/
final class RecurrenceControllerTest extends TestCase
{
/**
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\RecurrenceController
*/
use RefreshDatabase;
private function createTestRecurrences(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {
$recurrence = Recurrence::create([
'user_id' => $user->id,
'user_group_id' => $user->user_group_id,
'transaction_type_id' => 1,
'title' => 'Recurrence '.$i,
'description' => 'Recurrence '.$i,
'first_date' => today(),
'apply_rules' => 1,
'active' => 1,
'repetitions' => 5,
]);
}
}
public function testUnAuthenticatedCall(): void
{
// test API
$response = $this->get(route('api.v1.autocomplete.recurring'), ['Accept' => 'application/json']);
$response->assertStatus(401);
$response->assertHeader('Content-Type', 'application/json');
$response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}');
}
public function testAuthenticatedCall(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$response = $this->get(route('api.v1.autocomplete.recurring'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWithItems(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRecurrences(5, $user);
$response = $this->get(route('api.v1.autocomplete.recurring'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(5);
$response->assertJsonFragment(['name' => 'Recurrence 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'active',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLimited(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRecurrences(5, $user);
$response = $this->get(route('api.v1.autocomplete.recurring', [
'query' => 'Recurrence',
'limit' => 3,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(3);
$response->assertJsonFragment(['name' => 'Recurrence 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'active',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLots(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRecurrences(20, $user);
$response = $this->get(route('api.v1.autocomplete.recurring', [
'query' => 'Recurrence 1',
'limit' => 20,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
// Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
$response->assertJsonCount(11);
$response->assertJsonMissing(['name' => 'Recurrence 2']);
}
}

View File

@@ -0,0 +1,156 @@
<?php
/*
* BillControllerTest.php
* Copyright (c) 2024 tasnim0tantawi
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace Tests\integration\Api\Autocomplete;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleGroup;
use FireflyIII\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* @internal
*
* @coversNothing
*/
final class RuleControllerTest extends TestCase
{
/**
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\RecurrenceController
*/
use RefreshDatabase;
private function createTestRules(int $count, User $user): void
{
$ruleGroup = RuleGroup::create(
[
'user_id' => $user->id,
'user_group_id' => $user->user_group_id,
'title' => 'RuleGroup 1',
'description' => 'RuleGroup 1',
'order' => 1,
'active' => 1,
'stop_processing' => 0,
]
);
for ($i = 1; $i <= $count; ++$i) {
$rule = Rule::create([
'user_id' => $user->id,
'user_group_id' => $user->user_group_id,
'rule_group_id' => $ruleGroup->id,
'title' => 'Rule '.$i,
'description' => 'Rule '.$i,
'order' => 1,
'active' => 1,
'stop_processing' => 0,
'strict' => 0,
]);
}
}
public function testUnauthenticatedCall(): void
{
// test API
$response = $this->get(route('api.v1.autocomplete.rules'), ['Accept' => 'application/json']);
$response->assertStatus(401);
$response->assertHeader('Content-Type', 'application/json');
$response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}');
}
public function testAuthenticatedCall(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$response = $this->get(route('api.v1.autocomplete.rules'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWithItems(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRules(5, $user);
$response = $this->get(route('api.v1.autocomplete.rules'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(5);
$response->assertJsonFragment(['name' => 'Rule 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'active',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLimited(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRules(5, $user);
$response = $this->get(route('api.v1.autocomplete.rules', [
'query' => 'Rule',
'limit' => 3,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(3);
$response->assertJsonFragment(['name' => 'Rule 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'active',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLots(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRules(20, $user);
$response = $this->get(route('api.v1.autocomplete.rules', [
'query' => 'Rule 1',
'limit' => 20,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
// Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
$response->assertJsonCount(11);
$response->assertJsonMissing(['name' => 'Rule 2']);
}
}

View File

@@ -0,0 +1,145 @@
<?php
/*
* BillControllerTest.php
* Copyright (c) 2024 tasnim0tantawi
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace Tests\integration\Api\Autocomplete;
use FireflyIII\Models\RuleGroup;
use FireflyIII\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* @internal
*
* @coversNothing
*/
final class RuleGroupControllerTest extends TestCase
{
/**
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\RecurrenceController
*/
use RefreshDatabase;
private function createTestRuleGroups(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {
$ruleGroup = RuleGroup::create(
[
'user_id' => $user->id,
'user_group_id' => $user->user_group_id,
'title' => 'RuleGroup '.$i,
'description' => 'RuleGroup '.$i,
'order' => 1,
'active' => 1,
'stop_processing' => 0,
]
);
}
}
public function testUnauthenticatedCall(): void
{
// test API
$response = $this->get(route('api.v1.autocomplete.rule-groups'), ['Accept' => 'application/json']);
$response->assertStatus(401);
$response->assertHeader('Content-Type', 'application/json');
$response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}');
}
public function testAuthenticatedCall(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$response = $this->get(route('api.v1.autocomplete.rule-groups'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWithItems(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRuleGroups(5, $user);
$response = $this->get(route('api.v1.autocomplete.rule-groups'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(5);
$response->assertJsonFragment(['name' => 'RuleGroup 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'active',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLimited(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRuleGroups(5, $user);
$response = $this->get(route('api.v1.autocomplete.rule-groups', [
'query' => 'RuleGroup',
'limit' => 3,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(3);
$response->assertJsonFragment(['name' => 'RuleGroup 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'active',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLots(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestRuleGroups(20, $user);
$response = $this->get(route('api.v1.autocomplete.rule-groups', [
'query' => 'RuleGroup 1',
'limit' => 20,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
// Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
$response->assertJsonCount(11);
$response->assertJsonMissing(['name' => 'RuleGroup 2']);
}
}

View File

@@ -0,0 +1,142 @@
<?php
/*
* BillControllerTest.php
* Copyright (c) 2024 tasnim0tantawi
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace Tests\integration\Api\Autocomplete;
use FireflyIII\Models\Tag;
use FireflyIII\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\integration\TestCase;
/**
* @internal
*
* @coversNothing
*/
final class TagControllerTest extends TestCase
{
/**
* @covers \FireflyIII\Api\V1\Controllers\Autocomplete\RecurrenceController
*/
use RefreshDatabase;
private function createTestTags(int $count, User $user): void
{
for ($i = 1; $i <= $count; ++$i) {
$tag = Tag::create(
[
'user_id' => $user->id,
'user_group_id' => $user->user_group_id,
'tag' => 'Tag '.$i,
'tag_mode' => 'nothing',
]
);
}
}
public function testUnauthenticatedCall(): void
{
// test API
$response = $this->get(route('api.v1.autocomplete.tags'), ['Accept' => 'application/json']);
$response->assertStatus(401);
$response->assertHeader('Content-Type', 'application/json');
$response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}');
}
public function testAuthenticatedCall(): void
{
// act as a user
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$response = $this->get(route('api.v1.autocomplete.tags'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
}
public function testGivenAuthenticatedRequestWithItems(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestTags(5, $user);
$response = $this->get(route('api.v1.autocomplete.tags'), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(5);
$response->assertJsonFragment(['name' => 'Tag 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'tag',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLimited(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestTags(5, $user);
$response = $this->get(route('api.v1.autocomplete.tags', [
'query' => 'Tag',
'limit' => 3,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
$response->assertJsonCount(3);
$response->assertJsonFragment(['name' => 'Tag 1']);
$response->assertJsonStructure([
'*' => [
'id',
'name',
'tag',
],
]);
}
public function testGivenAuthenticatedRequestWithItemsLots(): void
{
$user = $this->createAuthenticatedUser();
$this->actingAs($user);
$this->createTestTags(20, $user);
$response = $this->get(route('api.v1.autocomplete.tags', [
'query' => 'Tag 1',
'limit' => 20,
]), ['Accept' => 'application/json']);
$response->assertStatus(200);
$response->assertHeader('Content-Type', 'application/json');
// Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11)
$response->assertJsonCount(11);
$response->assertJsonMissing(['name' => 'Tag 2']);
}
}

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* AccountControllerTest.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace Tests\integration\Api\Chart; namespace Tests\integration\Api\Chart;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* BalanceControllerTest.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace Tests\integration\Api\Chart; namespace Tests\integration\Api\Chart;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* BudgetControllerTest.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace Tests\integration\Api\Chart; namespace Tests\integration\Api\Chart;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* CategoryControllerTest.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace Tests\integration\Api\Chart; namespace Tests\integration\Api\Chart;

View File

@@ -22,7 +22,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace Tests\integration\Api\About; namespace Tests\integration\Api\System;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Testing\Fluent\AssertableJson; use Illuminate\Testing\Fluent\AssertableJson;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* AbstractQueryParserInterfaceParseQueryTester.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace Tests\unit\Support\Search\QueryParser; namespace Tests\unit\Support\Search\QueryParser;

View File

@@ -1,5 +1,26 @@
<?php <?php
/*
* QueryParserParseQueryTest.php
* Copyright (c) 2025 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1); declare(strict_types=1);
namespace Tests\unit\Support\Search\QueryParser; namespace Tests\unit\Support\Search\QueryParser;